Full Version : not working correctly
xmlspawner >>XMLSockets Troubleshooting >>not working correctly


<< Prev | Next >>

fixxxer- 05-24-2010
The system will add sockets to weapons, armor, and jewlery after the item has been dropped as loot or created. This can be the next day or a few days after the fact, but it doesn't do it to all items and in no particular order. My guess is when the server restarts the socket system will check again to see if an item is socketed and can add the ablility whenever the server restarts.

Any help would be great thanks...


BaseWeapon.cs


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;
using Server.Spells.Spellweaving;
using Server.Engines.XmlSpawner2;

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

public abstract class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability, ISetItem
{
#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; } }

// Mondain's Legacy Mod
public override int PhysicalResistance{ get{ return m_AosWeaponAttributes.ResistPhysicalBonus + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.ResistPhysicalBonus : 0 ); } }
public override int FireResistance{ get{ return m_AosWeaponAttributes.ResistFireBonus + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.ResistFireBonus : 0 ); } }
public override int ColdResistance{ get{ return m_AosWeaponAttributes.ResistColdBonus + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.ResistColdBonus : 0 ); } }
public override int PoisonResistance{ get{ return m_AosWeaponAttributes.ResistPoisonBonus + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.ResistPoisonBonus : 0 ); } }
public override int EnergyResistance{ get{ return m_AosWeaponAttributes.ResistEnergyBonus + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.ResistEnergyBonus : 0 ); } }

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

// equip/remove on doubleclick
public override void OnDoubleClick(Mobile from)
{
if ( from.FindItemOnLayer( this.Layer ) == this )
{
from.Backpack.DropItem( this );
return;
}

if ( RootParent != from )
{
from.LocalOverheadMessage( MessageType.Regular, 906, 1042004 ); // That must be in your pack...
return;
}

if ( from.FindItemOnLayer( this.Layer ) != this )
{
if ( this.Layer == Layer.TwoHanded )
{
from.Backpack.DropItem( from.FindItemOnLayer( Layer.TwoHanded ) );
from.Backpack.DropItem( from.FindItemOnLayer( Layer.FirstValid ) );
from.EquipItem( this );
return;
}
else
{
from.Backpack.DropItem( from.FindItemOnLayer( this.Layer ) );
from.EquipItem( this );
return;
}
}
}
// end equip/remove on doubleclick

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

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

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

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

public int GetDurabilityBonus()
{
int bonus = 0;

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

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

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

#region Mondain's Legacy
if ( m_Resource == CraftResource.Heartwood )
return bonus;
#endregion

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

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

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

return bonus;
}

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

int v = m_AosWeaponAttributes.LowerStatReq;

#region Mondain's Legacy
if ( m_Resource == CraftResource.Heartwood )
return v;
#endregion

CraftResourceInfo info = CraftResources.GetInfo( m_Resource );

if ( info != null )
{
CraftAttributeInfo attrInfo = info.AttributeInfo;

if ( attrInfo != null )
v += attrInfo.WeaponLowerRequirements;
}

if ( v > 100 )
v = 100;

return v;
}

public static void BlockEquip( Mobile m, TimeSpan duration )
{
if ( m.BeginAction( typeof( BaseWeapon ) ) )
new ResetEquipTimer( m, duration ).Start();
}

private class ResetEquipTimer : Timer
{
private 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
// XmlAttachment check for CanEquip
if (!Server.Engines.XmlSpawner2.XmlAttach.CheckCanEquip(this, from))
{
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 );
}

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

return true;
}

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

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

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

#region Mondain's Legacy
if ( IsSetItem )
m_SetEquipped = SetHelper.FullSetPresent( from, SetID, Pieces );

if ( m_SetEquipped )
{
m_LastEquipped = true;

SetHelper.AddSetBonus( from, SetID );
}
#endregion

from.CheckStatTimers();
from.Delta( MobileDelta.WeaponDamage );
}
}

public override void OnRemoved( object parent )
{
if ( parent is Mobile )
{
Mobile m = (Mobile)parent;
BaseWeapon weapon = m.Weapon as BaseWeapon;

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


if ( IsSetItem ? m_SetEquipped : false )
SetHelper.RemoveSetBonus( m, SetID, this );
// XmlAttachment check for OnRemoved
Server.Engines.XmlSpawner2.XmlAttach.CheckOnRemoved(this, parent);

}


InvalidateProperties();
}

public virtual SkillName GetUsedSkill( Mobile m, bool checkSkillAttrs )
{
SkillName sk;

// Mondain's Legacy Mod
if ( checkSkillAttrs && m_AosWeaponAttributes.UseBestSkill + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.UseBestSkill : 0 ) != 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; }
}
// Mondain's Legacy Mod
else if ( m_AosWeaponAttributes.MageWeapon + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.MageWeapon : 0 ) != 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;

TransformContext context = TransformationSpellHelper.GetContext( m );

if( context != null && context.Spell is ReaperFormSpell )
bonus += ((ReaperFormSpell)context.Spell).SwingSpeedBonus;

int discordanceEffect = 0;

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

if( EssenceOfWindSpell.IsDebuffed( m ) )
bonus -= EssenceOfWindSpell.GetSSIMalus( m );

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 bushidoNonRacial = defender.Skills[SkillName.Bushido].NonRacialValue;
double bushido = defender.Skills[SkillName.Bushido].Value;

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


// Parry over 100 grants a 5% bonus.
if ( parry >= 100.0 )
chance += 0.05;

// Evasion grants a variable bonus post ML. 50% prior.
if ( Evasion.IsEvading( defender ) )
chance *= Evasion.GetParryScalar( defender );

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

return defender.CheckSkill( SkillName.Parry, chance );
}
else if ( !(defender.Weapon is Fists) && !(defender.Weapon is BaseRanged) )
{
BaseWeapon weapon = defender.Weapon as BaseWeapon;

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

double chance = (parry * bushido) / divisor;

double aosChance = parry / 800.0;

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

// Evasion grants a variable bonus post ML. 50% prior.
if( Evasion.IsEvading( defender ) )
chance *= Evasion.GetParryScalar( defender );

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

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

return false;
}

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

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

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

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

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

if ( weapon != null )
weapon.OnSwing( defender, attacker );

CounterAttack.StopCountering( defender );
}

if ( Confidence.IsConfident( defender ) )
{
defender.SendLocalizedMessage( 1063117 ); // Your confidence reassures you as you successfully block your opponent's blow.

double bushido = defender.Skills.Bushido.Value;

defender.Hits += Utility.RandomMinMax( 1, (int)(bushido / 12) );
defender.Stam += Utility.RandomMinMax( 1, (int)(bushido / 5) );
}

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

if ( shield != null )
{
shield.OnHit( this, damage );

// XmlAttachment check for OnArmorHit
Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, shield, this, originaldamage);
}
}
}

if ( !blocked )
{
double positionChance = Utility.RandomDouble();

Item armorItem;

if( positionChance < 0.07 )
armorItem = defender.NeckArmor;
else if( positionChance < 0.14 )
armorItem = defender.HandArmor;
else if( positionChance < 0.28 )
armorItem = defender.ArmsArmor;
else if( positionChance < 0.43 )
armorItem = defender.HeadArmor;
else if( positionChance < 0.65 )
armorItem = defender.LegsArmor;
else
armorItem = defender.ChestArmor;

IWearableDurability armor = armorItem as IWearableDurability;

if (armor != null)
{
armor.OnHit(this, damage); // call OnHit to lose durability

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

return damage;
}

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

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

int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod;

if ( virtualArmor > 0 )
{
double scalar;

if ( chance < 0.14 )
scalar = 0.07;
else if ( chance < 0.28 )
scalar = 0.14;
else if ( chance < 0.43 )
scalar = 0.15;
else if ( chance < 0.65 )
scalar = 0.22;
else
scalar = 0.35;

int from = (int)(virtualArmor * scalar) / 2;
int to = (int)(virtualArmor * scalar);

damage -= Utility.Random( from, (to - from) + 1 );
}

return damage;
}

