fix: Cleans up movement code (#787)
* Removes FastMovementImpl since it isn't used and I am not convinced it is better. * Moves some of the new movement logic from FastMovementImpl to MovementImpl * Makes MovementImpl more readable
This commit is contained in:
parent
7785f7e06c
commit
73c65a43ad
13 changed files with 312 additions and 989 deletions
|
|
@ -692,7 +692,7 @@ namespace Server
|
|||
var tile = staticTiles[i];
|
||||
var id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
|
||||
if (id.Surface || (id.Flags & TileFlag.Wet) != 0)
|
||||
if (id.Surface || id.Wet)
|
||||
{
|
||||
var tileZ = tile.Z + id.CalcHeight;
|
||||
|
||||
|
|
@ -720,7 +720,7 @@ namespace Server
|
|||
{
|
||||
var id = item.ItemData;
|
||||
|
||||
if (id.Surface || (id.Flags & TileFlag.Wet) != 0)
|
||||
if (id.Surface || id.Wet)
|
||||
{
|
||||
var itemZ = item.Z + id.CalcHeight;
|
||||
|
||||
|
|
|
|||
|
|
@ -104,11 +104,28 @@ namespace Server
|
|||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public int CalcHeight => (Flags & TileFlag.Bridge) != 0 ? _height / 2 : _height;
|
||||
public int CalcHeight => Bridge ? _height / 2 : _height;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Door
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Door];
|
||||
set => this[TileFlag.Door] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Background
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Background];
|
||||
set => this[TileFlag.Background] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Bridge
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Bridge];
|
||||
set => this[TileFlag.Bridge] = value;
|
||||
}
|
||||
|
|
@ -116,6 +133,7 @@ namespace Server
|
|||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Wall
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Wall];
|
||||
set => this[TileFlag.Wall] = value;
|
||||
}
|
||||
|
|
@ -123,13 +141,21 @@ namespace Server
|
|||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Window
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Window];
|
||||
set => this[TileFlag.Window] = value;
|
||||
}
|
||||
|
||||
public bool ImpassableSurface
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Impassable | TileFlag.Surface];
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Impassable
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Impassable];
|
||||
set => this[TileFlag.Impassable] = value;
|
||||
}
|
||||
|
|
@ -137,6 +163,7 @@ namespace Server
|
|||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Surface
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Surface];
|
||||
set => this[TileFlag.Surface] = value;
|
||||
}
|
||||
|
|
@ -144,6 +171,7 @@ namespace Server
|
|||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Roof
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Roof];
|
||||
set => this[TileFlag.Roof] = value;
|
||||
}
|
||||
|
|
@ -151,10 +179,19 @@ namespace Server
|
|||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool LightSource
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.LightSource];
|
||||
set => this[TileFlag.LightSource] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public bool Wet
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => this[TileFlag.Wet];
|
||||
set => this[TileFlag.Wet] = value;
|
||||
}
|
||||
|
||||
public bool this[TileFlag flag]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
|
|||
|
|
@ -1078,7 +1078,7 @@ namespace Server.Commands
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ((TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.LightSource) != 0)
|
||||
else if (TileData.ItemTable[itemID & TileData.MaxItemValue].LightSource)
|
||||
{
|
||||
eable = map.GetItemsInRange(new Point3D(x, y, z), 0);
|
||||
|
||||
|
|
@ -1100,7 +1100,7 @@ namespace Server.Commands
|
|||
res = true;
|
||||
}
|
||||
}
|
||||
else if ((item.ItemData.Flags & TileFlag.LightSource) != 0 && item.ItemData.Name == srcName)
|
||||
else if (item.ItemData.LightSource && item.ItemData.Name == srcName)
|
||||
{
|
||||
m_DeleteQueue.Enqueue(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1074,7 +1074,7 @@ namespace Server.Commands
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ((TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.LightSource) != 0)
|
||||
else if (TileData.ItemTable[itemID & TileData.MaxItemValue].LightSource)
|
||||
{
|
||||
eable = map.GetItemsInRange(new Point3D(x, y, z), 0);
|
||||
|
||||
|
|
@ -1096,7 +1096,7 @@ namespace Server.Commands
|
|||
res = true;
|
||||
}
|
||||
}
|
||||
else if ((item.ItemData.Flags & TileFlag.LightSource) != 0 && item.ItemData.Name == srcName)
|
||||
else if (item.ItemData.LightSource && item.ItemData.Name == srcName)
|
||||
{
|
||||
m_DeleteQueue.Enqueue(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,674 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Movement
|
||||
{
|
||||
public class FastMovementImpl : IMovementImpl
|
||||
{
|
||||
private const int PersonHeight = 16;
|
||||
private const int StepHeight = 2;
|
||||
|
||||
private const TileFlag ImpassableSurface = TileFlag.Impassable | TileFlag.Surface;
|
||||
public static bool Enabled = false;
|
||||
|
||||
private static IMovementImpl _Successor;
|
||||
|
||||
private FastMovementImpl()
|
||||
{
|
||||
}
|
||||
|
||||
public bool CheckMovement(Mobile m, Map map, Point3D loc, Direction d, out int newZ)
|
||||
{
|
||||
if (!Enabled && _Successor != null)
|
||||
{
|
||||
return _Successor.CheckMovement(m, map, loc, d, out newZ);
|
||||
}
|
||||
|
||||
if (map == null || map == Map.Internal)
|
||||
{
|
||||
newZ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
var xStart = loc.X;
|
||||
var yStart = loc.Y;
|
||||
|
||||
int xForward = xStart, yForward = yStart;
|
||||
int xRight = xStart, yRight = yStart;
|
||||
int xLeft = xStart, yLeft = yStart;
|
||||
|
||||
var checkDiagonals = ((int)d & 0x1) == 0x1;
|
||||
|
||||
Offset(d, ref xForward, ref yForward);
|
||||
Offset((Direction)(((int)d - 1) & 0x7), ref xLeft, ref yLeft);
|
||||
Offset((Direction)(((int)d + 1) & 0x7), ref xRight, ref yRight);
|
||||
|
||||
if (xForward < 0 || yForward < 0 || xForward >= map.Width || yForward >= map.Height)
|
||||
{
|
||||
newZ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerable<Item> itemsStart, itemsForward, itemsLeft, itemsRight;
|
||||
|
||||
var ignoreMovableImpassables = MovementImpl.IgnoreMovableImpassables;
|
||||
var reqFlags = ImpassableSurface;
|
||||
|
||||
if (m.CanSwim)
|
||||
{
|
||||
reqFlags |= TileFlag.Wet;
|
||||
}
|
||||
|
||||
if (checkDiagonals)
|
||||
{
|
||||
var sStart = map.GetSector(xStart, yStart);
|
||||
var sForward = map.GetSector(xForward, yForward);
|
||||
var sLeft = map.GetSector(xLeft, yLeft);
|
||||
var sRight = map.GetSector(xRight, yRight);
|
||||
|
||||
itemsStart = sStart.Items.Where(i => Verify(i, reqFlags, ignoreMovableImpassables, xStart, yStart));
|
||||
itemsForward = sForward.Items.Where(i => Verify(i, reqFlags, ignoreMovableImpassables, xForward, yForward));
|
||||
itemsLeft = sLeft.Items.Where(i => Verify(i, reqFlags, ignoreMovableImpassables, xLeft, yLeft));
|
||||
itemsRight = sRight.Items.Where(i => Verify(i, reqFlags, ignoreMovableImpassables, xRight, yRight));
|
||||
}
|
||||
else
|
||||
{
|
||||
var sStart = map.GetSector(xStart, yStart);
|
||||
var sForward = map.GetSector(xForward, yForward);
|
||||
|
||||
itemsStart = sStart.Items.Where(i => Verify(i, reqFlags, ignoreMovableImpassables, xStart, yStart));
|
||||
itemsForward = sForward.Items.Where(i => Verify(i, reqFlags, ignoreMovableImpassables, xForward, yForward));
|
||||
itemsLeft = Enumerable.Empty<Item>();
|
||||
itemsRight = Enumerable.Empty<Item>();
|
||||
}
|
||||
|
||||
GetStartZ(m, map, loc, itemsStart, out var startZ, out var startTop);
|
||||
|
||||
List<Item> list = null;
|
||||
|
||||
MovementPool.AcquireMoveCache(ref list, itemsForward);
|
||||
|
||||
var moveIsOk = Check(map, m, list, xForward, yForward, startTop, startZ, m.CanSwim, m.CantWalk, out newZ);
|
||||
|
||||
if (moveIsOk && checkDiagonals)
|
||||
{
|
||||
if (m.Player && m.AccessLevel < AccessLevel.GameMaster)
|
||||
{
|
||||
MovementPool.AcquireMoveCache(ref list, itemsLeft);
|
||||
|
||||
if (!Check(map, m, list, xLeft, yLeft, startTop, startZ, m.CanSwim, m.CantWalk, out _))
|
||||
{
|
||||
moveIsOk = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
MovementPool.AcquireMoveCache(ref list, itemsRight);
|
||||
|
||||
if (!Check(map, m, list, xRight, yRight, startTop, startZ, m.CanSwim, m.CantWalk, out _))
|
||||
{
|
||||
moveIsOk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MovementPool.AcquireMoveCache(ref list, itemsLeft);
|
||||
|
||||
if (!Check(map, m, list, xLeft, yLeft, startTop, startZ, m.CanSwim, m.CantWalk, out _))
|
||||
{
|
||||
MovementPool.AcquireMoveCache(ref list, itemsRight);
|
||||
|
||||
if (!Check(map, m, list, xRight, yRight, startTop, startZ, m.CanSwim, m.CantWalk, out _))
|
||||
{
|
||||
moveIsOk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MovementPool.ClearMoveCache(ref list, true);
|
||||
|
||||
if (!moveIsOk)
|
||||
{
|
||||
newZ = startZ;
|
||||
}
|
||||
|
||||
return moveIsOk;
|
||||
}
|
||||
|
||||
public bool CheckMovement(Mobile m, Direction d, out int newZ) =>
|
||||
!Enabled && _Successor != null
|
||||
? _Successor.CheckMovement(m, d, out newZ)
|
||||
: CheckMovement(m, m.Map, m.Location, d, out newZ);
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
_Successor = Movement.Impl;
|
||||
Movement.Impl = new FastMovementImpl();
|
||||
}
|
||||
|
||||
private static bool IsOk(StaticTile tile, int ourZ, int ourTop)
|
||||
{
|
||||
var itemData = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
|
||||
return tile.Z + itemData.CalcHeight <= ourZ || ourTop <= tile.Z || (itemData.Flags & ImpassableSurface) == 0;
|
||||
}
|
||||
|
||||
private static bool IsOk(Item item, int ourZ, int ourTop, bool ignoreDoors, bool ignoreSpellFields)
|
||||
{
|
||||
var itemID = item.ItemID & TileData.MaxItemValue;
|
||||
var itemData = TileData.ItemTable[itemID];
|
||||
|
||||
if ((itemData.Flags & ImpassableSurface) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (((itemData.Flags & TileFlag.Door) != 0 || itemID == 0x692 || itemID == 0x846 || itemID == 0x873 ||
|
||||
itemID >= 0x6F5 && itemID <= 0x6F6) && ignoreDoors)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((itemID == 0x82 || itemID == 0x3946 || itemID == 0x3956) && ignoreSpellFields)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return item.Z + itemData.CalcHeight <= ourZ || ourTop <= item.Z;
|
||||
}
|
||||
|
||||
private static bool IsOk(
|
||||
bool ignoreDoors,
|
||||
bool ignoreSpellFields,
|
||||
int ourZ,
|
||||
int ourTop,
|
||||
IEnumerable<StaticTile> tiles,
|
||||
IEnumerable<Item> items
|
||||
)
|
||||
{
|
||||
return tiles.All(t => IsOk(t, ourZ, ourTop)) &&
|
||||
items.All(i => IsOk(i, ourZ, ourTop, ignoreDoors, ignoreSpellFields));
|
||||
}
|
||||
|
||||
private static bool Check(
|
||||
Map map,
|
||||
Mobile m,
|
||||
List<Item> items,
|
||||
int x,
|
||||
int y,
|
||||
int startTop,
|
||||
int startZ,
|
||||
bool canSwim,
|
||||
bool cantWalk,
|
||||
out int newZ
|
||||
)
|
||||
{
|
||||
newZ = 0;
|
||||
|
||||
var tiles = map.Tiles.GetStaticTiles(x, y, true);
|
||||
var landTile = map.Tiles.GetLandTile(x, y);
|
||||
var landData = TileData.LandTable[landTile.ID & TileData.MaxLandValue];
|
||||
var considerLand = !landTile.Ignored;
|
||||
var landBlocks = (landData.Flags & TileFlag.Impassable) != 0;
|
||||
|
||||
if (landBlocks && canSwim && (landData.Flags & TileFlag.Wet) != 0)
|
||||
{
|
||||
landBlocks = false;
|
||||
}
|
||||
else if (cantWalk && (landData.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
landBlocks = true;
|
||||
}
|
||||
|
||||
map.GetAverageZ(x, y, out var landZ, out var landCenter, out _);
|
||||
|
||||
var moveIsOk = false;
|
||||
|
||||
var stepTop = startTop + StepHeight;
|
||||
var checkTop = startZ + PersonHeight;
|
||||
|
||||
var ignoreDoors = MovementImpl.AlwaysIgnoreDoors || !m.Alive || m.IsDeadBondedPet || m.Body.IsGhost ||
|
||||
m.Body.BodyID == 987;
|
||||
var ignoreSpellFields = m is PlayerMobile && map.MapID != 0;
|
||||
|
||||
int itemZ, itemTop, ourZ, ourTop, testTop;
|
||||
ItemData itemData;
|
||||
TileFlag flags;
|
||||
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
itemData = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
|
||||
if (m.Flying && itemData.Name.InsensitiveEquals("hover over"))
|
||||
{
|
||||
newZ = tile.Z;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stygian Dragon
|
||||
if (m.Body == 826 && map?.MapID == 5)
|
||||
{
|
||||
if (x >= 307 && x <= 354 && y >= 126 && y <= 192)
|
||||
{
|
||||
if (tile.Z > newZ)
|
||||
{
|
||||
newZ = tile.Z;
|
||||
}
|
||||
|
||||
moveIsOk = true;
|
||||
}
|
||||
else if (x >= 42 && x <= 89)
|
||||
{
|
||||
if (y >= 333 && y <= 399 || y >= 531 && y <= 597 || y >= 739 && y <= 805)
|
||||
{
|
||||
if (tile.Z > newZ)
|
||||
{
|
||||
newZ = tile.Z;
|
||||
}
|
||||
|
||||
moveIsOk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags = itemData.Flags;
|
||||
|
||||
if ((flags & ImpassableSurface) != TileFlag.Surface && (!canSwim || (flags & TileFlag.Wet) == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cantWalk && (flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemZ = tile.Z;
|
||||
itemTop = itemZ;
|
||||
ourZ = itemZ + itemData.CalcHeight;
|
||||
ourTop = ourZ + PersonHeight;
|
||||
testTop = checkTop;
|
||||
|
||||
if (moveIsOk)
|
||||
{
|
||||
var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs();
|
||||
|
||||
if (cmp > 0 || cmp == 0 && ourZ > newZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ourTop > testTop)
|
||||
{
|
||||
testTop = ourTop;
|
||||
}
|
||||
|
||||
if (!itemData.Bridge)
|
||||
{
|
||||
itemTop += itemData.Height;
|
||||
}
|
||||
|
||||
if (stepTop < itemTop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var landCheck = itemZ;
|
||||
|
||||
if (itemData.Height >= StepHeight)
|
||||
{
|
||||
landCheck += StepHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
landCheck += itemData.Height;
|
||||
}
|
||||
|
||||
if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newZ = ourZ;
|
||||
moveIsOk = true;
|
||||
}
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
itemData = item.ItemData;
|
||||
flags = itemData.Flags;
|
||||
|
||||
if (m.Flying && itemData.Name.InsensitiveEquals("hover over"))
|
||||
{
|
||||
newZ = item.Z;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.Movable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((flags & ImpassableSurface) != TileFlag.Surface && (!m.CanSwim || (flags & TileFlag.Wet) == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cantWalk && (flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemZ = item.Z;
|
||||
itemTop = itemZ;
|
||||
ourZ = itemZ + itemData.CalcHeight;
|
||||
ourTop = ourZ + PersonHeight;
|
||||
testTop = checkTop;
|
||||
|
||||
if (moveIsOk)
|
||||
{
|
||||
var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs();
|
||||
|
||||
if (cmp > 0 || cmp == 0 && ourZ > newZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ourTop > testTop)
|
||||
{
|
||||
testTop = ourTop;
|
||||
}
|
||||
|
||||
if (!itemData.Bridge)
|
||||
{
|
||||
itemTop += itemData.Height;
|
||||
}
|
||||
|
||||
if (stepTop < itemTop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var landCheck = itemZ;
|
||||
|
||||
if (itemData.Height >= StepHeight)
|
||||
{
|
||||
landCheck += StepHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
landCheck += itemData.Height;
|
||||
}
|
||||
|
||||
if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newZ = ourZ;
|
||||
moveIsOk = true;
|
||||
}
|
||||
|
||||
if (!considerLand || landBlocks || stepTop < landZ)
|
||||
{
|
||||
return moveIsOk;
|
||||
}
|
||||
|
||||
ourZ = landCenter;
|
||||
ourTop = ourZ + PersonHeight;
|
||||
testTop = checkTop;
|
||||
|
||||
if (ourTop > testTop)
|
||||
{
|
||||
testTop = ourTop;
|
||||
}
|
||||
|
||||
var shouldCheck = true;
|
||||
|
||||
if (moveIsOk)
|
||||
{
|
||||
var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs();
|
||||
|
||||
if (cmp > 0 || cmp == 0 && ourZ > newZ)
|
||||
{
|
||||
shouldCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldCheck || !IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
{
|
||||
return moveIsOk;
|
||||
}
|
||||
|
||||
newZ = ourZ;
|
||||
moveIsOk = true;
|
||||
|
||||
return moveIsOk;
|
||||
}
|
||||
|
||||
private static bool Verify(Item item, int x, int y) => item.AtWorldPoint(x, y);
|
||||
|
||||
private static bool Verify(Item item, TileFlag reqFlags, bool ignoreMovableImpassables) =>
|
||||
item != null && (!ignoreMovableImpassables || !item.Movable || !item.ItemData.Impassable) &&
|
||||
(item.ItemData.Flags & reqFlags) != 0 && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue;
|
||||
|
||||
private static bool Verify(Item item, TileFlag reqFlags, bool ignoreMovableImpassables, int x, int y) =>
|
||||
Verify(item, reqFlags, ignoreMovableImpassables) && Verify(item, x, y);
|
||||
|
||||
private static void GetStartZ(Mobile m, Map map, Point3D loc, IEnumerable<Item> itemList, out int zLow, out int zTop)
|
||||
{
|
||||
int xCheck = loc.X, yCheck = loc.Y;
|
||||
|
||||
var landTile = map.Tiles.GetLandTile(xCheck, yCheck);
|
||||
var landData = TileData.LandTable[landTile.ID & TileData.MaxLandValue];
|
||||
var landBlocks = (landData.Flags & TileFlag.Impassable) != 0;
|
||||
|
||||
if (landBlocks && m.CanSwim && (landData.Flags & TileFlag.Wet) != 0)
|
||||
{
|
||||
landBlocks = false;
|
||||
}
|
||||
else if (m.CantWalk && (landData.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
landBlocks = true;
|
||||
}
|
||||
|
||||
map.GetAverageZ(xCheck, yCheck, out var landZ, out var landCenter, out var landTop);
|
||||
|
||||
var considerLand = !landTile.Ignored;
|
||||
|
||||
var zCenter = zLow = zTop = 0;
|
||||
var isSet = false;
|
||||
|
||||
if (considerLand && !landBlocks && loc.Z >= landCenter)
|
||||
{
|
||||
zLow = landZ;
|
||||
zCenter = landCenter;
|
||||
zTop = landTop;
|
||||
isSet = true;
|
||||
}
|
||||
|
||||
var staticTiles = map.Tiles.GetStaticTiles(xCheck, yCheck, true);
|
||||
|
||||
foreach (var tile in staticTiles)
|
||||
{
|
||||
var tileData = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
var calcTop = tile.Z + tileData.CalcHeight;
|
||||
|
||||
if (isSet && calcTop < zCenter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((tileData.Flags & TileFlag.Surface) == 0 &&
|
||||
(!m.CanSwim || (tileData.Flags & TileFlag.Wet) == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loc.Z < calcTop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.CantWalk && (tileData.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
zLow = tile.Z;
|
||||
zCenter = calcTop;
|
||||
|
||||
var top = tile.Z + tileData.Height;
|
||||
|
||||
if (!isSet || top > zTop)
|
||||
{
|
||||
zTop = top;
|
||||
}
|
||||
|
||||
isSet = true;
|
||||
}
|
||||
|
||||
foreach (var item in itemList)
|
||||
{
|
||||
var itemData = item.ItemData;
|
||||
|
||||
var calcTop = item.Z + itemData.CalcHeight;
|
||||
|
||||
if (isSet && calcTop < zCenter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((itemData.Flags & TileFlag.Surface) == 0 &&
|
||||
(!m.CanSwim || (itemData.Flags & TileFlag.Wet) == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loc.Z < calcTop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.CantWalk && (itemData.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
zLow = item.Z;
|
||||
zCenter = calcTop;
|
||||
|
||||
var top = item.Z + itemData.Height;
|
||||
|
||||
if (!isSet || top > zTop)
|
||||
{
|
||||
zTop = top;
|
||||
}
|
||||
|
||||
isSet = true;
|
||||
}
|
||||
|
||||
if (!isSet)
|
||||
{
|
||||
zLow = zTop = loc.Z;
|
||||
}
|
||||
else if (loc.Z > zTop)
|
||||
{
|
||||
zTop = loc.Z;
|
||||
}
|
||||
}
|
||||
|
||||
public void Offset(Direction d, ref int x, ref int y)
|
||||
{
|
||||
switch (d & Direction.Mask)
|
||||
{
|
||||
case Direction.North:
|
||||
--y;
|
||||
break;
|
||||
case Direction.South:
|
||||
++y;
|
||||
break;
|
||||
case Direction.West:
|
||||
--x;
|
||||
break;
|
||||
case Direction.East:
|
||||
++x;
|
||||
break;
|
||||
case Direction.Right:
|
||||
++x;
|
||||
--y;
|
||||
break;
|
||||
case Direction.Left:
|
||||
--x;
|
||||
++y;
|
||||
break;
|
||||
case Direction.Down:
|
||||
++x;
|
||||
++y;
|
||||
break;
|
||||
case Direction.Up:
|
||||
--x;
|
||||
--y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MovementPool
|
||||
{
|
||||
private static readonly object _MovePoolLock = new();
|
||||
private static readonly Queue<List<Item>> _MoveCachePool = new(0x400);
|
||||
|
||||
public static void AcquireMoveCache(ref List<Item> cache, IEnumerable<Item> items)
|
||||
{
|
||||
if (cache == null)
|
||||
{
|
||||
lock (_MovePoolLock)
|
||||
{
|
||||
cache = _MoveCachePool.Count > 0 ? _MoveCachePool.Dequeue() : new List<Item>(0x10);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cache.Clear();
|
||||
}
|
||||
|
||||
cache.AddRange(items);
|
||||
}
|
||||
|
||||
public static void ClearMoveCache(ref List<Item> cache, bool free)
|
||||
{
|
||||
cache?.Clear();
|
||||
|
||||
if (!free)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_MovePoolLock)
|
||||
{
|
||||
if (_MoveCachePool.Count < 0x400)
|
||||
{
|
||||
_MoveCachePool.Enqueue(cache);
|
||||
}
|
||||
}
|
||||
|
||||
cache = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,13 +11,18 @@ namespace Server.Movement
|
|||
|
||||
private const TileFlag ImpassableSurface = TileFlag.Impassable | TileFlag.Surface;
|
||||
|
||||
private static Point3D m_Goal;
|
||||
private static Point3D _goal;
|
||||
|
||||
private readonly List<Mobile>[] m_MobPools = { new(), new(), new() };
|
||||
public static void Configure()
|
||||
{
|
||||
Movement.Impl = new MovementImpl();
|
||||
}
|
||||
|
||||
private readonly List<Item>[] m_Pools = { new(), new(), new(), new() };
|
||||
private readonly List<Mobile>[] _mobPools = { new(), new(), new() };
|
||||
|
||||
private readonly List<Sector> m_Sectors = new();
|
||||
private readonly List<Item>[] _pools = { new(), new(), new(), new() };
|
||||
|
||||
private readonly HashSet<Sector> _sectors = new();
|
||||
|
||||
private MovementImpl()
|
||||
{
|
||||
|
|
@ -25,12 +30,11 @@ namespace Server.Movement
|
|||
|
||||
public static bool AlwaysIgnoreDoors { get; set; }
|
||||
public static bool IgnoreMovableImpassables { get; set; }
|
||||
public static bool IgnoreSpellFields { get; set; }
|
||||
|
||||
public static Point3D Goal
|
||||
{
|
||||
get => m_Goal;
|
||||
set => m_Goal = value;
|
||||
get => _goal;
|
||||
set => _goal = value;
|
||||
}
|
||||
|
||||
public bool CheckMovement(Mobile m, Map map, Point3D loc, Direction d, out int newZ)
|
||||
|
|
@ -43,6 +47,7 @@ namespace Server.Movement
|
|||
|
||||
var xStart = loc.X;
|
||||
var yStart = loc.Y;
|
||||
|
||||
int xForward = xStart, yForward = yStart;
|
||||
int xRight = xStart, yRight = yStart;
|
||||
int xLeft = xStart, yLeft = yStart;
|
||||
|
|
@ -59,10 +64,10 @@ namespace Server.Movement
|
|||
return false;
|
||||
}
|
||||
|
||||
var itemsStart = m_Pools[0];
|
||||
var itemsForward = m_Pools[1];
|
||||
var itemsLeft = m_Pools[2];
|
||||
var itemsRight = m_Pools[3];
|
||||
var itemsStart = _pools[0];
|
||||
var itemsForward = _pools[1];
|
||||
var itemsLeft = _pools[2];
|
||||
var itemsRight = _pools[3];
|
||||
|
||||
var ignoreMovableImpassables = IgnoreMovableImpassables;
|
||||
var reqFlags = ImpassableSurface;
|
||||
|
|
@ -72,11 +77,11 @@ namespace Server.Movement
|
|||
reqFlags |= TileFlag.Wet;
|
||||
}
|
||||
|
||||
var mobsForward = m_MobPools[0];
|
||||
var mobsLeft = m_MobPools[1];
|
||||
var mobsRight = m_MobPools[2];
|
||||
var mobsForward = _mobPools[0];
|
||||
var mobsLeft = _mobPools[1];
|
||||
var mobsRight = _mobPools[2];
|
||||
|
||||
var checkMobs = (m as BaseCreature)?.Controlled == false && (xForward != m_Goal.X || yForward != m_Goal.Y);
|
||||
var checkMobs = (m as BaseCreature)?.Controlled == false && (xForward != _goal.X || yForward != _goal.Y);
|
||||
|
||||
if (checkDiagonals)
|
||||
{
|
||||
|
|
@ -85,40 +90,24 @@ namespace Server.Movement
|
|||
var sectorLeft = map.GetSector(xLeft, yLeft);
|
||||
var sectorRight = map.GetSector(xRight, yRight);
|
||||
|
||||
var sectors = m_Sectors;
|
||||
_sectors.Add(sectorStart);
|
||||
|
||||
sectors.Add(sectorStart);
|
||||
_sectors.Add(sectorForward);
|
||||
_sectors.Add(sectorLeft);
|
||||
_sectors.Add(sectorRight);
|
||||
|
||||
if (!sectors.Contains(sectorForward))
|
||||
foreach (var sector in _sectors)
|
||||
{
|
||||
sectors.Add(sectorForward);
|
||||
}
|
||||
|
||||
if (!sectors.Contains(sectorLeft))
|
||||
{
|
||||
sectors.Add(sectorLeft);
|
||||
}
|
||||
|
||||
if (!sectors.Contains(sectorRight))
|
||||
{
|
||||
sectors.Add(sectorRight);
|
||||
}
|
||||
|
||||
for (var i = 0; i < sectors.Count; ++i)
|
||||
{
|
||||
var sector = sectors[i];
|
||||
|
||||
for (var j = 0; j < sector.Items.Count; ++j)
|
||||
{
|
||||
var item = sector.Items[j];
|
||||
|
||||
if (ignoreMovableImpassables && item.Movable &&
|
||||
(item.ItemData.Flags & ImpassableSurface) != 0)
|
||||
if (ignoreMovableImpassables && item.Movable && item.ItemData.ImpassableSurface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((item.ItemData.Flags & reqFlags) == 0)
|
||||
if (!item.ItemData[reqFlags])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -168,29 +157,26 @@ namespace Server.Movement
|
|||
}
|
||||
}
|
||||
|
||||
if (m_Sectors.Count > 0)
|
||||
{
|
||||
m_Sectors.Clear();
|
||||
}
|
||||
_sectors.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sectorStart = map.GetSector(xStart, yStart);
|
||||
var sectorForward = map.GetSector(xForward, yForward);
|
||||
var sectorStartIsForward = sectorStart == sectorForward;
|
||||
|
||||
if (sectorStart == sectorForward)
|
||||
if (!sectorStartIsForward)
|
||||
{
|
||||
for (var i = 0; i < sectorStart.Items.Count; ++i)
|
||||
for (var i = 0; i < sectorForward.Items.Count; ++i)
|
||||
{
|
||||
var item = sectorStart.Items[i];
|
||||
var item = sectorForward.Items[i];
|
||||
|
||||
if (ignoreMovableImpassables && item.Movable &&
|
||||
(item.ItemData.Flags & ImpassableSurface) != 0)
|
||||
if (ignoreMovableImpassables && item.Movable && item.ItemData.ImpassableSurface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((item.ItemData.Flags & reqFlags) == 0)
|
||||
if (!item.ItemData[reqFlags])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -200,60 +186,35 @@ namespace Server.Movement
|
|||
continue;
|
||||
}
|
||||
|
||||
if (item.AtWorldPoint(xStart, yStart))
|
||||
{
|
||||
itemsStart.Add(item);
|
||||
}
|
||||
else if (item.AtWorldPoint(xForward, yForward))
|
||||
if (item.AtWorldPoint(xForward, yForward))
|
||||
{
|
||||
itemsForward.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
for (var i = 0; i < sectorStart.Items.Count; ++i)
|
||||
{
|
||||
for (var i = 0; i < sectorForward.Items.Count; ++i)
|
||||
var item = sectorStart.Items[i];
|
||||
|
||||
if (ignoreMovableImpassables && item.Movable && item.ItemData.ImpassableSurface)
|
||||
{
|
||||
var item = sectorForward.Items[i];
|
||||
|
||||
if (ignoreMovableImpassables && item.Movable &&
|
||||
(item.ItemData.Flags & ImpassableSurface) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((item.ItemData.Flags & reqFlags) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.AtWorldPoint(xForward, yForward) && !(item is BaseMulti) &&
|
||||
item.ItemID <= TileData.MaxItemValue)
|
||||
{
|
||||
itemsForward.Add(item);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var i = 0; i < sectorStart.Items.Count; ++i)
|
||||
if (!item.ItemData[reqFlags])
|
||||
{
|
||||
var item = sectorStart.Items[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ignoreMovableImpassables && item.Movable &&
|
||||
(item.ItemData.Flags & ImpassableSurface) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item is BaseMulti || item.ItemID > TileData.MaxItemValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((item.ItemData.Flags & reqFlags) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.AtWorldPoint(xStart, yStart) && !(item is BaseMulti) &&
|
||||
item.ItemID <= TileData.MaxItemValue)
|
||||
{
|
||||
itemsStart.Add(item);
|
||||
}
|
||||
if (item.AtWorldPoint(xStart, yStart) || sectorStartIsForward && item.AtWorldPoint(xForward, yForward))
|
||||
{
|
||||
itemsStart.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,58 +234,22 @@ namespace Server.Movement
|
|||
|
||||
GetStartZ(m, map, loc, itemsStart, out var startZ, out var startTop);
|
||||
|
||||
var moveIsOk = Check(
|
||||
map,
|
||||
m,
|
||||
itemsForward,
|
||||
mobsForward,
|
||||
xForward,
|
||||
yForward,
|
||||
startTop,
|
||||
startZ,
|
||||
m.CanSwim,
|
||||
m.CantWalk,
|
||||
out newZ
|
||||
);
|
||||
var moveIsOk = Check(map, m, itemsForward, mobsForward, xForward, yForward, startTop, startZ, out newZ);
|
||||
|
||||
if (moveIsOk && checkDiagonals)
|
||||
{
|
||||
if (m.Player && m.AccessLevel < AccessLevel.GameMaster)
|
||||
{
|
||||
if (!Check(map, m, itemsLeft, mobsLeft, xLeft, yLeft, startTop, startZ, m.CanSwim, m.CantWalk, out _) ||
|
||||
!Check(
|
||||
map,
|
||||
m,
|
||||
itemsRight,
|
||||
mobsRight,
|
||||
xRight,
|
||||
yRight,
|
||||
startTop,
|
||||
startZ,
|
||||
m.CanSwim,
|
||||
m.CantWalk,
|
||||
out _
|
||||
))
|
||||
if (!Check(map, m, itemsLeft, mobsLeft, xLeft, yLeft, startTop, startZ, out _) ||
|
||||
!Check(map, m, itemsRight, mobsRight, xRight, yRight, startTop, startZ, out _))
|
||||
{
|
||||
moveIsOk = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Check(map, m, itemsLeft, mobsLeft, xLeft, yLeft, startTop, startZ, m.CanSwim, m.CantWalk, out _) &&
|
||||
!Check(
|
||||
map,
|
||||
m,
|
||||
itemsRight,
|
||||
mobsRight,
|
||||
xRight,
|
||||
yRight,
|
||||
startTop,
|
||||
startZ,
|
||||
m.CanSwim,
|
||||
m.CantWalk,
|
||||
out _
|
||||
))
|
||||
if (!Check(map, m, itemsLeft, mobsLeft, xLeft, yLeft, startTop, startZ, out _) &&
|
||||
!Check(map, m, itemsRight, mobsRight, xRight, yRight, startTop, startZ, out _))
|
||||
{
|
||||
moveIsOk = false;
|
||||
}
|
||||
|
|
@ -333,12 +258,12 @@ namespace Server.Movement
|
|||
|
||||
for (int i = 0, c = checkDiagonals ? 4 : 2; i < c; ++i)
|
||||
{
|
||||
m_Pools[i].Clear();
|
||||
_pools[i].Clear();
|
||||
}
|
||||
|
||||
for (int i = 0, c = checkDiagonals ? 3 : 1; i < c; ++i)
|
||||
{
|
||||
m_MobPools[i].Clear();
|
||||
_mobPools[i].Clear();
|
||||
}
|
||||
|
||||
if (!moveIsOk)
|
||||
|
|
@ -351,11 +276,6 @@ namespace Server.Movement
|
|||
|
||||
public bool CheckMovement(Mobile m, Direction d, out int newZ) => CheckMovement(m, m.Map, m.Location, d, out newZ);
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
Movement.Impl = new MovementImpl();
|
||||
}
|
||||
|
||||
private bool IsOk(
|
||||
bool ignoreDoors, bool ignoreSpellFields, int ourZ, int ourTop, StaticTile[] tiles, List<Item> items
|
||||
)
|
||||
|
|
@ -365,7 +285,7 @@ namespace Server.Movement
|
|||
var check = tiles[i];
|
||||
var itemData = TileData.ItemTable[check.ID & TileData.MaxItemValue];
|
||||
|
||||
if ((itemData.Flags & ImpassableSurface) != 0) // Impassable || Surface
|
||||
if (itemData.ImpassableSurface)
|
||||
{
|
||||
var checkZ = check.Z;
|
||||
var checkTop = checkZ + itemData.CalcHeight;
|
||||
|
|
@ -382,18 +302,15 @@ namespace Server.Movement
|
|||
var item = items[i];
|
||||
var itemID = item.ItemID & TileData.MaxItemValue;
|
||||
var itemData = TileData.ItemTable[itemID];
|
||||
var flags = itemData.Flags;
|
||||
|
||||
if ((flags & ImpassableSurface) != 0) // Impassable || Surface
|
||||
if (itemData.ImpassableSurface)
|
||||
{
|
||||
if (ignoreDoors && ((flags & TileFlag.Door) != 0 || itemID == 0x692 || itemID == 0x846 ||
|
||||
itemID == 0x873 ||
|
||||
itemID >= 0x6F5 && itemID <= 0x6F6))
|
||||
if (ignoreDoors && (itemData.Door || itemID is 0x692 or 0x846 or 0x873 || itemID >= 0x6F5 && itemID <= 0x6F6))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ignoreSpellFields && (itemID == 0x82 || itemID == 0x3946 || itemID == 0x3956))
|
||||
if (ignoreSpellFields && itemID is 0x82 or 0x3946 or 0x3956)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -412,12 +329,21 @@ namespace Server.Movement
|
|||
}
|
||||
|
||||
private bool Check(
|
||||
Map map, Mobile m, List<Item> items, List<Mobile> mobiles, int x, int y, int startTop, int startZ,
|
||||
bool canSwim, bool cantWalk, out int newZ
|
||||
Map map,
|
||||
Mobile m,
|
||||
List<Item> items,
|
||||
List<Mobile> mobiles,
|
||||
int x,
|
||||
int y,
|
||||
int startTop,
|
||||
int startZ,
|
||||
out int newZ
|
||||
)
|
||||
{
|
||||
newZ = 0;
|
||||
|
||||
var cantWalk = m.CantWalk;
|
||||
var canSwim = m.CanSwim;
|
||||
var tiles = map.Tiles.GetStaticTiles(x, y, true);
|
||||
var landTile = map.Tiles.GetLandTile(x, y);
|
||||
var flags = TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags;
|
||||
|
|
@ -438,17 +364,45 @@ namespace Server.Movement
|
|||
var ignoreDoors = AlwaysIgnoreDoors || !m.Alive || m.Body.BodyID == 0x3DB || m.IsDeadBondedPet;
|
||||
var ignoreSpellFields = m is PlayerMobile && map != Map.Felucca;
|
||||
|
||||
int testTop;
|
||||
|
||||
for (var i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
var tile = tiles[i];
|
||||
var itemData = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
flags = itemData.Flags;
|
||||
|
||||
var notWater = (flags & TileFlag.Wet) == 0;
|
||||
if (m.Flying && itemData.Name.InsensitiveEquals("hover over"))
|
||||
{
|
||||
newZ = tile.Z;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Surface && !Impassable
|
||||
if ((flags & ImpassableSurface) != TileFlag.Surface && (!canSwim || notWater) ||
|
||||
cantWalk && notWater)
|
||||
// Stygian Dragon
|
||||
if (m.Body == 826 && map == Map.TerMur)
|
||||
{
|
||||
if (x is >= 307 and <= 354 && y is >= 126 and <= 192)
|
||||
{
|
||||
if (tile.Z > newZ)
|
||||
{
|
||||
newZ = tile.Z;
|
||||
}
|
||||
|
||||
moveIsOk = true;
|
||||
}
|
||||
else if (x is >= 42 and <= 89 && y is >= 333 and <= 399 or >= 531 and <= 597 or >= 739 and <= 805)
|
||||
{
|
||||
if (tile.Z > newZ)
|
||||
{
|
||||
newZ = tile.Z;
|
||||
}
|
||||
|
||||
moveIsOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
var notWater = !itemData.Wet;
|
||||
|
||||
if (!itemData.Surface && itemData.Impassable && (!canSwim || notWater) || cantWalk && notWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -456,8 +410,7 @@ namespace Server.Movement
|
|||
var itemZ = tile.Z;
|
||||
var itemTop = itemZ;
|
||||
var ourZ = itemZ + itemData.CalcHeight;
|
||||
// int ourTop = ourZ + PersonHeight;
|
||||
var testTop = checkTop;
|
||||
testTop = checkTop;
|
||||
|
||||
if (moveIsOk)
|
||||
{
|
||||
|
|
@ -479,29 +432,31 @@ namespace Server.Movement
|
|||
itemTop += itemData.Height;
|
||||
}
|
||||
|
||||
if (stepTop >= itemTop)
|
||||
if (stepTop < itemTop)
|
||||
{
|
||||
var landCheck = itemZ;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (itemData.Height >= StepHeight)
|
||||
{
|
||||
landCheck += StepHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
landCheck += itemData.Height;
|
||||
}
|
||||
var landCheck = itemZ;
|
||||
|
||||
if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (itemData.Height >= StepHeight)
|
||||
{
|
||||
landCheck += StepHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
landCheck += itemData.Height;
|
||||
}
|
||||
|
||||
if (IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
{
|
||||
newZ = ourZ;
|
||||
moveIsOk = true;
|
||||
}
|
||||
if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
{
|
||||
newZ = ourZ;
|
||||
moveIsOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -509,14 +464,21 @@ namespace Server.Movement
|
|||
{
|
||||
var item = items[i];
|
||||
var itemData = item.ItemData;
|
||||
flags = itemData.Flags;
|
||||
|
||||
var notWater = (flags & TileFlag.Wet) == 0;
|
||||
if (m.Flying && itemData.Name.InsensitiveEquals("hover over"))
|
||||
{
|
||||
newZ = item.Z;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Surface && !Impassable && !Movable
|
||||
if (item.Movable ||
|
||||
(flags & ImpassableSurface) != TileFlag.Surface && (!m.CanSwim || notWater) ||
|
||||
cantWalk && notWater)
|
||||
if (!item.Movable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var notWater = !itemData.Wet;
|
||||
|
||||
if (!itemData.Surface && itemData.Impassable && (!canSwim || notWater) || cantWalk && notWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -524,8 +486,7 @@ namespace Server.Movement
|
|||
var itemZ = item.Z;
|
||||
var itemTop = itemZ;
|
||||
var ourZ = itemZ + itemData.CalcHeight;
|
||||
// int ourTop = ourZ + PersonHeight;
|
||||
var testTop = checkTop;
|
||||
testTop = checkTop;
|
||||
|
||||
if (moveIsOk)
|
||||
{
|
||||
|
|
@ -547,62 +508,64 @@ namespace Server.Movement
|
|||
itemTop += itemData.Height;
|
||||
}
|
||||
|
||||
if (stepTop >= itemTop)
|
||||
if (stepTop < itemTop)
|
||||
{
|
||||
var landCheck = itemZ;
|
||||
|
||||
if (itemData.Height >= StepHeight)
|
||||
{
|
||||
landCheck += StepHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
landCheck += itemData.Height;
|
||||
}
|
||||
|
||||
if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
{
|
||||
newZ = ourZ;
|
||||
moveIsOk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (considerLand && !landBlocks && stepTop >= landZ)
|
||||
{
|
||||
var ourZ = landCenter;
|
||||
// int ourTop = ourZ + PersonHeight;
|
||||
var testTop = checkTop;
|
||||
|
||||
if (ourZ + PersonHeight > testTop)
|
||||
{
|
||||
testTop = ourZ + PersonHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
var shouldCheck = true;
|
||||
var landCheck = itemZ;
|
||||
|
||||
if (moveIsOk)
|
||||
if (itemData.Height >= StepHeight)
|
||||
{
|
||||
var cmp = (ourZ - m.Z).Abs() - (newZ - m.Z).Abs();
|
||||
|
||||
if (cmp > 0 || cmp == 0 && ourZ > newZ)
|
||||
{
|
||||
shouldCheck = false;
|
||||
}
|
||||
landCheck += StepHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
landCheck += itemData.Height;
|
||||
}
|
||||
|
||||
if (shouldCheck && IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items))
|
||||
{
|
||||
newZ = ourZ;
|
||||
moveIsOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!considerLand || landBlocks || stepTop < landZ)
|
||||
{
|
||||
return moveIsOk;
|
||||
}
|
||||
|
||||
testTop = checkTop;
|
||||
|
||||
if (landCenter + PersonHeight > testTop)
|
||||
{
|
||||
testTop = landCenter + PersonHeight;
|
||||
}
|
||||
|
||||
var shouldCheck = true;
|
||||
|
||||
if (moveIsOk)
|
||||
{
|
||||
var cmp = (landCenter - m.Z).Abs() - (newZ - m.Z).Abs();
|
||||
|
||||
if (cmp > 0 || cmp == 0 && landCenter > newZ)
|
||||
{
|
||||
shouldCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldCheck && IsOk(ignoreDoors, ignoreSpellFields, landCenter, testTop, tiles, items))
|
||||
{
|
||||
newZ = landCenter;
|
||||
moveIsOk = true;
|
||||
}
|
||||
|
||||
if (moveIsOk)
|
||||
{
|
||||
for (var i = 0; moveIsOk && i < mobiles.Count; ++i)
|
||||
|
|
@ -659,26 +622,27 @@ namespace Server.Movement
|
|||
|
||||
var calcTop = tile.Z + id.CalcHeight;
|
||||
|
||||
if ((!isSet || calcTop >= zCenter) &&
|
||||
((id.Flags & TileFlag.Surface) != 0 || m.CanSwim && (id.Flags & TileFlag.Wet) != 0) && loc.Z >= calcTop)
|
||||
if (isSet && calcTop < zCenter || !id.Surface && !(m.CanSwim && id.Wet) || loc.Z < calcTop)
|
||||
{
|
||||
if (m.CantWalk && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
zLow = tile.Z;
|
||||
zCenter = calcTop;
|
||||
|
||||
var top = tile.Z + id.Height;
|
||||
|
||||
if (!isSet || top > zTop)
|
||||
{
|
||||
zTop = top;
|
||||
}
|
||||
|
||||
isSet = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.CantWalk && !id.Wet)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
zLow = tile.Z;
|
||||
zCenter = calcTop;
|
||||
|
||||
var top = tile.Z + id.Height;
|
||||
|
||||
if (!isSet || top > zTop)
|
||||
{
|
||||
zTop = top;
|
||||
}
|
||||
|
||||
isSet = true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < itemList.Count; ++i)
|
||||
|
|
@ -689,26 +653,27 @@ namespace Server.Movement
|
|||
|
||||
var calcTop = item.Z + id.CalcHeight;
|
||||
|
||||
if ((!isSet || calcTop >= zCenter) &&
|
||||
((id.Flags & TileFlag.Surface) != 0 || m.CanSwim && (id.Flags & TileFlag.Wet) != 0) && loc.Z >= calcTop)
|
||||
if (isSet && calcTop < zCenter || !id.Surface && !(m.CanSwim && id.Wet) || loc.Z < calcTop)
|
||||
{
|
||||
if (m.CantWalk && (id.Flags & TileFlag.Wet) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
zLow = item.Z;
|
||||
zCenter = calcTop;
|
||||
|
||||
var top = item.Z + id.Height;
|
||||
|
||||
if (!isSet || top > zTop)
|
||||
{
|
||||
zTop = top;
|
||||
}
|
||||
|
||||
isSet = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.CantWalk && !id.Wet)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
zLow = item.Z;
|
||||
zCenter = calcTop;
|
||||
|
||||
var top = item.Z + id.Height;
|
||||
|
||||
if (!isSet || top > zTop)
|
||||
{
|
||||
zTop = top;
|
||||
}
|
||||
|
||||
isSet = true;
|
||||
}
|
||||
|
||||
if (!isSet)
|
||||
|
|
|
|||
|
|
@ -67,8 +67,7 @@ namespace Server.Engines.Spawners
|
|||
{
|
||||
var staticTile = staticTiles[i];
|
||||
|
||||
if (staticTile.Z == z &&
|
||||
(TileData.ItemTable[staticTile.ID & TileData.MaxItemValue].Flags & TileFlag.Wet) != 0)
|
||||
if (staticTile.Z == z && TileData.ItemTable[staticTile.ID & TileData.MaxItemValue].Wet)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ namespace Server.Items
|
|||
|
||||
public static void ApplyLightTo(Item item)
|
||||
{
|
||||
if ((item.ItemData.Flags & TileFlag.LightSource) == 0)
|
||||
if (!item.ItemData.LightSource)
|
||||
{
|
||||
return; // not a light source
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1751,14 +1751,12 @@ namespace Server.Mobiles
|
|||
|
||||
var speed = ComputeMovementSpeed(d);
|
||||
|
||||
bool res;
|
||||
|
||||
if (!Alive)
|
||||
{
|
||||
MovementImpl.IgnoreMovableImpassables = true;
|
||||
}
|
||||
|
||||
res = base.Move(d);
|
||||
var res = base.Move(d);
|
||||
|
||||
MovementImpl.IgnoreMovableImpassables = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -1471,7 +1471,7 @@ namespace Server.Multis
|
|||
var data = TileData.ItemTable[id];
|
||||
|
||||
// Slanted roofs do not count; they overhang blocking south and east sides of the multi
|
||||
if ((data.Flags & TileFlag.Roof) != 0)
|
||||
if (data.Roof)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,13 +185,13 @@ namespace Server.Multis
|
|||
var data = TileData.ItemTable[entry.ItemId & TileData.MaxItemValue];
|
||||
|
||||
// door
|
||||
if ((data.Flags & TileFlag.Door) != 0)
|
||||
if (data.Door)
|
||||
{
|
||||
AddDoor(entry.ItemId, entry.OffsetX, entry.OffsetY, entry.OffsetZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
Item st = new Static((int)entry.ItemId);
|
||||
Item st = new Static(entry.ItemId);
|
||||
|
||||
st.MoveToWorld(new Point3D(X + entry.OffsetX, Y + entry.OffsetY, entry.OffsetZ), Map);
|
||||
AddFixture(st);
|
||||
|
|
|
|||
|
|
@ -1305,7 +1305,7 @@ namespace Server.Multis
|
|||
public static bool ValidPiece(int itemID, bool roof = false)
|
||||
{
|
||||
itemID &= TileData.MaxItemValue;
|
||||
return roof != ((TileData.ItemTable[itemID].Flags & TileFlag.Roof) == 0) && Verification.IsItemValid(itemID);
|
||||
return roof == TileData.ItemTable[itemID].Roof && Verification.IsItemValid(itemID);
|
||||
}
|
||||
|
||||
public static bool IsStairBlock(int id)
|
||||
|
|
@ -1479,12 +1479,12 @@ namespace Server.Multis
|
|||
}
|
||||
|
||||
/* Client chose to delete a component
|
||||
* - Read data detailing which component to delete
|
||||
* - Verify component is deletable
|
||||
* - Remove the component
|
||||
* - If needed, replace removed component with a dirt tile
|
||||
* - Update revision
|
||||
*/
|
||||
* - Read data detailing which component to delete
|
||||
* - Verify component is deletable
|
||||
* - Remove the component
|
||||
* - If needed, replace removed component with a dirt tile
|
||||
* - Update revision
|
||||
*/
|
||||
|
||||
// Read data detailing which component to delete
|
||||
var itemID = reader.ReadInt32();
|
||||
|
|
@ -1502,9 +1502,9 @@ namespace Server.Multis
|
|||
if (z == 0 && ax >= 0 && ax < mcl.Width && ay >= 0 && ay < mcl.Height - 1)
|
||||
{
|
||||
/* Component is not deletable
|
||||
* - Resend design state
|
||||
* - Return without further processing
|
||||
*/
|
||||
* - Resend design state
|
||||
* - Return without further processing
|
||||
*/
|
||||
|
||||
design.SendDetailedInfoTo(state);
|
||||
return;
|
||||
|
|
@ -1644,10 +1644,10 @@ namespace Server.Multis
|
|||
}
|
||||
|
||||
/* Client chose to add a component
|
||||
* - Read data detailing component graphic and location
|
||||
* - Add component
|
||||
* - Update revision
|
||||
*/
|
||||
* - Read data detailing component graphic and location
|
||||
* - Add component
|
||||
* - Update revision
|
||||
*/
|
||||
|
||||
// Read data detailing component graphic and location
|
||||
var itemID = reader.ReadInt32();
|
||||
|
|
@ -1690,13 +1690,13 @@ namespace Server.Multis
|
|||
}
|
||||
|
||||
/* Client closed his house design window
|
||||
* - Remove design context
|
||||
* - Notify the client that customization has ended
|
||||
* - Refresh client with current visible design state
|
||||
* - If a signpost is needed, add it
|
||||
* - Eject all from house
|
||||
* - Restore relocated entities
|
||||
*/
|
||||
* - Remove design context
|
||||
* - Notify the client that customization has ended
|
||||
* - Refresh client with current visible design state
|
||||
* - If a signpost is needed, add it
|
||||
* - Eject all from house
|
||||
* - Restore relocated entities
|
||||
*/
|
||||
|
||||
// Remove design context
|
||||
DesignContext.Remove(from);
|
||||
|
|
@ -1739,13 +1739,13 @@ namespace Server.Multis
|
|||
}
|
||||
|
||||
/* Client is moving to a new floor level
|
||||
* - Read data detailing the target level
|
||||
* - Validate target level
|
||||
* - Update design context with new level
|
||||
* - Teleport mobile to new level
|
||||
* - Update client
|
||||
*
|
||||
*/
|
||||
* - Read data detailing the target level
|
||||
* - Validate target level
|
||||
* - Update design context with new level
|
||||
* - Teleport mobile to new level
|
||||
* - Update client
|
||||
*
|
||||
*/
|
||||
|
||||
// Read data detailing the target level
|
||||
var newLevel = reader.ReadInt32();
|
||||
|
|
@ -1823,7 +1823,7 @@ namespace Server.Multis
|
|||
|
||||
if (mte.OffsetX == x && mte.OffsetY == y &&
|
||||
GetZLevel(mte.OffsetZ, context.Foundation) == context.Level &&
|
||||
(TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Flags & TileFlag.Roof) != 0)
|
||||
TileData.ItemTable[mte.ItemId & TileData.MaxItemValue].Roof)
|
||||
{
|
||||
mcl.Remove(mte.ItemId, x, y, mte.OffsetZ);
|
||||
}
|
||||
|
|
@ -1856,7 +1856,7 @@ namespace Server.Multis
|
|||
var design = context.Foundation.DesignState;
|
||||
var mcl = design.Components;
|
||||
|
||||
if ((TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.Roof) == 0)
|
||||
if (!TileData.ItemTable[itemID & TileData.MaxItemValue].Roof)
|
||||
{
|
||||
design.SendDetailedInfoTo(state);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -177,9 +177,9 @@ namespace Server.Multis
|
|||
continue;
|
||||
}
|
||||
|
||||
var addTileFlags = TileData.ItemTable[addTile.ID & TileData.MaxItemValue].Flags;
|
||||
var addTileData = TileData.ItemTable[addTile.ID & TileData.MaxItemValue];
|
||||
|
||||
var isFoundation = addTile.Z == 0 && (addTileFlags & TileFlag.Wall) != 0;
|
||||
var isFoundation = addTile.Z == 0 && addTileData.Wall;
|
||||
var hasSurface = false;
|
||||
|
||||
if (isFoundation)
|
||||
|
|
@ -190,7 +190,7 @@ namespace Server.Multis
|
|||
var addTileZ = center.Z + addTile.Z;
|
||||
var addTileTop = addTileZ + addTile.Height;
|
||||
|
||||
if ((addTileFlags & TileFlag.Surface) != 0)
|
||||
if (addTileData.Surface)
|
||||
{
|
||||
addTileTop += 16;
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ namespace Server.Multis
|
|||
var oldTile = oldTiles[j];
|
||||
var id = TileData.ItemTable[oldTile.ID & TileData.MaxItemValue];
|
||||
|
||||
if ((id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0) &&
|
||||
if ((id.Impassable || id.Surface && !id.Background) &&
|
||||
addTileTop > oldTile.Z && oldTile.Z + id.CalcHeight > addTileZ)
|
||||
{
|
||||
return HousePlacementResult.BadStatic; // Broke rule #2
|
||||
|
|
@ -233,7 +233,7 @@ namespace Server.Multis
|
|||
{
|
||||
toMove.Add(item);
|
||||
}
|
||||
else if (id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0)
|
||||
else if (id.Impassable || id.Surface && !id.Background)
|
||||
{
|
||||
return HousePlacementResult.BadItem; // Broke rule #2
|
||||
}
|
||||
|
|
@ -359,8 +359,7 @@ namespace Server.Multis
|
|||
var tile = tiles[j];
|
||||
var id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
|
||||
|
||||
if (id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0 &&
|
||||
tile.Z + id.CalcHeight > center.Z + 2)
|
||||
if (id.Impassable || id.Surface && !id.Background && tile.Z + id.CalcHeight > center.Z + 2)
|
||||
{
|
||||
return HousePlacementResult.BadStatic; // Broke rule #1
|
||||
}
|
||||
|
|
@ -380,8 +379,7 @@ namespace Server.Multis
|
|||
|
||||
var id = item.ItemData;
|
||||
|
||||
if (id.Impassable || id.Surface && (id.Flags & TileFlag.Background) == 0 &&
|
||||
item.Z + id.CalcHeight > center.Z + 2)
|
||||
if (id.Impassable || id.Surface && !id.Background && item.Z + id.CalcHeight > center.Z + 2)
|
||||
{
|
||||
return HousePlacementResult.BadItem; // Broke rule #1
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue