fix: Fixes door monster LOS exploit & AOS House Gump NPE (#2091)

This commit is contained in:
mark1145 2025-01-27 18:04:01 +11:00 committed by GitHub
parent f241a9dec0
commit c0eb6c81fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 66 additions and 64 deletions

View file

@ -961,31 +961,28 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
return _invalidSector; return _invalidSector;
} }
public bool LineOfSight(Point3D org, Point3D dest) public bool LineOfSight(Point3D origin, Point3D destination)
{ {
if (this == Internal) if (this == Internal)
{ {
return false; return false;
} }
if (!Utility.InRange(org, dest, MaxLOSDistance)) if (!Utility.InRange(origin, destination, MaxLOSDistance))
{ {
return false; return false;
} }
var end = dest; if (origin.X > destination.X || origin.X == destination.X && origin.Y > destination.Y || origin.X == destination.X && origin.Y == destination.Y && origin.Z > destination.Z)
if (org.X > dest.X || org.X == dest.X && org.Y > dest.Y || org.X == dest.X && org.Y == dest.Y && org.Z > dest.Z)
{ {
(org, dest) = (dest, org); (origin, destination) = (destination, origin);
} }
int height;
Point3D p; Point3D p;
var path = new Point3DList(); var path = new Point3DList();
TileFlag flags; TileFlag flags;
if (org == dest) if (origin == destination)
{ {
return true; return true;
} }
@ -995,9 +992,9 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
path.Clear(); path.Clear();
} }
var xd = dest.m_X - org.m_X; var xd = destination.X - origin.X;
var yd = dest.m_Y - org.m_Y; var yd = destination.Y - origin.Y;
var zd = dest.m_Z - org.m_Z; var zd = destination.Z - origin.Z;
var zslp = Math.Sqrt(xd * xd + yd * yd); var zslp = Math.Sqrt(xd * xd + yd * yd);
var sq3d = zd != 0 ? Math.Sqrt(zslp * zslp + zd * zd) : zslp; var sq3d = zd != 0 ? Math.Sqrt(zslp * zslp + zd * zd) : zslp;
@ -1005,11 +1002,11 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
var run = xd / sq3d; var run = xd / sq3d;
zslp = zd / sq3d; zslp = zd / sq3d;
double y = org.m_Y; double y = origin.Y;
double z = org.m_Z; double z = origin.Z;
double x = org.m_X; double x = origin.X;
while (Utility.NumberBetween(x, dest.m_X, org.m_X, 0.5) && Utility.NumberBetween(y, dest.m_Y, org.m_Y, 0.5) && while (Utility.NumberBetween(x, destination.X, origin.X, 0.5) && Utility.NumberBetween(y, destination.Y, origin.Y, 0.5) &&
Utility.NumberBetween(z, dest.m_Z, org.m_Z, 0.5)) Utility.NumberBetween(z, destination.Z, origin.Z, 0.5))
{ {
var ix = (int)Math.Round(x); var ix = (int)Math.Round(x);
var iy = (int)Math.Round(y); var iy = (int)Math.Round(y);
@ -1018,7 +1015,7 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
{ {
p = path.Last; p = path.Last;
if (p.m_X != ix || p.m_Y != iy || p.m_Z != iz) if (p.X != ix || p.Y != iy || p.Z != iz)
{ {
path.Add(ix, iy, iz); path.Add(ix, iy, iz);
} }
@ -1040,27 +1037,27 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
p = path.Last; p = path.Last;
if (p != dest) if (p != destination)
{ {
path.Add(dest); path.Add(destination);
} }
Point3D pTop = org, pBottom = dest; Point3D pTop = origin, pBottom = destination;
Utility.FixPoints(ref pTop, ref pBottom); Utility.FixPoints(ref pTop, ref pBottom);
var pathCount = path.Count; var pathCount = path.Count;
var endTop = end.m_Z + 1; var endTop = destination.Z + 1;
for (var i = 0; i < pathCount; ++i) for (var i = 0; i < pathCount; ++i)
{ {
var point = path[i]; var point = path[i];
var pointTop = point.m_Z + 1; var pointTop = point.Z + 1;
var landTile = Tiles.GetLandTile(point.X, point.Y); var landTile = Tiles.GetLandTile(point.X, point.Y);
GetAverageZ(point.m_X, point.m_Y, out var landZ, out _, out var landTop); GetAverageZ(point.X, point.Y, out var landZ, out _, out var landTop);
if (landZ <= pointTop && landTop >= point.m_Z && if (landZ <= pointTop && landTop >= point.m_Z &&
(point.m_X != end.m_X || point.m_Y != end.m_Y || landZ > endTop || landTop < end.m_Z) && (point.X != destination.X || point.Y != destination.Y || landZ > endTop || landTop < destination.Z) &&
!landTile.Ignored) !landTile.Ignored)
{ {
return false; return false;
@ -1082,22 +1079,22 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
bool foundStatic = false; bool foundStatic = false;
foreach (var t in Tiles.GetStaticAndMultiTiles(point.m_X, point.m_Y)) foreach (var t in Tiles.GetStaticAndMultiTiles(point.X, point.Y))
{ {
foundStatic = true; foundStatic = true;
var id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; var id = TileData.ItemTable[t.ID & TileData.MaxItemValue];
flags = id.Flags; flags = id.Flags;
height = id.CalcHeight;
if (t.Z <= pointTop && t.Z + height >= point.Z && (flags & (TileFlag.Window | TileFlag.NoShoot)) != 0) if (
t.Z <= pointTop && t.Z + id.CalcHeight >= point.Z &&
(flags & (TileFlag.Window | TileFlag.NoShoot)) != 0 &&
(point.X != destination.X ||
point.Y != destination.Y ||
t.Z > endTop || t.Z + id.CalcHeight < destination.Z)
)
{ {
if (point.m_X == end.m_X && point.m_Y == end.m_Y && t.Z <= endTop && t.Z + height >= end.m_Z)
{
continue;
}
return false; return false;
} }
} }
@ -1120,21 +1117,21 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
} }
} }
var rect = new Rectangle2D(pTop.m_X, pTop.m_Y, pBottom.m_X - pTop.m_X + 1, pBottom.m_Y - pTop.m_Y + 1); var rect = new Rectangle2D(pTop.X, pTop.Y, pBottom.X - pTop.X + 1, pBottom.Y - pTop.Y + 1);
foreach (var i in GetItemsInBounds(rect)) foreach (var item in GetItemsInBounds(rect))
{ {
if (!i.Visible) if (!item.Visible)
{ {
continue; continue;
} }
if (i is BaseMulti || i.ItemID > TileData.MaxItemValue) if (item is BaseMulti || item.ItemID > TileData.MaxItemValue)
{ {
continue; continue;
} }
var id = i.ItemData; var id = item.ItemData;
flags = id.Flags; flags = id.Flags;
if ((flags & (TileFlag.Window | TileFlag.NoShoot)) == 0) if ((flags & (TileFlag.Window | TileFlag.NoShoot)) == 0)
@ -1142,35 +1139,40 @@ public sealed partial class Map : IComparable<Map>, ISpanFormattable, ISpanParsa
continue; continue;
} }
height = id.CalcHeight; for (var i = 0; i < path.Count; ++i)
var found = false;
var count = path.Count;
for (var j = 0; j < count; ++j)
{ {
var point = path[j]; var pathPoint = path[i];
var pointTop = point.m_Z + 1; var pointTop = pathPoint.Z + 1;
var loc = i.Location; var itemLocation = item.Location;
// if (t.Z <= point.Z && t.Z+height >= point.Z && ( height != 0 || ( t.Z == dest.Z && zd != 0 ) )) if (
if (loc.m_X == point.m_X && loc.m_Y == point.m_Y && loc.m_Z <= pointTop && loc.m_Z + height >= point.m_Z) // Item is on same tile as this point along the LOS path
itemLocation.X == pathPoint.X &&
itemLocation.Y == pathPoint.Y &&
itemLocation.Z <= pointTop &&
// Item rests on the same level as the path
itemLocation.Z + id.CalcHeight >= pathPoint.Z &&
// Fix door bugging monsters when door is at the START or END of the LOS path by allowing LOS
!(flags.HasFlag(TileFlag.Door) &&
itemLocation.X == origin.X && itemLocation.Y == origin.Y ||
itemLocation.X == destination.X && itemLocation.Y == destination.Y) &&
// Item is at some point along the path BEFORE the target
(itemLocation.X != destination.X ||
itemLocation.Y != destination.Y ||
// Item is diagonally looking DOWN at the target
itemLocation.Z > endTop ||
// Item is diagonally looking UP at the target
itemLocation.Z + id.CalcHeight < destination.Z)
)
{ {
if (loc.m_X != end.m_X || loc.m_Y != end.m_Y || loc.m_Z > endTop || loc.m_Z + height < end.m_Z) return false;
{
found = true;
break;
}
} }
} }
if (!found)
{
continue;
}
return false;
} }
return true; return true;

View file

@ -111,10 +111,10 @@ namespace Server.Gumps
AddImage(10, 10, 100); AddImage(10, 10, 100);
if (m_House.Sign != null) var lines = m_House.Sign?.GetName().Wrap(10, 6);
{
var lines = m_House.Sign.GetName().Wrap(10, 6);
if (lines != null)
{
for (int i = 0, y = (114 - lines.Count * 14) / 2; i < lines.Count; ++i, y += 14) for (int i = 0, y = (114 - lines.Count * 14) / 2; i < lines.Count; ++i, y += 14)
{ {
var s = lines[i]; var s = lines[i];