public virtual int GetPackInstinctBonus( Mobile attacker, Mobile defender )
{
if ( attacker.Player || defender.Player )
return 0;

BaseCreature bc = attacker as BaseCreature;

if ( bc == null || bc.PackInstinct == PackInstinct.None || (!bc.Controlled && !bc.Summoned) )
return 0;

Mobile master = bc.ControlMaster;

if ( master == null )
master = bc.SummonMaster;

if ( master == null )
return 0;

int inPack = 1;

foreach ( Mobile m in defender.GetMobilesInRange( 1 ) )
{
if ( m != attacker && m is BaseCreature )
{
BaseCreature tc = (BaseCreature)m;

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

Mobile theirMaster = tc.ControlMaster;

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

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

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

return 0;
}

private static bool m_InDoubleStrike;

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

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

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

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

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

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

defender = m;
break;
}
}
}

PlaySwingAnimation( attacker );
PlayHurtAnimation( defender );

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

int damage = ComputeDamage( attacker, defender );

#region Damage Multipliers
/*
* The following damage bonuses multiply damage by a factor.
* Capped at x3 (300%).
*/
//double factor = 1.0;
int percentageBonus = 0;

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

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

if( move != null )
{
//factor *= move.GetDamageScalar( attacker, defender );
percentageBonus += (int)(move.GetDamageScalar( attacker, defender ) * 100) - 100;
}

//factor *= damageBonus;
percentageBonus += (int)(damageBonus * 100) - 100;

CheckSlayerResult cs = CheckSlayers( attacker, defender );

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

//factor *= 2.0;
percentageBonus += 100;
}

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

if( pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType() )
{
//factor *= 2.0;
percentageBonus += 100;
}
}
}
else if ( !defender.Player )
{
if ( attacker is PlayerMobile )
{
PlayerMobile pm = (PlayerMobile)attacker;

if ( pm.WaitingForEnemy )
{
pm.EnemyOfOneType = defender.GetType();
pm.WaitingForEnemy = false;
}

if ( pm.EnemyOfOneType == defender.GetType() )
{
defender.FixedEffect( 0x37B9, 10, 5, 1160, 0 );
//factor *= 1.5;
percentageBonus += 50;
}
}
}

int packInstinctBonus = GetPackInstinctBonus( attacker, defender );

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

if( m_InDoubleStrike )
{
//factor *= 0.9; // 10% loss when attacking with double-strike
percentageBonus -= 10;
}

TransformContext context = TransformationSpellHelper.GetContext( defender );

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

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

if( pmAttacker.HonorActive && pmAttacker.InRange( defender, 1 ) )
{
//factor *= 1.25;
percentageBonus += 25;
}

if( pmAttacker.SentHonorContext != null && pmAttacker.SentHonorContext.Target == defender )
{
//pmAttacker.SentHonorContext.ApplyPerfectionDamageBonus( ref factor );
percentageBonus += pmAttacker.SentHonorContext.PerfectionDamageBonus;
}
}

//if ( factor > 3.0 )
// factor = 3.0;

#region Mondain's Legacy
if ( Core.ML )
{
if ( this is ButchersWarCleaver )
{
if ( defender is Bull || defender is Cow || defender is Gaman )
percentageBonus += 100;
}

if ( defender.Poison == Poison.Darkglow && attacker.InRange( defender.Location, 1 ) )
percentageBonus += 10;
}
#endregion

percentageBonus = Math.Min( percentageBonus, 300 );

//damage = (int)(damage * factor);
damage = AOS.Scale( damage, 100 + percentageBonus );

#endregion

