/*************************************************************************** * 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, Dungeon3, Tavern05, Travel } public class Region : IComparable { private static List m_Regions = new List(); public static List 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 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.FromSeconds( 10.0 ); 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 m_Children = new List(); 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 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 sectors = new List(); 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 GetPlayers() { List list = new List(); 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 GetMobiles() { List list = new List(); 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 NoMounts( Mobile from, Point3D p ) { if ( m_Parent != null ) return m_Parent.NoMounts( from, p ); return false; } 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 ) m_Parent.SpellDamageScalar( caster, target, ref damage ); } public virtual void OnSpeech( SpeechEventArgs args ) { if ( m_Parent != null ) m_Parent.OnSpeech( args ); } public virtual bool OnSkillUse( Mobile m, int Skill ) { if ( m_Parent != null ) return m_Parent.OnSkillUse( m, Skill ); return true; } public virtual bool OnBeginSpellCast( Mobile m, ISpell s ) { if ( m_Parent != null ) return m_Parent.OnBeginSpellCast( m, s ); return true; } public virtual void OnSpellCast( Mobile m, ISpell s ) { if ( m_Parent != null ) m_Parent.OnSpellCast( m, s ); } public virtual bool OnResurrect( Mobile m ) { if ( m_Parent != null ) return m_Parent.OnResurrect( m ); return true; } public virtual bool OnBeforeDeath( Mobile m ) { if ( m_Parent != null ) return m_Parent.OnBeforeDeath( m ); return true; } public virtual void OnDeath( Mobile m ) { if ( m_Parent != null ) m_Parent.OnDeath( m ); } public virtual bool OnDamage( Mobile m, ref int Damage ) { if ( m_Parent != null ) return m_Parent.OnDamage( m, ref Damage ); return true; } public virtual bool OnHeal( Mobile m, ref int Heal ) { if ( m_Parent != null ) return m_Parent.OnHeal( m, ref Heal ); return true; } public virtual bool OnDoubleClick( Mobile m, object o ) { if ( m_Parent != null ) return m_Parent.OnDoubleClick( m, o ); return true; } public virtual bool OnSingleClick( Mobile m, object o ) { if ( m_Parent != null ) return m_Parent.OnSingleClick( m, o ); return true; } public virtual bool AllowSpawn() { if ( m_Parent != null ) return m_Parent.AllowSpawn(); return true; } public virtual void AlterLightLevel( Mobile m, ref int global, ref int personal ) { if ( m_Parent != null ) m_Parent.AlterLightLevel( m, ref global, ref personal ); } public virtual TimeSpan GetLogoutDelay( Mobile m ) { if ( m_Parent != null ) return m_Parent.GetLogoutDelay( m ); else if ( m.AccessLevel > AccessLevel.Player ) return m_StaffLogoutDelay; else return m_DefaultLogoutDelay; } internal static bool CanMove( Mobile m, Direction d, Point3D newLocation, Point3D oldLocation, Map map ) { Region oldRegion = m.Region; Region newRegion = Find( newLocation, map ); while ( oldRegion != newRegion ) { if ( !newRegion.OnMoveInto( m, d, newLocation, oldLocation ) ) return false; if ( newRegion.m_Parent == null ) return true; newRegion = newRegion.m_Parent; } return true; } internal static void OnRegionChange( Mobile m, Region oldRegion, Region newRegion ) { if ( newRegion != null && m.NetState != null ) { m.CheckLightLevels( false ); if ( oldRegion == null || oldRegion.Music != newRegion.Music ) { m.Send( PlayMusic.GetInstance( newRegion.Music ) ); } } Region oldR = oldRegion; Region newR = newRegion; while ( oldR != newR ) { int oldRChild = ( oldR != null ? oldR.ChildLevel : -1 ); int newRChild = ( newR != null ? newR.ChildLevel : -1 ); if ( oldRChild >= newRChild ) { oldR.OnExit( m ); oldR = oldR.Parent; } if ( newRChild >= oldRChild ) { newR.OnEnter( m ); newR = newR.Parent; } } } internal static void Load() { if ( !System.IO.File.Exists( "Data/Config/Regions.xml" ) ) { Console.WriteLine( "Error: Data/Config/Regions.xml does not exist" ); return; } Console.Write( "Regions: Loading..." ); XmlDocument doc = new XmlDocument(); doc.Load( System.IO.Path.Combine( Core.BaseDirectory, "Data/Config/Regions.xml" ) ); XmlElement root = doc["ServerRegions"]; if ( root == null ) { Console.WriteLine( "Could not find root element 'ServerRegions' in Regions.xml" ); } else { foreach ( XmlElement facet in root.SelectNodes( "Facet" ) ) { Map map = null; if ( ReadMap( facet, "name", ref map ) ) { if ( map == Map.Internal ) Console.WriteLine( "Invalid internal map in a facet element" ); else LoadRegions( facet, map, null ); } } } Console.WriteLine( "done" ); } private static void LoadRegions( XmlElement xml, Map map, Region parent ) { foreach ( XmlElement xmlReg in xml.SelectNodes( "region" ) ) { Type type = DefaultRegionType; ReadType( xmlReg, "type", ref type, false ); if ( !typeof( Region ).IsAssignableFrom( type ) ) { Console.WriteLine( "Invalid region type '{0}' in regions.xml", type.FullName ); continue; } Region region = null; try { region = (Region) Activator.CreateInstance( type, new object[] { xmlReg, map, parent } ); } catch ( Exception ex ) { Console.WriteLine( "Error during the creation of region type '{0}': {1}", type.FullName, ex ); continue; } region.Register(); LoadRegions( xmlReg, map, region ); } } public Region( XmlElement xml, Map map, Region parent ) { m_Map = map; m_Parent = parent; m_Dynamic = false; if ( m_Parent == null ) { m_ChildLevel = 0; m_Priority = DefaultPriority; } else { m_ChildLevel = m_Parent.ChildLevel + 1; m_Priority = m_Parent.Priority; } ReadString( xml, "name", ref m_Name, false ); if ( parent == null ) ReadInt32( xml, "priority", ref m_Priority, false ); int minZ = MinZ; int maxZ = MaxZ; XmlElement zrange = xml["zrange"]; ReadInt32( zrange, "min", ref minZ, false ); ReadInt32( zrange, "max", ref maxZ, false ); List area = new List(); foreach ( XmlElement xmlRect in xml.SelectNodes( "rect" ) ) { Rectangle3D rect = new Rectangle3D(); if ( ReadRectangle3D( xmlRect, minZ, maxZ, ref rect ) ) area.Add( rect ); } m_Area = area.ToArray(); if ( m_Area.Length == 0 ) Console.WriteLine( "Empty area for region '{0}'", this ); if ( !ReadPoint3D( xml["go"], map, ref m_GoLocation, false ) && m_Area.Length > 0 ) { Point3D start = m_Area[0].Start; Point3D end = m_Area[0].End; int x = start.X + (end.X - start.X) / 2; int y = start.Y + (end.Y - start.Y) / 2; m_GoLocation = new Point3D( x, y, m_Map.GetAverageZ( x, y ) ); } MusicName music = this.DefaultMusic; ReadEnum( xml["music"], "name", ref music, false ); m_Music = music; } protected static string GetAttribute( XmlElement xml, string attribute, bool mandatory ) { if ( xml == null ) { if ( mandatory ) Console.WriteLine( "Missing element for attribute '{0}'", attribute ); return null; } else if ( xml.HasAttribute( attribute ) ) { return xml.GetAttribute( attribute ); } else { if ( mandatory ) Console.WriteLine( "Missing attribute '{0}' in element '{1}'", attribute, xml.Name ); return null; } } public static bool ReadString( XmlElement xml, string attribute, ref string value ) { return ReadString( xml, attribute, ref value, true ); } public static bool ReadString( XmlElement xml, string attribute, ref string value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; value = s; return true; } public static bool ReadInt32( XmlElement xml, string attribute, ref int value ) { return ReadInt32( xml, attribute, ref value, true ); } public static bool ReadInt32( XmlElement xml, string attribute, ref int value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; try { value = XmlConvert.ToInt32( s ); } catch { Console.WriteLine( "Could not parse integer attribute '{0}' in element '{1}'", attribute, xml.Name ); return false; } return true; } public static bool ReadBoolean( XmlElement xml, string attribute, ref bool value ) { return ReadBoolean( xml, attribute, ref value, true ); } public static bool ReadBoolean( XmlElement xml, string attribute, ref bool value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; try { value = XmlConvert.ToBoolean( s ); } catch { Console.WriteLine( "Could not parse boolean attribute '{0}' in element '{1}'", attribute, xml.Name ); return false; } return true; } public static bool ReadDateTime( XmlElement xml, string attribute, ref DateTime value ) { return ReadDateTime( xml, attribute, ref value, true ); } public static bool ReadDateTime( XmlElement xml, string attribute, ref DateTime value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; try { value = XmlConvert.ToDateTime( s, XmlDateTimeSerializationMode.Local ); } catch { Console.WriteLine( "Could not parse DateTime attribute '{0}' in element '{1}'", attribute, xml.Name ); return false; } return true; } public static bool ReadTimeSpan( XmlElement xml, string attribute, ref TimeSpan value ) { return ReadTimeSpan( xml, attribute, ref value, true ); } public static bool ReadTimeSpan( XmlElement xml, string attribute, ref TimeSpan value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; try { value = XmlConvert.ToTimeSpan( s ); } catch { Console.WriteLine( "Could not parse TimeSpan attribute '{0}' in element '{1}'", attribute, xml.Name ); return false; } return true; } public static bool ReadEnum( XmlElement xml, string attribute, ref T value ) { return ReadEnum( xml, attribute, ref value, true ); } public static bool ReadEnum( XmlElement xml, string attribute, ref T value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; Type type = typeof(T); try { value = (T)Enum.Parse(type, s, true); //TODO: On .NET 4.0, use Enum.TryParse } catch { Console.WriteLine( "Could not parse {0} enum attribute '{1}' in element '{2}'", type, attribute, xml.Name ); return false; } return true; } public static bool ReadMap( XmlElement xml, string attribute, ref Map value ) { return ReadMap( xml, attribute, ref value, true ); } public static bool ReadMap( XmlElement xml, string attribute, ref Map value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; try { value = Map.Parse( s ); } catch { Console.WriteLine( "Could not parse Map attribute '{0}' in element '{1}'", attribute, xml.Name ); return false; } return true; } public static bool ReadType( XmlElement xml, string attribute, ref Type value ) { return ReadType( xml, attribute, ref value, true ); } public static bool ReadType( XmlElement xml, string attribute, ref Type value, bool mandatory ) { string s = GetAttribute( xml, attribute, mandatory ); if ( s == null ) return false; Type type; try { type = ScriptCompiler.FindTypeByName( s, false ); } catch { Console.WriteLine( "Could not parse Type attribute '{0}' in element '{1}'", attribute, xml.Name ); return false; } if ( type == null ) { Console.WriteLine( "Could not find Type '{0}'", s ); return false; } value = type; return true; } public static bool ReadPoint3D( XmlElement xml, Map map, ref Point3D value ) { return ReadPoint3D( xml, map, ref value, true ); } public static bool ReadPoint3D( XmlElement xml, Map map, ref Point3D value, bool mandatory ) { int x = 0, y = 0, z = 0; bool xyOk = ReadInt32( xml, "x", ref x, mandatory ) & ReadInt32( xml, "y", ref y, mandatory ); bool zOk = ReadInt32( xml, "z", ref z, mandatory && map == null ); if ( xyOk && ( zOk || map != null ) ) { if ( !zOk ) z = map.GetAverageZ( x, y ); value = new Point3D( x, y, z ); return true; } return false; } public static bool ReadRectangle3D( XmlElement xml, int defaultMinZ, int defaultMaxZ, ref Rectangle3D value ) { return ReadRectangle3D( xml, defaultMinZ, defaultMaxZ, ref value, true ); } public static bool ReadRectangle3D( XmlElement xml, int defaultMinZ, int defaultMaxZ, ref Rectangle3D value, bool mandatory ) { int x1 = 0, y1 = 0, x2 = 0, y2 = 0; if ( xml.HasAttribute( "x" ) ) { if ( ReadInt32( xml, "x", ref x1, mandatory ) & ReadInt32( xml, "y", ref y1, mandatory ) & ReadInt32( xml, "width", ref x2, mandatory ) & ReadInt32( xml, "height", ref y2, mandatory ) ) { x2 += x1; y2 += y1; } else { return false; } } else { if ( !ReadInt32( xml, "x1", ref x1, mandatory ) | !ReadInt32( xml, "y1", ref y1, mandatory ) | !ReadInt32( xml, "x2", ref x2, mandatory ) | !ReadInt32( xml, "y2", ref y2, mandatory ) ) { return false; } } int z1 = defaultMinZ; int z2 = defaultMaxZ; ReadInt32( xml, "zmin", ref z1, false ); ReadInt32( xml, "zmax", ref z2, false ); value = new Rectangle3D( new Point3D( x1, y1, z1 ), new Point3D( x2, y2, z2 ) ); return true; } } }