Exemple #1
0
            public List <IntVec3> Unobstructed(IntVec3 motivator, bool removed = false)
            {
                //1. What is the test is?
                bool     lazy      = motivator == IntVec3.Zero;
                cellTest motivated = (target, inside) => target == motivator ? removed : IsClear(target, inside);
                cellTest clear     = lazy ? IsClear : motivated;

                //2. Determine facing
                IntVec3 dummy;
                bool    overhangFwd = !ClearForward(position, horizontal, clear, false, 1, out dummy);  //sets facing Down/Left
                bool    overhangBwd = !ClearBackward(position, horizontal, clear, false, 1, out dummy); //sets facing Up/Right

                facingSet = SetFacing(overhangFwd, overhangBwd);
                if (!facingSet)
                {
                    return(new List <IntVec3>());           //escape if unable to determine sides
                }
                bool southward = facing == LinkDirections.Down || facing == LinkDirections.Left;

                //3. Determine clearence and max reach on each side
                Dictionary <IntVec3, int> cleared = new Dictionary <IntVec3, int>();
                int reachFwd = 0;
                int reachBwd = 0;

                //forward (walks North/East)
                for (int i = 1; i <= maxreach; i++)
                {
                    IntVec3 clearedFwd;
                    if (ClearForward(position, horizontal, clear, southward, i, out clearedFwd))
                    {
                        cleared.Add(clearedFwd, i);
                        reachFwd++;
                    }
                    else
                    {
                        break;
                    }
                }
                //backward (walks South/West)
                for (int i = 1; i <= maxreach; i++)
                {
                    IntVec3 clearedBwd;
                    if (ClearBackward(position, horizontal, clear, !southward, i, out clearedBwd))
                    {
                        cleared.Add(clearedBwd, i);
                        reachBwd++;
                    }
                    else
                    {
                        break;
                    }
                }

                //5. Apply clearance.
                int obstructed = southward ? reachBwd : reachFwd;

                cleared.RemoveAll(x => x.Key.IsInterior(position, facing) && x.Value > obstructed);
                return(cleared.Keys.ToList());
            }
        public static bool ClearBackward(IntVec3 position, bool horizontal, cellTest test, bool inside, int dist, out IntVec3 output)
        {
            int     cellx   = position.x;
            int     cellz   = position.z;
            int     targetX = horizontal ? Math.Max(0, cellx - dist) : cellx;
            int     targetZ = horizontal ? cellz : Math.Max(0, cellz - dist);
            IntVec3 target  = new IntVec3(targetX, 0, targetZ);
            bool    result  = test(target, inside);

            output = result ? target : IntVec3.Zero;
            return(result);
        }
        public static bool ClearForward(IntVec3 position, bool horizontal, cellTest test, bool inside, int dist, out IntVec3 output)
        {
            int     cellx  = position.x;
            int     cellz  = position.z;
            int     deltaX = horizontal ? dist : 0;
            int     deltaZ = horizontal ? 0 : dist;
            IntVec3 target = new IntVec3(cellx + deltaX, 0, cellz + deltaZ);
            bool    result = test(target, inside);

            output = result ? target : IntVec3.Zero;
            return(result);
        }
        public static List <IntVec3> UnobstructedGhost(IntVec3 position, Rot4 rot, Map map, int maxreach, bool horizontal, bool bleedRight, bool bleedLeft)
        {
            bool     southward = rot == Rot4.South || rot == Rot4.West;
            cellTest clear     = (c, b) => c.InBounds(map) && c.CanBeSeenOverFast(map) && !map.roofGrid.Roofed(c);

            //3. Determine clearance and max reach on each side
            Dictionary <IntVec3, int> cleared = new Dictionary <IntVec3, int>();
            int reachFwd = 0;
            int reachBwd = 0;

            //forward (walks North/East)
            for (int i = 1; i <= maxreach; i++)
            {
                IntVec3 clearedFwd;
                if (ClearForward(position, horizontal, clear, southward, i, out clearedFwd))
                {
                    cleared.Add(clearedFwd, i);
                    reachFwd++;
                }
                else
                {
                    break;
                }
            }
            //backward (walks South/West)
            for (int i = 1; i <= maxreach; i++)
            {
                IntVec3 clearedBwd;
                if (ClearBackward(position, horizontal, clear, !southward, i, out clearedBwd))
                {
                    cleared.Add(clearedBwd, i);
                    reachBwd++;
                }
                else
                {
                    break;
                }
            }

            //5. Apply clearance.
            int obstructed = Math.Min(reachBwd, reachFwd);

            cleared.RemoveAll(x => x.Value > obstructed);
            var            result = cleared.Keys.ToList();
            List <IntVec3> bleed  = new List <IntVec3>();

            //6. Apply Bleed
            if (bleedRight)
            {
                IntVec3 dir = rot.IsHorizontal ? IntVec3.North : IntVec3.East;
                foreach (var cell in result)
                {
                    var edge = cell + dir;
                    if (clear(edge, false))
                    {
                        bleed.Add(edge);
                    }
                }
            }
            if (bleedLeft)
            {
                IntVec3 dir = rot.IsHorizontal ? IntVec3.South : IntVec3.West;
                foreach (var cell in result)
                {
                    var edge = cell + dir;
                    if (clear(edge, false))
                    {
                        bleed.Add(edge);
                    }
                }
            }
            if (!bleed.NullOrEmpty())
            {
                result.AddRange(bleed);
            }
            return(result);
        }