RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

[RunUO 2.0 RC1] XmlSpawner2

Status
Not open for further replies.
I am having troublke saving spawns, it says its saving them, then my client disconnects, and there is no file with the filename. Is it just overworked and not ablke to do it or is this a bug?
 

ArteGordon

Wanderer
Anti-Basic said:
I am having troublke saving spawns, it says its saving them, then my client disconnects, and there is no file with the filename. Is it just overworked and not ablke to do it or is this a bug?

What is the actual command line that you are using?

Do you see the messages indicating the individual spawners being saved?

It is possible that the status messages displayed while the spawners are being saved is causing the client disconnect. This can happen with long strings being displayed. Do you have any spawners with very long names?

(edit)

you can also change the saves so that they are not so verbose by making this change in xmlspawner2.cs around line 6680
Code:
			// save the list
			SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, [color=red]false[/color]);

I think that I will just make this the default in the next version and then provide a -verbose flag that you can use if you really want to see each individual spawner being reported as it is saved.
 

milkman_dan

Wanderer
Is there a global command to set all Xmlspawners to despawn after say 2 minutes if no players are around?

Id like for em to basically not spawn anything unless a player shows up
 
ArteGordon said:
What is the actual command line that you are using?

Do you see the messages indicating the individual spawners being saved?

It is possible that the status messages displayed while the spawners are being saved is causing the client disconnect. This can happen with long strings being displayed. Do you have any spawners with very long names?

(edit)

you can also change the saves so that they are not so verbose by making this change in xmlspawner2.cs around line 6680
Code:
			// save the list
			SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, [color=red]false[/color]);

I think that I will just make this the default in the next version and then provide a -verbose flag that you can use if you really want to see each individual spawner being reported as it is saved.
Aye I saw the messages (the ones before I disconn) and got some long one, I imported neruns and some reagent msfs into it and some of them have long names. Will try that edit, I had a feeling it was something like that and not an actual bug, I often get disconn using addon generator or UOAR, So I figured it might be the same sorta thing except with text instead of items. I need a better conn lol

@milkman dan, your sig is annoying and in violation of the rules, please change it, ty.
 

ArteGordon

Wanderer
milkman_dan said:
Is there a global command to set all Xmlspawners to despawn after say 2 minutes if no players are around?

Id like for em to basically not spawn anything unless a player shows up

Just configure them for smartspawning. That is exactly what it does.

Just use this command to quickly configure all of your spawners

