This commit is contained in:
xavier@runuo.com 2013-05-07 19:19:24 +00:00
parent 10a21d850d
commit 110bd99e56
3 changed files with 336 additions and 89 deletions

View file

@ -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<IEntity> 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<IEntity> 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<IEntity> 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<IEntity> 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<IEntity> GetMovingEntities()
{
List<IEntity> list = new List<IEntity>();
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<IEntity> 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<IEntity> 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<IEntity> 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
}
}