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