context: using System;
  using System.Collections;
  using Server;
  using Server.Network;
  using Server.Targeting;
  using Server.Factions;
  
  namespace Server.Engines.PartySystem
  {
  	public class Party : IParty
  	{
  		private Mobile m_Leader;
  		private ArrayList m_Members;
  		private ArrayList m_Candidates;
  		private ArrayList m_Listeners; // staff listening
  
  		public const int Capacity = 10;
  
  		public static void Initialize()
  		{
  			EventSink.Logout += new LogoutEventHandler( EventSink_Logout );
  			EventSink.Login += new LoginEventHandler( EventSink_Login );
  			EventSink.PlayerDeath += new PlayerDeathEventHandler( EventSink_PlayerDeath );
  
  			Server.Commands.Register( "ListenToParty", AccessLevel.GameMaster, new CommandEventHandler( ListenToParty_OnCommand ) );
  		}
  
  		public static void ListenToParty_OnCommand( CommandEventArgs e )
  		{
  			e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( ListenToParty_OnTarget ) );
  			e.Mobile.SendMessage( "Target a partied player." );
  		}
  
  		public static void ListenToParty_OnTarget( Mobile from, object obj )
  		{
  			if ( obj is Mobile )
  			{
  				Party p = Party.Get( (Mobile) obj );
  
  				if ( p == null )
  				{
  					from.SendMessage( "They are not in a party." );
  				}
  				else if ( p.m_Listeners.Contains( from ) )
  				{
  					p.m_Listeners.Remove( from );
  					from.SendMessage( "You are no longer listening to that party." );
  				}
  				else
  				{
  					p.m_Listeners.Add( from );
  					from.SendMessage( "You are now listening to that party." );
  				}
  			}
  		}
  
  		public static void EventSink_PlayerDeath( PlayerDeathEventArgs e )
  		{
  			Mobile from = e.Mobile;
  			Party p = Party.Get( from );
  
  			if ( p != null )
  			{
  				Mobile m = from.LastKiller;
  
  				if ( m == from )
  					p.SendPublicMessage( from, "I killed myself !!" );
  				else if ( m == null )
  					p.SendPublicMessage( from, "I was killed !!" );
  				else
  					p.SendPublicMessage( from, String.Format( "I was killed by {0} !!", m.Name ) );
  			}
  		}
  
  		private class RejoinTimer : Timer
  		{
  			private Mobile m_Mobile;
  
  			public RejoinTimer( Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ) )
  			{
  				m_Mobile = m;
  			}
  
  			protected override void OnTick()
  			{
  				Party p = Party.Get( m_Mobile );
  
  				if ( p == null )
  					return;
  
  				m_Mobile.SendLocalizedMessage( 1005437 ); // You have rejoined the party.
  				m_Mobile.Send( new PartyMemberList( p ) );
  
  				Packet message = new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008087, "", AffixType.Prepend | AffixType.System, m_Mobile.Name, "" );
  				Packet attrs   = new MobileAttributesN( m_Mobile );
  
  				foreach ( PartyMemberInfo mi in p.Members )
  				{
  					Mobile m = mi.Mobile;
  
  					if ( m != m_Mobile )
  					{
  						m.Send( message );
  						m.Send( new MobileStatusCompact( m_Mobile.CanBeRenamedBy( m ), m_Mobile ) );
  						m.Send( attrs );
  						m_Mobile.Send( new MobileStatusCompact( m.CanBeRenamedBy( m_Mobile ), m ) );
  						m_Mobile.Send( new MobileAttributesN( m ) );
  					}
  				}
  			}
  		}
  
  		public static void EventSink_Login( LoginEventArgs e )
  		{
  			Mobile from = e.Mobile;
  			Party p = Party.Get( from );
  
  			if ( p != null )
  				new RejoinTimer( from ).Start();
  			else
  				from.Party = null;
  		}
  
  		public static void EventSink_Logout( LogoutEventArgs e )
  		{
  			Mobile from = e.Mobile;
  			Party p = Party.Get( from );
  
  			if ( p != null )
  				p.Remove( from );
  
  			from.Party = null;
  		}
  
  		public static Party Get( Mobile m )
  		{
  			if ( m == null )
  				return null;
  
  			return m.Party as Party;
  		}
  
  		public Party( Mobile leader )
  		{
  			m_Leader = leader;
  
  			m_Members = new ArrayList();
  			m_Candidates = new ArrayList();
  			m_Listeners = new ArrayList();
  
  			m_Members.Add( new PartyMemberInfo( leader ) );
  		}
  
  		public void Add( Mobile m )
  		{
  			PartyMemberInfo mi = this[m];
  
  			if ( mi == null )
  			{
  				m_Members.Add( new PartyMemberInfo( m ) );
  				m.Party = this;
  
  				Packet memberList = new PartyMemberList( this );
  				Packet attrs  = new MobileAttributesN( m );
  
  				for ( int i = 0; i < m_Members.Count; ++i )
  				{
  					Mobile f = ((PartyMemberInfo)m_Members[i]).Mobile;
  
  					f.Send( memberList );
  
  					if ( f != m )
  					{
  						f.Send( new MobileStatusCompact( m.CanBeRenamedBy( f ), m ) );
  						f.Send( attrs );
  						m.Send( new MobileStatusCompact( f.CanBeRenamedBy( m ), f ) );
  						m.Send( new MobileAttributesN( f ) );
  					}
  				}
  			}
  		}
  
  		public void OnAccept( Mobile from )
  		{
  			OnAccept( from, false );
  		}
  
  		public void OnAccept( Mobile from, bool force )
  		{
  			Faction ourFaction = Faction.Find( m_Leader );
  			Faction theirFaction = Faction.Find( from );
  
  			if ( !force && ourFaction != null && theirFaction != null && ourFaction != theirFaction )
  				return;
  
  			//  : joined the party.
  			SendToAll( new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008094, "", AffixType.Prepend | AffixType.System, from.Name, "" ) );
  
  			from.SendLocalizedMessage( 1005445 ); // You have been added to the party.
  
  			m_Candidates.Remove( from );
  			Add( from );
  		}
  
  		public void OnDecline( Mobile from, Mobile leader )
  		{
  			//  : Does not wish to join the party.
  			leader.SendLocalizedMessage( 1008091, false, from.Name );
  
  			from.SendLocalizedMessage( 1008092 ); // You notify them that you do not wish to join the party.
  
  			m_Candidates.Remove( from );
  			from.Send( new PartyEmptyList( from ) );
  
  			if ( m_Candidates.Count == 0 && m_Members.Count <= 1 )
  			{
  				for ( int i = 0; i < m_Members.Count; ++i )
  				{
  					this[i].Mobile.Send( new PartyEmptyList( this[i].Mobile ) );
  					this[i].Mobile.Party = null;
  				}
  
  				m_Members.Clear();
  			}
  		}
  
  		public void Remove( Mobile m )
  		{
  			if ( m == m_Leader )
  			{
  				Disband();
  			}
  			else
  			{
  				for ( int i = 0; i < m_Members.Count; ++i )
  				{
  					if ( ((PartyMemberInfo)m_Members[i]).Mobile == m )
  					{
  						m_Members.RemoveAt( i );
  
  						m.Party = null;
  						m.Send( new PartyEmptyList( m ) );
  
  						m.SendLocalizedMessage( 1005451 ); // You have been removed from the party.
  
  						SendToAll( new PartyRemoveMember( m, this ) );
  						SendToAll( 1005452 ); // A player has been removed from your party.
  
  						break;
  					}
  				}
  
  				if ( m_Members.Count == 1 )
  				{
  					SendToAll( 1005450 ); // The last person has left the party...
  					Disband();
  				}
  			}
  		}
  
  		public bool Contains( Mobile m )
  		{
  			return ( this[m] != null );
  		}
  
  		public void Disband()
  		{
  			SendToAll( 1005449 ); // Your party has disbanded.
  
  			for ( int i = 0; i < m_Members.Count; ++i )
  			{
  				this[i].Mobile.Send( new PartyEmptyList( this[i].Mobile ) );
  				this[i].Mobile.Party = null;
  			}
  
  			m_Members.Clear();
  		}
  
  		public static void Invite( Mobile from, Mobile target )
  		{
  			Faction ourFaction = Faction.Find( from );
  			Faction theirFaction = Faction.Find( target );
  
  			if ( ourFaction != null && theirFaction != null && ourFaction != theirFaction )
  			{
  				from.SendLocalizedMessage( 1008088 ); // You cannot have players from opposing factions in the same party!
  				target.SendLocalizedMessage( 1008093 ); // The party cannot have members from opposing factions.
  				return;
  			}
  
  			Party p = Party.Get( from );
  
  			if ( p == null )
  				from.Party = p = new Party( from );
  
  			if ( !p.Candidates.Contains( target ) )
  				p.Candidates.Add( target );
  
  			//  : You are invited to join the party. Type /accept to join or /decline to decline the offer.
  			target.Send( new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008089, "", AffixType.Prepend | AffixType.System, from.Name, "" ) );
  
  			from.SendLocalizedMessage( 1008090 ); // You have invited them to join the party.
  
  			target.Send( new PartyInvitation( from ) );
  			target.Party = from;
  
  			DeclineTimer.Start( target, from );
  		}
  
  		public void SendToAll( int number )
  		{
  			SendToAll( number, "", 0x3B2 );
  		}
  
  		public void SendToAll( int number, string args )
  		{
  			SendToAll( number, args, 0x3B2 );
  		}
  
  		public void SendToAll( int number, string args, int hue )
  		{
  			SendToAll( new MessageLocalized( Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args ) );
  		}
  
  		public void SendPublicMessage( Mobile from, string text )
  		{
  
gt: 			SendToAll( new PartyTextMessage( true, from, text ) );