using System;
using System.Collections;
using System.Collections.Generic;
using Server.Commands;
using Server.Engines.PartySystem;
using Server.Factions;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Spells;
using Server.Spells.Bushido;
using Server.Spells.Chivalry;
using Server.Spells.Necromancy;
using Server.Spells.Ninjitsu;
using Server.Spells.Seventh;
using Server.Spells.Spellweaving;
namespace Server.Engines.ConPVP
{
    public delegate void CountdownCallback( int count );
	public class DuelContext
	{
		private Mobile m_Initiator;
		private ArrayList m_Participants;
		private Ruleset m_Ruleset;
		private Arena m_Arena;
		private bool m_Registered = true;
		private bool m_Finished, m_Started;
		private bool m_ReadyWait;
		private int m_ReadyCount;
		private bool m_Rematch;
		public bool Rematch{ get{ return m_Rematch; } }
		public bool ReadyWait{ get{ return m_ReadyWait; } }
		public int ReadyCount{ get{ return m_ReadyCount; } }
		public bool Registered{ get{ return m_Registered; } }
		public bool Finished{ get{ return m_Finished; } }
		public bool Started{ get{ return m_Started; } }
		public Mobile Initiator{ get{ return m_Initiator; } }
		public ArrayList Participants{ get{ return m_Participants; } }
		public Ruleset Ruleset{ get{ return m_Ruleset; } }
		public Arena Arena{ get{ return m_Arena; } }
		private bool CantDoAnything( Mobile mob )
		{
			if ( m_EventGame != null )
				return m_EventGame.CantDoAnything( mob );
			else
				return false;
		}
		public static bool IsFreeConsume( Mobile mob )
		{
			PlayerMobile pm = mob as PlayerMobile;
			if ( pm == null || pm.DuelContext == null || pm.DuelContext.m_EventGame == null )
				return false;
			return pm.DuelContext.m_EventGame.FreeConsume;
		}
		public void DelayBounce( TimeSpan ts, Mobile mob, Container corpse )
		{
			Timer.DelayCall( ts, new TimerStateCallback( DelayBounce_Callback ), new object[]{ mob, corpse } );
		}
		public static bool AllowSpecialMove( Mobile from, string name, SpecialMove move )
		{
			PlayerMobile pm = from as PlayerMobile;
			if( pm == null )
				return true;
			DuelContext dc = pm.DuelContext;
			return (dc == null || dc.InstAllowSpecialMove( from, name, move ));
		}
		public bool InstAllowSpecialMove( Mobile from, string name, SpecialMove move )
		{
			if ( !m_StartedBeginCountdown )
				return true;
			DuelPlayer pl = Find( from );
			if ( pl == null || pl.Eliminated )
				return true;
			if ( CantDoAnything( from ) )
				return false;
			string title = null;
			if( move is NinjaMove )
				title = "Bushido";
			else if( move is SamuraiMove )
				title = "Ninjitsu";
			if ( title == null || name == null || m_Ruleset.GetOption( title, name ) )
				return true;
			from.SendMessage( "The dueling ruleset prevents you from using this move." );
			return false;
		}
		public bool AllowSpellCast( Mobile from, Spell spell )
		{
			if ( !m_StartedBeginCountdown )
				return true;
			DuelPlayer pl = Find( from );
			if ( pl == null || pl.Eliminated )
				return true;
			if ( CantDoAnything( from ) )
				return false;
			if ( spell is Server.Spells.Fourth.RecallSpell )
				from.SendMessage( "You may not cast this spell." );
			string title = null, option = null;
			if( spell is ArcanistSpell )
			{
				title = "Spellweaving";
				option = spell.Name;
			}
			else if ( spell is PaladinSpell )
			{
				title = "Chivalry";
				option = spell.Name;
			}
			else if ( spell is NecromancerSpell )
			{
				title = "Necromancy";
				option = spell.Name;
			}
			else if ( spell is NinjaSpell )
			{
				title = "Ninjitsu";
				option = spell.Name;
			}
			else if ( spell is SamuraiSpell )
			{
				title = "Bushido";
				option = spell.Name;
			}
			else if( spell is MagerySpell )
			{
				switch( ((MagerySpell)spell).Circle )
				{
					case SpellCircle.First: title = "1st Circle"; break;
					case SpellCircle.Second: title = "2nd Circle"; break;
					case SpellCircle.Third: title = "3rd Circle"; break;
					case SpellCircle.Fourth: title = "4th Circle"; break;
					case SpellCircle.Fifth: title = "5th Circle"; break;
					case SpellCircle.Sixth: title = "6th Circle"; break;
					case SpellCircle.Seventh: title = "7th Circle"; break;
					case SpellCircle.Eighth: title = "8th Circle"; break;
				}
				option = spell.Name;
			}
			else
			{
				title = "Other Spell";
				option = spell.Name;
			}
			if ( title == null || option == null || m_Ruleset.GetOption( title, option ) )
				return true;
			from.SendMessage( "The dueling ruleset prevents you from casting this spell." );
			return false;
		}
		public bool AllowItemEquip( Mobile from, Item item )
		{
			if ( !m_StartedBeginCountdown )
				return true;
			DuelPlayer pl = Find( from );
			if ( pl == null || pl.Eliminated )
				return true;
			if ( item is Dagger || CheckItemEquip( from, item ) )
				return true;
			from.SendMessage( "The dueling ruleset prevents you from equiping this item." );
			return false;
		}
		public static bool AllowSpecialAbility( Mobile from, string name, bool message )
		{
			PlayerMobile pm = from as PlayerMobile;
			if ( pm == null )
				return true;
			DuelContext dc = pm.DuelContext;
			return ( dc == null || dc.InstAllowSpecialAbility( from, name, message ) );
		}
		public bool InstAllowSpecialAbility( Mobile from, string name, bool message )
		{
			if ( !m_StartedBeginCountdown )
				return true;
			DuelPlayer pl = Find( from );
			if ( pl == null || pl.Eliminated )
				return true;
			if ( CantDoAnything( from ) )
				return false;
			if ( m_Ruleset.GetOption( "Combat Abilities", name ) )
				return true;
			if ( message )
				from.SendMessage( "The dueling ruleset prevents you from using this combat ability." );
			return false;
		}
		public bool CheckItemEquip( Mobile from, Item item )
		{
			if ( item is Fists )
			{
				if ( !m_Ruleset.GetOption( "Weapons", "Wrestling" ) )
					return false;
			}
			else if ( item is BaseArmor )
			{
				BaseArmor armor = (BaseArmor)item;
				if ( armor.ProtectionLevel > ArmorProtectionLevel.Regular && !m_Ruleset.GetOption( "Armor", "Magical" ) )
					return false;
				if ( !Core.AOS && armor.Resource != armor.DefaultResource && !m_Ruleset.GetOption( "Armor", "Colored" ) )
					return false;
				if ( armor is BaseShield && !m_Ruleset.GetOption( "Armor", "Shields" ) )
					return false;
			}
			else if ( item is BaseWeapon )
			{
				BaseWeapon weapon = (BaseWeapon)item;
				if ( (weapon.DamageLevel > WeaponDamageLevel.Regular || weapon.AccuracyLevel > WeaponAccuracyLevel.Regular) && !m_Ruleset.GetOption( "Weapons", "Magical" ) )
					return false;
				if ( !Core.AOS && weapon.Resource != CraftResource.Iron && weapon.Resource != CraftResource.None && !m_Ruleset.GetOption( "Weapons", "Runics" ) )
					return false;
				if ( weapon is BaseRanged && !m_Ruleset.GetOption( "Weapons", "Ranged" ) )
					return false;
				if ( !(weapon is BaseRanged) && !m_Ruleset.GetOption( "Weapons", "Melee" ) )
					return false;
				if ( weapon.PoisonCharges > 0 && weapon.Poison != null && !m_Ruleset.GetOption( "Weapons", "Poisoned" ) )
					return false;
				if ( weapon is BaseWand && !m_Ruleset.GetOption( "Items", "Wands" ) )
					return false;
			}
			return true;
		}
		public bool AllowSkillUse( Mobile from, SkillName skill )
		{
			if ( !m_StartedBeginCountdown )
				return true;
			DuelPlayer pl = Find( from );
			if ( pl == null || pl.Eliminated )
				return true;
			if ( CantDoAnything( from ) )
				return false;
			int id = (int)skill;
			if ( id >= 0 && id < SkillInfo.Table.Length )
			{
				if ( m_Ruleset.GetOption( "Skills", SkillInfo.Table[id].Name ) )
					return true;
			}
			from.SendMessage( "The dueling ruleset prevents you from using this skill." );
			return false;
		}
		public bool AllowItemUse( Mobile from, Item item )
		{
			if ( !m_StartedBeginCountdown )
				return true;
			DuelPlayer pl = Find( from );
			if ( pl == null || pl.Eliminated )
				return true;
			if ( !(item is BaseRefreshPotion) )
			{
				if ( CantDoAnything( from ) )
					return false;
			}
			string title = null, option = null;
			if ( item is BasePotion )
			{
				title = "Potions";
				if ( item is BaseAgilityPotion )
					option = "Agility";
				else if ( item is BaseCurePotion )
					option = "Cure";
				else if ( item is BaseHealPotion )
					option = "Heal";
				else if ( item is NightSightPotion )
					option = "Nightsight";
				else if ( item is BasePoisonPotion )
					option = "Poison";
				else if ( item is BaseStrengthPotion )
					option = "Strength";
				else if ( item is BaseExplosionPotion )
					option = "Explosion";
				else if ( item is BaseRefreshPotion )
					option = "Refresh";
			}
			else if ( item is Bandage )
			{
				title = "Items";
				option = "Bandages";
			}
			else if ( item is TrapableContainer )
			{
				if ( ((TrapableContainer)item).TrapType != TrapType.None )
				{
					title = "Items";
					option = "Trapped Containers";
				}
			}
			else if ( item is Bola )
			{
				title = "Items";
				option = "Bolas";
			}
			else if ( item is OrangePetals )
			{
				title = "Items";
				option = "Orange Petals";
			}
			else if ( item is EtherealMount || item.Layer == Layer.Mount )
			{
				title = "Items";
				option = "Mounts";
			}
			else if ( item is LeatherNinjaBelt )
			{
				title = "Items";
				option = "Shurikens";
			}
			else if ( item is Fukiya )
			{
				title = "Items";
				option = "Fukiya Darts";
			}
			else if ( item is FireHorn )
			{
				title = "Items";
				option = "Fire Horns";
			}
			else if ( item is BaseWand )
			{
				title = "Items";
				option = "Wands";
			}
			if ( title != null && option != null && m_StartedBeginCountdown && !m_Started )
			{
				from.SendMessage( "You may not use this item before the duel begins." );
				return false;
			}
			else if ( item is BasePotion && !(item is BaseExplosionPotion) && !(item is BaseRefreshPotion) && IsSuddenDeath )
			{
				from.SendMessage( 0x22, "You may not drink potions in sudden death." );
				return false;
			}
			else if ( item is Bandage && IsSuddenDeath )
			{
				from.SendMessage( 0x22, "You may not use bandages in sudden death." );
				return false;
			}
			if ( title == null || option == null || m_Ruleset.GetOption( title, option ) )
				return true;
			from.SendMessage( "The dueling ruleset prevents you from using this item." );
			return false;
		}
		private void DelayBounce_Callback( object state )
		{
			object[] states = (object[])state;
			Mobile mob = (Mobile) states[0];
			Container corpse = (Container) states[1];
			RemoveAggressions( mob );
			SendOutside( mob );
			Refresh( mob, corpse );
			Debuff( mob );
			CancelSpell( mob );
			mob.Frozen = false;
		}
		public void OnMapChanged( Mobile mob )
		{
			OnLocationChanged( mob );
		}
		public void OnLocationChanged( Mobile mob )
		{
			if ( !m_Registered || !m_StartedBeginCountdown || m_Finished )
				return;
			Arena arena = m_Arena;
			if ( arena == null )
				return;
			if ( mob.Map == arena.Facet && arena.Bounds.Contains( mob.Location ) )
				return;
			DuelPlayer pl = Find( mob );
			if ( pl == null || pl.Eliminated )
				return;
			if ( mob.Map == Map.Internal ) {
				// they've logged out
				if ( mob.LogoutMap == arena.Facet && arena.Bounds.Contains( mob.LogoutLocation ) ) {
					// they logged out inside the arena.. set them to eject on login
					mob.LogoutLocation = arena.Outside;
				}
			}
			pl.Eliminated = true;
			mob.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have forfeited your position in the duel." );
			mob.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has forfeited by leaving the dueling arena.", mob.Name ) );
			Participant winner = CheckCompletion();
			if ( winner != null )
				Finish( winner );
		}
		private bool m_Yielding;
		public void OnDeath( Mobile mob, Container corpse )
		{
			if ( !m_Registered || !m_Started )
				return;
			DuelPlayer pl = Find( mob );
			if ( pl != null && !pl.Eliminated )
			{
				if ( m_EventGame != null && !m_EventGame.OnDeath( mob, corpse ) )
					return;
				pl.Eliminated = true;
				if ( mob.Poison != null )
					mob.Poison = null;
				Requip( mob, corpse );
				DelayBounce( TimeSpan.FromSeconds( 4.0 ), mob, corpse );
				Participant winner = CheckCompletion();
				if ( winner != null )
				{
					Finish( winner );
				}
				else if ( !m_Yielding )
				{
					mob.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have been defeated." );
					mob.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has been defeated.", mob.Name ) );
				}
			}
		}
		public bool CheckFull()
		{
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant p = (Participant)m_Participants[i];
				if ( p.HasOpenSlot )
					return false;
			}
			return true;
		}
		public void Requip( Mobile from, Container cont )
		{
			Corpse corpse = cont as Corpse;
			if ( corpse == null )
				return;
			List<Item> items = new List<Item>( corpse.Items );
			bool gathered = false;
			bool didntFit = false;
			Container pack = from.Backpack;
			for ( int i = 0; !didntFit && i < items.Count; ++i )
			{
				Item item = items[i];
				Point3D loc = item.Location;
				if ( (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) || !item.Movable )
					continue;
				if ( pack != null )
				{
					pack.DropItem( item );
					gathered = true;
				}
				else
				{
					didntFit = true;
				}
			}
			corpse.Carved = true;
			if ( corpse.ItemID == 0x2006 )
			{
				corpse.ProcessDelta();
				corpse.SendRemovePacket();
				corpse.ItemID = Utility.Random( 0xECA, 9 ); // bone graphic
				corpse.Hue = 0;
				corpse.ProcessDelta();
				Mobile killer = from.FindMostRecentDamager( false );
				if ( killer != null && killer.Player )
					killer.AddToBackpack( new Head( m_Tournament == null ? HeadType.Duel : HeadType.Tournament, from.Name ) );
			}
			from.PlaySound( 0x3E3 );
			if ( gathered && !didntFit )
				from.SendLocalizedMessage( 1062471 ); // You quickly gather all of your belongings.
			else if ( gathered && didntFit )
				from.SendLocalizedMessage( 1062472 ); // You gather some of your belongings. The rest remain on the corpse.
		}
		public void Refresh( Mobile mob, Container cont )
		{
			if ( !mob.Alive )
			{
				mob.Resurrect();
				DeathRobe robe = mob.FindItemOnLayer( Layer.OuterTorso ) as DeathRobe;
				if ( robe != null )
					robe.Delete();
				if ( cont is Corpse )
				{
					Corpse corpse = (Corpse) cont;
					for ( int i = 0; i < corpse.EquipItems.Count; ++i )
					{
						Item item = corpse.EquipItems[i];
						if ( item.Movable && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair && item.IsChildOf( mob.Backpack ) )
							mob.EquipItem( item );
					}
				}
			}
			mob.Hits = mob.HitsMax;
			mob.Stam = mob.StamMax;
			mob.Mana = mob.ManaMax;
			mob.Poison = null;
		}
		public void SendOutside( Mobile mob )
		{
			if ( m_Arena == null )
				return;
			mob.Combatant = null;
			mob.MoveToWorld( m_Arena.Outside, m_Arena.Facet );
		}
		private Point3D m_GatePoint;
		private Map m_GateFacet;
		public void Finish( Participant winner )
		{
			if ( m_Finished )
				return;
			EndAutoTie();
			StopSDTimers();
			m_Finished = true;
			for ( int i = 0; i < winner.Players.Length; ++i )
			{
				DuelPlayer pl = winner.Players[i];
				if ( pl != null && !pl.Eliminated )
					DelayBounce( TimeSpan.FromSeconds( 8.0 ), pl.Mobile, null );
			}
			winner.Broadcast( 0x59, null, winner.Players.Length == 1 ? "{0} has won the duel." : "{0} and {1} team have won the duel.", winner.Players.Length == 1 ? "You have won the duel." : "Your team has won the duel." );
			if ( m_Tournament != null && winner.TournyPart != null )
			{
				m_Match.Winner = winner.TournyPart;
				winner.TournyPart.WonMatch( m_Match );
				m_Tournament.HandleWon( m_Arena, m_Match, winner.TournyPart );
			}
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant loser = (Participant)m_Participants[i];
				if ( loser != winner )
				{
					loser.Broadcast( 0x22, null, loser.Players.Length == 1 ? "{0} has lost the duel." : "{0} and {1} team have lost the duel.", loser.Players.Length == 1 ? "You have lost the duel." : "Your team has lost the duel." );
					if ( m_Tournament != null && loser.TournyPart != null )
						loser.TournyPart.LostMatch( m_Match );
				}
				for ( int j = 0; j < loser.Players.Length; ++j )
				{
					if ( loser.Players[j] != null )
					{
						RemoveAggressions( loser.Players[j].Mobile );
						loser.Players[j].Mobile.Delta( MobileDelta.Noto );
						loser.Players[j].Mobile.CloseGump( typeof( BeginGump ) );
						if ( m_Tournament != null )
							loser.Players[j].Mobile.SendEverything();
					}
				}
			}
			if ( IsOneVsOne )
			{
				DuelPlayer dp1 = ((Participant)m_Participants[0]).Players[0];
				DuelPlayer dp2 = ((Participant)m_Participants[1]).Players[0];
				if ( dp1 != null && dp2 != null )
				{
					Award( dp1.Mobile, dp2.Mobile, dp1.Participant == winner );
					Award( dp2.Mobile, dp1.Mobile, dp2.Participant == winner );
				}
			}
			if ( m_EventGame != null )
				m_EventGame.OnStop();
			Timer.DelayCall( TimeSpan.FromSeconds( 9.0 ), new TimerCallback( UnregisterRematch ) );
		}
		public void Award( Mobile us, Mobile them, bool won )
		{
			Ladder ladder = ( m_Arena == null ? Ladder.Instance : m_Arena.AcquireLadder() );
			if ( ladder == null )
				return;
			LadderEntry ourEntry = ladder.Find( us );
			LadderEntry theirEntry = ladder.Find( them );
			if ( ourEntry == null || theirEntry == null )
				return;
			int xpGain = Ladder.GetExperienceGain( ourEntry, theirEntry, won );
			if ( xpGain == 0 )
				return;
			if ( m_Tournament != null )
				xpGain *= ( xpGain > 0 ? 5 : 2 );
			if ( won )
				++ourEntry.Wins;
			else
				++ourEntry.Losses;
			int oldLevel = Ladder.GetLevel( ourEntry.Experience );
			ourEntry.Experience += xpGain;
			if ( ourEntry.Experience < 0 )
				ourEntry.Experience = 0;
			ladder.UpdateEntry( ourEntry );
			int newLevel = Ladder.GetLevel( ourEntry.Experience );
			if ( newLevel > oldLevel )
				us.SendMessage( 0x59, "You have achieved level {0}!", newLevel );
			else if ( newLevel < oldLevel )
				us.SendMessage( 0x22, "You have lost a level. You are now at {0}.", newLevel );
		}
		public void UnregisterRematch()
		{
			Unregister(true);
		}
		public void Unregister()
		{
			Unregister(false);
		}
		public void Unregister( bool queryRematch )
		{
			DestroyWall();
			if ( !m_Registered )
				return;
			m_Registered = false;
			if ( m_Arena != null )
				m_Arena.Evict();
			StopSDTimers();
			Type[] types = new Type[]{ typeof( BeginGump ), typeof( DuelContextGump ), typeof( ParticipantGump ), typeof( PickRulesetGump ), typeof( ReadyGump ), typeof( ReadyUpGump ), typeof( RulesetGump ) };
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant p = (Participant)m_Participants[i];
				for ( int j = 0; j < p.Players.Length; ++j )
				{
					DuelPlayer pl = (DuelPlayer)p.Players[j];
					if ( pl == null )
						continue;
					if ( pl.Mobile is PlayerMobile )
						((PlayerMobile)pl.Mobile).DuelPlayer = null;
					for ( int k = 0; k < types.Length; ++k )
						pl.Mobile.CloseGump( types[k] );
				}
			}
			if ( queryRematch && m_Tournament == null )
				QueryRematch();
		}
		public void QueryRematch()
		{
			DuelContext dc = new DuelContext( m_Initiator, m_Ruleset.Layout, false );
			dc.m_Ruleset = m_Ruleset;
			dc.m_Rematch = true;
			dc.m_Participants.Clear();
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant oldPart = (Participant)m_Participants[i];
				Participant newPart = new Participant( dc, oldPart.Players.Length );
				for ( int j = 0; j < oldPart.Players.Length; ++j )
				{
					DuelPlayer oldPlayer = oldPart.Players[j];
					if ( oldPlayer != null )
						newPart.Players[j] = new DuelPlayer( oldPlayer.Mobile, newPart );
				}
				dc.m_Participants.Add( newPart );
			}
			dc.CloseAllGumps();
			dc.SendReadyUpGump();
		}
		public DuelPlayer Find( Mobile mob )
		{
			if ( mob is PlayerMobile )
			{
				PlayerMobile pm = (PlayerMobile)mob;
				if ( pm.DuelContext == this )
					return pm.DuelPlayer;
				return null;
			}
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant p = (Participant)m_Participants[i];
				DuelPlayer pl = p.Find( mob );
				if ( pl != null )
					return pl;
			}
			return null;
		}
		public bool IsAlly( Mobile m1, Mobile m2 )
		{
			DuelPlayer pl1 = Find( m1 );
			DuelPlayer pl2 = Find( m2 );
			return ( pl1 != null && pl2 != null && pl1.Participant == pl2.Participant );
		}
		public Participant CheckCompletion()
		{
			Participant winner = null;
			bool hasWinner = false;
			int eliminated = 0;
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant p = (Participant)m_Participants[i];
				if ( p.Eliminated )
				{
					++eliminated;
					if ( eliminated == (m_Participants.Count - 1) )
						hasWinner = true;
				}
				else
				{
					winner = p;
				}
			}
			if ( hasWinner )
				return winner == null ? (Participant) m_Participants[0] : winner;
			return null;
		}
		private Timer m_Countdown;
		public void StartCountdown( int count, CountdownCallback cb )
		{
			cb(count);
			m_Countdown=Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), count, new TimerStateCallback( Countdown_Callback ), new object[]{ count-1, cb } );
		}
		public void StopCountdown()
		{
			if ( m_Countdown != null )
				m_Countdown.Stop();
			m_Countdown = null;
		}
		private void Countdown_Callback( object state )
		{
			object[] states = (object[])state;
			int count = (int)states[0];
			CountdownCallback cb = (CountdownCallback)states[1];
			if ( count==0 )
			{
				if ( m_Countdown != null )
					m_Countdown.Stop();
				m_Countdown=null;
			}
			cb( count );
			states[0] = count - 1;
		}
		private Timer m_AutoTieTimer;
		private bool m_Tied;
		public bool Tied{ get{ return m_Tied; } }
		private bool m_IsSuddenDeath;
		public bool IsSuddenDeath{ get{ return m_IsSuddenDeath; } set{ m_IsSuddenDeath = value; } }
		private Timer m_SDWarnTimer, m_SDActivateTimer;
		public void StopSDTimers()
		{
			if ( m_SDWarnTimer != null )
				m_SDWarnTimer.Stop();
			m_SDWarnTimer = null;
			if ( m_SDActivateTimer != null )
				m_SDActivateTimer.Stop();
			m_SDActivateTimer = null;
		}
		public void StartSuddenDeath( TimeSpan timeUntilActive )
		{
			if ( m_SDWarnTimer != null )
				m_SDWarnTimer.Stop();
			m_SDWarnTimer = Timer.DelayCall( TimeSpan.FromMinutes( timeUntilActive.TotalMinutes * 0.9 ), new TimerCallback( WarnSuddenDeath ) );
			if ( m_SDActivateTimer != null )
				m_SDActivateTimer.Stop();
			m_SDActivateTimer = Timer.DelayCall( timeUntilActive, new TimerCallback( ActivateSuddenDeath ) );
		}
		public void WarnSuddenDeath()
		{
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant p = (Participant)m_Participants[i];
				for ( int j = 0; j < p.Players.Length; ++j )
				{
					DuelPlayer pl = p.Players[j];
					if ( pl == null || pl.Eliminated )
						continue;
					pl.Mobile.SendSound( 0x1E1 );
					pl.Mobile.SendMessage( 0x22, "Warning! Warning! Warning!" );
					pl.Mobile.SendMessage( 0x22, "Sudden death will be active soon!" );
				}
			}
			if ( m_Tournament != null )
				m_Tournament.Alert( m_Arena, "Sudden death will be active soon!" );
			if ( m_SDWarnTimer != null )
				m_SDWarnTimer.Stop();
			m_SDWarnTimer = null;
		}
		public static bool CheckSuddenDeath( Mobile mob )
		{
			if ( mob is PlayerMobile )
			{
				PlayerMobile pm = (PlayerMobile)mob;
				if ( pm.DuelPlayer != null && !pm.DuelPlayer.Eliminated && pm.DuelContext != null && pm.DuelContext.IsSuddenDeath )
					return true;
			}
			return false;
		}
		public void ActivateSuddenDeath()
		{
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant p = (Participant)m_Participants[i];
				for ( int j = 0; j < p.Players.Length; ++j )
				{
					DuelPlayer pl = p.Players[j];
					if ( pl == null || pl.Eliminated )
						continue;
					pl.Mobile.SendSound( 0x1E1 );
					pl.Mobile.SendMessage( 0x22, "Warning! Warning! Warning!" );
					pl.Mobile.SendMessage( 0x22, "Sudden death has ACTIVATED. You are now unable to perform any beneficial actions." );
				}
			}
			if ( m_Tournament != null )
				m_Tournament.Alert( m_Arena, "Sudden death has been activated!" );
			m_IsSuddenDeath = true;
			if ( m_SDActivateTimer != null )
				m_SDActivateTimer.Stop();
			m_SDActivateTimer = null;
		}
		public void BeginAutoTie()
		{
			if ( m_AutoTieTimer != null )
				m_AutoTieTimer.Stop();
			TimeSpan ts = ( m_Tournament == null || m_Tournament.TournyType == TournyType.Standard )
				? AutoTieDelay
				: TimeSpan.FromMinutes( 90.0 );
			m_AutoTieTimer = Timer.DelayCall( ts, new TimerCallback( InvokeAutoTie ) );
		}
		public void EndAutoTie()
		{
			if ( m_AutoTieTimer != null )
				m_AutoTieTimer.Stop();
			m_AutoTieTimer = null;
		}
		public void InvokeAutoTie()
		{
			m_AutoTieTimer = null;
			if ( !m_Started || m_Finished )
				return;
			m_Tied = true;
			m_Finished = true;
			StopSDTimers();
			ArrayList remaining = new ArrayList();
			for ( int i = 0; i < m_Participants.Count; ++i )
			{
				Participant p = (Participant)m_Participants[i];
				if ( p.Eliminated )
				{
					p.Broadcast( 0x22, null, p.Players.Length == 1 ? "{0} has lost the duel." : "{0} and {1} team have lost the duel.", p.Players.Length == 1 ? "You have lost the duel." : "Your team has lost the duel." );
				}
				else
				{
					p.Broadcast( 0x59, null, p.Players.Length == 1 ? "{0} has tied the duel due to time expiration." : "{0} and {1} team have tied the duel due to time expiration.", p.Players.Length == 1 ? "You have tied the duel due to time expiration." : "Your team has tied the duel due to time expiration." );
					for ( int j = 0; j < p.Players.Length; ++j )
					{
						DuelPlayer pl = p.Players[j];
						if ( pl != null && !pl.Eliminated )
							DelayBounce( TimeSpan.FromSeconds( 8.0 ), pl.Mobile, null );
					}
					if ( p.TournyPart != null )
						remaining.Add( p.TournyPart );
				}
				for ( int j = 0; j < p.Players.Length; ++j )
				{
					DuelPlayer pl = p.Players[j];
					if ( pl != null )
					{
						pl.Mobile.Delta( MobileDelta.Noto );
						pl.Mobile.SendEverything();
					}
				}
			}
			if ( m_Tournament != null )
				m_Tournament.HandleTie( m_Arena, m_Match, remaining );
			Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Unregister ) );
		}
		public bool IsOneVsOne
		{
			get
			{
				if ( m_Participants.Count != 2 )
					return false;
				if ( ((Participant)m_Participants[0]).Players.Length != 1 )
					return false;
				if ( ((Participant)m_Participants[1]).Players.Length != 1 )
					return false;
				return true;
			}
		}
		public static void Initialize()
		{
			EventSink.Speech += new SpeechEventHandler( EventSink_Speech );
			EventSink.Login += new LoginEventHandler( EventSink_Login );
			CommandSystem.Register( "vli", AccessLevel.GameMaster, new CommandEventHandler( vli_oc ) );
		}
		private static void vli_oc( CommandEventArgs e )
		{
			e.Mobile.BeginTarget( -1, false, Targeting.TargetFlags.None, new TargetCallback( vli_ot ) );
		}
		private static void vli_ot( Mobile from, object obj )
		{
			if ( obj is PlayerMobile )
			{
				PlayerMobile pm = (PlayerMobile)obj;
				Ladder ladder = Ladder.Instance;
				if ( ladder == null )
					return;
				LadderEntry entry = ladder.Find( pm );
				if ( entry != null )
					from.SendGump( new PropertiesGump( from, entry ) );
			}
		}
		private static TimeSpan CombatDelay = TimeSpan.FromSeconds( 30.0 );
		private static TimeSpan AutoTieDelay = TimeSpan.FromMinutes( 15.0 );
		public static bool CheckCombat( Mobile m )
		{
			for ( int i = 0; i < m.Aggressed.Count; ++i )
			{
				AggressorInfo info = m.Aggressed[i];
				if ( info.Defender.Player && (DateTime.UtcNow - info.LastCombatTime) < CombatDelay )
					return true;
			}
			for ( int i = 0; i < m.Aggressors.Count; ++i )
			{
				AggressorInfo info = m.Aggressors[i];
				if ( info.Attacker.Player && (DateTime.UtcNow - info.LastCombatTime) < CombatDelay )
					return true;
			}
			return false;
		}
		private static void EventSink_Login( LoginEventArgs e )
		{
			PlayerMobile pm = e.Mobile as PlayerMobile;
			if ( pm == null )
				return;
			DuelContext dc = pm.DuelContext;
			if ( dc == null )
				return;
			if ( dc.ReadyWait && pm.DuelPlayer.Ready && !dc.Started && !dc.StartedBeginCountdown && !dc.Finished )
			{
				if ( dc.m_Tournament == null )
					pm.SendGump( new ReadyGump( pm, dc, dc.m_ReadyCount ) );
			}
			else if ( dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished )
			{
				if ( dc.m_Tournament == null )
					pm.SendGump( new ReadyUpGump( pm, dc ) );
			}
			else if ( dc.Initiator == pm && !dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished )
				pm.SendGump( new DuelContextGump( pm, dc ) );
		}
		private static void ViewLadder_OnTarget( Mobile from, object obj, object state )
		{
			if ( obj is PlayerMobile )
			{
				PlayerMobile pm = (PlayerMobile)obj;
				Ladder ladder = (Ladder)state;
				LadderEntry entry = ladder.Find( pm );
				if ( entry == null )
					return; // sanity
				string text = String.Format( "{{0}} are ranked {0} at level {1}.", LadderGump.Rank( entry.Index + 1 ), Ladder.GetLevel( entry.Experience ) );
				pm.PrivateOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, from==pm?"You":"They" ), from.NetState );
			}
			else if ( obj is Mobile )
			{
				Mobile mob = (Mobile)obj;
				if ( mob.Body.IsHuman )
					mob.PrivateOverheadMessage( MessageType.Regular, mob.SpeechHue, false, "I'm not a duelist, and quite frankly, I resent the implication.", from.NetState );
				else
					mob.PrivateOverheadMessage( MessageType.Regular, 0x3B2, true, "It's probably better than you.", from.NetState );
			}
			else
			{
				from.SendMessage( "That's not a player." );
			}
		}
		private static void EventSink_Speech( SpeechEventArgs e )
		{
			if ( e.Handled )
				return;
			PlayerMobile pm = e.Mobile as PlayerMobile;
			if ( pm == null )
				return;
			if ( Insensitive.Contains( e.Speech, "i wish to duel" ) )
			{
				if ( !pm.CheckAlive() )
				{
				}
				else if ( pm.Region.IsPartOf( typeof( Regions.Jail ) ) )
				{
				}
				else if ( CheckCombat( pm ) )
				{
					e.Mobile.SendMessage( 0x22, "You have recently been in combat with another player and must wait before starting a duel." );
				}
				else if ( pm.DuelContext != null )
				{
					if ( pm.DuelContext.Initiator == pm )
						e.Mobile.SendMessage( 0x22, "You have already started a duel." );
					else
						e.Mobile.SendMessage( 0x22, "You have already been challenged in a duel." );
				}
				else if ( TournamentController.IsActive )
				{
					e.Mobile.SendMessage( 0x22, "You may not start a duel while a tournament is active." );
				}
				else
				{
					pm.SendGump( new DuelContextGump( pm, new DuelContext( pm, RulesetLayout.Root ) ) );
					e.Handled = true;
				}
			}
			else if ( Insensitive.Equals( e.Speech, "change arena preferences" ) )
			{
				if ( !pm.CheckAlive() )
				{
				}
				else
				{
					Preferences prefs = Preferences.Instance;
					if ( prefs != null )
					{
						e.Mobile.CloseGump( typeof( PreferencesGump ) );
						e.Mobile.SendGump( new PreferencesGump( e.Mobile, prefs ) );
					}
				}
			}
			else if ( Insensitive.Equals( e.Speech, "showladder" ) )
			{
				e.Blocked=true;
				if ( !pm.CheckAlive() )
				{
				}
				else
				{
					Ladder instance = Ladder.Instance;
					if ( instance == null )
					{
						//pm.SendMessage( "Ladder not yet initialized." );
					}
					else
					{
						LadderEntry entry = instance.Find( pm );
						if ( entry == null )
							return; // sanity
						string text = String.Format( "{{0}} {{1}} ranked {0} at level {1}.", LadderGump.Rank( entry.Index + 1 ), Ladder.GetLevel( entry.Experience ) );
						pm.LocalOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, "You", "are" ) );
						pm.NonlocalOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, pm.Name, "is" ) );
						//pm.PublicOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( "Level {0} with {1} win{2} and {3} loss{4}.", Ladder.GetLevel( entry.Experience ), entry.Wins, entry.Wins==1?"":"s", entry.Losses, entry.Losses==1?"":"es" ) );
						//pm.PublicOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( "Level {0} with {1} win{2} and {3} loss{4}.", Ladder.GetLevel( entry.Experience ), entry.Wins, entry.Wins==1?"":"s", entry.Losses, entry.Losses==1?"":"es" ) );
					}
				}
			}
			else if ( Insensitive.Equals( e.Speech, "viewladder" ) )
			{
				e.Blocked=true;
				if ( !pm.CheckAlive() )
				{
				}
				else
				{
					Ladder instance = Ladder.Instance;
					if ( instance == null )
					{
						//pm.SendMessage( "Ladder not yet initialized." );
					}
					else
					{
						pm.SendMessage( "Target a player to view their ranking and level." );
						pm.BeginTarget( 16, false, Targeting.TargetFlags.None, new TargetStateCallback( ViewLadder_OnTarget ), instance );
					}
				}
			}
			else if ( Insensitive.Contains( e.Speech, "i yield" ) )
			{
				if ( !pm.CheckAlive() )
				{
				}
				else if ( pm.DuelContext == null )
				{
				}
				else if ( pm.DuelContext.Finished )
				{
					e.Mobile.SendMessage( 0x22, "The duel is already finished." );
				}
				else if ( !pm.DuelContext.Started )
				{
					DuelContext dc = pm.DuelContext;
					Mobile init = dc.Initiator;
					if ( pm.DuelContext.StartedBeginCountdown )
					{
						e.Mobile.SendMessage( 0x22, "The duel has not yet started." );
					}
					else
					{
						DuelPlayer pl = pm.DuelContext.Find( pm );
						if ( pl == null )
							return;
						Participant p = pl.Participant;
						if ( !pm.DuelContext.ReadyWait ) // still setting stuff up
						{
							p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." );
							if ( init == pm )
							{
								dc.Unregister();
							}
							else
							{
								p.Nullify( pl );
								pm.DuelPlayer=null;
								NetState ns = init.NetState;
								if ( ns != null )
								{
									foreach ( Gump g in ns.Gumps )
									{
										if ( g is ParticipantGump )
										{
											ParticipantGump pg = (ParticipantGump)g;
											if ( pg.Participant == p )
											{
												init.SendGump( new ParticipantGump( init, dc, p ) );
												break;
											}
										}
										else if ( g is DuelContextGump )
										{
											DuelContextGump dcg = (DuelContextGump)g;
											if ( dcg.Context == dc )
											{
												init.SendGump( new DuelContextGump( init, dc ) );
												break;
											}
										}
									}
								}
							}
						}
						else if ( !pm.DuelContext.StartedReadyCountdown ) // at ready stage
						{
							p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." );
							dc.m_Yielding=true;
							dc.RejectReady( pm, null );
							dc.m_Yielding=false;
							if ( init == pm )
							{
								dc.Unregister();
							}
							else if ( dc.m_Registered )
							{
								p.Nullify( pl );
								pm.DuelPlayer=null;
								NetState ns = init.NetState;
								if ( ns != null )
								{
									bool send=true;
									foreach ( Gump g in ns.Gumps )
									{
										if ( g is ParticipantGump )
										{
											ParticipantGump pg = (ParticipantGump)g;
											if ( pg.Participant == p )
											{
												init.SendGump( new ParticipantGump( init, dc, p ) );
												send=false;
												break;
											}
										}
										else if ( g is DuelContextGump )
										{
											DuelContextGump dcg = (DuelContextGump)g;
											if ( dcg.Context == dc )
											{
												init.SendGump( new DuelContextGump( init, dc ) );
												send=false;
												break;
											}
										}
									}
									if ( send )
										init.SendGump( new DuelContextGump( init, dc ) );
								}
							}
						}
						else
						{
							if ( pm.DuelContext.m_Countdown != null )
								pm.DuelContext.m_Countdown.Stop();
							pm.DuelContext.m_Countdown= null;
							pm.DuelContext.m_StartedReadyCountdown=false;
							p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." );
							dc.m_Yielding=true;
							dc.RejectReady( pm, null );
							dc.m_Yielding=false;
							if ( init == pm )
							{
								dc.Unregister();
							}
							else if ( dc.m_Registered )
							{
								p.Nullify( pl );
								pm.DuelPlayer=null;
								NetState ns = init.NetState;
								if ( ns != null )
								{
									bool send=true;
									foreach ( Gump g in ns.Gumps )
									{
										if ( g is ParticipantGump )
										{
											ParticipantGump pg = (ParticipantGump)g;
											if ( pg.Participant == p )
											{
												init.SendGump( new ParticipantGump( init, dc, p ) );
												send=false;
												break;
											}
										}
										else if ( g is DuelContextGump )
										{
											DuelContextGump dcg = (DuelContextGump)g;
											if ( dcg.Context == dc )
											{
												init.SendGump( new DuelContextGump( init, dc ) );
												send=false;
												break;
											}
										}
									}
									if ( send )
										init.SendGump( new DuelContextGump( init, dc ) );
								}
							}
						}
					}
				}
				else
				{
					DuelPlayer pl = pm.DuelContext.Find( pm );
					if ( pl != null )
					{
						if ( pm.DuelContext.IsOneVsOne )
						{
							e.Mobile.SendMessage( 0x22, "You may not yield a 1 on 1 match." );
						}
						else if ( pl.Eliminated )
						{
							e.Mobile.SendMessage( 0x22, "You have already been eliminated." );
						}
						else
						{
							pm.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have yielded." );
							pm.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has yielded.", pm.Name ) );
							pm.DuelContext.m_Yielding=true;
							pm.Kill();
							pm.DuelContext.m_Yielding=false;
							if ( pm.Alive ) // invul, ...
							{
								pl.Eliminated = true;
								pm.DuelContext.RemoveAggressions( pm );
								pm.DuelContext.SendOutside( pm );
								pm.DuelContext.Refresh( pm, null );
								Debuff( pm );
								CancelSpell( pm );
								pm.Frozen = false;
								Participant winner = pm.DuelContext.CheckCompletion();
								if ( winner != null )
									pm.DuelContext.Finish( winner );
							}
						}
					}
					else
					{
						e.Mobile.SendMessage( 0x22, "BUG: Unable to find duel context." );
					}
				}
			}
		}
		public DuelContext( Mobile initiator, RulesetLayout layout ) : this( initiator, layout, true )
		{
		}
		public DuelContext( Mobile initiator, RulesetLayout layout, bool addNew )
		{
			m_Initiator = initiator;
			m_Participants = new ArrayList();
			m_Ruleset = new Ruleset( layout );
			m_Ruleset.ApplyDefault( layout.Defaults[0] );
			if ( addNew )
			{
				m_Participants.Add( new Participant( this, 1 ) );
				m_Participants.Add( new Participant( this, 1 ) );
				((Participant)m_Participants[0]).Add( initiator );
			}
		}
		public void CloseAllGumps()
		{
			Type[] types = new Type[]{ typeof( DuelContextGump ), typeof( ParticipantGump ), typeof( RulesetGump ) };
			int[] defs = new int[]{ -1, -1, -1 };
			for ( int i = 0; i < m_Participants.Count; ++i )
			{


Answer: 				Participant p = (Participant)m_Participants[i];