public bool LineOfSight( Point3D org, Point3D dest ) { if( this == Map.Internal ) return false; if( !Utility.InRange( org, dest, m_MaxLOSDistance ) ) return false; Point3D start = org; 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.m_X - org.m_X; yd = dest.m_Y - org.m_Y; zd = dest.m_Z - org.m_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.m_Y; z = org.m_Z; x = org.m_X; while( Utility.NumberBetween( x, dest.m_X, org.m_X, 0.5 ) && Utility.NumberBetween( y, dest.m_Y, org.m_Y, 0.5 ) && Utility.NumberBetween( z, dest.m_Z, org.m_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.m_X != ix || p.m_Y != iy || p.m_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]; LandTile landTile = Tiles.GetLandTile( point.X, point.Y ); int landZ = 0, landAvg = 0, landTop = 0; GetAverageZ( point.m_X, point.m_Y, ref landZ, ref landAvg, ref landTop ); if( landZ <= point.m_Z && landTop >= point.m_Z && (point.m_X != end.m_X || point.m_Y != end.m_Y || landZ > end.m_Z || landTop < end.m_Z) && !landTile.Ignored ) return false; /* --Do land tiles need to be checked? There is never land between two people, always statics.-- LandTile landTile = Tiles.GetLandTile( point.X, point.Y ); if ( landTile.Z-1 >= point.Z && landTile.Z+1 <= point.Z && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) != 0 ) return false; */ StaticTile[] statics = Tiles.GetStaticTiles( point.m_X, point.m_Y, true ); bool contains = false; int ltID = landTile.ID; for( int j = 0; !contains && j < m_InvalidLandTiles.Length; ++j ) contains = (ltID == m_InvalidLandTiles[j]); if( contains && statics.Length == 0 ) { IPooledEnumerable eable = GetItemsInRange( point, 0 ); foreach( Item item in eable ) { if( item.Visible ) contains = false; if( !contains ) break; } eable.Free(); if( contains ) return false; } for( int j = 0; j < statics.Length; ++j ) { StaticTile 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.m_X == end.m_X && point.m_Y == end.m_Y && t.Z <= end.m_Z && t.Z + height >= end.m_Z ) continue; return false; } /*if ( t.Z <= point.Z && t.Z+height >= point.Z && (flags&TileFlag.Window)==0 && (flags&TileFlag.NoShoot)!=0 && ( (flags&TileFlag.Wall)!=0 || (flags&TileFlag.Roof)!=0 || (((flags&TileFlag.Surface)!=0 && zd != 0)) ) )*/ /*{ //Console.WriteLine( "LoS: Blocked by Static \"{0}\" Z:{1} T:{3} P:{2} F:x{4:X}", TileData.ItemTable[t.ID&TileData.MaxItemValue].Name, t.Z, point, t.Z+height, flags ); //Console.WriteLine( "if ( {0} && {1} && {2} && ( {3} || {4} || {5} || ({6} && {7} && {8}) ) )", t.Z <= point.Z, t.Z+height >= point.Z, (flags&TileFlag.Window)==0, (flags&TileFlag.Impassable)!=0, (flags&TileFlag.Wall)!=0, (flags&TileFlag.Roof)!=0, (flags&TileFlag.Surface)!=0, t.Z != dest.Z, zd != 0 ) ; return false; }*/ } } Rectangle2D rect = new Rectangle2D( pTop.m_X, pTop.m_Y, (pBottom.m_X - pTop.m_X) + 1, (pBottom.m_Y - pTop.m_Y) + 1 ); IPooledEnumerable area = GetItemsInBounds( rect ); foreach( Item i in area ) { 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 ( t.Z <= point.Z && t.Z+height >= point.Z && ( height != 0 || ( t.Z == dest.Z && zd != 0 ) ) ) if( loc.m_X == point.m_X && loc.m_Y == point.m_Y && loc.m_Z <= point.m_Z && loc.m_Z + height >= point.m_Z ) { if( loc.m_X == end.m_X && loc.m_Y == end.m_Y && loc.m_Z <= end.m_Z && loc.m_Z + height >= end.m_Z ) continue; found = true; break; } } if( !found ) continue; area.Free(); return false; /*if ( (flags & (TileFlag.Impassable | TileFlag.Surface | TileFlag.Roof)) != 0 ) //flags = TileData.ItemTable[i.ItemID&TileData.MaxItemValue].Flags; //if ( (flags&TileFlag.Window)==0 && (flags&TileFlag.NoShoot)!=0 && ( (flags&TileFlag.Wall)!=0 || (flags&TileFlag.Roof)!=0 || (((flags&TileFlag.Surface)!=0 && zd != 0)) ) ) { //height = TileData.ItemTable[i.ItemID&TileData.MaxItemValue].Height; //Console.WriteLine( "LoS: Blocked by ITEM \"{0}\" P:{1} T:{2} F:x{3:X}", TileData.ItemTable[i.ItemID&TileData.MaxItemValue].Name, i.Location, i.Location.Z+height, flags ); area.Free(); return false; }*/ } area.Free(); return true; }
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); }