コード例 #1
0
        /// <summary>
        /// Draws a bundle of halls from one direction, going up to the specified point, and connects them.
        /// </summary>
        /// <param name="map"></param>
        /// <param name="dir"></param>
        /// <param name="forwardEnd"></param>
        /// <param name="starts"></param>
        public void DrawCombinedHall(ITiledGenContext map, Dir4 dir, int forwardEnd, int[] starts)
        {
            bool vertical = dir.ToAxis() == Axis4.Vert;

            // Choose whether to start at the min X/Y, or the max X/Y
            Loc forwardStartLoc = (dir == Dir4.Up || dir == Dir4.Left) ? this.Draw.Start : this.Draw.End - new Loc(1);

            IntRange start = this.Draw.GetSide(dir.ToAxis());

            start.Max -= 1;
            start      = new IntRange(start.Max, start.Min);

            // draw the halls
            for (int jj = 0; jj < starts.Length; jj++)
            {
                start.Min = Math.Min(start.Min, starts[jj]);
                start.Max = Math.Max(start.Max, starts[jj]);

                Loc startLoc = new Loc(vertical ? starts[jj] : forwardStartLoc.X, vertical ? forwardStartLoc.Y : starts[jj]);
                Loc endLoc   = new Loc(vertical ? starts[jj] : forwardEnd, vertical ? forwardEnd : starts[jj]);
                this.DrawHall(map, startLoc, endLoc, vertical);
            }

            // combine the halls
            Loc combineStart = new Loc(vertical ? start.Min : forwardEnd, vertical ? forwardEnd : start.Min);
            Loc combineEnd   = new Loc(vertical ? start.Max : forwardEnd, vertical ? forwardEnd : start.Max);

            this.DrawHall(map, combineStart, combineEnd, !vertical);
        }
コード例 #2
0
        public static Rect GetSupportRect(FloorPlan floorPlan, IRoomGen oldGen, IRoomGen newGen, Dir4 dir, List <RoomHallIndex> adjacentsInDir)
        {
            bool vertical    = dir.ToAxis() == Axis4.Vert;
            Rect supportRect = newGen.Draw;

            supportRect.Start += dir.GetLoc() * supportRect.Size.GetScalar(dir.ToAxis());
            supportRect.SetScalar(dir, oldGen.Draw.GetScalar(dir));

            IntRange minMax = newGen.Draw.GetSide(dir.ToAxis());

            foreach (RoomHallIndex adj in adjacentsInDir)
            {
                IRoomGen adjGen    = floorPlan.GetRoomHall(adj).RoomGen;
                IntRange adjMinMax = adjGen.Draw.GetSide(dir.ToAxis());
                minMax = new IntRange(Math.Min(adjMinMax.Min, minMax.Min), Math.Max(adjMinMax.Max, minMax.Max));
            }

            IntRange oldMinMax = oldGen.Draw.GetSide(dir.ToAxis());

            minMax = new IntRange(Math.Max(oldMinMax.Min, minMax.Min), Math.Min(oldMinMax.Max, minMax.Max));

            if (vertical)
            {
                supportRect.SetScalar(Dir4.Left, minMax.Min);
                supportRect.SetScalar(Dir4.Right, minMax.Max);
            }
            else
            {
                supportRect.SetScalar(Dir4.Up, minMax.Min);
                supportRect.SetScalar(Dir4.Down, minMax.Max);
            }

            return(supportRect);
        }