[optimalsmartspawning

It will automatically select the spawners that it thinks are good candidates, and will ignore those like vendor spawners, or triggered spawners, that it thinks shouldnt be smartspawned.

If you want it to include more spawners then use a command like

[optimalsmartspawning 100

where 100 indicates that maximum difference between the spawnrange and the homerange that it will allow when selecting spawners for smartspawning. It is purely a cosmetic thing so you can enter any number you like. It is just that when spawners that have a big difference between spawn and home range respawn, you will be able to tell the difference between the mob distributions before and after respawning (since with a larger homerange, the spawns could have wandered well beyond the spawnrange before respawning)

If you actually wanted to force all of the spawners (including things like vendor spawners) to smartspawn, you could do

[global set smartspawning true where xmlspawner

But the [optimalsmartspawning command will give you much better results.
 

milkman_dan

Wanderer
ArteGordon said:
Just configure them for smartspawning. That is exactly what it does.

Just use this command to quickly configure all of your spawners

[optimalsmartspawning

It will automatically select the spawners that it thinks are good candidates, and will ignore those like vendor spawners, or triggered spawners, that it thinks shouldnt be smartspawned.

If you want it to include more spawners then use a command like

[optimalsmartspawning 100

where 100 indicates that maximum difference between the spawnrange and the homerange that it will allow when selecting spawners for smartspawning. It is purely a cosmetic thing so you can enter any number you like. It is just that when spawners that have a big difference between spawn and home range respawn, you will be able to tell the difference between the mob distributions before and after respawning (since with a larger homerange, the spawns could have wandered well beyond the spawnrange before respawning)

If you actually wanted to force all of the spawners (including things like vendor spawners) to smartspawn, you could do

[global set smartspawning true where xmlspawner

But the [optimalsmartspawning command will give you much better results.

Thanks artie.

I used [optimalsmartspawning

It reduced my Item/mobile counts from 115000/ 3000

Down to 89000/2400 which is a huge difference. And thats with a complete transformation of Neruns distro, plus my Peerless Maps etc.. all spawned hehe
you rock!!
 

ArteGordon

Wanderer
you can also use the [smartstat command to give you more information about spawner counts and smartspawning performance.
 

ArteGordon

Wanderer
updated to version 3.14

from the changelog

updated to RunUO 2.0 version 3.14

New to version 3.14
updated 8/13/06

Bug Fixes
- modified the spawner Reset function to properly reset the refractory period for triggered spawners if that was set (thanks to Vladimir for pointing that out).

- fixed a possible crash bug with the playermade questholder editing gump (thanks to Auriel for pointing it out).

- fixed a problem with MinD, MaxD, or Rng values for individual spawn entries being inappropriately cleared when editing an entry string with the text entry book.

- modified the ASCIIMSG keyword to deal with text sometimes not being visible to all nearby players (thanks to aph for pointing this out).

- modified the way xmlspawners keep themselves from being included in container item counts to fix an issue with negative counts under RunUO 2.0 (thanks to haazen for pointing this out).

- fixed a crash bug with xmlfind when using an invalid region (thanks to seirge for pointing this out).

- fixed a possible crash bug with improperly formatted TriggerOnCarried strings (thanks to XavierWER for pointing this out).

- fixed a problem with the Repeatable flag on quests not being restored across restarts when set to false (thanks to Vladimir for pointing this out). This led to people sometimes being able to repeat non-repeatable quests.

Modified Features
- made the SENDMSG and SENDASCIIMSG keywords usable as value type keywords and not just standalone keywords. so you can do things like

SETONNEARBY,5,,playermobile/SENDMSG/Greetings friends

to send messages to all nearby players (thanks to snicker7 for the suggestion).

The syntax for these keywords is

SENDMSG[,probability][,hue]/message text
SENDASCIIMSG[,probability][,hue][,font]/message text

- modified questholders to prevent snooping by other players, but allow staff to open the questholder status gump from questholders being carried by players (thanks to snicker7 for the suggestion).

- modified the way that the DAMAGE and POISON keywords work when used as value keywords.
Now, if they are used to modify a spawn object, then their effects will be applied to the spawn object, and if a range argument is used, then things within that range from the spawn object will be affected. (thanks to aph for the suggestion)
For example this spawn entry would apply damage to all players within 5 tiles of the mob named "Blather"

SETONMOB,Blather/DAMAGE,50,20,20,20,20,20,5,playeronly

Their behavior when used as standalone keywords was not changed.

- added protection against creating infinitely looping sequential spawn definitions. Spawn entries can now only be executed once per spawner tick.

New Features
-added the new standalone keyword "SPAWN[,spawnername],subgroup" which can be used to force spawning of a particular subgroup on a particular spawner. If the spawnername arg is omitted, then the current spawner will be used.

- added a TYPE property keyword that returns the object class type. For example "GETONTRIGMOB,TYPE" would return the type of the triggering mob.

- added support for the core ISpawner interface. This now means that all items/mobiles keep track of the xmlspawner that created them through their Spawner property.
Deleted/killed spawns are now immediately removed from the spawned list instead of having to wait until the next spawner tick. When monitoring kills, this means that the spawner killcount will be updated as soon as the kills occur.

- added the new #WET and #TILES,startid[,endid] spawn control keywords. These allow you to restrict the land/static tiles that the spawns for an entry will be placed on. This works for both normal and regional spawning. Only tiles that have been frozen into the map will be checked. It will not check for static items or multis that have simply been placed in the world.
Use of either of these keywords will automatically ignore surface restrictions during spawn placement (like using * in front of the entry).
You can determine the id of a tile by simply doing a [props on it and looking at the TileID for land targets, and ItemID for static targets. You can specify a single tile or a range of tiles to be included.
The example below has 5 spawn entries.
The first uses the #WET keyword to specify that the waterelemental spawns should only be placed on tiles that have the Wet tiledata flag set (water tiles).
The second entry uses the #TILES keyword to specify that the orcs should only be spawned on dirt tiles with ids between 113-120.
The third entry has trolls that are only spawned on a variety of grass tiles.
The dolphins spawn only on water tiles with an id of 6044.
The fifth entry spawns eagles on tree tiles with id 3296.

 

ArteGordon

Wanderer
a quick update to v3.14a

from the changelog

New to version 3.14a
updated 8/13/06

Bug Fixes
- a quick fix for a possible crash bug when using region spawning with certain custom regions. Only xmlspawner2.cs in XmlSpawner2-20-v314a-1of3.zip needs updating if you had v3.14 installed.
 

Zaknafrien

Wanderer
um i had this problem, anyhelp?

Errors:
+ Custom/XMLSpawner/XmlSpawner2.cs:
CS0029: Line 9304: Cannot implicitly convert type 'System.Collections.ArrayL
ist' to 'System.Collections.Generic.List<Server.Tile>'

EDIT: sorry didnt see the other post about this , thank you anyway, dont criticize me im very tried and have to go to work
 

ArteGordon

Wanderer
updated to version 3.15

from the changelog

New to version 3.15
Bug Fixes
- modified the [WriteMulti command to support staff names that have spaces in them when accessing files (thanks to Xavier_WER for the suggestion).

- fixed a problem that was introduced in v3.14 with the addition of ISpawner support in which [xmlhome would not be able to find the home spawner of a creature after a restart. I had incorrectly assumed that the Spawner information on items/mobiles was being serialized and it isnt. Now initialization code has been added to restore Spawner information after restarts.

Modified Features
- modified XmlSpawnerGumps.cs to accomodate changes to Gump handling introduced in SVN rev 78 of the RunUO server. This should allow you to compile with the latest version of the server and should also work with pre-78 servers.

- custom regions that get registered after initialization will now be detected and can be used by region spawners.

- added support for assigning a mobile used to allow spawners to issue commands using the "COMMAND/commandstring" keyword by assigning the name of the mobile in the static CommandMobileName variable at line 341 in basexmlspawner.cs.
Commands in RunUO are required to have a mobile associated with their execution to allow accesslevel verification. This mobile will be used to issue all commands executed with the COMMAND keyword. The accesslevel of the mobile will determine the commands that can be issued.

This mobile can be a dummy character/creature that was created just for this purpose, or an existing character.
The commandstring is any string that you would normally type on the command line (without the command prefix).

Code:
        private static string CommandMobileName = null;

If the value is left null, then the COMMAND keyword will only work with triggered spawners when the triggering player has sufficient accesslevel to issue the command.

- modified random subgroup spawning. Subgroups that cannot be completely spawned will not be selected for random spawning. All spawn entries in the subgroup have to be below their individual maxcount, and fully spawning the subgroup cannot exceed the overall spawner maxcount. Previously those subgroups would simply spawn the entries of the subgroup that could be spawned.
This will apply to both random and sequential spawning but note that forced subgroup spawning, as part of a conditional statement, for example, will still allow partial spawning of the target subgroup.


New Features
- added the new #NOTILES,startid[,endid] spawn control keyword. This is similar to the #TILES keyword, but it allows you to specify the land/static tiles that the spawns for an entry will NOT be placed on. Only passable tiles that are not on the #NOTILES list will be used for spawn placement.

The example below has 2 spawn entries.
The first entry uses the #NOTILES keyword to specify that the orcs should NOT be spawned on grass tiles with ids of 3. Note that the lava tiles are not passable and so the orcs are placed on dirt, which is the only passable, non-grass tile around.
The second entry uses the #TILES keyword to place the lavalizards on the lava tiles.


- added an optional 'equippedonly' argument to the existing SETONCARRIED keyword that would allows access things like a players bankbox. The new syntax is
SETONCARRIED,itemname[,itemtype][,equippedonly]/prop/value/prop2/value...
where specifying 'true' or 'equippedonly' for the equipped only arg will only look at items that are directly equipped on the mobile, and that would include bankboxes.
So to add something to a players bankbox you would do
SETONCARRIED,,bankbox,equippedonly/ADD/gold,500

- added the new KILL keyword that can be used to kill mobiles. For example, the spawn entry
SETONTRIGMOB/KILL
would kill the triggering mob, or
SETONNEARBY,5,,rat/KILL
would kill all of the rats within 5 tiles

- added optional args for specifying hue and font in the BCAST keyword (thanks to Xavier_WER for the suggestion). The new syntax is
BCAST[,hue][,font]/message
Note that this uses the same hues and fonts as the SENDASCIIMSG and ASCIIMSG keywords,
SENDASCIIMSG[,probability][,hue][,font]/message text
ASCIIMSG[,probability][,hue][,font]/text
so you can use them to test out various text/color combinations without having to actually broadcast to see what it looks like.
 

Johabius

Knight
Hello Arte, was wondering if you could help me fix this latest error with baseweapon. I think it may have something to do with my merging skills. Here is the error:
Code:
RunUO - [www.runuo.com] Version 2.0, Build 2357.32527
Core: Running on .NET Framework Version 2.0.50727
Scripts: Compiling C# scripts...failed (1 errors, 1 warnings)

Errors:
 + Items/Weapons/BaseWeapon.cs:
    CS0103: Line 1147: The name 'originaldamage' does not exist in the current c
ontext
    CS0103: Line 1178: The name 'originaldamage' does not exist in the current c
ontext
Scripts: One or more scripts failed to compile or no script files were found.
 - Press return to exit, or R to try again.

And here is my latest BaseWeapon:

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

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_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;
        #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 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 ? Core.AOS ? AosMaxRange : OldMaxRange : m_MaxRange ); }
            set{ m_MaxRange = value; InvalidateProperties(); }
        }

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

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

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

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

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

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

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

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

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

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

        [CommandProperty( AccessLevel.GameMaster )]
        public int IntRequirement
        {
            get{ return ( m_IntReq == -1 ? Core.AOS ? AosIntelligenceReq : OldIntelligenceReq : m_IntReq ); }
            set{ m_IntReq = value; }
        }

        [CommandProperty( AccessLevel.GameMaster )]
        public WeaponAccuracyLevel AccuracyLevel
        {
            get
            {
                return m_AccuracyLevel;
            }
            set
            {
                if ( m_AccuracyLevel != value )
                {
                    m_AccuracyLevel = value;

                    if ( UseSkillMod )
                    {
                        if ( m_AccuracyLevel == WeaponAccuracyLevel.Regular )
                        {
                            if ( m_SkillMod != null )
                                m_SkillMod.Remove();

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

                    InvalidateProperties();
                }
            }
        }

        #endregion

        public virtual void UnscaleDurability()
        {
            int scale = 100 + GetDurabilityBonus();

            m_Hits = ((m_Hits * 100) + (scale - 1)) / scale;
            m_MaxHits = ((m_MaxHits * 100) + (scale - 1)) / scale;
            InvalidateProperties();
        }

        public virtual void ScaleDurability()
        {
            int scale = 100 + GetDurabilityBonus();

            m_Hits = ((m_Hits * scale) + 99) / 100;
            m_MaxHits = ((m_MaxHits * scale) + 99) / 100;
            InvalidateProperties();
        }

        public int GetDurabilityBonus()
        {
            int bonus = 0;

            if ( m_Quality == WeaponQuality.Exceptional )
                bonus += 20;

            switch ( m_DurabilityLevel )
            {
                case WeaponDurabilityLevel.Durable: bonus += 20; break;
                case WeaponDurabilityLevel.Substantial: bonus += 50; break;
                case WeaponDurabilityLevel.Massive: bonus += 70; break;
                case WeaponDurabilityLevel.Fortified: bonus += 100; break;
                case WeaponDurabilityLevel.Indestructible: bonus += 120; break;
            }

            if ( Core.AOS )
            {
                bonus += m_AosWeaponAttributes.DurabilityBonus;

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

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

                if ( attrInfo != null )
                    bonus += attrInfo.WeaponDurability;
            }

            return bonus;
        }

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

            int v = m_AosWeaponAttributes.LowerStatReq;

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

        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
            {
                return base.CanEquip( from );
            }
        }

        public virtual bool UseSkillMod{ get{ return !Core.AOS; } }

        public override bool OnEquip( Mobile from )
        {
            int strBonus = m_AosAttributes.BonusStr;
            int dexBonus = m_AosAttributes.BonusDex;
            int intBonus = m_AosAttributes.BonusInt;

            if ( (strBonus != 0 || dexBonus != 0 || intBonus != 0) )
            {
                Mobile m = from;

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

            return true;
        }

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

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

                if ( Core.AOS )
                    m_AosSkillBonuses.AddTo( from );

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

                if ( Core.AOS )
                    m_AosSkillBonuses.Remove();

                m.CheckStatTimers();

                m.Delta( MobileDelta.WeaponDamage );
            }
        }

        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 ( Core.AOS )
            {
                if ( atkValue <= -20.0 )
                    atkValue = -19.9;

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

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

                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 = 45%
                bonus = AosAttributes.GetValue( defender, AosAttribute.DefendChance );
                if ( bonus > 45 )
                    bonus = 45;

                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);
                theirValue = (defValue + 50.0);
            }

            double chance = ourValue / (theirValue * 2.0);

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

            if ( Core.AOS && chance < 0.02 )
                chance = 0.02;

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

            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 ) )
                    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 < 5 )
                    ticks = 5;

                delayInSeconds = ticks * 0.25;
            }
            else if ( Core.AOS )
            {
                int v = (m.Stam + 100) * 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.25 )
                    delayInSeconds = 1.25;
            }
            else
            {
                int v = (m.Stam + 100) * speed;

                if ( v <= 0 )
                    v = 1;

                delayInSeconds = 15000.0 / v;
            }

            return TimeSpan.FromSeconds( delayInSeconds );
        }

        public virtual void OnBeforeSwing( Mobile attacker, Mobile defender )
        {
            WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker );

            if( a != null && !a.OnBeforeSwing( attacker, defender ) )
                WeaponAbility.ClearCurrentAbility( attacker );

            SpecialMove move = SpecialMove.GetCurrentMove( attacker );

            if( move != null && !move.OnBeforeSwing( attacker, defender ) )
                SpecialMove.ClearCurrentMove( attacker );
        }

        public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender )
        {
            return OnSwing( attacker, defender, 1.0 );
        }

        public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender, double damageBonus )
        {
            bool canSwing = true;

            if ( Core.AOS )
            {
                canSwing = ( !attacker.Paralyzed && !attacker.Frozen );

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

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

            if ( canSwing && attacker.HarmfulCheck( defender ) )
            {
                attacker.DisruptiveAction();

                if ( attacker.NetState != null )
                    attacker.Send( new Swing( 0, attacker, defender ) );

                if ( attacker is BaseCreature )
                {
                    BaseCreature bc = (BaseCreature)attacker;
                    WeaponAbility ab = bc.GetWeaponAbility();

                    if ( ab != null )
                    {
                        if ( bc.WeaponAbilityChance > Utility.RandomDouble() )
                            WeaponAbility.SetCurrentAbility( bc, ab );
                        else
                            WeaponAbility.ClearCurrentAbility( bc );
                    }
                }

                if ( CheckHit( attacker, defender ) )
                    OnHit( attacker, defender, damageBonus );
                else
                    OnMiss( attacker, defender );
            }

            return GetDelay( attacker );
        }

        #region Sounds
        public virtual int GetHitAttackSound( Mobile attacker, Mobile defender )
        {
            int sound = attacker.GetAttackSound();

            if ( sound == -1 )
                sound = HitSound;

            return sound;
        }

        public virtual int GetHitDefendSound( Mobile attacker, Mobile defender )
        {
            return defender.GetHurtSound();
        }

        public virtual int GetMissAttackSound( Mobile attacker, Mobile defender )
        {
            if ( attacker.GetAttackSound() == -1 )
                return MissSound;
            else
                return -1;
        }

        public virtual int GetMissDefendSound( Mobile attacker, Mobile defender )
        {
            return -1;
        }
        #endregion

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

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

            double parry = defender.Skills[SkillName.Parry].Value;
            double parryNonRacial = defender.Skills[SkillName.Parry].NonRacialValue;
            double bushido = defender.Skills[SkillName.Bushido].Value;

            if ( shield != null )
            {
                double chance = (parryNonRacial - bushido) / 400.0;    //As per OSI, no negitive effect from the Racial stuffs, ie, 120 bushido and '0' parry with humans

                // Parry over 100 grants a 5% bonus.
                if ( parry >= 100.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 defender.CheckSkill( SkillName.Parry, chance );
            }
            else if ( !(defender.Weapon is Fists) && !(defender.Weapon is BaseRanged) )
            {
                BaseWeapon weapon = defender.Weapon as BaseWeapon;

                double divisor = (weapon.Layer == Layer.OneHanded) ? 48000.0 : 41140.0;

                double chance = (parry * bushido) / divisor;

                double aosChance = parry / 800.0;

                // Parry or Bushido over 100 grant a 5% bonus.
                if( parry >= 100.0 )
                {
                    chance += 0.05;
                    aosChance += 0.05;
                }
                else if( bushido >= 100.0 )
                {
                    chance += 0.05;
                }

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

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

                if ( chance > aosChance )
                    return defender.CheckSkill( SkillName.Parry, chance );
                else
                    return (aosChance > Utility.RandomDouble()); // Only skillcheck if wielding a shield & there's no effect from Bushido
            }

            return false;
        }

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

            if ( defender.Player || defender.Body.IsHuman )
            {
                blocked = CheckParry( defender );

                if ( blocked )
                {
                    defender.FixedEffect( 0x37B9, 10, 16 );
                    damage = 0;

                    // Successful block removes the Honorable Execution penalty.
                    HonorableExecution.RemovePenalty( defender );

                    if ( CounterAttack.IsCountering( defender ) )
                    {
                        BaseWeapon weapon = defender.Weapon as BaseWeapon;

                        if ( weapon != null )
                            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 );
                    }
                }
            }

            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
            }

            return damage;
        }

        public virtual int AbsorbDamage( Mobile attacker, Mobile defender, int damage )
        {
            if ( Core.AOS )
                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 );

            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( 1 ) )
            {
                if ( m != attacker && m is BaseCreature )
                {
                    BaseCreature tc = (BaseCreature)m;

                    if ( (tc.PackInstinct & bc.PackInstinct) == 0 || (!tc.Controlled && !tc.Summoned) )
                        continue;

                    Mobile theirMaster = tc.ControlMaster;

                    if ( theirMaster == null )
                        theirMaster = tc.SummonMaster;

                    if ( master == theirMaster && tc.Combatant == defender )
                        ++inPack;
                }
            }

            if ( inPack >= 5 )
                return 100;
            else if ( inPack >= 4 )
                return 75;
            else if ( inPack >= 3 )
                return 50;
            else if ( inPack >= 2 )
                return 25;

            return 0;
        }

        private static bool m_InDoubleStrike;

        public static bool InDoubleStrike
        {
            get{ return m_InDoubleStrike; }
            set{ m_InDoubleStrike = value; }
        }

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

        public virtual void OnHit( Mobile attacker, Mobile defender, double damageBonus )
        {
            if ( MirrorImage.HasClone( defender ) && (defender.Skills.Ninjitsu.Value / 150.0) > Utility.RandomDouble() )
            {
                Clone bc;

                foreach ( Mobile m in defender.GetMobilesInRange( 4 ) )
                {
                    bc = m as Clone;

                    if ( bc != null && bc.Summoned && bc.SummonMaster == defender )
                    {
                        attacker.SendLocalizedMessage( 1063141 ); // Your attack has been diverted to a nearby mirror image of your target!
                        defender.SendLocalizedMessage( 1063140 ); // You manage to divert the attack onto one of your nearby mirror images.

                        /*
                         * TODO: What happens if the Clone parries a blow?
                         * And what about if the attacker is using Honorable Execution
                         * and kills it?
                         */

                        defender = m;
                        break;
                    }
                }
            }

            PlaySwingAnimation( attacker );
            PlayHurtAnimation( defender );

            attacker.PlaySound( GetHitAttackSound( attacker, defender ) );
            defender.PlaySound( GetHitDefendSound( attacker, defender ) );

            int damage = ComputeDamage( attacker, defender );

            #region Damage Multipliers
            /*
             * The following damage bonuses multiply damage by a factor.
             * Capped at x3 (300%).
             */
            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;
            }

            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 *= 1.5;
                    }
                }
            }

            int packInstinctBonus = GetPackInstinctBonus( attacker, defender );

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

            if ( m_InDoubleStrike )
                factor *= 0.9; // 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 )
            {
                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;

            damage = (int)(damage * factor);
            #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!
                }
            }

            AddBlood( attacker, defender, damage );

            int phys, fire, cold, pois, nrgy;

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

            if ( m_Consecrated )
            {
                phys = defender.PhysicalResistance;
                fire = defender.FireResistance;
                cold = defender.ColdResistance;
                pois = defender.PoisonResistance;
                nrgy = defender.EnergyResistance;

                int low = phys, type = 0;

                if ( fire < low ){ low = fire; type = 1; }
                if ( cold < low ){ low = cold; type = 2; }
                if ( pois < low ){ low = pois; type = 3; }
                if ( nrgy < low ){ low = nrgy; type = 4; }

                phys = fire = cold = pois = nrgy = 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 );

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

            if ( Core.AOS )
            {
                int lifeLeech = 0;
                int stamLeech = 0;
                int manaLeech = 0;
                int wraithLeech = 0;

                if ( (int)(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 ( 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 += AOS.Scale( damageGiven, lifeLeech );

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

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

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

            if ( m_MaxHits > 0 && ((MaxRange <= 1 && (defender is Slime || defender is ToxicElemental)) || 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;
            }

            if ( Core.AOS )
            {
                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) )
            {
                if ( AnimalForm.UnderTransformation( attacker, typeof( GiantSerpent ) ) )
                    defender.ApplyPoison( attacker, Poison.Lesser );

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

        public virtual double GetAosDamage( Mobile attacker, int bonus, int dice, int sides )
        {
            int damage = Utility.Dice( dice, sides, bonus ) * 100;
            int damageBonus = 0;

            // Inscription bonus
            int inscribeSkill = attacker.Skills[SkillName.Inscribe].Fixed;

            damageBonus += inscribeSkill / 200;

            if ( inscribeSkill >= 1000 )
                damageBonus += 5;

            if ( attacker.Player )
            {
                // Int bonus
                damageBonus += (attacker.Int / 10);

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

            damage = AOS.Scale( damage, 100 + damageBonus );

            return damage / 100;
        }

        #region Do<AoSEffect>
        public virtual void DoMagicArrow( Mobile attacker, Mobile defender )
        {
            if ( !attacker.CanBeHarmful( defender, false ) )
                return;

            attacker.DoHarmful( defender );

            double damage = GetAosDamage( attacker, 10, 1, 4 );

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

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

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

            attacker.DoHarmful( defender );

            double damage = GetAosDamage( attacker, 17, 1, 5 );

            if ( !defender.InRange( attacker, 2 ) )
                damage *= 0.25; // 1/4 damage at > 2 tile range
            else if ( !defender.InRange( attacker, 1 ) )
                damage *= 0.50; // 1/2 damage at 2 tile range

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

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

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

            attacker.DoHarmful( defender );

            double damage = GetAosDamage( attacker, 19, 1, 5 );

            attacker.MovingParticles( defender, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160 );
            attacker.PlaySound( 0x15E );

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

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

            attacker.DoHarmful( defender );

            double damage = GetAosDamage( attacker, 23, 1, 4 );

            defender.BoltEffect( 0 );

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

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

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

            if ( !dispellable )
                return;

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

            attacker.DoHarmful( defender );

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

            if ( sp.CheckResisted( defender ) )
            {
                defender.FixedEffect( 0x3779, 10, 20 );
            }
            else
            {
                Effects.SendLocationParticles( EffectItem.Create( defender.Location, defender.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 );
                Effects.PlaySound( defender, defender.Map, 0x201 );

                defender.Delete();
            }
        }

        public virtual void DoLowerAttack( Mobile from, Mobile defender )
        {
            if ( HitLower.ApplyAttack( defender ) )
            {
                defender.PlaySound( 0x28E );
                Effects.SendTargetEffect( defender, 0x37BE, 1, 4, 0xA, 3 );
            }
        }

        public virtual void DoLowerDefense( Mobile from, Mobile defender )
        {
            if ( HitLower.ApplyDefense( defender ) )
            {
                defender.PlaySound( 0x28E );
                Effects.SendTargetEffect( defender, 0x37BE, 1, 4, 0x23, 3 );
            }
        }

        public virtual void DoAreaAttack( Mobile from, Mobile defender, int sound, int hue, int phys, int fire, int cold, int pois, int nrgy )
        {
            Map map = from.Map;

            if ( map == null )
                return;

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

            foreach ( Mobile m in from.GetMobilesInRange( 10 ) )
            {
                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 = (11 - from.GetDistanceToSqrt( m )) / 10;

                if ( scalar > 1.0 )
                    scalar = 1.0;
                else if ( scalar < 0.0 )
                    continue;

                from.DoHarmful( m, true );
                m.FixedEffect( 0x3779, 1, 15, hue, 0 );
                AOS.Damage( m, from, (int)(GetBaseDamage( from ) * scalar), phys, fire, cold, pois, nrgy );
            }
        }
        #endregion

        public virtual CheckSlayerResult CheckSlayers( Mobile attacker, Mobile defender )
        {
            BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon;
            SlayerEntry atkSlayer = SlayerGroup.GetEntryByName( atkWeapon.Slayer );
            SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName( atkWeapon.Slayer2 );

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

            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()
        {
            if ( !Core.AOS )
                return 0;

            int bonus = 0;

            switch ( m_AccuracyLevel )
            {
                case WeaponAccuracyLevel.Accurate:        bonus += 02; break;
                case WeaponAccuracyLevel.Surpassingly:    bonus += 04; break;
                case WeaponAccuracyLevel.Eminently:        bonus += 06; break;
                case WeaponAccuracyLevel.Exceedingly:    bonus += 08; break;
                case WeaponAccuracyLevel.Supremely:        bonus += 10; break;
            }

            return bonus;
        }

        public virtual int GetDamageBonus()
        {
            int bonus = VirtualDamageBonus;

            switch ( m_Quality )
            {
                case WeaponQuality.Low:            bonus -= 20; break;
                case WeaponQuality.Exceptional:    bonus += 20; break;
            }

            switch ( m_DamageLevel )
            {
                case WeaponDamageLevel.Ruin:    bonus += 15; break;
                case WeaponDamageLevel.Might:    bonus += 20; break;
                case WeaponDamageLevel.Force:    bonus += 25; break;
                case WeaponDamageLevel.Power:    bonus += 30; break;
                case WeaponDamageLevel.Vanq:    bonus += 35; break;
            }

            return bonus;
        }

        public virtual void GetStatusDamage( Mobile from, out int min, out int max )
        {
            int baseMin, baseMax;

            GetBaseDamageRange( from, out baseMin, out baseMax );

            if ( Core.AOS )
            {
                min = Math.Max( (int)ScaleDamageAOS( from, baseMin, false ), 1 );
                max = Math.Max( (int)ScaleDamageAOS( from, baseMax, false ), 1 );
            }
            else
            {
                min = Math.Max( (int)ScaleDamageOld( from, baseMin, false ), 1 );
                max = Math.Max( (int)ScaleDamageOld( from, baseMax, false ), 1 );
            }
        }

        public virtual double ScaleDamageAOS( Mobile attacker, double damage, bool checkSkills )
        {
            if ( checkSkills )
            {
                attacker.CheckSkill( SkillName.Tactics, 0.0, 120.0 ); // Passively check tactics for gain
                attacker.CheckSkill( SkillName.Anatomy, 0.0, 120.0 ); // Passively check Anatomy for gain

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

            #region Physical bonuses
            /*
             * These are the bonuses given by the physical characteristics of the mobile.
             * No caps apply.
             */
            double strengthBonus = GetBonus( attacker.Str,                                        0.300, 100.0,  5.00 );
            double  anatomyBonus = GetBonus( attacker.Skills[SkillName.Anatomy].Value,            0.500, 100.0,  5.00 );
            double  tacticsBonus = GetBonus( attacker.Skills[SkillName.Tactics].Value,            0.625, 100.0,  6.25 );
            double   lumberBonus = GetBonus( attacker.Skills[SkillName.Lumberjacking].Value,    0.200, 100.0, 10.00 );

            if ( Type != WeaponType.Axe )
                lumberBonus = 0.0;
            #endregion

            #region Modifiers
            /*
             * The following are damage modifiers whose effect shows on the status bar.
             * Capped at 100% total.
             */
            int damageBonus = AosAttributes.GetValue( attacker, AosAttribute.WeaponDamage );

            // Horrific Beast transformation gives a +25% bonus to damage.
            if ( 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 > 100 )
                damageBonus = 100;
            #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, 120.0 ); // Passively check tactics for gain
                attacker.CheckSkill( SkillName.Anatomy, 0.0, 120.0 ); // Passively check Anatomy for gain

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

            /* Compute tactics modifier
             * :   0.0 = 50% loss
             * :  50.0 = unchanged
             * : 100.0 = 50% bonus
             */
            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;

            // 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 ( Core.AOS )
                return ComputeDamageAOS( attacker, defender );

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

        public virtual void PlayHurtAnimation( Mobile from )
        {
            int action;
            int frames;

            switch ( from.Body.Type )
            {
                case BodyType.Sea:
                case BodyType.Animal:
                {
                    action = 7;
                    frames = 5;
                    break;
                }
                case BodyType.Monster:
                {
                    action = 10;
                    frames = 4;
                    break;
                }
                case BodyType.Human:
                {
                    action = 20;
                    frames = 5;
                    break;
                }
                default: return;
            }

            if ( from.Mounted )
                return;

            from.Animate( action, frames, 1, true, false, 0 );
        }

        public virtual void PlaySwingAnimation( Mobile from )
        {
            int action;

            switch ( from.Body.Type )
            {
                case BodyType.Sea:
                case BodyType.Animal:
                {
                    action = Utility.Random( 5, 2 );
                    break;
                }
                case BodyType.Monster:
                {
                    switch ( Animation )
                    {
                        default:
                        case WeaponAnimation.Wrestle:
                        case WeaponAnimation.Bash1H:
                        case WeaponAnimation.Pierce1H:
                        case WeaponAnimation.Slash1H:
                        case WeaponAnimation.Bash2H:
                        case WeaponAnimation.Pierce2H:
                        case WeaponAnimation.Slash2H: action = Utility.Random( 4, 3 ); break;
                        case WeaponAnimation.ShootBow:  return; // 7
                        case WeaponAnimation.ShootXBow: return; // 8
                    }

                    break;
                }
                case BodyType.Human:
                {
                    if ( !from.Mounted )
                    {
                        action = (int)Animation;
                    }
                    else
                    {
                        switch ( Animation )
                        {
                            default:
                            case WeaponAnimation.Wrestle:
                            case WeaponAnimation.Bash1H:
                            case WeaponAnimation.Pierce1H:
                            case WeaponAnimation.Slash1H: action = 26; break;
                            case WeaponAnimation.Bash2H:
                            case WeaponAnimation.Pierce2H:
                            case WeaponAnimation.Slash2H: action = 29; break;
                            case WeaponAnimation.ShootBow: action = 27; break;
                            case WeaponAnimation.ShootXBow: action = 28; break;
                        }
                    }

                    break;
                }
                default: return;
            }

            from.Animate( action, 7, 1, true, false, 0 );
        }

        #region Serialization/Deserialization
        private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf )
        {
            if ( setIf )
                flags |= toSet;
        }

        private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet )
        {
            return ( (flags & toGet) != 0 );
        }

        public override void Serialize( GenericWriter writer )
        {
            base.Serialize( writer );

            writer.Write( (int) 8 ); // version

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

        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 )
        {
            int oreType;

            switch ( m_Resource )
            {
                case CraftResource.DullCopper:        oreType = 1053108; break; // dull copper
                case CraftResource.ShadowIron:        oreType = 1053107; break; // shadow iron
                case CraftResource.Copper:            oreType = 1053106; break; // copper
                case CraftResource.Bronze:            oreType = 1053105; break; // bronze
                case CraftResource.Gold:            oreType = 1053104; break; // golden
                case CraftResource.Agapite:            oreType = 1053103; break; // agapite
                case CraftResource.Verite:            oreType = 1053102; break; // verite
                case CraftResource.Valorite:        oreType = 1053101; break; // valorite
                case CraftResource.SpinedLeather:    oreType = 1061118; break; // spined
                case CraftResource.HornedLeather:    oreType = 1061117; break; // horned
                case CraftResource.BarbedLeather:    oreType = 1061116; break; // barbed
                case CraftResource.RedScales:        oreType = 1060814; break; // red
                case CraftResource.YellowScales:    oreType = 1060818; break; // yellow
                case CraftResource.BlackScales:        oreType = 1060820; break; // black
                case CraftResource.GreenScales:        oreType = 1060819; break; // green
                case CraftResource.WhiteScales:        oreType = 1060821; break; // white
                case CraftResource.BlueScales:        oreType = 1060815; break; // blue
                default: oreType = 0; 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 ( m_Crafter != null )
                list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~

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

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

            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, m_PoisonCharges.ToString() );

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

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


            base.AddResistanceProperties( 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~%

            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~

            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 )
                list.Add( 1060639, "{0}\t{1}", m_Hits, m_MaxHits ); // durability ~1_val~ / ~2_val~
        }

        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;

            Type resourceType = typeRes;

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

            if ( Core.AOS )
            {
                Resource = CraftResources.GetFromType( resourceType );

                CraftContext context = craftSystem.GetContext( from );

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

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

                if ( quality == 2 )
                {
                    if ( Attributes.WeaponDamage > 35 )
                        Attributes.WeaponDamage -= 20;
                    else
                        Attributes.WeaponDamage = 15;
                }
            }
            else if ( tool is BaseRunicTool )
            {
                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:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Durable;
                            AccuracyLevel = WeaponAccuracyLevel.Accurate;
                            break;
                        }
                        case CraftResource.ShadowIron:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Durable;
                            DamageLevel = WeaponDamageLevel.Ruin;
                            break;
                        }
                        case CraftResource.Copper:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Fortified;
                            DamageLevel = WeaponDamageLevel.Ruin;
                            AccuracyLevel = WeaponAccuracyLevel.Surpassingly;
                            break;
                        }
                        case CraftResource.Bronze:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Fortified;
                            DamageLevel = WeaponDamageLevel.Might;
                            AccuracyLevel = WeaponAccuracyLevel.Surpassingly;
                            break;
                        }
                        case CraftResource.Gold:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                            DamageLevel = WeaponDamageLevel.Force;
                            AccuracyLevel = WeaponAccuracyLevel.Eminently;
                            break;
                        }
                        case CraftResource.Agapite:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                            DamageLevel = WeaponDamageLevel.Power;
                            AccuracyLevel = WeaponAccuracyLevel.Eminently;
                            break;
                        }
                        case CraftResource.Verite:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                            DamageLevel = WeaponDamageLevel.Power;
                            AccuracyLevel = WeaponAccuracyLevel.Exceedingly;
                            break;
                        }
                        case CraftResource.Valorite:
                        {
                            Identified = true;
                            DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                            DamageLevel = WeaponDamageLevel.Vanq;
                            AccuracyLevel = WeaponAccuracyLevel.Supremely;
                            break;
                        }
                    }
                }
            }

            return quality;
        }

        #endregion
    }

    public enum CheckSlayerResult
    {
        None,
        Slayer,
        Opposition
    }
}
 

