示例#1
0
        public static LocRay4 GetWallDir(Loc loc, Grid.LocTest checkBlock, Grid.LocTest checkGround)
        {
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }
            if (checkGround == null)
            {
                throw new ArgumentNullException(nameof(checkGround));
            }

            // check the four directions
            Dir4 chosenDir = Dir4.None;

            // ensure that there is only one direction where it is unblocked
            foreach (Dir4 dir in DirExt.VALID_DIR4)
            {
                Loc newLoc = loc + dir.GetLoc();
                if (checkGround(newLoc))
                {
                    if (chosenDir != Dir4.None)
                    {
                        return(new LocRay4(loc));
                    }
                    else
                    {
                        chosenDir = dir.Reverse();
                    }
                }
                else if (!checkBlock(newLoc))
                {
                    // all four directions must be valid ground, or valid block
                    return(new LocRay4(loc));
                }
            }

            if (chosenDir == Dir4.None)
            {
                return(new LocRay4(loc));
            }

            // then check to make sure that the left and right diagonal of this direction are also valid blocked
            Loc lLoc = loc + DirExt.AddAngles(chosenDir.ToDir8(), Dir8.DownLeft).GetLoc();

            if (!checkBlock(lLoc))
            {
                return(new LocRay4(loc));
            }
            Loc rLoc = loc + DirExt.AddAngles(chosenDir.ToDir8(), Dir8.DownRight).GetLoc();

            if (!checkBlock(rLoc))
            {
                return(new LocRay4(loc));
            }

            return(new LocRay4(loc, chosenDir));
        }
示例#2
0
        private static void ScanFill(
            Rect rect,
            LocTest checkBlock,
            LocTest checkDiagBlock,
            LocAction fillOp,
            int min,
            int max,
            int range_min,
            int range_max,
            int y,
            bool isNext,
            DirV dir,
            Stack <ScanLineTile> stack)
        {
            if (checkBlock == null)
            {
                throw new ArgumentNullException(nameof(checkBlock));
            }
            if (fillOp == null)
            {
                throw new ArgumentNullException(nameof(fillOp));
            }

            // move y down or up
            int new_y = y + dir.GetLoc().Y;

            // for diagonal checking: check slightly further
            int sub = (range_min > rect.Start.X) ? 1 : 0;
            int add = (range_max < rect.Start.X + rect.Size.X - 1) ? 1 : 0;

            int line_start = -1;
            int x          = range_min - sub;

            for (; x <= range_max + add; x++)
            {
                bool unblocked = !checkBlock(new Loc(x, new_y));

                // check diagonal if applicable
                if (x < range_min)
                {
                    unblocked &= !IsDirBlocked(new Loc(range_min, y), DirExt.Combine(DirH.Left, dir), checkBlock, checkDiagBlock);
                }
                else if (x > range_max)
                {
                    unblocked &= !IsDirBlocked(new Loc(range_max, y), DirExt.Combine(DirH.Right, dir), checkBlock, checkDiagBlock);
                }

                // skip testing, if testing previous line within previous range
                bool empty = (isNext || (x <min || x> max)) && unblocked;

                if (line_start == -1 && empty)
                {
                    line_start = x;
                }
                else if (line_start > -1 && !empty)
                {
                    stack.Push(new ScanLineTile(new IntRange(line_start, x - 1), new_y, dir, line_start <= range_min, x > range_max));
                    line_start = -1;
                }

                if (line_start > -1)
                {
                    fillOp(new Loc(x, new_y));
                }

                if (!isNext && x == min)
                {
                    x = max;
                }
            }

            if (line_start > -1)
            {
                stack.Push(new ScanLineTile(new IntRange(line_start, x - 1), new_y, dir, line_start <= range_min, true));
            }
        }
示例#3
0
        protected static ListPathTraversalNode?GetRoomToConnect(FloorPlan floorPlan, RoomHallIndex chosenFrom, Dir4 dir)
        {
            // extend a rectangle to the border of the floor in the chosen direction
            bool     vertical   = dir.ToAxis() == Axis4.Vert;
            int      dirSign    = dir.GetLoc().GetScalar(dir.ToAxis());
            IRoomGen genFrom    = floorPlan.GetRoomHall(chosenFrom).RoomGen;
            Rect     sampleRect = genFrom.Draw;

            // expand from the start of that border direction to the borders of the floor
            sampleRect.Start += dir.GetLoc() * sampleRect.Size.GetScalar(dir.ToAxis());

            // it doesn't have to be exactly the borders so just add the total size to be sure
            sampleRect.Expand(dir, vertical ? floorPlan.Size.Y : floorPlan.Size.X);

            // find the closest room.
            var chosenTo = new RoomHallIndex(-1, false);

            foreach (RoomHallIndex collision in floorPlan.CheckCollision(sampleRect))
            {
                Rect collidedRect = floorPlan.GetRoomHall(collision).RoomGen.Draw;

                // limit the expansion by direction
                int  sampleScalar   = sampleRect.GetScalar(dir);
                int  collidedScalar = collidedRect.GetScalar(dir.Reverse());
                bool limit          = dirSign == Math.Sign(sampleScalar - collidedScalar);
                if (limit)
                {
                    // update the boundaries
                    sampleRect.SetScalar(dir, collidedScalar);
                    chosenTo = collision;
                }
            }

            // if it didn't collide with ANYTHING, then quit
            if (chosenTo.Index == -1)
            {
                return(null);
            }

            IRoomGen genTo = floorPlan.GetRoomHall(chosenTo).RoomGen;

            // narrow the rectangle if touching something on the side
            // widen the rectangle by width
            Rect widthRect = sampleRect;

            widthRect.Inflate(vertical ? 1 : 0, vertical ? 0 : 1);
            bool retractLeft  = false;
            bool retractRight = false;
            Dir4 leftDir      = DirExt.AddAngles(dir, Dir4.Left);
            Dir4 rightDir     = DirExt.AddAngles(dir, Dir4.Right);

            foreach (RoomHallIndex collision in floorPlan.CheckCollision(widthRect))
            {
                Rect collidedRect = floorPlan.GetRoomHall(collision).RoomGen.Draw;
                if (!retractLeft)
                {
                    if (collidedRect.GetScalar(leftDir.Reverse()) == sampleRect.GetScalar(leftDir))
                    {
                        retractLeft = true;
                    }
                }

                if (!retractRight)
                {
                    if (collidedRect.GetScalar(rightDir.Reverse()) == sampleRect.GetScalar(rightDir))
                    {
                        retractRight = true;
                    }
                }
            }

            // retract the rectangle
            if (retractLeft)
            {
                sampleRect.Expand(leftDir, -1);
            }
            if (retractRight)
            {
                sampleRect.Expand(rightDir, -1);
            }

            // if the rectangle has been retracted too much, we can't go on
            if (sampleRect.Area <= 0)
            {
                return(null);
            }

            // check for border availability between start and end
            bool foundFrom = HasBorderOpening(genFrom, sampleRect, dir);
            bool foundTo   = HasBorderOpening(genTo, sampleRect, dir.Reverse());

            // return the expansion if one is found
            if (foundFrom && foundTo)
            {
                return(new ListPathTraversalNode(chosenFrom, chosenTo, sampleRect));
            }
            else
            {
                return(null);
            }
        }