context: using System;
  using System.Collections;
  using Server;
  using Server.Network;
  using Server.Mobiles;
  using Server.Targeting;
  using Server.Engines.Craft;
  
  namespace Server.Items
  {
  	public delegate void InstrumentPickedCallback( Mobile from, BaseInstrument instrument );
  
  	public enum InstrumentQuality
  	{
  		Low,
  		Regular,
  		Exceptional
  	}
  
  	public abstract class BaseInstrument : Item, ICraftable
  	{
  		private int m_WellSound, m_BadlySound;
  		private SlayerName m_Slayer, m_Slayer2;
  		private InstrumentQuality m_Quality;
  		private Mobile m_Crafter;
  		private int m_UsesRemaining;
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int SuccessSound
  		{
  			get{ return m_WellSound; }
  			set{ m_WellSound = value; }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int FailureSound
  		{
  			get{ return m_BadlySound; }
  			set{ m_BadlySound = value; }
  		}
  
  		[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 InstrumentQuality Quality
  		{
  			get{ return m_Quality; }
  			set{ UnscaleUses(); m_Quality = value; InvalidateProperties(); ScaleUses(); }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public Mobile Crafter
  		{
  			get{ return m_Crafter; }
  			set{ m_Crafter = value; InvalidateProperties(); }
  		}
  
  		public virtual int InitMinUses{ get{ return 350; } }
  		public virtual int InitMaxUses{ get{ return 450; } }
  
  		public int UsesRemaining
  		{
  			get{ return m_UsesRemaining; }
  			set{ m_UsesRemaining = value; InvalidateProperties(); }
  		}
  
  		public void ScaleUses()
  		{
  			m_UsesRemaining = (m_UsesRemaining * GetUsesScalar()) / 100;
  			InvalidateProperties();
  		}
  
  		public void UnscaleUses()
  		{
  			m_UsesRemaining = (m_UsesRemaining * 100) / GetUsesScalar();
  		}
  
  		public int GetUsesScalar()
  		{
  			if ( m_Quality == InstrumentQuality.Exceptional )
  				return 200;
  
  			return 100;
  		}
  
  		public void ConsumeUse( Mobile from )
  		{
  			// TODO: Confirm what must happen here?
  
  			if ( UsesRemaining > 1 )
  			{
  				--UsesRemaining;
  			}
  			else
  			{
  				if ( from != null )
  					from.SendLocalizedMessage( 502079 ); // The instrument played its last tune.
  
  				Delete();
  			}
  		}
  
  		private static Hashtable m_Instruments = new Hashtable();
  
  		public static BaseInstrument GetInstrument( Mobile from )
  		{
  			BaseInstrument item = m_Instruments[from] as BaseInstrument;
  
  			if ( item == null )
  				return null;
  
  			if ( !item.IsChildOf( from.Backpack ) )
  			{
  				m_Instruments.Remove( from );
  				return null;
  			}
  
  			return item;
  		}
  
  		public static int GetBardRange( Mobile bard, SkillName skill )
  		{
  			return 8 + (int)(bard.Skills[skill].Value / 15);
  		}
  
  		public static void PickInstrument( Mobile from, InstrumentPickedCallback callback )
  		{
  			BaseInstrument instrument = GetInstrument( from );
  
  			if ( instrument != null )
  			{
  				if ( callback != null )
  					callback( from, instrument );
  			}
  			else
  			{
  				from.SendLocalizedMessage( 500617 ); // What instrument shall you play?
  				from.BeginTarget( 1, false, TargetFlags.None, new TargetStateCallback( OnPickedInstrument ), callback );
  			}
  		}
  
  		public static void OnPickedInstrument( Mobile from, object targeted, object state )
  		{
  			BaseInstrument instrument = targeted as BaseInstrument;
  
  			if ( instrument == null )
  			{
  				from.SendLocalizedMessage( 500619 ); // That is not a musical instrument.
  			}
  			else
  			{
  				SetInstrument( from, instrument );
  
  				InstrumentPickedCallback callback = state as InstrumentPickedCallback;
  
  				if ( callback != null )
  					callback( from, instrument );
  			}
  		}
  
  		public static bool IsMageryCreature( BaseCreature bc )
  		{
  			return ( bc != null && bc.AI == AIType.AI_Mage && bc.Skills[SkillName.Magery].Base > 5.0 );
  		}
  
  		public static bool IsFireBreathingCreature( BaseCreature bc )
  		{
  			if ( bc == null )
  				return false;
  
  			return bc.HasBreath;
  		}
  
  		public static bool IsPoisonImmune( BaseCreature bc )
  		{
  			return ( bc != null && bc.PoisonImmune != null );
  		}
  
  		public static int GetPoisonLevel( BaseCreature bc )
  		{
  			if ( bc == null )
  				return 0;
  
  			Poison p = bc.HitPoison;
  
  			if ( p == null )
  				return 0;
  
  			return p.Level + 1;
  		}
  
  		public double GetDifficultyFor( Mobile targ )
  		{
  			/* Difficulty TODO: Add another 100 points for each of the following abilities:
  				- Radiation or Aura Damage (Heat, Cold etc.)
  				- Summoning Undead
  			*/
  
  			double val = targ.Hits + targ.Stam + targ.Mana;
  
  			for ( int i = 0; i < targ.Skills.Length; i++ )
  				val += targ.Skills[i].Base;
  
  			if ( val > 700 )
  				val = 700 + ((val - 700) / 3.66667);
  
  			BaseCreature bc = targ as BaseCreature;
  
  			if ( IsMageryCreature( bc ) )
  				val += 100;
  
  			if ( IsFireBreathingCreature( bc ) )
  				val += 100;
  
  			if ( IsPoisonImmune( bc ) )
  				val += 100;
  
  			if ( targ is VampireBat || targ is VampireBatFamiliar )
  				val += 100;
  
  
gt: 			val += GetPoisonLevel( bc ) * 20;