context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using Server;
  using Server.Engines.BuffIcons;
  using Server.Mobiles;
  using Server.Items;
  using Server.Network;
  using Server.Targeting;
  using Server.Gumps;
  
  namespace Server.Items
  {
  	public class Bandage : Item, IDyable
  	{
  		public static readonly int Range = 2;
  
  		[Constructable]
  		public Bandage()
  			: this( 1 )
  		{
  		}
  
  		[Constructable]
  		public Bandage( int amount )
  			: base( 0xE21 )
  		{
  			Stackable = true;
  			Weight = 0.1;
  			Amount = amount;
  		}
  
  		public Bandage( Serial serial )
  			: base( serial )
  		{
  		}
  
  		public virtual int HealingBonus { get { return 0; } }
  
  		public virtual bool Dye( Mobile from, IDyeTub sender )
  		{
  			if ( Deleted )
  				return false;
  
  			Hue = sender.DyedHue;
  
  			return true;
  		}
  
  		public override void Serialize( GenericWriter writer )
  		{
  			base.Serialize( writer );
  
  			writer.Write( (int) 0 ); // version
  		}
  
  		public override void Deserialize( GenericReader reader )
  		{
  			base.Deserialize( reader );
  
  			/*int version = */
  			reader.ReadInt();
  		}
  
  		public override void OnDoubleClick( Mobile from )
  		{
  			if ( from.InRange( GetWorldLocation(), Range ) )
  			{
  				from.RevealingAction();
  
  				from.SendLocalizedMessage( 500948 ); // Who will you use the bandages on?
  				from.Target = new InternalTarget( this );
  			}
  			else
  			{
  				from.SendLocalizedMessage( 500295 ); // You are too far away to do that.
  			}
  		}
  
  		private class InternalTarget : Target
  		{
  			private Bandage m_Bandage;
  
  			public InternalTarget( Bandage bandage )
  				: base( Bandage.Range, false, TargetFlags.Beneficial )
  			{
  				m_Bandage = bandage;
  			}
  
  			protected override void OnTarget( Mobile from, object targeted )
  			{
  				if ( m_Bandage.Deleted )
  					return;
  
  				if ( targeted is Mobile )
  				{
  					if ( from.InRange( m_Bandage.GetWorldLocation(), Range ) )
  					{
  						BandageContext context;
  
  						if ( ( context = BandageContext.BeginHeal( from, (Mobile) targeted, m_Bandage ) ) != null )
  						{
  							m_Bandage.OnHealStarted( context );
  							m_Bandage.Consume();
  						}
  					}
  					else
  					{
  						from.SendLocalizedMessage( 500295 ); // You are too far away to do that.
  					}
  				}
  				else
  				{
  					from.SendLocalizedMessage( 500970 ); // Bandages can not be used on that.
  				}
  			}
  		}
  
  		public virtual void OnHealStarted( BandageContext context )
  		{
  		}
  
  		public virtual void OnHealFinished( BandageContext context )
  		{
  		}
  
  		public virtual bool AttemptsMidlifeCure { get { return true; } }
  	}
  
  	public class BandageContext
  	{
  		private Mobile m_Healer;
  		private Mobile m_Patient;
  		private Bandage m_Bandage;
  		private int m_Slips;
  		private TimeSpan m_Delay;
  		private Timer m_Timer;
  		private int m_AmountDivisor;
  
  		public Mobile Healer { get { return m_Healer; } }
  		public Mobile Patient { get { return m_Patient; } }
  		public Bandage Bandage { get { return m_Bandage; } }
  		public int Slips { get { return m_Slips; } set { m_Slips = value; } }
  		public TimeSpan Delay { get { return m_Delay; } }
  		public Timer Timer { get { return m_Timer; } }
  
  		public void Slip()
  		{
  			m_Healer.SendLocalizedMessage( 500961 ); // Your fingers slip!
  			++m_Slips;
  		}
  
  		public BandageContext( Mobile healer, Mobile patient, TimeSpan delay, Bandage bandage )
  		{
  			m_Healer = healer;
  			m_Patient = patient;
  			m_Bandage = bandage;
  			m_Delay = delay;
  
  			m_Timer = new InternalTimer( this, delay );
  			m_Timer.Start();
  		}
  
  		public void RefreshTimer( TimeSpan newDelay )
  		{
  			m_Delay = newDelay;
  
  			if ( m_Timer != null )
  				m_Timer.Stop();
  
  			m_Timer = new InternalTimer( this, newDelay );
  			m_Timer.Start();
  		}
  
  		private static Hashtable m_Table = new Hashtable();
  
  		public static BandageContext GetContext( Mobile healer )
  		{
  			return (BandageContext) m_Table[healer];
  		}
  
  		public static SkillName GetPrimarySkill( Mobile m, Mobile n )
  		{
  			if ( m is CuSidhe && n is CuSidhe )
  				return SkillName.Healing;
  			else if ( !m.Player && ( m.Body.IsMonster || m.Body.IsAnimal ) )
  				return SkillName.Veterinary;
  			else
  				return SkillName.Healing;
  		}
  
  		public static SkillName GetSecondarySkill( Mobile m, Mobile n )
  		{
  			if ( m is CuSidhe && n is CuSidhe )
  				return SkillName.Healing;
  			else if ( !m.Player && ( m.Body.IsMonster || m.Body.IsAnimal ) )
  				return SkillName.AnimalLore;
  			else
  				return SkillName.Anatomy;
  		}
  
  		public void AttemptMidlifeCure()
  		{
  			if ( m_Bandage == null || !m_Bandage.AttemptsMidlifeCure )
  				return;
  
  			if ( m_Healer != m_Patient || !m_Healer.Alive || !m_Healer.Player )
  				return;
  
  			SkillName primarySkill = GetPrimarySkill( m_Patient, m_Healer );
  			SkillName secondarySkill = GetSecondarySkill( m_Patient, m_Healer );
  
  			double healing = m_Healer.Skills[primarySkill].Value;
  			double anatomy = m_Healer.Skills[secondarySkill].Value;
  
  			if ( healing >= 80.0 && anatomy >= 80.0 )
  			{
  				int poisonStrength = GetPoisonStrength( m_Patient );
  				if ( poisonStrength > 0 )
  				{
  					double chance = ( healing + anatomy - 120 ) * 25 / ( poisonStrength * 2000 );
  					if ( chance > Utility.RandomDouble() )
  					{
  						if ( BleedAttack.IsBleeding( m_Patient ) )
  						{
  							m_Patient.SendLocalizedMessage( 1060167 ); // The bleeding wounds have healed, you are no longer bleeding!
  
  							BleedAttack.EndBleed( m_Patient, message: false );
  						}
  						else if ( m_Patient.Poisoned && m_Patient.CurePoison( m_Healer ) )
  						{
  							m_Patient.SendLocalizedMessage( 1010059 ); // You have been cured of all poisons.
  						}
  
  						m_AmountDivisor = poisonStrength;
  					}
  				}
  			}
  		}
  
  		private static int GetPoisonStrength( Mobile patient )
  		{
  			if ( BleedAttack.IsBleeding( patient ) )
  				return 3;
  
  			if ( patient.Poisoned )
  				return patient.Poison.Level;
  
  			return 0;
  		}
  
  		public void EndHeal()
  		{
  			m_Table.Remove( m_Healer );
  
  			if ( m_Timer != null )
  				m_Timer.Stop();
  
  			m_Timer = null;
  
  			if ( m_Bandage != null )
  				m_Bandage.OnHealFinished( this );
  
  			int healerNumber = -1, patientNumber = -1;
  			bool playSound = true;
  			bool checkSkills = false;
  
  			SkillName primarySkill = GetPrimarySkill( m_Patient, m_Healer );
  			SkillName secondarySkill = GetSecondarySkill( m_Patient, m_Healer );
  
  			BaseCreature petPatient = m_Patient as BaseCreature;
  
  			if ( !m_Healer.Alive )
  			{
  				healerNumber = 500962; // You were unable to finish your work before you died.
  				patientNumber = -1;
  				playSound = false;
  			}
  			else if ( !m_Healer.InRange( m_Patient, Bandage.Range ) )
  			{
  				healerNumber = 500963; // You did not stay close enough to heal your target.
  				patientNumber = -1;
  				playSound = false;
  			}
  			else if ( !m_Patient.Alive || ( petPatient != null && petPatient.IsDeadPet ) )
  			{
  				double healing = m_Healer.Skills[primarySkill].Value;
  				double anatomy = m_Healer.Skills[secondarySkill].Value;
  				double chance = ( ( healing - 68.0 ) / 50.0 ) - ( m_Slips * 0.02 );
  
  				if ( m_Patient is BaseMount && m_Healer == (Mobile) petPatient.ControlMaster && ( ( (BaseMount) m_Patient ).ItemID == 16047 || ( (BaseMount) m_Patient ).ItemID == 16048 || ( (BaseMount) m_Patient ).ItemID == 16049 || ( (BaseMount) m_Patient ).ItemID == 16050 ) )
  				{
  					healerNumber = 503255; // You are able to resurrect the creature.
  					patientNumber = -1;
  
  					m_Patient.PlaySound( 0x214 );
  					m_Patient.FixedEffect( 0x376A, 10, 16 );
  
  					petPatient.ControlMaster.CloseGump<PetResurrectGump>();
  
  					if ( petPatient.ControlMaster == m_Healer )
  					{
  						petPatient.ResurrectPet();
  
  						for ( int i = 0; i < petPatient.Skills.Length; ++i ) // Decrease all skills on pet.
  							petPatient.Skills[i].Base -= 0.1;
  					}
  					else
  					{
  						petPatient.ControlMaster.SendGump( new PetResurrectGump( m_Healer, petPatient ) );
  					}
  				}
  				else if ( ( checkSkills = ( healing >= 80.0 && anatomy >= 80.0 ) ) && chance > Utility.RandomDouble() )
  				{
  					if ( m_Patient.Map == null || !m_Patient.Map.CanFit( m_Patient.Location, 16, false, false ) )
  					{
  						healerNumber = 501042; // Target can not be resurrected at that location.
  
gt: 						patientNumber = 502391; // Thou can not be resurrected there!