コード例 #3
0
ファイル: GridPlan.cs プロジェクト: ejbelt/RogueElements
        /// <summary>
        ///
        /// </summary>
        /// <param name="room"></param>
        /// <param name="dir">Direction from room to hall.</param>
        /// <param name="tier"></param>
        /// <returns></returns>
        public virtual IntRange GetHallTouchRange(IRoomGen room, Dir4 dir, int tier)
        {
            bool vertical = dir.ToAxis() == Axis4.Vert;

            // The hall will touch the entire side of each room under normal circumstances.
            // Things get tricky for a target room that occupies more than one cell.
            // First, try to cover only the part of the target room that's in the cell.
            // If that's not possible, try to extend the hall until it covers one tile of the target room.
            IntRange startRange = room.Draw.GetSide(dir.ToAxis());

            // factor possibletiles into this calculation
            int borderLength = room.GetBorderLength(dir);

            for (int ii = 0; ii < borderLength; ii++)
            {
                if (room.GetFulfillableBorder(dir, ii))
                {
                    startRange.Min += ii;
                    break;
                }
            }

            for (int ii = 0; ii < borderLength; ii++)
            {
                if (room.GetFulfillableBorder(dir, borderLength - 1 - ii))
                {
                    startRange.Max -= ii;
                    break;
                }
            }

            int      tierStart  = vertical ? tier * (this.WidthPerCell + this.CellWall) : tier * (this.HeightPerCell + this.CellWall);
            int      tierLength = vertical ? this.WidthPerCell : this.HeightPerCell;
            IntRange newRange   = new IntRange(Math.Max(startRange.Min, tierStart), Math.Min(startRange.Max, tierStart + tierLength));

            if (newRange.Max <= newRange.Min)
            {
                // try to extend the hall until it covers one tile of the target room.
                // first, note that the current end range is covering the zone between the tier and the edge of the room (inverted)
                // un-invert this and inflate by 1, and you will have a zone that covers 1 tile with the room
                // get the intersection of this zone and the room.
                newRange = new IntRange(Math.Max(startRange.Min, newRange.Max - 1), Math.Min(startRange.Max, newRange.Min + 1));
            }

            return(newRange);
        }
