public bool LineOfSight(Point3D org, Point3D dest)
{
if (this == Map.Internal)
{
return(false);
}
if (!org.InRange(dest, MaxLOSDistance))
{
return(false);
}
Point3D end = dest;
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))
{
Point3D swap = org;
org = dest;
dest = swap;
}
double rise, run, zslp;
double sq3d;
double x, y, z;
int xd, yd, zd;
int ix, iy, iz;
int height;
bool found;
Point3D p;
Point3DList path = m_PathList;
TileFlag flags;
if (org == dest)
{
return(true);
}
if (path.Count > 0)
{
path.Clear();
}
xd = dest.X - org.X;
yd = dest.Y - org.Y;
zd = dest.Z - org.Z;
zslp = Math.Sqrt(xd * xd + yd * yd);
if (zd != 0)
{
sq3d = Math.Sqrt(zslp * zslp + zd * zd);
}
else
{
sq3d = zslp;
}
rise = ((float)yd) / sq3d;
run = ((float)xd) / sq3d;
zslp = ((float)zd) / sq3d;
y = org.Y;
z = org.Z;
x = org.X;
while (Utility.NumberBetween(x, dest.X, org.X, 0.5) && Utility.NumberBetween(y, dest.Y, org.Y, 0.5) && Utility.NumberBetween(z, dest.Z, org.Z, 0.5))
{
ix = (int)Math.Round(x);
iy = (int)Math.Round(y);
iz = (int)Math.Round(z);
if (path.Count > 0)
{
p = path.Last;
if (p.X != ix || p.Y != iy || p.Z != iz)
{
path.Add(ix, iy, iz);
}
}
else
{
path.Add(ix, iy, iz);
}
x += run;
y += rise;
z += zslp;
}
if (path.Count == 0)
{
return(true); // should never happen, but to be safe.
}
p = path.Last;
if (p != dest)
{
path.Add(dest);
}
Point3D pTop = org, pBottom = dest;
Utility.FixPoints(ref pTop, ref pBottom);
int pathCount = path.Count;
for (int i = 0; i < pathCount; ++i)
{
Point3D point = path[i];
Tile landTile = Tiles.GetLandTile(point.X, point.Y);
int landZ = 0, landAvg = 0, landTop = 0;
GetAverageZ(point.X, point.Y, ref landZ, ref landAvg, ref landTop);
if (landZ <= point.Z && landTop >= point.Z && (point.X != end.X || point.Y != end.Y || landZ > end.Z || landTop < end.Z) && !landTile.Ignored)
{
return(false);
}
Tile[] statics = Tiles.GetStaticTiles(point.X, point.Y, true);
bool contains = false;
int ltID = landTile.ID;
for (int j = 0; !contains && j < InvalidLandTiles.Length; ++j)
{
contains = (ltID == InvalidLandTiles[j]);
}
if (contains && statics.Length == 0)
{
foreach (Item item in GetItemsInRange(point, 0))
{
if (item.Visible)
{
contains = false;
}
if (!contains)
{
break;
}
}
if (contains)
{
return(false);
}
}
for (int j = 0; j < statics.Length; ++j)
{
Tile t = statics[j];
ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue];
flags = id.Flags;
height = id.CalcHeight;
if (t.Z <= point.Z && t.Z + height >= point.Z && (flags & (TileFlag.Window | TileFlag.NoShoot)) != 0)
{
if (point.X == end.X && point.Y == end.Y && t.Z <= end.Z && t.Z + height >= end.Z)
{
continue;
}
return(false);
}
}
}
Rectangle2D rect = new Rectangle2D(pTop.X, pTop.Y, (pBottom.X - pTop.X) + 1, (pBottom.Y - pTop.Y) + 1);
foreach (Item i in GetItemsInBounds(rect))
{
if (!i.Visible)
{
continue;
}
if (i is BaseMulti || i.ItemID > TileData.MaxItemValue)
{
continue;
}
ItemData id = i.ItemData;
flags = id.Flags;
if ((flags & (TileFlag.Window | TileFlag.NoShoot)) == 0)
{
continue;
}
height = id.CalcHeight;
found = false;
int count = path.Count;
for (int j = 0; j < count; ++j)
{
Point3D point = path[j];
Point3D loc = i.Location;
if (loc.X == point.X && loc.Y == point.Y &&
loc.Z <= point.Z && loc.Z + height >= point.Z)
{
if (loc.X == end.X && loc.Y == end.Y && loc.Z <= end.Z && loc.Z + height >= end.Z)
{
continue;
}
found = true;
break;
}
}
if (!found)
{
continue;
}
return(false);
}
return(true);
}