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