/**********************************************************
RunUO 2.0 AoV C# script file
Official Age of Valor Script :: www.uovalor.com
Last modified by 
Filepath: scripts\Items\Skill Items\Magical\Potions\Explosion Potions\BaseExplosionPotion.cs
Lines of code: 261
***********************************************************/


using System;
using System.Collections;
using Server;
using Server.Network;
using Server.Targeting;
using Server.Spells;
using Server.Mobiles;

namespace Server.Items
{
	public abstract class BaseExplosionPotion : BasePotion
	{
		public abstract int MinDamage { get; }
		public abstract int MaxDamage { get; }

		public override bool RequireFreeHand{ get{ return false; } }
		public override bool CanBeTriggered{get{return true;} }

		private static bool LeveledExplosion = true; // Should explosion potions explode other nearby potions?
		private static bool InstantExplosion = false; // Should explosion potions explode on impact?
		private const int   ExplosionRange   = 2;     // How long is the blast radius?
		
		public BaseExplosionPotion( PotionEffect effect ) : base( 0xF0D, effect )
		{
		}

		public BaseExplosionPotion( Serial serial ) : base( serial )
		{
		}

		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 virtual object FindParent( Mobile from )
		{
			Mobile m = this.HeldBy;

			if ( m != null && m.Holding == this )
				return m;

			object obj = this.RootParent;

			if ( obj != null )
				return obj;

			if ( Map == Map.Internal )
				return from;

			return this;
		}
		
		

		
		
		

		private Timer m_Timer;
		private ArrayList m_Users;
		private bool active;
		

		public override void Drink( Mobile from )
		{		
			if ( Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting)) )
			{
				from.SendLocalizedMessage( 1062725 ); // You can not use a purple potion while paralyzed.
				return;
			}
			else if(UseDelaySystem.CheckContext(from, DelayContextType.ExplosionPotion) && !active)
			{
				from.SendMessage("You must wait before throwing another potion");
				return;
			}
			
			bool showthrowmsg=false;
			

			if(IsChildOf( from.Backpack ))
			{
				showthrowmsg=true;
				ThrowTarget targ = from.Target as ThrowTarget;

				if ( targ != null && targ.Potion == this )
					return;
					
				from.Target = new ThrowTarget( this,from );
			}
			
			from.RevealingAction();

			if ( m_Users == null )
				m_Users = new ArrayList();

			if ( !m_Users.Contains( from ) )
				m_Users.Add( from );
				
			UseDelaySystem.AddContext(from, DelayContextType.ExplosionPotion, TimeSpan.FromSeconds(1));


