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:
Kamron Batman 2021-09-16 23:23:22 -07:00 committed by GitHub
parent 7785f7e06c
commit 73c65a43ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 312 additions and 989 deletions

View file

@ -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;

View file

@ -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)]

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}
}
}
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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
}