Beispiel #1
0
        /// <summary>
        /// Generate a 'normal' dungeon
        /// </summary>
        /// <param name="width">Width of dungeon to create</param>
        /// <param name="height">Height of dungeon to create</param>
        /// <returns>Generated Dungeon</returns>
        public static Dungeon Generate(int width, int height, List <Passage> passages = null)
        {
            var dungeon = new Dungeon(width, height);

            // Set start to middle of room
            dungeon.StartLocation = new XY(dungeon.Width / 2, dungeon.Height / 2);

            // Until filled, place rooms!
            var     possibleFeatures = GenerateFeatureLibrary();
            Feature nextFeature;
            var     possibleDoors = new List <XY>();

            // Create starting door
            possibleDoors.Add(new XY(Next(dungeon.Width - 4) + 2,
                                     Next(dungeon.Height - 4) + 2));
            var successfulDoors = new List <XY>();

            int failures = 0;

            // Unsure if this should be true, or lambda - this seemed neat enough
            while (
                (failures < MAX_FAILURES) &&
                (possibleDoors.Count > 0) &&
                dungeon.AnyEmpty())
            {
                // Get random feature, in random rotation
                nextFeature = possibleFeatures[Next(possibleFeatures.Count)]
                              .Rotate((Feature.Rotation)Next(4));

                // Choose a door to build on
                var baseDoor = possibleDoors[Next(possibleDoors.Count)];

                // List to put potentials in - doors on the opposite extremity in the feature
                // to the free side of the base door
                var possibleFeatureDoors = new List <XY>();

                // Randomise order of featureDoors to make any possible
                possibleFeatureDoors = nextFeature.PossibleDoors.OrderBy((i) =>
                                                                         Next()).ToList();

                // Whether the feature was successfully placed
                bool placed = false;

                foreach (XY featureDoor in possibleFeatureDoors)
                {
                    // Amount to add to feature to translate to global - this is baseDoor - door -
                    // so, for instance - base door X of 20, and door x of 5 would mean we need
                    // to add 15 to the feature x to translate it to the global x
                    var translate = baseDoor - featureDoor;

                    // If feature fits...
                    if (FeatureFits(translate, dungeon, nextFeature))
                    {
                        // Add the feature
                        AddFeature(translate, dungeon, nextFeature);

                        // And add its doors to the possible door list
                        possibleDoors.AddRange(nextFeature.PossibleDoors.Select(
                                                   i => (i + translate)));

                        // Clear any doors that are no longer usable
                        possibleDoors = possibleDoors.Where(door =>
                        {
                            return
                            // If in boundaries...
                            ((door.X > 1) &&
                             (door.X < (dungeon.Width - 1)) &&
                             (door.Y > 1) &&
                             (door.Y < (dungeon.Height - 1)) &&
                             // And at least one part there is free
                             (
                                 dungeon.GetCell(new XY(door.X - 1, door.Y)) == DungeonCell.Empty ||
                                 dungeon.GetCell(new XY(door.X + 1, door.Y)) == DungeonCell.Empty ||
                                 dungeon.GetCell(new XY(door.X, door.Y - 1)) == DungeonCell.Empty ||
                                 dungeon.GetCell(new XY(door.X, door.Y + 1)) == DungeonCell.Empty
                             ));
                        }).ToList();

                        // And go try a new feature
                        placed = true;
                        successfulDoors.Add(baseDoor);
                        break;
                    }
                }

                if (!placed)
                {
                    // We failed. If we fail too often, we're done.
                    failures += 1;
                }
            }

            // Make doors doors
            foreach (var door in successfulDoors)
            {
                dungeon.SetCell(door, DungeonCell.Door);
            }

            // Add passages to spawn areas...
            // They're guaranteed to be separated at least into different rooms
            foreach (var passage in passages ?? new List <Passage>())
            {
                var area          = dungeon.SpawnAreas.RandomItem();
                var startPosition = area.Area.RandomItem();

                // Remove spawn area from list - don't want surrounded soon as down, and don't want
                // multiple passages in same area
                dungeon.SpawnAreas.Remove(area);

                // Add passage to dungeon
                dungeon.Passages.Add(new Passage(passage.PassageType, passage.DestinationID,
                                                 startPosition));

                // Set tile to appropriate for passage type
                switch (passage.PassageType)
                {
                case Passage.PassageTypeEnum.StairsUp:
                    dungeon.SetCell(startPosition, DungeonCell.StairUp);
                    break;

                case Passage.PassageTypeEnum.StairsDown:
                    dungeon.SetCell(startPosition, DungeonCell.StairDown);
                    break;
                }
            }

            return(dungeon);
        }