コード例 #4
0
        protected static bool HasBorderOpening(IRoomGen roomFrom, Rect rectTo, Dir4 expandTo)
        {
            Loc diff   = roomFrom.Draw.Start - rectTo.Start; // how far ahead the start of source is to dest
            int offset = diff.GetScalar(expandTo.ToAxis().Orth());

            // Traverse the region that both borders touch
            int sourceLength = roomFrom.GetBorderLength(expandTo);
            int destLength   = rectTo.Size.GetScalar(expandTo.ToAxis().Orth());

            for (int ii = Math.Max(0, offset); ii - offset < sourceLength && ii < destLength; ii++)
            {
                bool sourceFulfill = roomFrom.GetFulfillableBorder(expandTo, ii - offset);
                if (sourceFulfill)
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #5
0
        public static int GetBorderMatch(IRoomGen roomFrom, IRoomGen room, Loc candLoc, Dir4 expandTo)
        {
            int totalMatch = 0;

            Loc diff   = roomFrom.Draw.Start - candLoc; // how far ahead the start of source is to dest
            int offset = diff.GetScalar(expandTo.ToAxis().Orth());

            // Traverse the region that both borders touch
            int sourceLength = roomFrom.GetBorderLength(expandTo);
            int destLength   = room.GetBorderLength(expandTo.Reverse());

            for (int ii = Math.Max(0, offset); ii - offset < sourceLength && ii < destLength; ii++)
            {
                bool sourceFulfill = roomFrom.GetFulfillableBorder(expandTo, ii - offset);
                bool destFulfill   = room.GetFulfillableBorder(expandTo.Reverse(), ii);
                if (sourceFulfill && destFulfill)
                {
                    totalMatch++;
                }
            }

            return(totalMatch);
        }
コード例 #6
0
        public override void ApplyToPath(IRandom rand, GridPlan floorPlan)
        {
            if (floorPlan.GridWidth < 3 || floorPlan.GridHeight < 3)
            {
                throw new InvalidOperationException("Not enough room to create path.");
            }

            int maxRooms = (2 * floorPlan.GridWidth) + (2 * floorPlan.GridHeight) - 4;
            int roomOpen = maxRooms * this.CircleRoomRatio.Pick(rand) / 100;
            int paths    = this.Paths.Pick(rand);

            if (roomOpen < 1 && paths < 1)
            {
                roomOpen = 1;
            }

            GenContextDebug.StepIn("Outer Circle");

            // draw the top and bottom
            for (int xx = 0; xx < floorPlan.GridWidth; xx++)
            {
                this.RollOpenRoom(rand, floorPlan, new Loc(xx, 0), ref roomOpen, ref maxRooms);
                GenContextDebug.DebugProgress("Room");
                this.RollOpenRoom(rand, floorPlan, new Loc(xx, floorPlan.GridHeight - 1), ref roomOpen, ref maxRooms);
                GenContextDebug.DebugProgress("Room");
                if (xx > 0)
                {
                    floorPlan.SetHall(new LocRay4(new Loc(xx, 0), Dir4.Left), this.GenericHalls.Pick(rand), this.HallComponents.Clone());
                    GenContextDebug.DebugProgress("Hall");
                    floorPlan.SetHall(new LocRay4(new Loc(xx, floorPlan.GridHeight - 1), Dir4.Left), this.GenericHalls.Pick(rand), this.HallComponents.Clone());
                    GenContextDebug.DebugProgress("Hall");
                }
            }

            // draw the left and right (excluding the top and bottom)
            for (int yy = 0; yy < floorPlan.GridHeight; yy++)
            {
                // exclude the top and bottom
                if (yy > 0 && yy < floorPlan.GridHeight - 1)
                {
                    this.RollOpenRoom(rand, floorPlan, new Loc(0, yy), ref roomOpen, ref maxRooms);
                    GenContextDebug.DebugProgress("Room");
                    this.RollOpenRoom(rand, floorPlan, new Loc(floorPlan.GridWidth - 1, yy), ref roomOpen, ref maxRooms);
                    GenContextDebug.DebugProgress("Room");
                }

                if (yy > 0)
                {
                    floorPlan.SetHall(new LocRay4(new Loc(0, yy), Dir4.Up), this.GenericHalls.Pick(rand), this.HallComponents.Clone());
                    GenContextDebug.DebugProgress("Hall");
                    floorPlan.SetHall(new LocRay4(new Loc(floorPlan.GridWidth - 1, yy), Dir4.Up), this.GenericHalls.Pick(rand), this.HallComponents.Clone());
                    GenContextDebug.DebugProgress("Hall");
                }
            }

            GenContextDebug.StepOut();

            GenContextDebug.StepIn("Inner Paths");

            Rect innerRect = new Rect(1, 1, floorPlan.GridWidth - 2, floorPlan.GridHeight - 2);

            // create inner paths
            for (int pathsMade = 0; pathsMade < paths; pathsMade++)
            {
                GenContextDebug.StepIn($"Path {pathsMade}");

                Dir4 startDir = DirExt.VALID_DIR4.ElementAt(rand.Next(DirExt.DIR4_COUNT));
                int  x        = rand.Next(innerRect.Start.X, innerRect.End.X);
                int  y        = rand.Next(innerRect.Start.Y, innerRect.End.Y);
                switch (startDir)
                {
                case Dir4.Down:
                    y = 0;
                    break;

                case Dir4.Left:
                    x = floorPlan.GridWidth - 1;
                    break;

                case Dir4.Up:
                    y = floorPlan.GridHeight - 1;
                    break;

                case Dir4.Right:
                    x = 0;
                    break;

                case Dir4.None:
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(startDir), "Invalid enum value.");
                }

                Loc  wanderer   = new Loc(x, y);
                Dir4 prevDir    = Dir4.None; // direction of movement
                int  pathLength = (startDir.ToAxis() == Axis4.Vert) ? innerRect.Height : innerRect.Width;
                for (int currentLength = 0; currentLength < pathLength; currentLength++)
                {
                    Dir4 chosenDir = startDir;

                    // avoid this block the first time
                    if (currentLength > 0)
                    {
                        List <Dir4> dirs = new List <Dir4>();
                        foreach (Dir4 dir in DirExt.VALID_DIR4)
                        {
                            // do not backtrack
                            if (dir == prevDir)
                            {
                                continue;
                            }

                            // do not hit edge
                            if (!Collision.InBounds(innerRect, wanderer + dir.GetLoc()))
                            {
                                continue;
                            }
                            dirs.Add(dir);
                        }

                        chosenDir = dirs[rand.Next(dirs.Count)];
                    }

                    Loc dest = wanderer + chosenDir.GetLoc();

                    GridRoomPlan existingRoom = floorPlan.GetRoomPlan(dest);
                    if (existingRoom == null)
                    {
                        if (currentLength == pathLength - 1) // only the end room can be a non-hall
                        {
                            floorPlan.AddRoom(dest, this.GenericRooms.Pick(rand), this.RoomComponents.Clone());
                        }
                        else
                        {
                            floorPlan.AddRoom(dest, this.GetDefaultGen(), this.HallComponents.Clone(), true);
                        }
                        GenContextDebug.DebugProgress("Room");
                    }
                    else if (existingRoom.PreferHall)
                    {
                        if (currentLength == pathLength - 1)
                        {
                            // override the hall room
                            existingRoom.RoomGen    = this.GenericRooms.Pick(rand).Copy();
                            existingRoom.PreferHall = false;
                        }
                    }

                    floorPlan.SetHall(new LocRay4(wanderer, chosenDir), this.GenericHalls.Pick(rand), this.HallComponents.Clone());
                    GenContextDebug.DebugProgress("Hall");

                    wanderer = dest;
                    prevDir  = chosenDir.Reverse();
                }

                GenContextDebug.StepOut();
            }

            GenContextDebug.StepOut();
        }
コード例 #7
0
        /// <summary>
        /// Gets the minimum range along the side of a room that includes all of its fulfillable borders.
        /// Special cases arise if the room is multi-cell.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="dir">Direction from room to hall.</param>
        /// <param name="tier"></param>
        /// <returns></returns>
        public virtual IntRange GetHallTouchRange(IRoomGen room, Dir4 dir, int tier)
        {
            bool vertical = dir.ToAxis() == Axis4.Vert;

            // The hall will touch the whole fulfillable side of each room under normal circumstances.
            // Things get tricky for a target room that occupies more than one cell.
            // First, try to cover only the part of the target room that's in the cell.
            int      tierStart  = vertical ? tier * (this.WidthPerCell + this.CellWall) : tier * (this.HeightPerCell + this.CellWall);
            int      tierLength = vertical ? this.WidthPerCell : this.HeightPerCell;
            IntRange tierRange  = new IntRange(tierStart, tierStart + tierLength);
            IntRange roomRange  = room.Draw.GetSide(dir.ToAxis());

            // factor possibletiles into this calculation
            int borderStart = tierStart - roomRange.Min;

            if (borderStart < 0)
            {
                tierRange.Min -= borderStart;
                borderStart    = 0;
            }

            for (int ii = borderStart; ii < roomRange.Length; ii++)
            {
                if (room.GetFulfillableBorder(dir, ii))
                {
                    break;
                }
                else
                {
                    tierRange.Min += 1;
                }
            }

            int borderEnd = tierStart + tierLength - roomRange.Min;

            if (borderEnd > roomRange.Length)
            {
                tierRange.Max += roomRange.Length - borderEnd;
                borderEnd      = roomRange.Length;
            }

            for (int ii = borderEnd - 1; ii >= 0; ii--)
            {
                if (room.GetFulfillableBorder(dir, ii))
                {
                    break;
                }
                else
                {
                    tierRange.Max -= 1;
                }
            }

            if (tierRange.Max > tierRange.Min)
            {
                return(tierRange);
            }

            // If that's not possible, then it means that the room must have fulfillable tiles outside of the current bound.
            // Try to extend the hall until it covers one fulfillable tile of the target room.
            // Easy method: note that the current tierRange range is covering the zone between the tier and the edge of the room (inverted)
            // There will be either a workable range at the start or a workable range at the end, never neither.
            IntRange startRange = new IntRange(tierRange.Max - 1, tierStart + 1);
            IntRange endRange   = new IntRange(tierStart + tierLength - 1, tierRange.Min + 1);

            bool chooseStart = true;
            bool chooseEnd   = true;

            // if tierRanges reached the absolute limits of the roomRange, then there is no fulfillable tile on that side
            if (startRange.Min < roomRange.Min)
            {
                chooseStart = false;
            }
            else if (endRange.Length > startRange.Length)
            {
                chooseEnd = false;
            }

            if (endRange.Max > roomRange.Max)
            {
                chooseEnd = false;
            }
            else if (startRange.Length > endRange.Length)
            {
                chooseStart = false;
            }

            if (!chooseStart && !chooseEnd)
            {
                throw new ArgumentException("PrepareFulfillableBorders did not open at least one open tile for each direction!");
            }

            if (chooseStart)
            {
                return(startRange);
            }
            return(endRange);
        }
コード例 #8
0
        /// <summary>
        /// Decides on the bounds for each hall.  Also writes to the adjacent rooms' SideReqs and tile permissions
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="vertical"></param>
        /// <param name="rand">todo: describe rand parameter on ChooseHallBounds</param>
        public void ChooseHallBounds(IRandom rand, int x, int y, bool vertical)
        {
            GridRoomPlan startRoom = this.GetRoomPlan(new Loc(x, y));
            GridRoomPlan endRoom   = this.GetRoomPlan(new Loc(x + (vertical ? 0 : 1), y + (vertical ? 1 : 0)));

            GridHallGroup hallGroup = vertical ? this.VHalls[x][y] : this.HHalls[x][y];

            if (hallGroup.MainHall != null)
            {
                // also sets the sidereqs
                int      tier          = vertical ? x : y;
                Dir4     dir           = vertical ? Dir4.Down : Dir4.Right;
                IntRange startRange    = this.GetHallTouchRange(startRoom.RoomGen, dir, tier);
                IntRange endRange      = this.GetHallTouchRange(endRoom.RoomGen, dir.Reverse(), tier);
                IntRange combinedRange = new IntRange(Math.Min(startRange.Min, endRange.Min), Math.Max(startRange.Max, endRange.Max));
                Loc      start         = startRoom.RoomGen.Draw.End;
                Loc      end           = endRoom.RoomGen.Draw.Start;

                Rect startCell = this.GetCellBounds(startRoom.Bounds);
                Rect endCell   = this.GetCellBounds(endRoom.Bounds);

                Rect bounds = vertical ? new Rect(combinedRange.Min, start.Y, combinedRange.Length, end.Y - start.Y)
                    : new Rect(start.X, combinedRange.Min, end.X - start.X, combinedRange.Length);

                // a side constitutes intruding bound when the rectangle moves forward enough to go to the other side
                // and the other side touched is outside of side B's bound (including borders)

                // startRange intrudes if startRange goes outside end's tier (borders included)
                bool startIntrude = !endCell.GetSide(dir.ToAxis()).Contains(startRange);

                // and end is greater than the edge (borders excluded)
                bool endTouch = bounds.GetScalar(dir) == endCell.GetScalar(dir.Reverse());

                bool endIntrude = !startCell.GetSide(dir.ToAxis()).Contains(endRange);

                // and end is greater than the edge (borders excluded)
                bool startTouch = bounds.GetScalar(dir.Reverse()) == startCell.GetScalar(dir);

                // neither side intrudes bound: use the computed rectangle
                if ((!startIntrude && !endIntrude) || (endTouch && startTouch) ||
                    (!(startIntrude && endIntrude) && ((startIntrude && endTouch) || (endIntrude && startTouch))))
                {
                    hallGroup.MainHall.RoomGen.PrepareSize(rand, bounds.Size);
                    hallGroup.MainHall.RoomGen.SetLoc(bounds.Start);
                }
                else
                {
                    int      divPoint      = startCell.GetScalar(dir) + 1;
                    IntRange startDivRange = startRange;
                    IntRange endDivRange   = endRange;
                    if (startIntrude && !endIntrude)
                    {
                        // side A intrudes bound, side B does not: divide A and B; doesn't matter who gets border
                        // side A touches border, side B does not: divide A and B; A gets border
                        //
                        // side A does not, side B touches border: A gets border; don't need B - this cannot happen
                        // side A touches border, side B touches border: A gets border; don't need B - this cannot happen
                        //
                        // in short, divide with start getting the border
                        // startDivRange needs to contain endRange
                        startDivRange = combinedRange;
                    }
                    else if (!startIntrude && endIntrude)
                    {
                        // side A does not, side B intrudes bound: divide A and B; doesn't matter who gets border
                        // side A does not, side B touches border: divide A and B; B gets border
                        //
                        // side A touches border, side B does not: B gets border; don't need A - this cannot happen
                        // side A touches border, side B touches border: B gets border; don't need B - this cannot happen
                        //
                        // in short, divide with end getting the border
                        // endDivRange needs to contain startRange
                        divPoint    = startCell.GetScalar(dir);
                        endDivRange = combinedRange;
                    }
                    else
                    {
                        // side A intrudes bound, side B intrudes bound: divide A and B; doesn't matter who gets border
                        if (startTouch)
                        {
                            // side A touches border, side B does not: divide A and B; A gets border
                        }

                        if (endTouch)
                        {
                            // side A does not, side B touches border: divide A and B; B gets border
                            divPoint = startCell.GetScalar(dir);
                        }

                        // side A touches border, side B touches border: A gets border; don't need B -  this cannot happen
                        // both sides need to cover the intersection of their cells
                        IntRange interCellSide = IntRange.Intersect(startCell.GetSide(dir.ToAxis()), endCell.GetSide(dir.ToAxis()));
                        startDivRange = IntRange.IncludeRange(startDivRange, interCellSide);
                        endDivRange   = IntRange.IncludeRange(endDivRange, interCellSide);
                    }

                    Rect startBox = vertical ? new Rect(startDivRange.Min, start.Y, startDivRange.Length, divPoint - start.Y)
                        : new Rect(start.X, startDivRange.Min, divPoint - start.X, startDivRange.Length);
                    Rect endBox = vertical ? new Rect(endDivRange.Min, divPoint, endDivRange.Length, end.Y - divPoint)
                        : new Rect(divPoint, endDivRange.Min, end.X - divPoint, endDivRange.Length);

                    GridHallPlan originalHall = hallGroup.MainHall;
                    hallGroup.HallParts.Add(new GridHallPlan((IPermissiveRoomGen)originalHall.RoomGen.Copy(), originalHall.Components));
                    hallGroup.HallParts[0].RoomGen.PrepareSize(rand, startBox.Size);
                    hallGroup.HallParts[0].RoomGen.SetLoc(startBox.Start);
                    hallGroup.HallParts[1].RoomGen.PrepareSize(rand, endBox.Size);
                    hallGroup.HallParts[1].RoomGen.SetLoc(endBox.Start);
                }
            }
        }
コード例 #9
0
        public static void AddLegalPlacements(SpawnList <Loc> possiblePlacements, FloorPlan floorPlan, RoomHallIndex indexFrom, IRoomGen roomFrom, IRoomGen room, Dir4 expandTo)
        {
            bool vertical = expandTo.ToAxis() == Axis4.Vert;

            // this scaling factor equalizes the chances of long sides vs short sides
            int reverseSideMult = vertical ? roomFrom.Draw.Width * room.Draw.Width : roomFrom.Draw.Height * room.Draw.Height;

            IntRange side = roomFrom.Draw.GetSide(expandTo.ToAxis());

            // subtract the room's original size, not the inflated trialrect size
            side.Min -= (vertical ? room.Draw.Size.X : room.Draw.Size.Y) - 1;

            Rect tryRect = room.Draw;

            // expand in every direction
            // this will create a one-tile buffer to check for collisions
            tryRect.Inflate(1, 1);
            int currentScalar = side.Min;

            while (currentScalar < side.Max)
            {
                // compute the location
                Loc trialLoc = roomFrom.GetEdgeRectLoc(expandTo, room.Draw.Size, currentScalar);
                tryRect.Start = trialLoc + new Loc(-1, -1);

                // check for collisions (not counting the rectangle from)
                List <RoomHallIndex> collisions = floorPlan.CheckCollision(tryRect);

                // find the first tile in which no collisions will be found
                int  maxCollideScalar = currentScalar;
                bool collided         = false;
                foreach (RoomHallIndex collision in collisions)
                {
                    if (collision != indexFrom)
                    {
                        IRoomGen collideRoom = floorPlan.GetRoomHall(collision).RoomGen;

                        // this is the point at which the new room will barely touch the collided room
                        // the +1 at the end will move it into the safe zone
                        maxCollideScalar = Math.Max(maxCollideScalar, vertical ? collideRoom.Draw.Right : collideRoom.Draw.Bottom);
                        collided         = true;
                    }
                }

                // if no collisions were hit, do final checks and add the room
                if (!collided)
                {
                    Loc locTo = roomFrom.GetEdgeRectLoc(expandTo, room.Draw.Size, currentScalar);

                    // must be within the borders of the floor!
                    if (floorPlan.DrawRect.Contains(new Rect(locTo, room.Draw.Size)))
                    {
                        // check the border match and if add to possible placements
                        int chanceTo = FloorPlan.GetBorderMatch(roomFrom, room, locTo, expandTo);
                        if (chanceTo > 0)
                        {
                            possiblePlacements.Add(locTo, chanceTo * reverseSideMult);
                        }
                    }
                }

                currentScalar = maxCollideScalar + 1;
            }
        }
コード例 #10
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);
            }
        }