ArteGordon

Wanderer
I didnt see the mod in the script that you posted, but I am guessing that you either missed the first part of installation step #10 or put it in the wrong spot.

STEP 10: (recommended but not required)
To allow attachments to make use of the OnArmorHit methods, the following changes must be made in BaseWeapon.cs.(note, you dont have to make this mod if you dont want to, the spawner and other items/attachments will work just fine without it, you just wont be able to use features of certain attachments that require this such as XmlCustomAttacks).


at the beginning of the AbsorbDamageAOS method around line 1103 of BaseWeapon.cs change

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

to

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

Johabius

Knight
ArteGordon said:
I didnt see the mod in the script that you posted, but I am guessing that you either missed the first part of installation step #10 or put it in the wrong spot.
Indeed, that is what I missed. Thank you very much for your time.
 

Broadside

Wanderer
I just got a crash off trying command [xml not sure if its even a commmand but figured it was for this systme and wanted to bring it to your attention so that people can watch for this. I am posting my crash report if that helps any.
Code:
Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
   at Server.Commands.HearAll.OnSpeech(SpeechEventArgs args)
   at Server.SpeechEventHandler.Invoke(SpeechEventArgs e)
   at Server.EventSink.InvokeSpeech(SpeechEventArgs e)
   at Server.Mobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue)
   at Server.Mobiles.PlayerMobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue)
   at Server.Network.PacketHandlers.UnicodeSpeech(NetState state, PacketReader pvSrc)
   at Server.Network.MessagePump.HandleReceive(NetState ns)
   at Server.Network.MessagePump.Slice()
   at Server.Core.Main(String[] args)
 

ArteGordon

Wanderer
Broadside said:
I just got a crash off trying command [xml not sure if its even a commmand but figured it was for this systme and wanted to bring it to your attention so that people can watch for this. I am posting my crash report if that helps any.
Code:
Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
   at Server.Commands.HearAll.OnSpeech(SpeechEventArgs args)
   at Server.SpeechEventHandler.Invoke(SpeechEventArgs e)
   at Server.EventSink.InvokeSpeech(SpeechEventArgs e)
   at Server.Mobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue)
   at Server.Mobiles.PlayerMobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue)
   at Server.Network.PacketHandlers.UnicodeSpeech(NetState state, PacketReader pvSrc)
   at Server.Network.MessagePump.HandleReceive(NetState ns)
   at Server.Network.MessagePump.Slice()
   at Server.Core.Main(String[] args)

I've seen this come up before with other people. It is a problem with your HearAll script. It isnt xmlspawner related.
 

Avelyn

Sorceror
Arte,

I just recently updated from the SVN and apparently they changed the gump list from a List<> to an IEnumerable<> in NetState.cs in the core. I am getting errors with the XML spawner because of this. All the errors are in the XML Gump file (there is no defination for count or remove... etc). Can you advise?
 
Status
Not open for further replies.
Top