if ( attacker is BaseCreature )
((BaseCreature)attacker).AlterMeleeDamageTo( defender, ref damage );

if ( defender is BaseCreature )
((BaseCreature)defender).AlterMeleeDamageFrom( attacker, ref damage );

damage = AbsorbDamage( attacker, defender, damage );

if ( !Core.AOS && damage < 1 )
damage = 1;
else if ( Core.AOS && damage == 0 ) // parried
{
if ( a != null && a.Validate( attacker ) /*&& a.CheckMana( attacker, true )*/ ) // Parried special moves have no mana cost
{
a = null;
WeaponAbility.ClearCurrentAbility( attacker );

attacker.SendLocalizedMessage( 1061140 ); // Your attack was parried!
}
}

AddBlood( attacker, defender, damage );

// Mondain's Legacy mod
int phys, fire, cold, pois, nrgy, chaos, direct;

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

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

// damage increase after resists applied
int damageIncrease = 0;

BaseQuiver quiver = attacker.FindItemOnLayer( Layer.Cloak ) as BaseQuiver;

if ( quiver != null )
damageIncrease = quiver.DamageIncrease;

// Mondain's Legacy Mod
damageGiven = AOS.Damage( defender, attacker, damage, ignoreArmor, phys, fire, cold, pois, nrgy, chaos, direct, damageIncrease );

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

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

// Mondain's Legacy Mod
if ( (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitLeechHits ) * propertyBonus) > Utility.Random( 100 ) )
lifeLeech += 30; // HitLeechHits% chance to leech 30% of damage as hit points

// Mondain's Legacy Mod
if ( (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitLeechStam ) * propertyBonus) > Utility.Random( 100 ) )
stamLeech += 100; // HitLeechStam% chance to leech 100% of damage as stamina

// Mondain's Legacy Mod
if ( (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitLeechMana ) * propertyBonus) > Utility.Random( 100 ) )
manaLeech += 40; // HitLeechMana% chance to leech 40% of damage as mana

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

context = TransformationSpellHelper.GetContext( attacker );

if ( context != null && context.Type == typeof( VampiricEmbraceSpell ) )
lifeLeech += 20; // Vampiric embrace gives an additional 20% life leech

if ( context != null && context.Type == typeof( WraithFormSpell ) )
{
wraithLeech = (5 + (int)((15 * attacker.Skills.SpiritSpeak.Value) / 100)); // Wraith form gives an additional 5-20% mana leech

// Mana leeched by the Wraith Form spell is actually stolen, not just leeched.
defender.Mana -= AOS.Scale( damageGiven, wraithLeech );

manaLeech += wraithLeech;
}

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

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

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

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

if ( m_MaxHits > 0 && ((MaxRange <= 1 && (defender is Slime || defender is ToxicElemental)) || 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!*
// Mondain's Legacy Mod
if ( Core.AOS && m_AosWeaponAttributes.SelfRepair + ( IsSetItem && m_SetEquipped ? m_SetWeaponAttributes.SelfRepair : 0 ) > Utility.Random( 10 ) )
{
HitPoints += 2;
}
else
{
if ( m_Hits > 0 )
{
--HitPoints;
}
else if ( m_MaxHits > 1 )
{
--MaxHitPoints;

if ( Parent is Mobile )
((Mobile)Parent).LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061121 ); // Your equipment is severely damaged.
}
else
{
Delete();
}
}
}

if ( attacker is VampireBatFamiliar )
{
BaseCreature bc = (BaseCreature)attacker;
Mobile caster = bc.ControlMaster;

if ( caster == null )
caster = bc.SummonMaster;

if ( caster != null && caster.Map == bc.Map && caster.InRange( bc, 2 ) )
caster.Hits += damage;
else
bc.Hits += damage;
}