			if ( m_Timer == null )
			{
				if(showthrowmsg)from.SendLocalizedMessage( 500236 ); // You should throw it now!
				m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 0.75 ), TimeSpan.FromSeconds( 1.0 ), 4, new TimerStateCallback( Detonate_OnTick ), new object[]{ from, 3 } );
			}
		}

		private void Detonate_OnTick( object state )
		{
			if ( Deleted )
				return;

			object[] states = (object[])state;
			Mobile from = (Mobile)states[0];
			int timer = (int)states[1];

			object parent = FindParent( from );

			if ( timer == 0 )
			{
				Point3D loc;
				Map map;

				if ( parent is Item )
				{
					Item item = (Item)parent;

					loc = item.GetWorldLocation();
					map = item.Map;
				}
				else if ( parent is Mobile )
				{
					Mobile m = (Mobile)parent;

					loc = m.Location;
					map = m.Map;
				}
				else
				{
					return;
				}

				Explode( from, true, loc, map );
			}
			else
			{
				if ( parent is Item )
					((Item)parent).PublicOverheadMessage( MessageType.Regular, 0x22, false, timer.ToString() );
				else if ( parent is Mobile )
					((Mobile)parent).PublicOverheadMessage( MessageType.Regular, 0x22, false, timer.ToString() );

				states[1] = timer - 1;
			}
		}

		private void Reposition_OnTick( object state )
		{
			if ( Deleted )
				return;

			object[] states = (object[])state;
			Mobile from = (Mobile)states[0];
			IPoint3D p = (IPoint3D)states[1];
			Map map = (Map)states[2];

			Point3D loc = new Point3D( p );
			

			if ( InstantExplosion )
				Explode( from, true, loc, map );
			else
				MoveToWorld( loc, map );
		}

		public class ThrowTarget : Target
		{
			private BaseExplosionPotion m_Potion;

			public BaseExplosionPotion Potion
			{
				get{ return m_Potion; }
			}

			public ThrowTarget( BaseExplosionPotion potion,Mobile from ) : base( 12, true, TargetFlags.None )
			{
			m_Potion = potion;
			
					if(potion.Amount>1)
					{
					Type t = potion.GetType();
					
					Item newstack = Activator.CreateInstance(t) as Item;
					newstack.Amount=potion.Amount-1;
					m_Potion.Amount=1;
					m_Potion.Stackable=false; //so new stack wont just get readded to it, this particular pot is going to blow anyway
					
					if(!potion.IsChildOf( from.Backpack ))newstack.MoveToWorld(from.Location,from.Map);
					else if(from.Backpack!=null)
					{
					Container pack = from.Backpack;
					pack.AddItem(newstack);					
					}
					newstack.X=m_Potion.X;
					newstack.Y=m_Potion.Y;					
					}			
			}

			protected override void OnTarget( Mobile from, object targeted )
			{
				if ( m_Potion.Deleted || m_Potion.Map == Map.Internal )
					return;

				IPoint3D p = targeted as IPoint3D;

				if ( p == null )
					return;

				Map map = from.Map;

				if ( map == null )
					return;
								

				SpellHelper.GetSurfaceTop( ref p );

				from.RevealingAction();

				IEntity to;

				if ( p is Mobile )
					to = (Mobile)p;
				else
					to = new Entity( Serial.Zero, new Point3D( p ), map );

				Effects.SendMovingEffect( from, to, m_Potion.ItemID & 0x3FFF, 7, 0, false, false, m_Potion.Hue, 0 );

				m_Potion.Internalize();
				Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( m_Potion.Reposition_OnTick ), new object[]{ from, p, map } );
			}
			
			protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType )
			{
			UseDelaySystem.RemoveContext(from,DelayContextType.ExplosionPotion);
			}
			
		
			
		}
		
		public override bool OnTrigger(Mobile from,Item itemfrom,TriggerType type)
		{
		if(0.1>Utility.RandomDouble())return false;
		
		bool dotrigger=false;
		if(type==TriggerType.Explosion)dotrigger=true;
		else if(type==TriggerType.Impact && 0.2>Utility.RandomDouble())dotrigger=true;
		else if(type==TriggerType.Heat && 0.4>Utility.RandomDouble())dotrigger=true;
		
		if(dotrigger)Explode( from, false, this.Location,this.Map );
		
		return dotrigger;
		}

		public void Explode( Mobile from, bool direct, Point3D loc, Map map )
		{
			if ( Deleted )
				return;

			Delete();

			for ( int i = 0; m_Users != null && i < m_Users.Count; ++i )
			{
				Mobile m = (Mobile)m_Users[i];
				ThrowTarget targ = m.Target as ThrowTarget;

				if ( targ != null && targ.Potion == this )
					Target.Cancel( m );
			}

			if ( map == null )
				return;

			Effects.PlaySound( loc, map, 0x207 );
			Effects.SendLocationEffect( loc, map, 0x36BD, 20 );
			
			int alchemyBonus = GetEnhancePot(from);
			
			
			// (alchemyBonus is max of about 110)
			bool critical = false; //(alchemyBonus>Utility.Random(500) && direct);		
			if(critical)from.SendMessage("You make a critical explosion!");

			IPooledEnumerable eable = map.GetObjectsInRange( loc, critical ? ExplosionRange*2 : ExplosionRange );
			ArrayList toExplode = new ArrayList();


			foreach ( object o in eable )
			{
				if ( o is Mobile )
				{
					toExplode.Add( o );
				}
				else if (o is Item)
				{
				toExplode.Add( o );				
				}
			}

			eable.Free();

			int min = Scale( from, MinDamage );
			int max = Scale( from, MaxDamage );

			for ( int i = 0; i < toExplode.Count; ++i )
			{
				object o = toExplode[i];

				if ( o is Mobile )
				{
					Mobile m = (Mobile)o;

					if ( from != null && (from.ShouldHarm( m ) || from==m))
					{
						if ( from != null )
							from.DoHarmful( m );

						int damage = Utility.RandomMinMax( min, max )*Amount;

						damage += alchemyBonus;
						
						if (critical)damage*=2;

						if ( m is PlayerMobile && from is PlayerMobile && damage > 50)
							damage = critical ? 100 : 50; //damage capped  for pvp
						
						if(critical)m.SendMessage("You are hit with a critical explosion!");
						AOS.Damage( m, from, damage, 0, 100, 0, 0, 0 );
					}
				}
				else if ( o is Item )
				{
					Item pot = (Item)o;

					pot.Trigger(from,this,TriggerType.Explosion);
				} 
			}
		}
	}
}