context: /***************************************************************************
   *                                 Region.cs
   *                            -------------------
   *   begin                : May 1, 2002
   *   copyright            : (C) The RunUO Software Team
   *   email                : info@runuo.com
   *
   *   $Id$
   *
   ***************************************************************************/
  
  /***************************************************************************
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   ***************************************************************************/
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Xml;
  using Server.Network;
  using Server.Targeting;
  
  namespace Server
  {
  	public enum MusicName
  	{
  		Invalid = -1,
  		OldUlt01 = 0,
  		Create1,
  		DragFlit,
  		OldUlt02,
  		OldUlt03,
  		OldUlt04,
  		OldUlt05,
  		OldUlt06,
  		Stones2,
  		Britain1,
  		Britain2,
  		Bucsden,
  		Jhelom,
  		LBCastle,
  		Linelle,
  		Magincia,
  		Minoc,
  		Ocllo,
  		Samlethe,
  		Serpents,
  		Skarabra,
  		Trinsic,
  		Vesper,
  		Wind,
  		Yew,
  		Cave01,
  		Dungeon9,
  		Forest_a,
  		InTown01,
  		Jungle_a,
  		Mountn_a,
  		Plains_a,
  		Sailing,
  		Swamp_a,
  		Tavern01,
  		Tavern02,
  		Tavern03,
  		Tavern04,
  		Combat1,
  		Combat2,
  		Combat3,
  		Approach,
  		Death,
  		Victory,
  		BTCastle,
  		Nujelm,
  		Dungeon2,
  		Cove,
  		Moonglow,
  		Zento,
  		TokunoDungeon,
  		Taiko,
  		DreadHornArea,
  		ElfCity,
  		GrizzleDungeon,
  		MelisandesLair,
  		ParoxysmusLair,
  		GwennoConversation,
  		GoodEndGame,
  		GoodVsEvil,
  		GreatEarthSerpents,
  		Humanoids_U9,
  		MinocNegative,
  		Paws,
  		SelimsBar,
  		SerpentIsleCombat_U7,
  		ValoriaShips
  	}
  
  	public class Region : IComparable
  	{
  		private static List<Region> m_Regions = new List<Region>();
  
  		public static List<Region> Regions{ get{ return m_Regions; } }
  
  		public static Region Find( Point3D p, Map map )
  		{
  			if ( map == null )
  				return Map.Internal.DefaultRegion;
  
  			Sector sector = map.GetSector( p );
  			List<RegionRect> list = sector.RegionRects;
  
  			for ( int i = 0; i < list.Count; ++i )
  			{
  				RegionRect regRect = list[i];
  
  				if ( regRect.Contains( p ) )
  					return regRect.Region;
  			}
  
  			return map.DefaultRegion;
  		}
  
  		private static Type m_DefaultRegionType = typeof( Region );
  		public static Type DefaultRegionType{ get{ return m_DefaultRegionType; } set{ m_DefaultRegionType = value; } }
  
  		private static TimeSpan m_StaffLogoutDelay = TimeSpan.Zero;
  		private static TimeSpan m_DefaultLogoutDelay = TimeSpan.FromMinutes( 5.0 );
  
  		public static TimeSpan StaffLogoutDelay{ get{ return m_StaffLogoutDelay; } set{ m_StaffLogoutDelay = value; } }
  		public static TimeSpan DefaultLogoutDelay{ get{ return m_DefaultLogoutDelay; } set{ m_DefaultLogoutDelay = value; } }
  
  		public static readonly int DefaultPriority = 50;
  
  		public static readonly int MinZ = sbyte.MinValue;
  		public static readonly int MaxZ = sbyte.MaxValue + 1;
  
  		public static Rectangle3D ConvertTo3D( Rectangle2D rect )
  		{
  			return new Rectangle3D( new Point3D( rect.Start, MinZ ), new Point3D( rect.End, MaxZ ) );
  		}
  
  		public static Rectangle3D[] ConvertTo3D( Rectangle2D[] rects )
  		{
  			Rectangle3D[] ret = new Rectangle3D[rects.Length];
  
  			for ( int i = 0; i < ret.Length; i++ )
  			{
  				ret[i] = ConvertTo3D( rects[i] );
  			}
  
  			return ret;
  		}
  
  
  		private string m_Name;
  		private Map m_Map;
  		private Region m_Parent;
  		private List<Region> m_Children = new List<Region>();
  		private Rectangle3D[] m_Area;
  		private Sector[] m_Sectors;
  		private bool m_Dynamic;
  		private int m_Priority;
  		private int m_ChildLevel;
  		private bool m_Registered;
  
  		private Point3D m_GoLocation;
  		private MusicName m_Music;
  
  		public string Name{ get{ return m_Name; } }
  		public Map Map{ get{ return m_Map; } }
  		public Region Parent{ get{ return m_Parent; } }
  		public List<Region> Children{ get{ return m_Children; } }
  		public Rectangle3D[] Area{ get{ return m_Area; } }
  		public Sector[] Sectors{ get{ return m_Sectors; } }
  		public bool Dynamic{ get{ return m_Dynamic; } }
  		public int Priority{ get{ return m_Priority; } }
  		public int ChildLevel{ get{ return m_ChildLevel; } }
  		public bool Registered{ get{ return m_Registered; } }
  
  		public Point3D GoLocation{ get{ return m_GoLocation; } set { m_GoLocation = value; } }
  		public MusicName Music{ get{ return m_Music; } set{ m_Music = value; } }
  
  		public bool IsDefault{ get{ return m_Map.DefaultRegion == this; } }
  		public virtual MusicName DefaultMusic{ get{ return m_Parent != null ? m_Parent.Music : MusicName.Invalid; } }
  
  		public Region( string name, Map map, int priority, params Rectangle2D[] area ) : this( name, map, priority, ConvertTo3D( area ) )
  		{
  		}
  
  		public Region( string name, Map map, int priority, params Rectangle3D[] area ) : this( name, map, null, area )
  		{
  			m_Priority = priority;
  		}
  
  		public Region( string name, Map map, Region parent, params Rectangle2D[] area ) : this( name, map, parent, ConvertTo3D( area ) )
  		{
  		}
  
  		public Region( string name, Map map, Region parent, params Rectangle3D[] area )
  		{
  			m_Name = name;
  			m_Map = map;
  			m_Parent = parent;
  			m_Area = area;
  			m_Dynamic = true;
  			m_Music = this.DefaultMusic;
  
  			if ( m_Parent == null )
  			{
  				m_ChildLevel = 0;
  				m_Priority = DefaultPriority;
  			}
  			else
  			{
  				m_ChildLevel = m_Parent.ChildLevel + 1;
  				m_Priority = m_Parent.Priority;
  			}
  		}
  
  		public void Register()
  		{
  			if ( m_Registered )
  				return;
  
  			OnRegister();
  
  			m_Registered = true;
  
  			if ( m_Parent != null )
  			{
  				m_Parent.m_Children.Add( this );
  				m_Parent.OnChildAdded( this );
  			}
  
  			m_Regions.Add( this );
  
  			m_Map.RegisterRegion( this );
  
  			List<Sector> sectors = new List<Sector>();
  
  			for ( int i = 0; i < m_Area.Length; i++ )
  			{
  				Rectangle3D rect = m_Area[i];
  
  				Point2D start = m_Map.Bound( new Point2D( rect.Start ) );
  				Point2D end = m_Map.Bound( new Point2D( rect.End ) );
  
  				Sector startSector = m_Map.GetSector( start );
  				Sector endSector = m_Map.GetSector( end );
  
  				for ( int x = startSector.X; x <= endSector.X; x++ )
  				{
  					for ( int y = startSector.Y; y <= endSector.Y; y++ )
  					{
  						Sector sector = m_Map.GetRealSector( x, y );
  
  						sector.OnEnter( this, rect );
  
  						if ( !sectors.Contains( sector ) )
  							sectors.Add( sector );
  					}
  				}
  			}
  
  			m_Sectors = sectors.ToArray();
  		}
  
  		public void Unregister()
  		{
  			if ( !m_Registered )
  				return;
  
  			OnUnregister();
  
  			m_Registered = false;
  
  			if ( m_Children.Count > 0 )
  				Console.WriteLine( "Warning: Unregistering region '{0}' with children", this );
  
  			if ( m_Parent != null )
  			{
  				m_Parent.m_Children.Remove( this );
  				m_Parent.OnChildRemoved( this );
  			}
  
  			m_Regions.Remove( this );
  
  			m_Map.UnregisterRegion( this );
  
  			if ( m_Sectors != null )
  			{
  				for ( int i = 0; i < m_Sectors.Length; i++ )
  					m_Sectors[i].OnLeave( this );
  			}
  
  			m_Sectors = null;
  		}
  
  		public bool Contains( Point3D p )
  		{
  			for ( int i = 0; i < m_Area.Length; i++ )
  			{
  				Rectangle3D rect = m_Area[i];
  
  				if ( rect.Contains( p ) )
  					return true;
  			}
  
  			return false;
  		}
  
  		public bool IsChildOf( Region region )
  		{
  			if ( region == null )
  				return false;
  
  			Region p = m_Parent;
  
  			while ( p != null )
  			{
  				if ( p == region )
  					return true;
  
  				p = p.m_Parent;
  			}
  
  			return false;
  		}
  
  		public Region GetRegion( Type regionType )
  		{
  			if ( regionType == null )
  				return null;
  
  			Region r = this;
  
  			do
  			{
  				if ( regionType.IsAssignableFrom( r.GetType() ) )
  					return r;
  
  				r = r.m_Parent;
  			}
  			while ( r != null );
  
  			return null;
  		}
  
  		public Region GetRegion( string regionName )
  		{
  			if ( regionName == null )
  				return null;
  
  			Region r = this;
  
  			do
  			{
  				if ( r.m_Name == regionName )
  					return r;
  
  				r = r.m_Parent;
  			}
  			while ( r != null );
  
  			return null;
  		}
  
  		public bool IsPartOf( Region region )
  		{
  			if ( this == region )
  				return true;
  
  			return IsChildOf( region );
  		}
  
  		public bool IsPartOf( Type regionType )
  		{
  			return ( GetRegion( regionType ) != null );
  		}
  
  		public bool IsPartOf( string regionName )
  		{
  			return ( GetRegion( regionName ) != null );
  		}
  
  		public virtual bool AcceptsSpawnsFrom( Region region )
  		{
  			if ( !AllowSpawn() )
  				return false;
  
  			if ( region == this )
  				return true;
  
  			if ( m_Parent != null )
  				return m_Parent.AcceptsSpawnsFrom( region );
  
  			return false;
  		}
  
  		public List<Mobile> GetPlayers()
  		{
  			List<Mobile> list = new List<Mobile>();
  
  			if ( m_Sectors != null )
  			{
  				for ( int i = 0; i < m_Sectors.Length; i++ )
  				{
  					Sector sector = m_Sectors[i];
  
  					foreach ( Mobile player in sector.Players )
  					{
  						if ( player.Region.IsPartOf( this ) )
  							list.Add( player );
  					}
  				}
  			}
  
  			return list;
  		}
  
  		public int GetPlayerCount()
  		{
  			int count = 0;
  
  			if ( m_Sectors != null )
  			{
  				for ( int i = 0; i < m_Sectors.Length; i++ )
  				{
  					Sector sector = m_Sectors[i];
  
  					foreach ( Mobile player in sector.Players )
  					{
  						if ( player.Region.IsPartOf( this ) )
  							count++;
  					}
  				}
  			}
  
  			return count;
  		}
  
  		public List<Mobile> GetMobiles()
  		{
  			List<Mobile> list = new List<Mobile>();
  
  			if ( m_Sectors != null )
  			{
  				for ( int i = 0; i < m_Sectors.Length; i++ )
  				{
  					Sector sector = m_Sectors[i];
  
  					foreach ( Mobile mobile in sector.Mobiles )
  					{
  						if ( mobile.Region.IsPartOf( this ) )
  							list.Add( mobile );
  					}
  				}
  			}
  
  			return list;
  		}
  
  		public int GetMobileCount()
  		{
  			int count = 0;
  
  			if ( m_Sectors != null )
  			{
  				for ( int i = 0; i < m_Sectors.Length; i++ )
  				{
  					Sector sector = m_Sectors[i];
  
  					foreach ( Mobile mobile in sector.Mobiles )
  					{
  						if ( mobile.Region.IsPartOf( this ) )
  							count++;
  					}
  				}
  			}
  
  			return count;
  		}
  
  		int IComparable.CompareTo( object obj )
  		{
  			if ( obj == null )
  				return 1;
  
  			Region reg = obj as Region;
  
  			if ( reg == null )
  				throw new ArgumentException( "obj is not a Region", "obj" );
  
  			// Dynamic regions go first
  			if ( this.Dynamic )
  			{
  				if ( !reg.Dynamic )
  					return -1;
  			}
  			else if ( reg.Dynamic )
  			{
  				return 1;
  			}
  
  			int thisPriority = this.Priority;
  			int regPriority = reg.Priority;
  
  			if ( thisPriority != regPriority )
  				return ( regPriority - thisPriority );
  
  			return ( reg.ChildLevel - this.ChildLevel );
  		}
  
  		public override string ToString()
  		{
  			if ( m_Name != null )
  				return m_Name;
  			else
  				return GetType().Name;
  		}
  
  
  		public virtual void OnRegister()
  		{
  		}
  
  		public virtual void OnUnregister()
  		{
  		}
  
  		public virtual void OnChildAdded( Region child )
  		{
  		}
  
  		public virtual void OnChildRemoved( Region child )
  		{
  		}
  
  		public virtual bool OnMoveInto( Mobile m, Direction d, Point3D newLocation, Point3D oldLocation )
  		{
  			return ( m.WalkRegion == null || AcceptsSpawnsFrom( m.WalkRegion ) );
  		}
  
  		public virtual void OnEnter( Mobile m )
  		{
  		}
  
  		public virtual void OnExit( Mobile m )
  		{
  		}
  
  		public virtual void MakeGuard( Mobile focus )
  		{
  			if ( m_Parent != null )
  				m_Parent.MakeGuard( focus );
  		}
  
  		public virtual Type GetResource( Type type )
  		{
  			if ( m_Parent != null )
  				return m_Parent.GetResource( type );
  
  			return type;
  		}
  
  		public virtual bool CanUseStuckMenu( Mobile m )
  		{
  			if ( m_Parent != null )
  				return m_Parent.CanUseStuckMenu( m );
  
  			return true;
  		}
  
  		public virtual void OnAggressed( Mobile aggressor, Mobile aggressed, bool criminal )
  		{
  			if ( m_Parent != null )
  				m_Parent.OnAggressed( aggressor, aggressed, criminal );
  		}
  
  		public virtual void OnDidHarmful( Mobile harmer, Mobile harmed )
  		{
  			if ( m_Parent != null )
  				m_Parent.OnDidHarmful( harmer, harmed );
  		}
  
  		public virtual void OnGotHarmful( Mobile harmer, Mobile harmed )
  		{
  			if ( m_Parent != null )
  				m_Parent.OnGotHarmful( harmer, harmed );
  		}
  
  		public virtual void OnLocationChanged( Mobile m, Point3D oldLocation )
  		{
  			if ( m_Parent != null )
  				m_Parent.OnLocationChanged( m, oldLocation );
  		}
  
  		public virtual bool OnTarget( Mobile m, Target t, object o )
  		{
  			if ( m_Parent != null )
  				return m_Parent.OnTarget( m, t, o );
  
  			return true;
  		}
  
  		public virtual bool OnCombatantChange( Mobile m, Mobile Old, Mobile New )
  		{
  			if ( m_Parent != null )
  				return m_Parent.OnCombatantChange( m, Old, New );
  
  			return true;
  		}
  
  		public virtual bool AllowHousing( Mobile from, Point3D p )
  		{
  			if ( m_Parent != null )
  				return m_Parent.AllowHousing( from, p );
  
  			return true;
  		}
  
  		public virtual bool SendInaccessibleMessage( Item item, Mobile from )
  		{
  			if ( m_Parent != null )
  				return m_Parent.SendInaccessibleMessage( item, from );
  
  			return false;
  		}
  
  		public virtual bool CheckAccessibility( Item item, Mobile from )
  		{
  			if ( m_Parent != null )
  				return m_Parent.CheckAccessibility( item, from );
  
  			return true;
  		}
  
  		public virtual bool OnDecay( Item item )
  		{
  			if ( m_Parent != null )
  				return m_Parent.OnDecay( item );
  
  			return true;
  		}
  
  		public virtual bool AllowHarmful( Mobile from, Mobile target )
  		{
  			if ( m_Parent != null )
  				return m_Parent.AllowHarmful( from, target );
  
  			if ( Mobile.AllowHarmfulHandler != null )
  				return Mobile.AllowHarmfulHandler( from, target );
  
  			return true;
  		}
  
  		public virtual void OnCriminalAction( Mobile m, bool message )
  		{
  			if ( m_Parent != null )
  				m_Parent.OnCriminalAction( m, message );
  			else if ( message )
  				m.SendLocalizedMessage( 1005040 ); // You've committed a criminal act!!
  		}
  
  		public virtual bool AllowBeneficial( Mobile from, Mobile target )
  		{
  			if ( m_Parent != null )
  				return m_Parent.AllowBeneficial( from, target );
  
  			if ( Mobile.AllowBeneficialHandler != null )
  				return Mobile.AllowBeneficialHandler( from, target );
  
  			return true;
  		}
  
  		public virtual void OnBeneficialAction( Mobile helper, Mobile target )
  		{
  			if ( m_Parent != null )
  				m_Parent.OnBeneficialAction( helper, target );
  		}
  
  		public virtual void OnGotBeneficialAction( Mobile helper, Mobile target )
  		{
  			if ( m_Parent != null )
  				m_Parent.OnGotBeneficialAction( helper, target );
  		}
  
  		public virtual void SpellDamageScalar( Mobile caster, Mobile target, ref double damage )
  		{
  			if ( m_Parent != null )
  
gt: 				m_Parent.SpellDamageScalar( caster, target, ref damage );