fix: Cleans up doors and house placement (#1560)
This commit is contained in:
parent
6239b418a8
commit
68f3e15e5b
4 changed files with 136 additions and 73 deletions
|
|
@ -21,7 +21,7 @@ namespace Server;
|
|||
public partial class Map
|
||||
{
|
||||
private int _iteratingItems;
|
||||
private List<(MapAction, Point3D, Item)> _delayedItemActions = new();
|
||||
private readonly List<(MapAction, Point3D, Item)> _delayedItemActions = new();
|
||||
|
||||
public bool IsIteratingItems
|
||||
{
|
||||
|
|
@ -29,15 +29,58 @@ public partial class Map
|
|||
get => _iteratingItems > 0;
|
||||
}
|
||||
|
||||
public ItemEnumerable<Item> GetItemsInRange(Point3D p) => GetItemsInRange(p, Core.GlobalMaxUpdateRange);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsAt(Point3D p) => GetItemsInRange(p, 0);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsAt<T>(Point3D p) where T : Item => GetItemsInRange<T>(p, 0);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsInRange(Point3D p) => GetItemsInRange<Item>(p);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsInRange(Point3D p, int range) => GetItemsInRange<Item>(p, range);
|
||||
|
||||
public ItemEnumerable<T> GetItemsInRange<T>(Point3D p, int range) where T : Item =>
|
||||
GetItemsInBounds<T>(new Rectangle2D(p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1));
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsInRange<T>(Point3D p) where T : Item => GetItemsInRange<T>(p, Core.GlobalMaxUpdateRange);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsInRange<T>(Point3D p, int range) where T : Item =>
|
||||
GetItemsInRange<T>(p.m_X, p.m_Y, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsAt(Point2D p) => GetItemsInRange(p, 0);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsAt<T>(Point2D p) where T : Item => GetItemsInRange<T>(p, 0);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsInRange(Point2D p) => GetItemsInRange<Item>(p);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsInRange(Point2D p, int range) => GetItemsInRange<Item>(p, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsInRange<T>(Point2D p) where T : Item => GetItemsInRange<T>(p, Core.GlobalMaxUpdateRange);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsInRange<T>(Point2D p, int range) where T : Item =>
|
||||
GetItemsInRange<T>(p.m_X, p.m_Y, range);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsAt(int x, int y) => GetItemsAt<Item>(x, y);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsAt<T>(int x, int y) where T : Item => GetItemsInRange<T>(x, y, 0);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsInRange<T>(int x, int y, int range) where T : Item =>
|
||||
GetItemsInBounds<T>(new Rectangle2D(x - range, y - range, range * 2 + 1, range * 2 + 1));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<Item> GetItemsInBounds(Rectangle2D bounds) => GetItemsInBounds<Item>(bounds);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ItemEnumerable<T> GetItemsInBounds<T>(Rectangle2D bounds, bool makeBoundsInclusive = false) where T : Item =>
|
||||
new(this, bounds, makeBoundsInclusive);
|
||||
|
||||
|
|
|
|||
|
|
@ -535,6 +535,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
|
|||
return new Point2D(x, y);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void CalculateSectors(
|
||||
Rectangle2D bounds,
|
||||
out int sectorStartX, out int sectorStartY,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ModernUO.Serialization;
|
||||
using Server.Targeting;
|
||||
|
||||
|
|
@ -226,12 +227,13 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
|
||||
private static void EventSink_OpenDoorMacroUsed(Mobile m)
|
||||
{
|
||||
if (m.Map == null)
|
||||
if (m.Map == null || !m.CheckAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int x = m.X, y = m.Y;
|
||||
int x = m.X;
|
||||
int y = m.Y;
|
||||
|
||||
switch (m.Direction & Direction.Mask)
|
||||
{
|
||||
|
|
@ -281,18 +283,13 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
}
|
||||
}
|
||||
|
||||
var sector = m.Map.GetSector(x, y);
|
||||
|
||||
foreach (var item in sector.Items)
|
||||
foreach (var item in m.Map.GetItemsAt(x, y))
|
||||
{
|
||||
if (item.Location.X == x && item.Location.Y == y && item.Z + item.ItemData.Height > m.Z &&
|
||||
if (item.Z + item.ItemData.Height > m.Z &&
|
||||
m.Z + 16 > item.Z && item is BaseDoor && m.CanSee(item) && m.InLOS(item))
|
||||
{
|
||||
if (m.CheckAlive())
|
||||
{
|
||||
m.SendLocalizedMessage(500024); // Opening door...
|
||||
item.OnDoubleClick(m);
|
||||
}
|
||||
m.SendLocalizedMessage(500024); // Opening door...
|
||||
item.OnDoubleClick(m);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -320,7 +317,7 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
return CheckFit(map, p, 16);
|
||||
}
|
||||
|
||||
private bool CheckFit(Map map, Point3D p, int height)
|
||||
private static bool CheckFit(Map map, Point3D p, int height)
|
||||
{
|
||||
if (map == Map.Internal)
|
||||
{
|
||||
|
|
@ -331,13 +328,9 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
var y = p.Y;
|
||||
var z = p.Z;
|
||||
|
||||
var sector = map.GetSector(x, y);
|
||||
var mobs = sector.Mobiles;
|
||||
|
||||
foreach (var item in sector.Items)
|
||||
foreach (var item in map.GetItemsAt(x, y))
|
||||
{
|
||||
if (item is not BaseMulti && item.ItemID <= TileData.MaxItemValue && item.AtWorldPoint(x, y) &&
|
||||
item is not BaseDoor)
|
||||
if (item.ItemID <= TileData.MaxItemValue && item is not (BaseMulti or BaseDoor))
|
||||
{
|
||||
var id = item.ItemData;
|
||||
var surface = id.Surface;
|
||||
|
|
@ -350,6 +343,8 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
}
|
||||
}
|
||||
|
||||
var mobs = map.GetSector(x, y).Mobiles;
|
||||
|
||||
for (var i = 0; i < mobs.Count; ++i)
|
||||
{
|
||||
var m = mobs[i];
|
||||
|
|
@ -376,19 +371,7 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
return true;
|
||||
}
|
||||
|
||||
public List<BaseDoor> GetChain()
|
||||
{
|
||||
var list = new List<BaseDoor>();
|
||||
var c = this;
|
||||
|
||||
do
|
||||
{
|
||||
list.Add(c);
|
||||
c = c.Link;
|
||||
} while (c?.Deleted == false && !list.Contains(c));
|
||||
|
||||
return list;
|
||||
}
|
||||
public ChainEnumerable GetChain() => new(this);
|
||||
|
||||
public bool IsFreeToClose()
|
||||
{
|
||||
|
|
@ -397,16 +380,15 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
return CanClose();
|
||||
}
|
||||
|
||||
var list = GetChain();
|
||||
|
||||
var freeToClose = true;
|
||||
|
||||
for (var i = 0; freeToClose && i < list.Count; ++i)
|
||||
foreach (var link in GetChain())
|
||||
{
|
||||
freeToClose = list[i].CanClose();
|
||||
if (!link.CanClose())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return freeToClose;
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool IsInside(Mobile from) => false;
|
||||
|
|
@ -419,28 +401,18 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster)
|
||||
{
|
||||
from.LocalOverheadMessage(
|
||||
MessageType.Regular,
|
||||
0x3B2,
|
||||
502502
|
||||
); // That is locked, but you open it with your godly powers.
|
||||
// from.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, 502502, "", "" ) ); // That is locked, but you open it with your godly powers.
|
||||
// That is locked, but you open it with your godly powers.
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502502);
|
||||
}
|
||||
else if (Key.ContainsKey(from.Backpack, KeyValue))
|
||||
{
|
||||
from.LocalOverheadMessage(
|
||||
MessageType.Regular,
|
||||
0x3B2,
|
||||
501282
|
||||
); // You quickly unlock, open, and relock the door
|
||||
// You quickly unlock, open, and relock the door
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501282);
|
||||
}
|
||||
else if (IsInside(from))
|
||||
{
|
||||
from.LocalOverheadMessage(
|
||||
MessageType.Regular,
|
||||
0x3B2,
|
||||
501280
|
||||
); // That is locked, but is usable from the inside.
|
||||
// That is locked, but is usable from the inside.
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501280);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -475,11 +447,9 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
{
|
||||
var open = !_open;
|
||||
|
||||
var list = GetChain();
|
||||
|
||||
for (var i = 0; i < list.Count; ++i)
|
||||
foreach (var link in GetChain())
|
||||
{
|
||||
list[i].Open = open;
|
||||
link.Open = open;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -540,4 +510,58 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct ChainEnumerable
|
||||
{
|
||||
private readonly BaseDoor _door;
|
||||
|
||||
public ChainEnumerable(BaseDoor door) => _door = door;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ChainEnumerator GetEnumerator() => new(_door);
|
||||
}
|
||||
|
||||
public ref struct ChainEnumerator
|
||||
{
|
||||
private BaseDoor _door;
|
||||
private BaseDoor _current;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal ChainEnumerator(BaseDoor door)
|
||||
{
|
||||
_door = door;
|
||||
_current = null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
bool valid;
|
||||
|
||||
if (_current == null)
|
||||
{
|
||||
_current = _door;
|
||||
valid = _current != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_current = _current.Link;
|
||||
valid = _current?.Deleted == false && _current != _door;
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
_door = null;
|
||||
_current = null;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
public BaseDoor Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Collections;
|
||||
using Server.Regions;
|
||||
using Server.Spells;
|
||||
|
||||
|
|
@ -80,7 +81,7 @@ namespace Server.Multis
|
|||
var start = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Min.Y, center.Z);
|
||||
|
||||
// These are storage lists. They hold items and mobiles found in the map for further processing
|
||||
var items = new List<Item>();
|
||||
using var items = PooledRefList<Item>.Create();
|
||||
var mobiles = new List<Mobile>();
|
||||
|
||||
// These are also storage lists. They hold location values indicating the yard and border locations.
|
||||
|
|
@ -138,11 +139,9 @@ namespace Server.Multis
|
|||
|
||||
var oldTiles = map.Tiles.GetStaticTiles(tileX, tileY, true);
|
||||
|
||||
var sector = map.GetSector(tileX, tileY);
|
||||
|
||||
items.Clear();
|
||||
|
||||
foreach (var item in sector.Items)
|
||||
foreach (var item in map.GetItemsAt(tileX, tileY))
|
||||
{
|
||||
if (item.Visible && item.X == tileX && item.Y == tileY)
|
||||
{
|
||||
|
|
@ -152,6 +151,8 @@ namespace Server.Multis
|
|||
|
||||
mobiles.Clear();
|
||||
|
||||
var sector = map.GetSector(tileX, tileY);
|
||||
|
||||
for (var i = 0; i < sector.Mobiles.Count; ++i)
|
||||
{
|
||||
var m = sector.Mobiles[i];
|
||||
|
|
@ -220,9 +221,8 @@ namespace Server.Multis
|
|||
hasSurface = true;*/
|
||||
}
|
||||
|
||||
for (var j = 0; j < items.Count; ++j)
|
||||
foreach (var item in items)
|
||||
{
|
||||
var item = items[j];
|
||||
var id = item.ItemData;
|
||||
|
||||
if (addTileTop > item.Z && item.Z + id.CalcHeight > addTileZ)
|
||||
|
|
@ -236,11 +236,6 @@ namespace Server.Multis
|
|||
return HousePlacementResult.BadItem; // Broke rule #2
|
||||
}
|
||||
}
|
||||
|
||||
/*else if (isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (item.Z + id.CalcHeight) == center.Z)
|
||||
{
|
||||
hasSurface = true;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (isFoundation && !hasSurface)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue