Beispiel #1
0
        protected override void _runAlgorithm(IAlgorithmContext context)
        {
            DungeonTiles workingTiles = context.D.Tiles;

            bool[,] algMask = context.Mask;

            if (this.ClearArea)
            {
                workingTiles.SetAllToo(Tile.MoveType.Wall, algMask);
            }

            bool[,] isExplored = (bool[, ])algMask.Clone();
            for (int y = 0; y < workingTiles.Height; ++y)
            {
                for (int x = 0; x < workingTiles.Width; ++x)
                {
                    isExplored[y, x] = !algMask[y, x];
                }
            }

            // If appropriate, mask out already-opened tiles
            if (!this.ClearArea && this.AvoidOpen)
            {
                for (int y = 0; y < workingTiles.Height; ++y)
                {
                    for (int x = 0; x < workingTiles.Width; ++x)
                    {
                        if (algMask[y, x] && workingTiles[y, x].Physics != Tile.MoveType.Wall)
                        {
                            isExplored[y, x] = true;
                        }
                    }
                }
            }

            // Create a pool of origins
            List <Point> unmaskedPoints = new List <Point>();

            for (int y = 0; y < isExplored.GetLength(0); ++y)
            {
                for (int x = 0; x < isExplored.GetLength(1); ++x)
                {
                    // If it's not masked out, add it to the pool of potential
                    // starting points
                    if (!isExplored[y, x])
                    {
                        unmaskedPoints.Add(new Point(x, y));
                    }
                }
            }

            // Only odd coordinates are valid starts due to limitations of algorithm below
            Predicate <Point> oddPoints          = p => p.X % 2 != 0 && p.Y % 2 != 0;
            Predicate <Point> paddedWithinBorder = p => p.X > BorderPadding && p.Y > BorderPadding && p.X < isExplored.GetLength(1) - BorderPadding && p.Y < isExplored.GetLength(0) - BorderPadding;
            List <Point>      originPool         = unmaskedPoints.FindAll(oddPoints).FindAll(paddedWithinBorder);

            if (originPool.Count == 0)
            {
                return;
            }

            int currentRooms   = 0;
            int currentAttempt = 0;

            while (++currentAttempt <= this.Attempts && currentRooms < this.TargetRoomCount)
            {
                int   originIdx  = context.R.Next(originPool.Count);
                Point nextOrigin = originPool[originIdx];

                int y = nextOrigin.Y;
                int x = nextOrigin.X;
                int w = context.R.Next(this.RoomWidthMin, this.RoomWidthMax) - 1 | 0x1;
                int h = context.R.Next(this.RoomHeightMin, this.RoomHeightMax) - 1 | 0x1;

                if (!workingTiles.TileIsValid(x, y) || !workingTiles.TileIsValid(x, y + h) || !workingTiles.TileIsValid(x + w, y) || !workingTiles.TileIsValid(x + w, y + h))
                {
                    continue;
                }

                bool overlapsOrAdjacent = false;
                for (int nuY = y - 1; nuY < y + h + 1; ++nuY)
                {
                    for (int nuX = x - 1; nuX < x + w + 1; ++nuX)
                    {
                        if (!workingTiles.TileIsValid(nuX, nuY) || isExplored[nuY, nuX])
                        {
                            overlapsOrAdjacent = true;
                            break;
                        }
                    }
                    if (overlapsOrAdjacent)
                    {
                        break;
                    }
                }
                if (overlapsOrAdjacent)
                {
                    continue;             // Failed attempt
                }
                ISet <Tile> newRoom = new HashSet <Tile>();
                for (int nuY = y; nuY < y + h; ++nuY)
                {
                    for (int nuX = x; nuX < x + w; ++nuX)
                    {
                        isExplored[nuY, nuX]           = true;
                        workingTiles[nuY, nuX].Physics = workingTiles[nuY, nuX].Physics.OpenUp(Tile.MoveType.Open_HORIZ);
                        originPool.Remove(workingTiles[nuY, nuX].Location);
                        newRoom.Add(workingTiles[nuY, nuX]);
                    }
                }
                // Close off boundaries if appropriate
                if (this.WallStrategy == WallFormation.Boundaries)
                {
                    for (int nuY = y; nuY < y + h; ++nuY)
                    {
                        for (int nuX = x; nuX < x + w; ++nuX)
                        {
                            if (nuY == y)
                            {
                                workingTiles[nuY, nuX].Physics = workingTiles[nuY, nuX].Physics.CloseOff(Tile.MoveType.Open_NORTH);
                            }
                            if (nuX == x)
                            {
                                workingTiles[nuY, nuX].Physics = workingTiles[nuY, nuX].Physics.CloseOff(Tile.MoveType.Open_WEST);
                            }
                            if (nuY == y + h - 1)
                            {
                                workingTiles[nuY, nuX].Physics = workingTiles[nuY, nuX].Physics.CloseOff(Tile.MoveType.Open_SOUTH);
                            }
                            if (nuX == x + w - 1)
                            {
                                workingTiles[nuY, nuX].Physics = workingTiles[nuY, nuX].Physics.CloseOff(Tile.MoveType.Open_EAST);
                            }
                        }
                    }
                }

                // Rooms should not be orphaned!
                workingTiles.Parent.CreateGroup(newRoom, TileCategory.Room);

                this.RunCallbacks(context);

                ++currentRooms;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Draws the border for tile (x, y) in the specified DungeonTiles,
        /// to the specified graphics and rectangle coordinates.
        /// </summary>
        /// <param name="tiles">The DungeonTiles for which this border is being drawn</param>
        /// <param name="x">The x-location of the tile whose border is being drawn</param>
        /// <param name="y">The x-location of the tile whose border is being drawn</param>
        /// <param name="moveDir">The move direction. Currently supports a single horizontal square direction, or all horizontal square directions, but no other combinations</param>
        /// <param name="g">The graphics on which to draw</param>
        /// <param name="x1">x1 of the tile's square in graphics.</param>
        /// <param name="y1">y1 of the tile's square in graphics.</param>
        /// <param name="x2">x2 of the tile's square in graphics.</param>
        /// <param name="y2">y2 of the tile's square in graphics.</param>
        private void DrawBorderFor(DungeonTiles tiles, int x, int y, Tile.MoveType moveDir, Graphics g, int x1, int y1, int x2, int y2)
        {
            if (tiles == null || g == null)
            {
                return;                       // no op
            }
            if (!tiles.TileIsValid(x, y))
            {
                return;
            }

            int adjacentTile_x = 0,
                adjacentTile_y = 0;

            // Determine the correct adjacent tile to check physics
            switch (moveDir)
            {
            case Tile.MoveType.Wall:
                return; // no op

            case Tile.MoveType.Open_NORTH:
                adjacentTile_x = x;
                adjacentTile_y = y - 1;
                break;

            case Tile.MoveType.Open_EAST:
                adjacentTile_x = x + 1;
                adjacentTile_y = y;
                break;

            case Tile.MoveType.Open_SOUTH:
                adjacentTile_x = x;
                adjacentTile_y = y + 1;
                break;

            case Tile.MoveType.Open_WEST:
                adjacentTile_x = x - 1;
                adjacentTile_y = y;
                break;

            case Tile.MoveType.Open_HORIZ:
                DrawBorderFor(tiles, x, y, Tile.MoveType.Open_NORTH, g, x1, y1, x2, y2);
                DrawBorderFor(tiles, x, y, Tile.MoveType.Open_EAST, g, x1, y1, x2, y2);
                DrawBorderFor(tiles, x, y, Tile.MoveType.Open_SOUTH, g, x1, y1, x2, y2);
                DrawBorderFor(tiles, x, y, Tile.MoveType.Open_WEST, g, x1, y1, x2, y2);
                return;

            default:
                throw new NotImplementedException("Unsupported Tile.MoveType specified");
            }

            // 1. Check if THIS cell is even open
            bool useWall = ((tiles[y, x].Physics & moveDir) == 0);

            // 2. Check if adjacent cell exists; if not, use a wall border
            useWall = (useWall || !tiles.TileIsValid(adjacentTile_x, adjacentTile_y));
            // 3. If adjacent cell exists, check if its corresponding wall is opened too; if not, use a wall border
            useWall = (useWall || (tiles[adjacentTile_y, adjacentTile_x].Physics & moveDir.GetOpposite()) == 0);

            if (this.WallBorder_Pen == null || this.OpenBorder_Pen == null)
            {
                throw new Exception("DungeonTileRenderer is in an invalid state: set WallBorder_Pen and OpenBorder_Pen");
            }

            Pen borderPen = useWall ? this.WallBorder_Pen : this.OpenBorder_Pen;

            // All this work, just to draw a single line.
            switch (moveDir)
            {
            case Tile.MoveType.Open_NORTH:
                g.DrawLine(borderPen, x1, y1, x2, y1);
                break;

            case Tile.MoveType.Open_EAST:
                g.DrawLine(borderPen, x2, y1, x2, y2);
                break;

            case Tile.MoveType.Open_SOUTH:
                g.DrawLine(borderPen, x1, y2, x2, y2);
                break;

            case Tile.MoveType.Open_WEST:
                g.DrawLine(borderPen, x1, y1, x1, y2);
                break;

            default:
                throw new ArgumentException("Unsupported moveDir to draw border");
            }
        }