if ( Core.AOS )
{
// Mondain's Legacy Mod
int physChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitPhysicalArea ) * propertyBonus);
int fireChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitFireArea ) * propertyBonus);
int coldChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitColdArea ) * propertyBonus);
int poisChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitPoisonArea ) * propertyBonus);
int nrgyChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitEnergyArea ) * propertyBonus);

if ( physChance != 0 && physChance > Utility.Random( 100 ) )
DoAreaAttack( attacker, defender, 0x10E, 50, 100, 0, 0, 0, 0 );

if ( fireChance != 0 && fireChance > Utility.Random( 100 ) )
DoAreaAttack( attacker, defender, 0x11D, 1160, 0, 100, 0, 0, 0 );

if ( coldChance != 0 && coldChance > Utility.Random( 100 ) )
DoAreaAttack( attacker, defender, 0x0FC, 2100, 0, 0, 100, 0, 0 );

if ( poisChance != 0 && poisChance > Utility.Random( 100 ) )
DoAreaAttack( attacker, defender, 0x205, 1166, 0, 0, 0, 100, 0 );

if ( nrgyChance != 0 && nrgyChance > Utility.Random( 100 ) )
DoAreaAttack( attacker, defender, 0x1F1, 120, 0, 0, 0, 0, 100 );

// Mondain's Legacy Mod
int maChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitMagicArrow ) * propertyBonus);
int harmChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitHarm ) * propertyBonus);
int fireballChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitFireball ) * propertyBonus);
int lightningChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitLightning ) * propertyBonus);
int dispelChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitDispel ) * propertyBonus);

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

// Mondain's Legacy Mod
int laChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitLowerAttack ) * propertyBonus);
int ldChance = (int)(AosWeaponAttributes.GetValue( attacker, AosWeaponAttribute.HitLowerDefend ) * propertyBonus);

if ( laChance != 0 && laChance > Utility.Random( 100 ) )
DoLowerAttack( attacker, defender );

if ( ldChance != 0 && ldChance > Utility.Random( 100 ) )
DoLowerDefense( attacker, defender );
}

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

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

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

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

if ( defender is IHonorTarget && ((IHonorTarget)defender).ReceivedHonorContext != null )
((IHonorTarget)defender).ReceivedHonorContext.OnTargetHit( attacker );

if ( !(this is BaseRanged) )
{
if ( AnimalForm.UnderTransformation( attacker, typeof( GiantSerpent ) ) )
defender.ApplyPoison( attacker, Poison.Lesser );

if ( AnimalForm.UnderTransformation( defender, typeof( BullFrog ) ) )
attacker.ApplyPoison( defender, Poison.Regular );
}
// hook for attachment OnWeaponHit method
Server.Engines.XmlSpawner2.XmlAttach.OnWeaponHit(this, attacker, defender, damageGiven);

}

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

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

damageBonus += inscribeSkill / 200;

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

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

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

TransformContext context = TransformationSpellHelper.GetContext( attacker );

if( context != null && context.Spell is ReaperFormSpell )
damageBonus += ((ReaperFormSpell)context.Spell).SpellDamageBonus;
}

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

return damage / 100;
}

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

attacker.DoHarmful( defender );

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

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

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

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

attacker.DoHarmful( defender );

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

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

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

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

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

attacker.DoHarmful( defender );

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

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

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

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

attacker.DoHarmful( defender );

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

defender.BoltEffect( 0 );

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

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

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

if ( !dispellable )
return;

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

attacker.DoHarmful( defender );

Spells.MagerySpell 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 ) && ( !Core.ML || from.InLOS( m ) ) )
list.Add( m );
}

if ( list.Count == 0 )
return;

Effects.PlaySound( from.Location, map, sound );

// TODO: What is the damage calculation?

for ( int i = 0; i < list.Count; ++i )
{
Mobile m = list[i];

double scalar = (11 - from.GetDistanceToSqrt( m )) / 10;

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

from.DoHarmful( m, true );
m.FixedEffect( 0x3779, 1, 15, hue