From 110bd99e565441c2df33bacb3696bdffb9d70675 Mon Sep 17 00:00:00 2001 From: "xavier@runuo.com" Date: Tue, 7 May 2013 19:19:24 +0000 Subject: [PATCH] --- Scripts/Multis/Boats/BaseBoat.cs | 400 ++++++++++++++++++++++++------- Server/Item.cs | 11 +- Server/Mobile.cs | 14 +- 3 files changed, 336 insertions(+), 89 deletions(-) diff --git a/Scripts/Multis/Boats/BaseBoat.cs b/Scripts/Multis/Boats/BaseBoat.cs index 609060b31..db2ba79a1 100644 --- a/Scripts/Multis/Boats/BaseBoat.cs +++ b/Scripts/Multis/Boats/BaseBoat.cs @@ -46,6 +46,7 @@ namespace Server.Multis private Direction m_Moving; private int m_Speed; + private int m_ClientSpeed; private bool m_Anchored; private string m_ShipName; @@ -416,14 +417,36 @@ namespace Server.Multis return false; } - private static TimeSpan SlowInterval = TimeSpan.FromSeconds( 0.75 ); - private static TimeSpan FastInterval = TimeSpan.FromSeconds( 0.75 ); + /* + * Intervals: + * drift forward + * fast | 0.25| 0.25 + * slow | 0.50| 0.50 + * + * Speed: + * drift forward + * fast | 0x4| 0x4 + * slow | 0x3| 0x3 + * + * Tiles (per interval): + * drift forward + * fast | 1| 1 + * slow | 1| 1 + * + * 'walking' in piloting mode has a 1s interval, speed 0x2 + */ + + // Legacy clients will continue to see the old-style movement, but speeds are adjusted + private static bool NewBoatMovement = true; + + private static TimeSpan SlowInterval = TimeSpan.FromSeconds( NewBoatMovement ? 0.50 : 0.75 ); + private static TimeSpan FastInterval = TimeSpan.FromSeconds( NewBoatMovement ? 0.25 : 0.75 ); private static int SlowSpeed = 1; - private static int FastSpeed = 3; + private static int FastSpeed = NewBoatMovement ? 1 : 3; - private static TimeSpan SlowDriftInterval = TimeSpan.FromSeconds( 1.50 ); - private static TimeSpan FastDriftInterval = TimeSpan.FromSeconds( 0.75 ); + private static TimeSpan SlowDriftInterval = TimeSpan.FromSeconds( NewBoatMovement ? 0.50 : 1.50 ); + private static TimeSpan FastDriftInterval = TimeSpan.FromSeconds( NewBoatMovement ? 0.25 : 0.75 ); private static int SlowDriftSpeed = 1; private static int FastDriftSpeed = 1; @@ -549,8 +572,9 @@ namespace Server.Multis bool drift = ( dir != Forward && dir != ForwardLeft && dir != ForwardRight ); TimeSpan interval = (fast ? (drift ? FastDriftInterval : FastInterval) : (drift ? SlowDriftInterval : SlowInterval)); int speed = (fast ? (drift ? FastDriftSpeed : FastSpeed) : (drift ? SlowDriftSpeed : SlowSpeed)); + int clientSpeed = fast ? 0x4 : 0x3; - if ( StartMove( dir, speed, interval, false, true ) ) + if ( StartMove( dir, speed, clientSpeed, interval, false, true ) ) { if ( m_TillerMan != null ) m_TillerMan.Say( 501429 ); // Aye aye sir. @@ -570,7 +594,7 @@ namespace Server.Multis TimeSpan interval = drift ? FastDriftInterval : FastInterval; int speed = drift ? FastDriftSpeed : FastSpeed; - if ( StartMove( dir, speed, interval, true, true ) ) + if ( StartMove( dir, speed, 0x1, interval, true, true ) ) { if ( m_TillerMan != null ) m_TillerMan.Say( 501429 ); // Aye aye sir. @@ -653,28 +677,11 @@ namespace Server.Multis if ( map == null || map == Map.Internal ) return DryDockResult.Items; - MultiComponentList mcl = Components; + List ents = GetMovingEntities(); - IPooledEnumerable eable = map.GetObjectsInBounds( new Rectangle2D( X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height ) ); + if ( ents.Count >= 1 ) + return ( ents[0] is Mobile ) ? DryDockResult.Mobiles : DryDockResult.Items; - foreach ( object o in eable ) - { - if ( o == this || o == m_Hold || o == m_SPlank || o == m_PPlank || o == m_TillerMan ) - continue; - - if ( o is Item && Contains( (Item)o ) ) - { - eable.Free(); - return DryDockResult.Items; - } - else if ( o is Mobile && Contains( (Mobile)o ) ) - { - eable.Free(); - return DryDockResult.Mobiles; - } - } - - eable.Free(); return DryDockResult.Valid; } @@ -1117,7 +1124,7 @@ namespace Server.Multis } } - public bool StartMove( Direction dir, int speed, TimeSpan interval, bool single, bool message ) + public bool StartMove( Direction dir, int speed, int clientSpeed, TimeSpan interval, bool single, bool message ) { if ( CheckDecay() ) return false; @@ -1132,6 +1139,7 @@ namespace Server.Multis m_Moving = dir; m_Speed = speed; + m_ClientSpeed = clientSpeed; m_Order = BoatOrder.Move; if ( m_MoveTimer != null ) @@ -1158,6 +1166,7 @@ namespace Server.Multis m_Moving = Direction.North; m_Speed = 0; + m_ClientSpeed = 0; m_MoveTimer.Stop(); m_MoveTimer = null; @@ -1322,12 +1331,13 @@ namespace Server.Multis public bool DoMovement( bool message ) { Direction dir; - int speed; + int speed, clientSpeed; if ( this.Order == BoatOrder.Move ) { - dir = this.Moving; - speed = this.Speed; + dir = m_Moving; + speed = m_Speed; + clientSpeed = m_ClientSpeed; } else if ( MapItem == null || MapItem.Deleted ) { @@ -1396,12 +1406,13 @@ namespace Server.Multis return Turn( 2, true ); speed = Math.Min( this.Speed, maxSpeed ); + clientSpeed = 0x4; } - return Move( dir, speed, true ); + return Move( dir, speed, clientSpeed, true ); } - public bool Move( Direction dir, int speed, bool message ) + public bool Move( Direction dir, int speed, int clientSpeed, bool message ) { Map map = Map; @@ -1417,7 +1428,8 @@ namespace Server.Multis } int rx = 0, ry = 0; - Movement.Movement.Offset( (Direction)(((int)m_Facing + (int)dir) & 0x7), ref rx, ref ry ); + Direction d = (Direction)(((int)m_Facing + (int)dir) & 0x7); + Movement.Movement.Offset( d, ref rx, ref ry ); for ( int i = 1; i <= speed; ++i ) { @@ -1476,48 +1488,129 @@ namespace Server.Multis } } - Teleport( xOffset, yOffset, 0 ); + if ( !NewBoatMovement || Math.Abs( xOffset ) > 1 || Math.Abs( yOffset ) > 1 ) + { + Teleport( xOffset, yOffset, 0 ); + } + else + { + List toMove = GetMovingEntities(); + + SafeAdd( m_TillerMan, toMove ); + SafeAdd( m_Hold, toMove ); + SafeAdd( m_PPlank, toMove ); + SafeAdd( m_SPlank, toMove ); + + // Packet must be sent before actual locations are changed + foreach ( NetState ns in Map.GetClientsInRange( Location, GetMaxUpdateRange() ) ) + { + Mobile m = ns.Mobile; + + if ( ns.HighSeas && m.CanSee( this ) && m.InRange( Location, GetUpdateRange( m ) ) ) + ns.Send( new MoveBoatHS( m, this, d, clientSpeed, toMove, xOffset, yOffset ) ); + } + + foreach ( IEntity e in toMove ) + { + if ( e is Item ) + { + Item item = (Item)e; + + item.NoMoveHS = true; + + if ( !( item is TillerMan || item is Hold || item is Plank ) ) + item.Location = new Point3D( item.X + xOffset, item.Y + yOffset, item.Z ); + } + else if ( e is Mobile ) + { + Mobile m = (Mobile)e; + + m.NoMoveHS = true; + m.Location = new Point3D( m.X + xOffset, m.Y + yOffset, m.Z ); + } + } + + NoMoveHS = true; + Location = new Point3D( X + xOffset, Y + yOffset, Z ); + + foreach ( IEntity e in toMove ) + { + if ( e is Item ) + ((Item)e).NoMoveHS = false; + else if ( e is Mobile ) + ((Mobile)e).NoMoveHS = false; + } + + NoMoveHS = false; + } return true; } + private static void SafeAdd( Item item, List toMove ) + { + if ( item != null ) + toMove.Add( item ); + } + public void Teleport( int xOffset, int yOffset, int zOffset ) { - MultiComponentList mcl = Components; - - ArrayList toMove = new ArrayList(); - - IPooledEnumerable eable = this.Map.GetObjectsInBounds( new Rectangle2D( X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height ) ); - - foreach ( object o in eable ) - { - if ( o != this && !(o is TillerMan || o is Hold || o is Plank) ) - toMove.Add( o ); - } - - eable.Free(); + List toMove = GetMovingEntities(); for ( int i = 0; i < toMove.Count; ++i ) { - object o = toMove[i]; + IEntity e = toMove[i]; + + if ( e is Item ) + { + Item item = (Item)e; + + item.Location = new Point3D( item.X + xOffset, item.Y + yOffset, item.Z + zOffset ); + } + else if ( e is Mobile ) + { + Mobile m = (Mobile)e; + + m.Location = new Point3D( m.X + xOffset, m.Y + yOffset, m.Z + zOffset ); + } + } + + Location = new Point3D( X + xOffset, Y + yOffset, Z + zOffset ); + } + + public List GetMovingEntities() + { + List list = new List(); + + Map map = Map; + + if ( map == null || map == Map.Internal ) + return list; + + MultiComponentList mcl = Components; + + foreach ( object o in map.GetObjectsInBounds( new Rectangle2D( X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height ) ) ) + { + if ( o == this || o is TillerMan || o is Hold || o is Plank ) + continue; if ( o is Item ) { Item item = (Item)o; if ( Contains( item ) && item.Visible && item.Z >= Z ) - item.Location = new Point3D( item.X + xOffset, item.Y + yOffset, item.Z + zOffset ); + list.Add( item ); } else if ( o is Mobile ) { Mobile m = (Mobile)o; if ( Contains( m ) ) - m.Location = new Point3D( m.X + xOffset, m.Y + yOffset, m.Z + zOffset ); + list.Add( m ); } } - Location = new Point3D( X + xOffset, Y + yOffset, Z + zOffset ); + return list; } public bool SetFacing( Direction facing ) @@ -1539,8 +1632,6 @@ namespace Server.Multis } } - this.Map.OnLeave( this ); - Direction old = m_Facing; m_Facing = facing; @@ -1557,34 +1648,11 @@ namespace Server.Multis if ( m_SPlank != null ) m_SPlank.SetFacing( facing ); - MultiComponentList mcl = Components; - - ArrayList toMove = new ArrayList(); + List toMove = GetMovingEntities(); toMove.Add( m_PPlank ); toMove.Add( m_SPlank ); - IPooledEnumerable eable = Map.GetObjectsInBounds( new Rectangle2D( X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height ) ); - - foreach ( object o in eable ) - { - if ( o is Item ) - { - Item item = (Item)o; - - if ( item != this && Contains( item ) && item.Visible && item.Z >= Z && !(item is TillerMan || item is Hold || item is Plank) ) - toMove.Add( item ); - } - else if ( o is Mobile && Contains( (Mobile)o ) ) - { - toMove.Add( o ); - - ((Mobile)o).Direction = (Direction)((int)((Mobile)o).Direction - (int)old + (int)facing); - } - } - - eable.Free(); - int xOffset = 0, yOffset = 0; Movement.Movement.Offset( facing, ref xOffset, ref yOffset ); @@ -1599,12 +1667,21 @@ namespace Server.Multis for ( int i = 0; i < toMove.Count; ++i ) { - object o = toMove[i]; + IEntity e = toMove[i]; - if ( o is Item ) - ((Item)o).Location = Rotate( ((Item)o).Location, count ); - else if ( o is Mobile ) - ((Mobile)o).Location = Rotate( ((Mobile)o).Location, count ); + if ( e is Item ) + { + Item item = (Item)e; + + item.Location = Rotate( item.Location, count ); + } + else if ( e is Mobile ) + { + Mobile m = (Mobile)e; + + m.Direction = ( m.Direction - old + facing ) & Direction.Mask; + m.Location = Rotate( m.Location, count ); + } } switch ( facing ) @@ -1615,8 +1692,6 @@ namespace Server.Multis case Direction.West: ItemID = WestID; break; } - this.Map.OnEnter( this ); - return true; } @@ -1665,5 +1740,160 @@ namespace Server.Multis UpdateAllComponents(); } } + + #region High Seas + + /* + * OSI sends the 0xF7 packet instead, holding 0xF3 packets + * for every entity on the boat. Though, the regular 0xF3 + * packets are still being sent as well as entities come + * into sight. Do we really need it? + */ + /* + protected override Packet GetWorldPacketFor( NetState state ) + { + if ( NewBoatMovement && state.HighSeas ) + return new DisplayBoatHS( state.Mobile, this ); + else + return base.GetWorldPacketFor( state ); + } + */ + + public sealed class MoveBoatHS : Packet + { + public MoveBoatHS( Mobile beholder, BaseBoat boat, Direction d, int speed, List ents, int xOffset, int yOffset ) + : base( 0xF6 ) + { + EnsureCapacity( 3 + 15 + ents.Count * 10 ); + + m_Stream.Write( (int) boat.Serial ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) d ); + m_Stream.Write( (byte) boat.Facing ); + m_Stream.Write( (short) ( boat.X + xOffset ) ); + m_Stream.Write( (short) ( boat.Y + yOffset ) ); + m_Stream.Write( (short) boat.Z ); + m_Stream.Write( (short) 0 ); // count placeholder + + int count = 0; + + foreach ( IEntity ent in ents ) + { + if ( !beholder.CanSee( ent ) ) + continue; + + m_Stream.Write( (int) ent.Serial ); + m_Stream.Write( (short) ( ent.X + xOffset ) ); + m_Stream.Write( (short) ( ent.Y + yOffset ) ); + m_Stream.Write( (short) ent.Z ); + ++count; + } + + m_Stream.Seek( 16, System.IO.SeekOrigin.Begin ); + m_Stream.Write( (short) count ); + } + } + + public sealed class DisplayBoatHS : Packet + { + public DisplayBoatHS( Mobile beholder, BaseBoat boat ) + : base( 0xF7 ) + { + List ents = boat.GetMovingEntities(); + + SafeAdd( boat.TillerMan, ents ); + SafeAdd( boat.Hold, ents ); + SafeAdd( boat.PPlank, ents ); + SafeAdd( boat.SPlank, ents ); + + ents.Add( boat ); + + EnsureCapacity( 3 + 2 + ents.Count * 26 ); + + m_Stream.Write( (short) 0 ); // count placeholder + + int count = 0; + + foreach ( IEntity ent in ents ) + { + if ( !beholder.CanSee( ent ) ) + continue; + + // Embedded WorldItemHS packets + m_Stream.Write( (byte) 0xF3 ); + m_Stream.Write( (short) 0x1 ); + + if ( ent is BaseMulti ) + { + BaseMulti bm = (BaseMulti)ent; + + m_Stream.Write( (byte) 0x02 ); + m_Stream.Write( (int) bm.Serial ); + // TODO: Mask no longer needed, merge with Item case? + m_Stream.Write( (ushort) ( bm.ItemID & 0x3FFF ) ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( (short) bm.Amount ); + m_Stream.Write( (short) bm.Amount ); + + m_Stream.Write( (short) ( bm.X & 0x7FFF ) ); + m_Stream.Write( (short) ( bm.Y & 0x3FFF ) ); + m_Stream.Write( (sbyte) bm.Z ); + + m_Stream.Write( (byte) bm.Light ); + m_Stream.Write( (short) bm.Hue ); + m_Stream.Write( (byte) bm.GetPacketFlags() ); + } + else if ( ent is Mobile ) + { + Mobile m = (Mobile)ent; + + m_Stream.Write( (byte) 0x01 ); + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) m.Body ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( (short) 1 ); + m_Stream.Write( (short) 1 ); + + m_Stream.Write( (short) ( m.X & 0x7FFF ) ); + m_Stream.Write( (short) ( m.Y & 0x3FFF ) ); + m_Stream.Write( (sbyte) m.Z ); + + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (short) m.Hue ); + m_Stream.Write( (byte) m.GetPacketFlags() ); + } + else if ( ent is Item ) + { + Item item = (Item)ent; + + m_Stream.Write( (byte) 0x00 ); + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (ushort) ( item.ItemID & 0xFFFF ) ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( (short) item.Amount ); + m_Stream.Write( (short) item.Amount ); + + m_Stream.Write( (short) ( item.X & 0x7FFF ) ); + m_Stream.Write( (short) ( item.Y & 0x3FFF ) ); + m_Stream.Write( (sbyte) item.Z ); + + m_Stream.Write( (byte) item.Light ); + m_Stream.Write( (short) item.Hue ); + m_Stream.Write( (byte) item.GetPacketFlags() ); + } + + m_Stream.Write( (short) 0x00 ); + ++count; + } + + m_Stream.Seek( 3, System.IO.SeekOrigin.Begin ); + m_Stream.Write( (short) count ); + } + } + + #endregion } } diff --git a/Server/Item.cs b/Server/Item.cs index 7e0c04c9d..a17513573 100644 --- a/Server/Item.cs +++ b/Server/Item.cs @@ -3029,6 +3029,14 @@ namespace Server } } + private bool m_NoMoveHS; + + public bool NoMoveHS + { + get { return m_NoMoveHS; } + set { m_NoMoveHS = value; } + } + public void ProcessDelta() { ItemDelta flags = m_DeltaFlags; @@ -3558,6 +3566,7 @@ namespace Server eable.Free(); } + Point3D oldLoc = m_Location; m_Location = value; ReleaseWorldPackets(); @@ -3569,7 +3578,7 @@ namespace Server { Mobile m = state.Mobile; - if ( m.CanSee( this ) && m.InRange( m_Location, GetUpdateRange( m ) ) ) + if ( m.CanSee( this ) && m.InRange( m_Location, GetUpdateRange( m ) ) && ( !state.HighSeas || !m_NoMoveHS || ( m_DeltaFlags & ItemDelta.Update ) != 0 || !m.InRange( oldLoc, GetUpdateRange( m ) ) ) ) SendInfoTo( state ); } diff --git a/Server/Mobile.cs b/Server/Mobile.cs index 525361063..766e7cd84 100644 --- a/Server/Mobile.cs +++ b/Server/Mobile.cs @@ -9101,7 +9101,7 @@ namespace Server if( m_Map != null ) m_Map.OnMove( oldLocation, this ); - if( isTeleport && m_NetState != null ) + if( isTeleport && m_NetState != null && ( !m_NetState.HighSeas || !m_NoMoveHS ) ) { m_NetState.Sequence = 0; @@ -9164,7 +9164,7 @@ namespace Server bool inOldRange = Utility.InUpdateRange( oldLocation, m.m_Location ); - if( (isTeleport || !inOldRange) && m.m_NetState != null && m.CanSee( this ) ) + if( m.m_NetState != null && ( ( isTeleport && ( !m.m_NetState.HighSeas || !m_NoMoveHS ) ) || !inOldRange ) && m.CanSee( this ) ) { if ( m.m_NetState.StygianAbyss ) { m.m_NetState.Send( new MobileIncoming( m, this ) ); @@ -9227,7 +9227,7 @@ namespace Server // We're not attached to a client, so simply send an Incoming foreach( NetState ns in eable ) { - if( (isTeleport || !Utility.InUpdateRange( oldLocation, ns.Mobile.Location )) && ns.Mobile.CanSee( this ) ) + if( ( ( isTeleport && ( !ns.HighSeas || !m_NoMoveHS ) ) || !Utility.InUpdateRange( oldLocation, ns.Mobile.Location )) && ns.Mobile.CanSee( this ) ) { if ( ns.StygianAbyss ) { ns.Send( new MobileIncoming( ns.Mobile, this ) ); @@ -9935,6 +9935,14 @@ namespace Server Core.Set(); } + private bool m_NoMoveHS; + + public bool NoMoveHS + { + get { return m_NoMoveHS; } + set { m_NoMoveHS = value; } + } + #region GetDirectionTo[..] public Direction GetDirectionTo( int x, int y )