using System; using System.Collections.Generic; using Server; using Server.Mobiles; namespace Server.Engines.ConPVP { public class ArenaController : Item { private Arena m_Arena; private bool m_IsPrivate; [CommandProperty( AccessLevel.GameMaster )] public Arena Arena{ get{ return m_Arena; } set{} } [CommandProperty( AccessLevel.GameMaster )] public bool IsPrivate{ get{ return m_IsPrivate; } set{ m_IsPrivate = value; } } public override string DefaultName { get { return "arena controller"; } } [Constructable] public ArenaController() : base( 0x1B7A ) { Visible = false; Movable = false; m_Arena = new Arena(); m_Instances.Add( this ); } public override void OnDelete() { base.OnDelete(); m_Instances.Remove( this ); m_Arena.Delete(); } public override void OnDoubleClick( Mobile from ) { if ( from.AccessLevel >= AccessLevel.GameMaster ) from.SendGump( new Gumps.PropertiesGump( from, m_Arena ) ); } public ArenaController( Serial serial ) : base( serial ) { } public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); writer.Write( (int) 1 ); writer.Write( (bool) m_IsPrivate ); m_Arena.Serialize( writer ); } public override void Deserialize( GenericReader reader ) { base.Deserialize( reader ); int version = reader.ReadInt(); switch ( version ) { case 1: { m_IsPrivate = reader.ReadBool(); goto case 0; } case 0: { m_Arena = new Arena( reader ); break; } } m_Instances.Add( this ); } private static List m_Instances = new List(); public static List Instances{ get{ return m_Instances; } set{ m_Instances = value; } } } [PropertyObject] public class ArenaStartPoints { private Point3D[] m_Points; public Point3D[] Points{ get{ return m_Points; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D EdgeWest{ get{ return m_Points[0]; } set{ m_Points[0] = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D EdgeEast{ get{ return m_Points[1]; } set{ m_Points[1] = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D EdgeNorth{ get{ return m_Points[2]; } set{ m_Points[2] = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D EdgeSouth{ get{ return m_Points[3]; } set{ m_Points[3] = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D CornerNW{ get{ return m_Points[4]; } set{ m_Points[4] = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D CornerSE{ get{ return m_Points[5]; } set{ m_Points[5] = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D CornerSW{ get{ return m_Points[6]; } set{ m_Points[6] = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D CornerNE{ get{ return m_Points[7]; } set{ m_Points[7] = value; } } public override string ToString() { return "..."; } public ArenaStartPoints() : this( new Point3D[8] ) { } public ArenaStartPoints( Point3D[] points ) { m_Points = points; } public ArenaStartPoints( GenericReader reader ) { m_Points = new Point3D[reader.ReadEncodedInt()]; for ( int i = 0; i < m_Points.Length; ++i ) m_Points[i] = reader.ReadPoint3D(); } public void Serialize( GenericWriter writer ) { writer.WriteEncodedInt( (int) m_Points.Length ); for ( int i = 0; i < m_Points.Length; ++i ) writer.Write( (Point3D) m_Points[i] ); } } [PropertyObject] public class Arena : IComparable { private Map m_Facet; private Rectangle2D m_Bounds; private Rectangle2D m_Zone; private Point3D m_Outside; private Point3D m_Wall; private Point3D m_GateIn; private Point3D m_GateOut; private ArenaStartPoints m_Points; private bool m_Active; private string m_Name; private bool m_IsGuarded; private Item m_Teleporter; private List m_Players; private TournamentController m_Tournament; private Mobile m_Announcer; private LadderController m_Ladder; [CommandProperty( AccessLevel.GameMaster )] public LadderController Ladder { get{ return m_Ladder; } set{ m_Ladder = value; } } [CommandProperty( AccessLevel.GameMaster )] public bool IsGuarded { get{ return m_IsGuarded; } set { m_IsGuarded = value; if ( m_Region != null ) m_Region.Disabled = !m_IsGuarded; } } public Ladder AcquireLadder() { if ( m_Ladder != null ) return m_Ladder.Ladder; return Server.Engines.ConPVP.Ladder.Instance; } [CommandProperty( AccessLevel.GameMaster )] public TournamentController Tournament { get{ return m_Tournament; } set { if ( m_Tournament != null ) m_Tournament.Tournament.Arenas.Remove( this ); m_Tournament = value; if ( m_Tournament != null ) m_Tournament.Tournament.Arenas.Add( this ); } } [CommandProperty( AccessLevel.GameMaster )] public Mobile Announcer { get{ return m_Announcer; } set{ m_Announcer = value; } } [CommandProperty( AccessLevel.GameMaster )] public string Name { get{ return m_Name; } set{ m_Name = value; if ( m_Active ) m_Arenas.Sort(); } } [CommandProperty( AccessLevel.GameMaster )] public Map Facet { get{ return m_Facet; } set { m_Facet = value; if ( m_Teleporter != null ) m_Teleporter.Map = value; if ( m_Region != null ) m_Region.Unregister(); if ( m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null ) m_Region = new SafeZone( m_Zone, m_Outside, m_Facet, m_IsGuarded ); else m_Region = null; } } [CommandProperty( AccessLevel.GameMaster )] public Rectangle2D Bounds{ get{ return m_Bounds; } set{ m_Bounds = value; } } private SafeZone m_Region; public int Spectators { get { if ( m_Region == null ) return 0; int specs = m_Region.GetPlayerCount() - m_Players.Count; if ( specs < 0 ) specs = 0; return specs; } } [CommandProperty( AccessLevel.GameMaster )] public Rectangle2D Zone { get{ return m_Zone; } set { m_Zone = value; if ( m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null ) { if ( m_Region != null ) m_Region.Unregister(); m_Region = new SafeZone( m_Zone, m_Outside, m_Facet, m_IsGuarded ); } else { if ( m_Region != null ) m_Region.Unregister(); m_Region = null; } } } [CommandProperty( AccessLevel.GameMaster )] public Point3D Outside{ get{ return m_Outside; } set{ m_Outside = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D GateIn{ get{ return m_GateIn; } set{ m_GateIn = value; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D GateOut{ get{ return m_GateOut; } set{ m_GateOut = value; if ( m_Teleporter != null ) m_Teleporter.Location = m_GateOut; } } [CommandProperty( AccessLevel.GameMaster )] public Point3D Wall{ get{ return m_Wall; } set{ m_Wall = value; } } [CommandProperty( AccessLevel.GameMaster )] public bool IsOccupied{ get{ return ( m_Players.Count > 0 ); } } [CommandProperty( AccessLevel.GameMaster )] public ArenaStartPoints Points{ get{ return m_Points; } set{} } public Item Teleporter{ get{ return m_Teleporter; } set{ m_Teleporter = value; } } public List Players{ get{ return m_Players; } } [CommandProperty( AccessLevel.GameMaster )] public bool Active { get{ return m_Active; } set { if ( m_Active == value ) return; m_Active = value; if ( m_Active ) { m_Arenas.Add( this ); m_Arenas.Sort(); } else { m_Arenas.Remove( this ); } } } public void Delete() { Active = false; if ( m_Region != null ) m_Region.Unregister(); m_Region = null; } public override string ToString() { return "..."; } public Point3D GetBaseStartPoint( int index ) { if ( index < 0 ) index = 0; return m_Points.Points[index % m_Points.Points.Length]; } #region Offsets & Rotation private static Point2D[] m_EdgeOffsets = new Point2D[] { /* * /\ * /\/\ * /\/\/\ * \/\/\/ * \/\/\ * \/\/ */ new Point2D( 0, 0 ), new Point2D( 0, -1 ), new Point2D( 0, +1 ), new Point2D( 1, 0 ), new Point2D( 1, -1 ), new Point2D( 1, +1 ), new Point2D( 2, 0 ), new Point2D( 2, -1 ), new Point2D( 2, +1 ), new Point2D( 3, 0 ) }; // nw corner private static Point2D[] m_CornerOffsets = new Point2D[] { /* * /\ * /\/\ * /\/\/\ * /\/\/\/\ * \/\/\/\/ */ new Point2D( 0, 0 ), new Point2D( 0, 1 ), new Point2D( 1, 0 ), new Point2D( 1, 1 ), new Point2D( 0, 2 ), new Point2D( 2, 0 ), new Point2D( 2, 1 ), new Point2D( 1, 2 ), new Point2D( 0, 3 ), new Point2D( 3, 0 ) }; private static int[][,] m_Rotate = new int[][,] { new int[,]{ { +1, 0 }, { 0, +1 } }, // west new int[,]{ { -1, 0 }, { 0, -1 } }, // east new int[,]{ { 0, +1 }, { +1, 0 } }, // north new int[,]{ { 0, -1 }, { -1, 0 } }, // south new int[,]{ { +1, 0 }, { 0, +1 } }, // nw new int[,]{ { -1, 0 }, { 0, -1 } }, // se new int[,]{ { 0, +1 }, { +1, 0 } }, // sw new int[,]{ { 0, -1 }, { -1, 0 } }, // ne }; #endregion public void MoveInside( DuelPlayer[] players, int index ) { if ( index < 0 ) index = 0; else index %= m_Points.Points.Length; Point3D start = GetBaseStartPoint( index ); int offset = 0; Point2D[] offsets = ( index < 4 ) ? m_EdgeOffsets : m_CornerOffsets; int[,] matrix = m_Rotate[index]; for ( int i = 0; i < players.Length; ++i ) { DuelPlayer pl = players[i]; if ( pl == null ) continue; Mobile mob = pl.Mobile; Point2D p; if ( offset < offsets.Length ) p = offsets[offset++]; else p = offsets[offsets.Length - 1]; p.X = (p.X * matrix[0, 0]) + (p.Y * matrix[0, 1]); p.Y = (p.X * matrix[1, 0]) + (p.Y * matrix[1, 1]); mob.MoveToWorld( new Point3D( start.X + p.X, start.Y + p.Y, start.Z ), m_Facet ); mob.Direction = mob.GetDirectionTo( m_Wall ); m_Players.Add( mob ); } } public Arena() { m_Points = new ArenaStartPoints(); m_Players = new List(); } public Arena( GenericReader reader ) { int version = reader.ReadEncodedInt(); switch ( version ) { case 7: { m_IsGuarded = reader.ReadBool(); goto case 6; } case 6: { m_Ladder = reader.ReadItem() as LadderController; goto case 5; } case 5: { m_Tournament = reader.ReadItem() as TournamentController; m_Announcer = reader.ReadMobile(); goto case 4; } case 4: { m_Name = reader.ReadString(); goto case 3; } case 3: { m_Zone = reader.ReadRect2D(); goto case 2; } case 2: { m_GateIn = reader.ReadPoint3D(); m_GateOut = reader.ReadPoint3D(); m_Teleporter = reader.ReadItem(); goto case 1; } case 1: { m_Players = reader.ReadStrongMobileList(); goto case 0; } case 0: { m_Facet = reader.ReadMap(); m_Bounds = reader.ReadRect2D(); m_Outside = reader.ReadPoint3D(); m_Wall = reader.ReadPoint3D(); if ( version == 0 ) { reader.ReadBool(); m_Players = new List(); } m_Active = reader.ReadBool(); m_Points = new ArenaStartPoints( reader ); if ( m_Active ) { m_Arenas.Add( this ); m_Arenas.Sort(); } break; } } if ( m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null ) m_Region = new SafeZone( m_Zone, m_Outside, m_Facet, m_IsGuarded ); if ( IsOccupied ) Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerCallback( Evict ) ); if ( m_Tournament != null ) Timer.DelayCall( TimeSpan.Zero, new TimerCallback( AttachToTournament_Sandbox ) ); } private void AttachToTournament_Sandbox() { if ( m_Tournament != null ) m_Tournament.Tournament.Arenas.Add( this ); } [CommandProperty( AccessLevel.Administrator, AccessLevel.Administrator )] public bool ForceEvict{ get{ return false; } set{ if ( value ) Evict(); } } public void Evict() { Point3D loc; Map facet; if ( m_Facet == null ) { loc = new Point3D( 2715, 2165, 0 ); facet = Map.Felucca; } else { loc = m_Outside; facet = m_Facet; } bool hasBounds = ( m_Bounds.Start != Point2D.Zero && m_Bounds.End != Point2D.Zero ); for ( int i = 0; i < m_Players.Count; ++i ) { Mobile mob = m_Players[i]; if ( mob == null ) continue; if ( mob.Map == Map.Internal ) { if ( (m_Facet == null || mob.LogoutMap == m_Facet) && (!hasBounds || m_Bounds.Contains( mob.LogoutLocation )) ) mob.LogoutLocation = loc; } else if ( (m_Facet == null || mob.Map == m_Facet) && (!hasBounds || m_Bounds.Contains( mob.Location )) ) { mob.MoveToWorld( loc, facet ); } mob.Combatant = null; mob.Frozen = false; DuelContext.Debuff( mob ); DuelContext.CancelSpell( mob ); } if ( hasBounds ) { List pets = new List(); foreach ( Mobile mob in facet.GetMobilesInBounds( m_Bounds ) ) { BaseCreature pet = mob as BaseCreature; if ( pet != null && pet.Controlled && pet.ControlMaster != null ) { if ( m_Players.Contains( pet.ControlMaster ) ) { pets.Add( pet ); } } } foreach ( Mobile pet in pets ) { pet.Combatant = null; pet.Frozen = false; pet.MoveToWorld( loc, facet ); } } m_Players.Clear(); } public void Serialize( GenericWriter writer ) { writer.WriteEncodedInt( (int) 7 ); writer.Write( (bool) m_IsGuarded ); writer.Write( (Item) m_Ladder ); writer.Write( (Item) m_Tournament ); writer.Write( (Mobile) m_Announcer ); writer.Write( (string) m_Name ); writer.Write( (Rectangle2D) m_Zone ); writer.Write( (Point3D) m_GateIn ); writer.Write( (Point3D) m_GateOut ); writer.Write( (Item) m_Teleporter ); writer.Write( m_Players ); writer.Write( (Map) m_Facet ); writer.Write( (Rectangle2D) m_Bounds ); writer.Write( (Point3D) m_Outside ); writer.Write( (Point3D) m_Wall ); writer.Write( (bool) m_Active ); m_Points.Serialize( writer ); } private static List m_Arenas = new List(); public static List Arenas{ get{ return m_Arenas; } } public static Arena FindArena( List players ) { Preferences prefs = Preferences.Instance; if ( prefs == null ) return FindArena(); if ( m_Arenas.Count == 0 ) return null; if ( players.Count > 0 ) { Mobile first = players[0]; List allControllers = ArenaController.Instances; for ( int i = 0; i < allControllers.Count; ++i ) { ArenaController controller = allControllers[i]; if ( controller != null && !controller.Deleted && controller.Arena != null && controller.IsPrivate && controller.Map == first.Map && first.InRange( controller, 24 ) ) { Multis.BaseHouse house = Multis.BaseHouse.FindHouseAt( controller ); bool allNear = true; for ( int j = 0; j < players.Count; ++j ) { Mobile check = players[j]; bool isNear; if ( house == null ) isNear = ( controller.Map == check.Map && check.InRange( controller, 24 ) ); else isNear = ( Multis.BaseHouse.FindHouseAt( check ) == house ); if ( !isNear ) { allNear = false; break; } } if ( allNear ) return controller.Arena; } } } List arenas = new List(); for ( int i = 0; i < m_Arenas.Count; ++i ) { Arena arena = m_Arenas[i]; if ( !arena.IsOccupied ) arenas.Add( new ArenaEntry( arena ) ); } if ( arenas.Count == 0 ) return m_Arenas[0]; int tc = 0; for ( int i = 0; i < arenas.Count; ++i ) { ArenaEntry ae = arenas[i]; for ( int j = 0; j < players.Count; ++j ) { PreferencesEntry pe = prefs.Find( players[j] ); if ( pe.Disliked.Contains( ae.m_Arena.Name ) ) ++ae.m_VotesAgainst; else ++ae.m_VotesFor; } tc += ae.Value; } int rn = Utility.Random( tc ); for ( int i = 0; i < arenas.Count; ++i ) { ArenaEntry ae = arenas[i]; if ( rn < ae.Value ) return ae.m_Arena; rn -= ae.Value; } return arenas[Utility.Random( arenas.Count )].m_Arena; } private class ArenaEntry { public Arena m_Arena; public int m_VotesFor; public int m_VotesAgainst; public int Value { get { return m_VotesFor; /*if ( m_VotesFor > m_VotesAgainst ) return m_VotesFor - m_VotesAgainst; else if ( m_VotesFor > 0 ) return 1; else return 0;*/ } } public ArenaEntry( Arena arena ) { m_Arena = arena; } } public static Arena FindArena() { if ( m_Arenas.Count == 0 ) return null; int offset = Utility.Random( m_Arenas.Count ); for ( int i = 0; i < m_Arenas.Count; ++i ) { Arena arena = m_Arenas[(i + offset) % m_Arenas.Count]; if ( !arena.IsOccupied ) return arena; } return m_Arenas[offset]; } public int CompareTo(object obj) { Arena c = (Arena)obj; string a = m_Name; string b = c.m_Name; if ( a == null && b == null ) return 0; else if ( a == null ) return -1; else if ( b == null ) return +1; return a.CompareTo( b ); } } }