Esempio n. 1
0
        /// <summary>
        /// Generates usually one random Monster chosen appropriately for the given depth. May
        /// generate more than one if the Monster chosen has escorts or appears in groups. Adds
        /// them to the current dungeon.
        /// </summary>
        /// <param name="level">Dungeon level to generate at.</param>
        /// <returns>The new Monsters that were added to the Dungeon.</returns>
        public static IList <Monster> AddRandom(Dungeon dungeon, int level, Vec startPos)
        {
            Race race = Race.Random(dungeon, level, true);

            List <Monster> monsters = new List <Monster>();

            // create the monster(s)
            Monster monster = new Monster(startPos, race);

            monsters.Add(monster);
            dungeon.Entities.Add(monster);

            // generate friends
            if (race.NumberInGroup > 1)
            {
                int numMonsters = Rng.TriangleInt(race.NumberInGroup, race.NumberInGroup / 3);
                int tries       = 0;
                while ((monsters.Count < numMonsters) && (tries < 100))
                {
                    tries++;

                    // pick a random spot next to one of the monsters in the group
                    Vec pos;
                    if (dungeon.TryFindOpenAdjacent(Rng.Item(monsters).Position, out pos))
                    {
                        // found one, so put another there
                        Monster buddy = new Monster(pos, race);
                        monsters.Add(buddy);
                        dungeon.Entities.Add(buddy);
                    }
                }
            }

            return(monsters);
        }
Esempio n. 2
0
        /// <summary>
        /// Implementation of the "growing tree" algorithm from here:
        /// http://www.astrolog.org/labyrnth/algrithm.htm.
        /// </summary>
        /// <remarks>
        /// This is a general algorithm, capable of creating Mazes of different textures. It requires
        /// storage up to the size of the Maze. Each time you carve a cell, add that cell to a list.
        /// Proceed by picking a cell from the list, and carving into an unmade cell next to it. If
        /// there are no unmade cells next to the current cell, remove the current cell from the list.
        /// The Maze is done when the list becomes empty. The interesting part that allows many possible
        /// textures is how you pick a cell from the list. For example, if you always pick the most
        /// recent cell added to it, this algorithm turns into the recursive backtracker. If you always
        /// pick cells at random, this will behave similarly but not exactly to Prim's algorithm. If you
        /// always pick the oldest cells added to the list, this will create Mazes with about as low a
        /// "river" factor as possible, even lower than Prim's algorithm. If you usually pick the most
        /// recent cell, but occasionally pick a random cell, the Maze will have a high "river" factor
        /// but a short direct solution. If you randomly pick among the most recent cells, the Maze will
        /// have a low "river" factor but a long windy solution.
        /// </remarks>
        public void GrowTree()
        {
            List <Vec> cells = new List <Vec>();

            // start with a random cell
            Vec pos = Rng.Vec(Bounds);

            Open(pos);
            cells.Add(pos);

            while (cells.Count > 0)
            {
                // weighting how the index is chosen here will affect the way the
                // maze looks. see the function description
                int index = Math.Abs(Rng.TriangleInt(0, cells.Count - 1));
                Vec cell  = cells[index];

                // see which adjacent cells are open
                List <Direction> unmadeCells = new List <Direction>();

                if (CanCarve(cell, Direction.N))
                {
                    unmadeCells.Add(Direction.N);
                }
                if (CanCarve(cell, Direction.S))
                {
                    unmadeCells.Add(Direction.S);
                }
                if (CanCarve(cell, Direction.E))
                {
                    unmadeCells.Add(Direction.E);
                }
                if (CanCarve(cell, Direction.W))
                {
                    unmadeCells.Add(Direction.W);
                }

                if (unmadeCells.Count > 0)
                {
                    Direction direction = Rng.Item(unmadeCells);

                    Carve(cell, direction);

                    cells.Add(cell + direction);
                }
                else
                {
                    // no adjacent uncarved cells
                    cells.RemoveAt(index);
                }
            }
        }
Esempio n. 3
0
        private Rect CreateRectRoom(Connector connector, int width, int height)
        {
            int x = 0;
            int y = 0;

            // position the room
            if (connector == null)
            {
                // initial room, so start near center
                x = Rng.TriangleInt((mWriter.Bounds.Width - width) / 2, (mWriter.Bounds.Width - width) / 2 - 4);
                y = Rng.TriangleInt((mWriter.Bounds.Height - height) / 2, (mWriter.Bounds.Height - height) / 2 - 4);
            }
            else if (connector.Direction == Direction.N)
            {
                // above the connector
                x = Rng.Int(connector.Position.X - width + 1, connector.Position.X + 1);
                y = connector.Position.Y - height;
            }
            else if (connector.Direction == Direction.E)
            {
                // to the right of the connector
                x = connector.Position.X + 1;
                y = Rng.Int(connector.Position.Y - height + 1, connector.Position.Y + 1);
            }
            else if (connector.Direction == Direction.S)
            {
                // below the connector
                x = Rng.Int(connector.Position.X - width + 1, connector.Position.X + 1);
                y = connector.Position.Y + 1;
            }
            else if (connector.Direction == Direction.W)
            {
                // to the left of the connector
                x = connector.Position.X - width;
                y = Rng.Int(connector.Position.Y - height + 1, connector.Position.Y + 1);
            }

            Rect bounds = new Rect(x, y, width, height);

            // check to see if the room can be positioned
            if (!mWriter.IsOpen(bounds.Inflate(1), (connector != null) ? (Vec?)connector.Position : (Vec?)null))
            {
                return(Rect.Empty);
            }

            return(bounds);
        }
Esempio n. 4
0
        /// <summary>
        /// Randomly walks the given level using a... unique distribution. The
        /// goal is to return a value that approximates a bell curve centered
        /// on the start level whose wideness increases as the level increases.
        /// Thus, starting at a low start level will only walk a short distance,
        /// while starting at a higher level can wander a lot farther.
        /// </summary>
        /// <returns></returns>
        public static int WalkLevel(int level)
        {
            int result = level;

            // stack a few triangles to approximate a bell
            for (int i = 0; i < Math.Min(5, level); i++)
            {
                // the width of the triangle is based on the level
                result += Rng.TriangleInt(0, 1 + (level / 20));
            }

            // also have an exponentially descreasing change of going out of depth
            while (Rng.OneIn(10))
            {
                result += 1 + Rng.Int(2 + (level / 5));
            }

            return(result);
        }
Esempio n. 5
0
 public static Roller Triangle(int center, int range)
 {
     return(new Roller(
                () => Rng.TriangleInt(center, range),
                center, center.ToString() + "t" + range.ToString()));
 }