/// <summary>
        /// Determine if a living can move from srcLoc to dir, without considering the destination
        /// </summary>
        public static bool CanMoveFrom(this IEnvironmentObject env, IntVector3 srcLoc, Direction dir)
        {
            Debug.Assert(dir.IsValid());

            if (env.Contains(srcLoc) == false)
            {
                return(false);
            }

            var td = env.GetTileData(srcLoc);

            if (td.IsUndefined)
            {
                return(false);
            }

            // Perhaps this check is not needed
            if (td.IsWalkable == false)
            {
                return(false);
            }

            if (dir.IsPlanar())
            {
                return(true);
            }

            if (dir == Direction.Up)
            {
                return(td.ID == TileID.Stairs);
            }

            if (dir == Direction.Down)
            {
                return(true);
            }

            if (dir.ContainsDown())
            {
                return(true);
            }

            if (dir.ContainsUp() && env.Size.Depth > srcLoc.Z + 1)
            {
                if (env.GetTileData(srcLoc.Up).IsEmpty == false)
                {
                    return(false);
                }

                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Can the given tile be seen from any adjacent tile
        /// </summary>
        public static bool CanBeSeen(this IEnvironmentObject env, IntVector3 location)
        {
            foreach (var d in DirectionExtensions.PlanarUpDownDirections)
            {
                var p = location + d;
                if (env.Contains(p) && env.GetTileData(p).IsSeeThrough)
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Can the given tile be seen from any direction
        /// </summary>
        public static bool CanBeSeen(IEnvironmentObject env, IntPoint3 location)
        {
            bool hidden = true;

            foreach (var d in DirectionExtensions.PlanarDirections)
            {
                var p = location + d;

                if (env.Contains(p) && env.GetTileData(p).IsSeeThrough)
                {
                    hidden = false;
                    break;
                }
            }

            if (hidden)
            {
                var p = location + Direction.Up;
                if (env.Contains(p) && env.GetTileData(p).IsSeeThroughDown)
                    hidden = false;
            }

            return !hidden;
        }
        /// <summary>
        /// Tile can be entered and stood upon
        /// </summary>
        public static bool CanEnter(this IEnvironmentObject env, IntVector3 location)
        {
            if (!env.Contains(location))
            {
                return(false);
            }

            var td = env.GetTileData(location);

            if (td.IsUndefined)
            {
                return(false);
            }

            return(td.IsWalkable);
        }
        /// <summary>
        /// Tile can be entered and stood upon
        /// </summary>
        public static bool CanEnter(IEnvironmentObject env, IntPoint3 location)
        {
            if (!env.Contains(location))
                return false;

            var td = env.GetTileData(location);

            if (td.IsUndefined)
                return false;

            var terrain = Terrains.GetTerrain(td.TerrainID);
            var interior = Interiors.GetInterior(td.InteriorID);
            var itemBlocks = (td.Flags & TileFlags.ItemBlocks) != 0;

            return terrain.IsSupporting && !terrain.IsBlocker && !interior.IsBlocker && !itemBlocks;
        }
            public IEnumerable <Direction> GetValidDirs(IntVector3 p)
            {
                var td = m_env.GetTileData(p);

                if (!td.IsSeeThrough)
                {
                    yield break;
                }

                foreach (var d in DirectionExtensions.PlanarUpDownDirections)
                {
                    var pp = p + d;
                    if (m_env.Contains(pp) && !m_tracker.GetVisible(pp))
                    {
                        yield return(d);
                    }
                }
            }
        /// <summary>
        /// Determine if a living can move from srcLoc to dir, without considering the destination
        /// </summary>
        public static bool CanMoveFrom(IEnvironmentObject env, IntPoint3 srcLoc, Direction dir)
        {
            Debug.Assert(dir.IsValid());

            if (env.Contains(srcLoc) == false)
                return false;

            var td = env.GetTileData(srcLoc);

            if (td.IsUndefined)
                return false;

            var srcTerrain = Terrains.GetTerrain(td.TerrainID);
            var srcInter = Interiors.GetInterior(td.InteriorID);
            var itemBlocks = (td.Flags & TileFlags.ItemBlocks) != 0;

            if (srcInter.IsBlocker || srcTerrain.IsBlocker || itemBlocks)
                return false;

            if (dir.IsPlanar())
                return true;

            if (dir == Direction.Up)
                return srcInter.ID == InteriorID.Stairs;

            if (dir == Direction.Down)
                return srcTerrain.ID == TerrainID.StairsDown;

            if (dir.ContainsDown())
            {
                return true;
            }

            if (dir.ContainsUp())
            {
                if (!srcTerrain.ID.IsSlope())
                    return false;

                if (env.GetTerrainID(srcLoc + Direction.Up) != TerrainID.Empty)
                    return false;

                return true;
            }

            return false;
        }