context: using System;
  using System.Collections.Generic;
  using Server.Network;
  using Server.Items;
  using Server.Targeting;
  using Server.Spells.Necromancy;
  using Server.Spells.Fourth;
  using Server.Engines.BuffIcons;
  using Server.Events;
  
  namespace Server.Spells.Mysticism
  {
  	public class SpellPlagueSpell : MysticismSpell
  	{
  		public static void Initialize()
  		{
  			EventSink.Instance.PlayerDeath += new PlayerDeathEventHandler( OnPlayerDeath );
  		}
  
  		private static SpellInfo m_Info = new SpellInfo(
  				"Spell Plague", "Vas Rel Jux Ort",
  				-1,
  				9002,
  				Reagent.DaemonBone,
  				Reagent.DragonsBlood,
  				Reagent.Nightshade,
  				Reagent.SulfurousAsh
  			);
  
  		public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.25 ); } }
  
  		public override double RequiredSkill { get { return 70.0; } }
  		public override int RequiredMana { get { return 40; } }
  
  		public SpellPlagueSpell( Mobile caster, Item scroll )
  			: base( caster, scroll, m_Info )
  		{
  		}
  
  		public override void OnCast()
  		{
  			Caster.Target = new InternalTarget( this );
  		}
  
  		public void Target( Mobile targeted )
  		{
  			if ( !Caster.CanSee( targeted ) )
  			{
  				Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
  			}
  			else if ( CheckHSequence( targeted ) )
  			{
  				SpellHelper.Turn( Caster, targeted );
  
  				SpellHelper.CheckReflect( 6, Caster, ref targeted );
  
  				/* The target is hit with an explosion of chaos damage and then inflicted
  				 * with the spell plague curse. Each time the target is damaged while under
  				 * the effect of the spell plague, they may suffer an explosion of chaos
  				 * damage. The initial chance to trigger the explosion starts at 90% and
  				 * reduces by 30% every time an explosion occurs. Once the target is
  				 * afflicted by 3 explosions or 8 seconds have passed, that spell plague
  				 * is removed from the target. Spell Plague will stack with other spell
  				 * plagues so that they are applied one after the other.
  				 */
  
  				VisualEffect( targeted );
  
  				/* Deal the damage */
  				double damage = GetNewAosDamage( 33, 1, 5, targeted );
  
  				int[] types = new int[4];
  				types[Utility.Random( types.Length )] = 100;
  
  				SpellHelper.Damage( this, targeted, damage, 0, types[0], types[1], types[2], types[3] );
  
  				/* Plague */
  				SpellPlagueContext context = new SpellPlagueContext( this, targeted );
  
  				if ( m_Table.ContainsKey( targeted ) )
  				{
  					SpellPlagueContext oldContext = m_Table[targeted];
  					oldContext.SetNext( context );
  				}
  				else
  				{
  					m_Table[targeted] = context;
  					context.Start();
  				}
  			}
  
  			FinishSequence();
  		}
  
  		public static bool UnderEffect( Mobile m )
  		{
  			return m_Table.ContainsKey( m );
  		}
  
  		public static void RemoveEffect( Mobile m )
  		{
  			if ( m_Table.ContainsKey( m ) )
  			{
  				SpellPlagueContext context = m_Table[m];
  
  				context.EndPlague( false );
  			}
  		}
  
  		public static void CheckPlague( Mobile m )
  		{
  			if ( m_Table.ContainsKey( m ) )
  			{
  				SpellPlagueContext context = m_Table[m];
  
  				context.OnDamage();
  			}
  		}
  
  		private static void OnPlayerDeath( PlayerDeathEventArgs e )
  		{
  			RemoveEffect( e.Mobile );
  		}
  
  		private static Dictionary<Mobile, SpellPlagueContext> m_Table = new Dictionary<Mobile, SpellPlagueContext>();
  
  		protected void VisualEffect( Mobile to )
  		{
  			to.PlaySound( 0x658 );
  
  			to.FixedParticles( 0x3728, 1, 13, 0x26B8, 0x47E, 7, EffectLayer.Head, 0 );
  			to.FixedParticles( 0x3779, 1, 15, 0x251E, 0x43, 7, EffectLayer.Head, 0 );
  		}
  
  		private class SpellPlagueContext
  		{
  			private SpellPlagueSpell m_Owner;
  			private Mobile m_Target;
  			private DateTime m_LastExploded;
  			private int m_Explosions;
  			private Timer m_Timer;
  			private SpellPlagueContext m_Next;
  
  			public SpellPlagueContext( SpellPlagueSpell owner, Mobile target )
  			{
  				m_Owner = owner;
  				m_Target = target;
  			}
  
  			public void SetNext( SpellPlagueContext context )
  			{
  				if ( m_Next == null )
  					m_Next = context;
  				else
  					m_Next.SetNext( context );
  			}
  
  			public void Start()
  			{
  				m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 8.0 ), new TimerCallback( EndPlague ) );
  				m_Timer.Start();
  
  				BuffInfo.AddBuff( m_Target, new BuffInfo( BuffIcon.SpellPlague, 1031690, 1080167, TimeSpan.FromSeconds( 8.5 ), m_Target ) );
  			}
  
  			public void OnDamage()
  			{
  				if ( DateTime.Now > ( m_LastExploded + TimeSpan.FromSeconds( 2.0 ) ) )
  				{
  					int exploChance = 90 - ( m_Explosions * 30 );
  
  					double resist = m_Target.Skills[SkillName.MagicResist].Value;
  
  					if ( resist >= 70 )
  						exploChance -= (int) ( ( resist - 70.0 ) * 3.0 / 10.0 );
  
  					if ( exploChance > Utility.Random( 100 ) )
  					{
  						m_Owner.VisualEffect( m_Target );
  
  						double damage = m_Owner.GetNewAosDamage( 15 + ( m_Explosions * 3 ), 1, 5, m_Target );
  
  						m_Explosions++;
  						m_LastExploded = DateTime.Now;
  
  						int[] types = new int[4];
  						types[Utility.Random( types.Length )] = 100;
  
  						SpellHelper.Damage( m_Owner, m_Target, damage, 0, types[0], types[1], types[2], types[3] );
  
  						if ( m_Explosions >= 3 )
  							EndPlague();
  					}
  				}
  			}
  
  			public void EndPlague()
  			{
  				EndPlague( true );
  			}
  
  			public void EndPlague( bool restart )
  			{
  				if ( m_Timer != null )
  					m_Timer.Stop();
  
  				if ( restart && m_Next != null )
  				{
  					m_Table[m_Target] = m_Next;
  					m_Next.Start();
  				}
  				else
  				{
  					m_Table.Remove( m_Target );
  
  
gt: 					BuffInfo.RemoveBuff( m_Target, BuffIcon.SpellPlague );