Exemplo n.º 1
0
        public void Create(BiomeData biome)
        {
            rooms     = new List <Room>(MAX_ROOMS);
            corridors = new List <Room>(2 * MAX_ROOMS);

            for (var i = 0; i < MAX_ROOMS; i++)
            {
                var w = Random.Next(ROOM_MIN_X, ROOM_MAX_X - 2);
                var h = Random.Next(ROOM_MIN_Y, ROOM_MAX_Y - 2);
                var l = Random.Next(1, Board.Width - w);
                var t = Random.Next(1, Board.Height - h);
                if (l + w >= Board.Width - 1)
                {
                    w = Board.Width - l - 2;
                }
                if (t + h >= Board.Height - 1)
                {
                    h = Board.Height - t - 2;
                }
                var room = new Room(new SysRectangle(l, t, w, h), (RoomMaterials)Random.Next(Enum.GetValues(typeof(RoomMaterials)).Length));
                var pass = false;
                if (i > 0)
                {
                    for (var j = 0; j < rooms.Count; j++)
                    {
                        if (room.Bounds.IntersectsWith(rooms[j].Bounds))
                        {
                            pass = true;
                        }
                    }
                }
                if (pass)
                {
                    continue;
                }
                rooms.Add(room);
                if (i > 0)
                {
                    var firstToLast  = Center(rooms[rooms.Count - 1]);
                    var secondToLast = Center(rooms[rooms.Count - 2]);

                    if (Random.Flip())
                    {
                        corridors.Add(new Room(new SysRectangle(firstToLast.X, firstToLast.Y, secondToLast.X - firstToLast.X, 1), RoomMaterials.Stone));
                        corridors.Add(new Room(new SysRectangle(secondToLast.X, firstToLast.Y, 1, secondToLast.Y - firstToLast.Y), RoomMaterials.Stone));
                    }
                    else
                    {
                        corridors.Add(new Room(new SysRectangle(firstToLast.X, firstToLast.Y, 1, secondToLast.Y - firstToLast.Y), RoomMaterials.Stone));
                        corridors.Add(new Room(new SysRectangle(firstToLast.X, secondToLast.Y, secondToLast.X - firstToLast.X, 1), RoomMaterials.Stone));
                    }
                }
            }
        }
Exemplo n.º 2
0
        public static BiomeData FromToken(Token t, int realmNum)
        {
            var n = new BiomeData();

            n.Realm = (Realms)realmNum;
            n.Name  = t.Text;

            var cvars = t.GetToken("rect").Text.Split(' ').Select(i => int.Parse(i)).ToArray();

            n.Rect = new System.Drawing.Rectangle(cvars[0], cvars[1], cvars[2] - cvars[0], cvars[3] - cvars[1]);

            n.GroundTile = (int)t.GetToken("ground").Value;
            if (n.GroundTile == 0)
            {
                n.GroundTile = TileDefinition.Find(t.GetToken("ground").Text, true).Index;
            }

            var encounters = t.GetToken("encounters");

            if (encounters == null)
            {
                n.Encounters = new string[0];
            }
            else
            {
                n.MaxEncounters = 10;
                if (encounters.Value > 0)
                {
                    n.MaxEncounters = (int)encounters.Value;
                }
                n.Encounters = encounters.Tokens.Select(x => x.Name).ToArray();
            }

            var cultures = t.GetToken("cultures");

            if (cultures == null)
            {
                n.Cultures = new[] { "human" }
            }
            ;
            else
            {
                n.Cultures = cultures.Tokens.Select(x => x.Name).Where(e => Culture.Cultures.ContainsKey(e)).ToArray();
            }

            if (t.HasToken("music"))
            {
                n.Music = t.GetToken("music").Text;
            }

            return(n);
        }
Exemplo n.º 3
0
        public static void LoadBiomes()
        {
            Biomes      = new List <BiomeData>();
            WaterLevels = new List <int>();
            WaterTypes  = new List <Fluids>();
            var biomeData = Mix.GetTokenTree("biomes.tml");
            var i         = 0;

            foreach (var realm in biomeData.Where(x => x.Name == "realm"))
            {
                var waterLevel = (int)realm.GetToken("waterlevel").Value;
                WaterLevels.Add(waterLevel);
                var waterType = (Fluids)Enum.Parse(typeof(Fluids), realm.GetToken("watertype").Text, true);
                WaterTypes.Add(waterType);
                foreach (var biome in realm.Tokens.Where(x => x.Name == "biome"))
                {
                    Biomes.Add(BiomeData.FromToken(biome, i));
                }
                i++;
            }
        }
Exemplo n.º 4
0
        public void Create(BiomeData biome)
        {
            this.biome = biome;

            //Do NOT use BaseDungeon.Create() -- we want a completely different method here.
            map = new int[Board.Width, Board.Height];

            //Draw a nice border for the passes to work within
            for (var i = 0; i < Board.Width; i++)
            {
                map[i, 0] = 1;
                map[i, Board.Height - 1] = 1;
            }
            for (var i = 0; i < Board.Height; i++)
            {
                map[0, i] = 1;
                map[1, i] = 1;
                map[Board.Width - 2, i] = 1;
                map[Board.Width - 1, i] = 1;
            }

            //Scatter some seed tiles
            for (var i = 0; i < Board.Height; i++)
            {
                for (var j = 0; j < Board.Width; j++)
                {
                    if (Random.NextDouble() < 0.25)
                    {
                        map[j, i] = 1;
                    }
                }
            }

            //Melt the cave layout with a cellular automata system.
            for (var pass = 0; pass < 5; pass++)
            {
                for (var i = 1; i < Board.Height - 1; i++)
                {
                    for (var j = 1; j < Board.Width - 1; j++)
                    {
                        //Count the neighboring live cells
                        var neighbors = 0;
                        for (int ni = -1; ni <= 1; ni++)
                        {
                            for (int nj = -1; nj <= 1; nj++)
                            {
                                if (ni == 0 && nj == 0)
                                {
                                    continue;
                                }
                                neighbors += map[j + nj, i + ni];
                            }
                        }

                        //Apply the rule
                        map[j, i] = ((map[j, i] == 1 && neighbors >= 2) ||
                                     (map[j, i] == 0 && neighbors >= 5)) ? 1 : 0;
                    }
                }
            }

            //TODO: define discrete rooms somehow?
            //TODO: get rid of small enclosed areas (total surface < 4 tiles or so)
            //Possibility to kill two birds with one stone: floodfills!
            //1. Prepare a checking map, initially a copy of the actual map.
            //2. Find the first open space on the checking map.
            //3. From there, run a floodfill. Mark every open space found on the checking map and count how many open spaces you find.
            //4. If you found only one, it's a goner. Set that spot to solid on the actual map. This is distinct from step 5 for efficiency.
            //5. If you counted only a few, it's a small enclosed space that ought to be filled in. Run the floodfill again, from the same spot, but on the actual map, setting all open spaces found to solid.
            //6. Repeat until the checking map is fully colored.
            //How to do step 6 in a fairly efficient way:
            //When making the initial copy, count the amount of solid spaces as you go. Remember that value. While floodfilling, increase the count. When the count equals 80*50, you have them all.
        }
Exemplo n.º 5
0
 public void Create(BiomeData biome)
 {
     Culture = Culture.Cultures[biome.Cultures.PickOne()];
     base.Create(biome, "town");
 }
Exemplo n.º 6
0
        public virtual void ToTilemap(ref Tile[,] map)
        {
            var woodFloor = Color.FromArgb(86, 63, 44);
            var caveFloor = Color.FromArgb(65, 66, 87);
            var wall      = Color.FromArgb(20, 15, 12);
            var water     = BiomeData.Biomes[BiomeData.ByName(biome.Realm == Realms.Nox ? "Water" : "KoolAid")];

            allowCaveFloor = false;

            Clutter.ParentBoardHack = Board;

            var doorCount = 0;

            var safeZones = new List <Rectangle>();

            for (var row = 0; row < plotRows; row++)
            {
                for (var col = 0; col < plotCols; col++)
                {
                    if (plots[col, row].BaseID == null)
                    {
                        //Can clutter this up!
                        if (includeClutter && Random.Flip())
                        {
                            Board.AddClutter(col * plotWidth, row * plotHeight, (col * plotWidth) + plotWidth, (row * plotHeight) + plotHeight + row);
                        }
                        else
                        {
                            safeZones.Add(new Rectangle()
                            {
                                Left = col * plotWidth, Top = row * plotHeight, Right = (col * plotWidth) + plotWidth, Bottom = (row * plotHeight) + plotHeight + row
                            });
                        }
                        continue;
                    }

                    if (plots[col, row].BaseID == "<spillover>")
                    {
                        continue;
                    }
                    var building = plots[col, row];
                    var template = building.Template;
                    var sX       = (col * plotWidth) + building.XShift;
                    var sY       = (row * plotHeight) + building.YShift;
                    for (var y = 0; y < template.Height; y++)
                    {
                        for (var x = 0; x < template.Width; x++)
                        {
                            var tc    = template.MapScans[y][x];
                            var def   = string.Empty;
                            var fluid = Fluids.Dry;

                            var addDoor = true;
                            if (tc == '/')
                            {
                                addDoor = false;
                                tc      = '\\';
                            }
                            switch (tc)
                            {
                            case '\'':
                                continue;

                            case ',':
                                def = "pathWay";                                         // FIXME: kind of ugly but does the job
                                break;

                            case '.':
                                def = "woodFloor";
                                break;

                            case '+':                                     //Exit -- can't be seen, coaxes walls into shape.
                                def = "doorwayClosed";

                                if (addDoor)
                                {
                                    doorCount++;
                                    var door = new Door()
                                    {
                                        XPosition       = sX + x,
                                        YPosition       = sY + y,
                                        ForegroundColor = woodFloor,
                                        BackgroundColor = woodFloor.Darken(),
                                        ID          = building.BaseID + "_Door" + doorCount,
                                        ParentBoard = Board,
                                        Closed      = true,
                                        Glyph       = '+'
                                    };
                                    Board.Entities.Add(door);
                                }
                                break;

                            case '=':
                                def = "outerWoodWall";
                                break;

                            case '-':
                                def = "innerWoodWall";
                                break;

                            case '#':
                                def = allowCaveFloor ? "stoneFloor" : "woodFloor";
                                break;

                            default:
                                if (template.Markings.ContainsKey(tc))
                                {
                                    #region Custom markings
                                    var m = template.Markings[tc];
                                    if (m.Text == "block")
                                    {
                                        throw new Exception("Got a BLOCK-type marking in a building template.");
                                    }

                                    if (m.Text != "tile" && m.Text != "floor" && m.Text != "water")
                                    {
                                        //Keep a floor here. The entity fills in the blank.
                                        def = "woodFloor";
                                        var tileDef = TileDefinition.Find(def, false);
                                        map[sX + x, sY + y].Index = tileDef.Index;
                                        //var owner = m.Owner == 0 ? null : building.Inhabitants[m.Owner - 1];
                                        var owner = (Character)null;
                                        if (m.HasToken("owner"))
                                        {
                                            owner = building.Inhabitants[(int)m.GetToken("owner").Value - 1];
                                        }
                                        if (m.Text == "bed")
                                        {
                                            var newBed = new Clutter()
                                            {
                                                XPosition   = sX + x,
                                                YPosition   = sY + y,
                                                Name        = "Bed",
                                                ID          = "Bed_" + (owner == null ? Board.Entities.Count.ToString() : owner.Name.ToID()),
                                                Description = owner == null?i18n.GetString("freebed") : i18n.Format("someonesbed", owner.Name.ToString(true)),
                                                                  ParentBoard = Board,
                                            };
                                            Clutter.ResetToKnown(newBed);
                                            Board.Entities.Add(newBed);
                                        }
                                        if (m.Text == "container")
                                        {
                                            //var type = c == '\x14B' ? "cabinet" : c == '\x14A' ? "chest" : "container";
                                            var type = "chest";
                                            if (m.HasToken("wardrobe"))
                                            {
                                                type = "wardrobe";
                                            }
                                            var contents = DungeonGenerator.GetRandomLoot("container", type, new Dictionary <string, string>()
                                            {
                                                { "gender", owner.PreferredGender.ToString().ToLowerInvariant() },
                                                { "biome", BiomeData.Biomes[DungeonGenerator.DungeonGeneratorBiome].Name.ToLowerInvariant() },
                                            });
                                            if (owner != null)
                                            {
                                                foreach (var content in contents)
                                                {
                                                    content.AddToken("owner", 0, owner.ID);
                                                }
                                            }
                                            var newContainer = new Container(type, contents)                                                     //owner == null ? type.Titlecase() : owner.Name.ToString(true) + "'s " + type, contents)
                                            {
                                                XPosition   = sX + x,
                                                YPosition   = sY + y,
                                                ID          = "Container_" + type + "_" + (owner == null ? Board.Entities.Count.ToString() : owner.Name.ToID()),
                                                ParentBoard = Board,
                                            };
                                            Clutter.ResetToKnown(newContainer);
                                            Board.Entities.Add(newContainer);
                                        }
                                        else if (m.Text == "clutter")
                                        {
                                            if (m.HasToken("id"))
                                            {
                                                var newClutter = new Clutter()
                                                {
                                                    XPosition   = sX + x,
                                                    YPosition   = sY + y,
                                                    ParentBoard = Board,
                                                    ID          = m.GetToken("id").Text,
                                                    Name        = string.Empty,
                                                };
                                                Clutter.ResetToKnown(newClutter);
                                                Board.Entities.Add(newClutter);
                                            }
                                            else
                                            {
                                                var newClutter = new Clutter()
                                                {
                                                    Glyph           = (char)m.GetToken("char").Value,                                                   //m.Params.Last()[0],
                                                    XPosition       = sX + x,
                                                    YPosition       = sY + y,
                                                    ForegroundColor = Color.Black,
                                                    BackgroundColor = tileDef.Background,
                                                    ParentBoard     = Board,
                                                    Name            = m.GetToken("name").Text,                                                  //Name,
                                                    Description     = m.HasToken("description") ? m.GetToken("description").Text : string.Empty,
                                                    Blocking        = m.HasToken("blocking"),
                                                };
                                                Board.Entities.Add(newClutter);
                                            }
                                        }
                                    }
                                    else if (m.Text == "water")
                                    {
                                        fluid = Fluids.Water;
                                    }
                                    else
                                    {
                                        def = TileDefinition.Find((int)m.GetToken("index").Value).Name;
                                    }
                                    #endregion
                                }
                                break;
                            }
                            map[sX + x, sY + y].Index = TileDefinition.Find(def).Index;
                            map[sX + x, sY + y].Fluid = fluid;
                        }
                    }

                    for (var i = 0; i < building.Inhabitants.Count; i++)
                    {
                        var inhabitant = building.Inhabitants[i];
                        //Find each inhabitant's bed so we can give them a starting place.
                        //Alternatively, place them anywhere there's a ' ' within their sector.
                        var bc = new BoardChar(inhabitant);
                        //var bedID = building.BaseID + "_Bed_" + inhabitant.Name.FirstName;
                        //var bed = Board.Entities.OfType<Clutter>().FirstOrDefault(b => b.ID == bedID);
                        //if (bed != null)
                        //{
                        //	bc.XPosition = bed.XPosition;
                        //	bc.YPosition = bed.YPosition;
                        //}
                        //else
                        {
                            //var okay = false;
                            var x     = 0;
                            var y     = 0;
                            var lives = 100;
                            while (lives > 0)
                            {
                                lives--;
                                x = (col * plotWidth) + Random.Next(plotWidth);
                                y = (row * plotHeight) + Random.Next(plotHeight);
                                if (!map[x, y].Definition.Wall &&
                                    (!template.AllowOutside && map[x, y].Definition.Ceiling) &&
                                    Board.Entities.FirstOrDefault(e => e.XPosition == x && e.YPosition == y) == null)
                                {
                                    break;
                                }
                            }
                            bc.XPosition = x;
                            bc.YPosition = y;
                        }
                        bc.Character.AddToken("sectorlock");
                        bc.ParentBoard = Board;
                        bc.AdjustView();
                        bc.Sector = string.Format("s{0}x{1}", row, col);
                        Board.Entities.Add(bc);
                    }
                }
            }

            Board.ResolveVariableWalls();

            if (safeZones.Count > 0 && includeWater)
            {
                Board.AddWater(safeZones);
            }
        }
Exemplo n.º 7
0
        public void Create(BiomeData biome, string templateSet)
        {
            Culture = Culture.Cultures[biome.Cultures.PickOne()];
            DungeonGenerator.DungeonGeneratorBiome = BiomeData.Biomes.IndexOf(biome);
            this.biome = biome;
            map        = new int[Board.Width, Board.Height];

            plotCols = Board.Width / plotWidth;
            plotRows = Board.Height / plotHeight;
            if (plotCols * plotWidth < Board.Width)
            {
                plotWidth = Board.Width / plotCols;
            }
            if (plotRows * plotHeight < Board.Height)
            {
                plotHeight = Board.Height / plotRows;
            }

            plots = new Building[plotCols, plotRows];

            if (templates == null)
            {
                templates = new Dictionary <string, List <Template> >();
                var templateSource = Mix.GetTokenTree("buildings.tml");
                CreateRotationsAndFlips(templateSource);
                foreach (var set in templateSource.Where(x => x.Name == "set"))
                {
                    var thisSet = new List <Template>();
                    foreach (var template in set.Tokens.Where(x => x.Name == "template"))
                    {
                        thisSet.Add(new Template(template));
                    }
                    templates.Add(set.Text, thisSet);
                }
            }

            var spill = new Building("<spillover>", null, 0, 0, Culture.DefaultCulture);

            //var justPlaced = false;

            for (var row = 0; row < plotRows; row++)
            {
                for (var col = 0; col < plotCols; col++)
                {
                    if (plots[col, row].BaseID == "<spillover>")
                    {
                        continue;
                    }
                    //Small chance of not having anything here, for variation.
                    if (Random.NextDouble() < 0.2)
                    {
                        //justPlaced = false;
                        continue;
                    }
                    var newTemplate = templates[templateSet].PickOne();
                    //TODO: check if chosen template spills over and if so, if there's room. For now, assume all templates are <= 8
                    //Each plot is 8x8. Given that and the template size, we can wiggle them around a bit from 0 to (8 - tSize).
                    var sX = newTemplate.Width < plotWidth?Random.Next(1, plotWidth - newTemplate.Width) : 0;

                    var sY = newTemplate.Height < plotHeight?Random.Next(1, plotHeight - newTemplate.Height) : 0;

                    //NEW: check for water in this plot.
                    var water = 0;
                    for (var y = 0; y < newTemplate.Height; y++)
                    {
                        for (var x = 0; x < newTemplate.Width; x++)
                        {
                            if (Board.Tilemap[(col * plotWidth) + x, (row * plotHeight) + y].Fluid != Fluids.Dry)
                            {
                                water++;
                            }
                        }
                    }
                    if (water > 0)
                    {
                        continue;
                    }

                    //Later on, we might be able to wiggle them out of their assigned plot a bit.
                    var newBuilding = new Building(string.Format("house{0}x{1}", row, col), newTemplate, sX, sY, Culture);
                    plots[col, row] = newBuilding;
                    //justPlaced = true;
                }
            }
        }
Exemplo n.º 8
0
        public void AddWater(List <Rectangle> safeZones)
        {
            //TODO: Tweak some more to prevent... ahum... water damage.

            var biome         = BiomeData.Biomes[(int)this.GetToken("biome").Value];
            var water         = BiomeData.Biomes[BiomeData.ByName(biome.Realm == Realms.Nox ? "Water" : "KoolAid")];
            var points        = new List <Point>();
            var pointsPerZone = 4;
            var threshold     = 0.66f;

            if (safeZones.Count == 1 && safeZones[0].Left == 0 && safeZones[0].Right == this.Width - 1)
            {
                safeZones.Clear();
                pointsPerZone = 8;
                var x = Random.Next(0, 40);
                var y = Random.Next(0, 10);
                safeZones.Add(new Rectangle()
                {
                    Left = x, Top = y, Right = x + 30, Bottom = y + 14
                });
                threshold = 0.5f;
            }
            foreach (var zone in safeZones)
            {
                for (var i = 0; i < pointsPerZone; i++)
                {
                    var x = Random.Next(zone.Left + 4, zone.Right - 4);
                    var y = Random.Next(zone.Top + 4, zone.Bottom - 4);
                    points.Add(new Point(x, y));
                }
            }

            var bitmap = new float[Height, Width];
            var sum    = 0.0;
            var radius = 0.4;

            for (var y = 0; y < Height; y++)
            {
                for (var x = 0; x < Width; x++)
                {
                    sum = 0;
                    foreach (var point in points)
                    {
                        sum += radius / Math.Sqrt((x - point.X) * (x - point.X) + (y - point.Y) * (y - point.Y));
                    }
                    if (sum > 1.0)
                    {
                        sum = 1.0;
                    }
                    if (sum < 0.0)
                    {
                        sum = 0.0;
                    }
                    bitmap[y, x] = (float)sum;
                }
            }

            for (var y = 0; y < Height; y++)
            {
                for (var x = 0; x < Width; x++)
                {
                    if (bitmap[y, x] < threshold || Tilemap[x, y].SolidToWalker)
                    {
                        continue;
                    }
                    Tilemap[x, y].Fluid = Realm == Realms.Nox ? Fluids.Water : Fluids.KoolAid;

                    /*
                     * Tilemap[x, y] = new Tile()
                     * {
                     *      Character = water.GroundGlyphs[Random.Next(water.GroundGlyphs.Length)],
                     *      Foreground = water.Color.Darken(), //.Darken(water.DarkenPlus + (Random.NextDouble() / water.DarkenDiv)),
                     *      Background = water.Color, //(water.DarkenPlus + (Random.NextDouble() / water.DarkenDiv)),
                     *      Water = true,
                     * };
                     */
                }
            }
        }
Exemplo n.º 9
0
 public void Clear(string biomeName)
 {
     Clear(BiomeData.ByName(biomeName));
 }
Exemplo n.º 10
0
        public static Board CreateDungeon(bool forTravel, string name)
        {
            var host = NoxicoGame.HostForm;
            var nox  = host.Noxico;

            new UIPNGBackground(Mix.GetBitmap("makecave.png")).Draw();
            host.Write("Generating dungeon. Please wait.", Color.Silver, Color.Transparent, 1, 2);
            host.Draw();

            var dunGen  = new StoneDungeonGenerator();
            var caveGen = new CaveGenerator();

            Func <Board, Warp> findWarpSpot = (b) =>
            {
                var eX       = 0;
                var eY       = 0;
                var attempts = 0;
                var minSides = 1;
                while (true)
                {
                    attempts++;
                    if (attempts == 10)
                    {
                        minSides = 0;
                    }

                    eX = Random.Next(1, b.Width - 1);
                    eY = Random.Next(1, b.Height - 1);

                    //2013-03-07: prevent placing warps on same tile as clutter
                    //<Ragath> Kawa, this is bad
                    //<Ragath> that should be a .Any() call
                    //if (b.Entities.FirstOrDefault(e => e.XPosition == eX && e.YPosition == eY) != null)
                    if (b.Entities.Any(e => e.XPosition == eX && e.YPosition == eY))
                    {
                        Program.WriteLine("Tried to place a warp below an entity -- rerolling...");
                        continue;
                    }

                    var sides = 0;
                    if (b.IsSolid(eY - 1, eX))
                    {
                        sides++;
                    }
                    if (b.IsSolid(eY + 1, eX))
                    {
                        sides++;
                    }
                    if (b.IsSolid(eY, eX - 1))
                    {
                        sides++;
                    }
                    if (b.IsSolid(eY, eX + 1))
                    {
                        sides++;
                    }
                    if (sides < 3 && sides >= minSides)
                    {
                        break;
                    }
                }
                return(new Warp()
                {
                    XPosition = eX, YPosition = eY
                });
            };

            Warp originalExit = null;

            BiomeData.LoadBiomes();
            var biomeData = BiomeData.Biomes[DungeonGeneratorBiome];

            /* Step 1 - Randomize jagged array, make boards for each entry.
             * ------------------------------------------------------------
             * ("goal" board is boss/treasure room, picked at random from bottom floor set.)
             * [EXIT] [ 01 ] [ 02 ]
             * [ 03 ] [ 04 ]
             * [ 05 ] [ 06 ] [ 07 ] [ 08 ]
             * [ 09 ] [ 10 ] [ 11 ]
             * [GOAL] [ 13 ]
             */
            var levels = new List <List <Board> >();
            var depth  = Random.Next(3, 6);

            var boardWidths  = new[] { 80, 80, 80, 40, 160, 120 };
            var boardHeights = new[] { 50, 50, 50, 25, 100, 75 };

            for (var i = 0; i < depth; i++)
            {
                levels.Add(new List <Board>());
                var length = Random.Next(2, 5);
                for (var j = 0; j < length; j++)
                {
                    var board = new Board(boardWidths.PickOne(), boardHeights.PickOne());
                    board.AllowTravel = false;
                    board.Clear(DungeonGeneratorBiome);
                    board.BoardNum   = nox.Boards.Count;
                    board.Coordinate = nox.Player.ParentBoard.Coordinate;
                    if (i > 0)
                    {
                        board.AddToken("dark");
                    }
                    nox.Boards.Add(board);
                    levels[i].Add(board);
                }
            }

            //Decide which boards are the exit and goal
            var entranceBoard = levels[0].PickOne();
            var goalBoard     = levels[levels.Count - 1].PickOne();

            //Generate content for each board
            for (var i = 0; i < levels.Count; i++)
            {
                for (var j = 0; j < levels[i].Count; j++)
                {
                    var board = levels[i][j];

                    if (Random.NextDouble() > 0.7 || board == entranceBoard)
                    {
                        caveGen.Board = board;
                        caveGen.Create(biomeData);
                        caveGen.ToTilemap(ref board.Tilemap);
                    }
                    else
                    {
                        dunGen.Board = board;
                        dunGen.Create(biomeData);
                        dunGen.ToTilemap(ref board.Tilemap);
                    }

                    board.Name = string.Format("Level {0}-{1}", i + 1, (char)('A' + j));
                    if (!name.IsBlank())
                    {
                        board.Name = string.Format("{0}, level {1}-{2}", name, i + 1, (char)('A' + j));
                    }
                    board.ID        = string.Format("Dng_{0}_{1}{2}", DungeonGeneratorEntranceBoardNum, i + 1, (char)('A' + j));
                    board.BoardType = BoardType.Dungeon;
                    board.Music     = "set://Dungeon";
                    var encounters = board.GetToken("encounters");
                    foreach (var e in biomeData.Encounters)
                    {
                        encounters.AddToken(e);
                    }
                    encounters.Value = biomeData.MaxEncounters;
                    encounters.GetToken("stock").Value = encounters.Value * Random.Next(3, 5);
                    board.RespawnEncounters();

                    //If this is the entrance board, add a warp back to the Overworld.
                    if (board == entranceBoard)
                    {
                        var exit = findWarpSpot(board);
                        originalExit = exit;
                        exit.ID      = "Dng_" + DungeonGeneratorEntranceBoardNum + "_Exit";
                        board.Warps.Add(exit);
                        board.SetTile(exit.YPosition, exit.XPosition, "dungeonExit");                         //board.SetTile(exit.YPosition, exit.XPosition, '<', Color.Silver, Color.Black);
                    }
                }
            }

            /* Step 2 - Randomly add up/down links
             * -----------------------------------
             * (imagine for the moment that each board can have more than one exit and that this goes for both directions.)
             * [EXIT] [ 01 ] [ 02 ]
             *    |
             * [ 03 ] [ 04 ]
             *           |
             * [ 05 ] [ 06 ] [ 07 ] [ 08 ]
             *    |             |
             * [ 09 ] [ 10 ] [ 11 ]
             *                  |
             *        [GOAL] [ 13 ]
             */
            var connected = new List <Board>();

            for (var i = 0; i < levels.Count; i++)
            {
                var j = Random.Next(0, levels[i].Count);
                //while (connected.Contains(levels[i][j]))
                //	j = Randomizer.Next(0, levels[i].Count);

                var up        = false;
                var destLevel = i + 1;
                if (destLevel == levels.Count)
                {
                    up        = true;
                    destLevel = i - 1;
                }
                var dest = Random.Next(0, levels[destLevel].Count);

                var boardHere  = levels[i][j];
                var boardThere = levels[destLevel][dest];

                var here  = findWarpSpot(boardHere);
                var there = findWarpSpot(boardThere);
                boardHere.Warps.Add(here);
                boardThere.Warps.Add(there);
                here.ID            = boardHere.ID + boardHere.Warps.Count;
                there.ID           = boardThere.ID + boardThere.Warps.Count;
                here.TargetBoard   = boardThere.BoardNum;
                there.TargetBoard  = boardHere.BoardNum;
                here.TargetWarpID  = there.ID;
                there.TargetWarpID = here.ID;
                boardHere.SetTile(here.YPosition, here.XPosition, up ? "dungeonUpstairs" : "dungeonDownstairs");                 //boardHere.SetTile(here.YPosition, here.XPosition, up ? '<' : '>', Color.Gray, Color.Black);
                boardThere.SetTile(there.YPosition, there.XPosition, up ? "dungeonDownstairs" : "dungeonUpstairs");              //boardThere.SetTile(there.YPosition, there.XPosition, !up ? '<' : '>', Color.Gray, Color.Black);

                Program.WriteLine("Connected {0} || {1}.", boardHere.ID, boardThere.ID);

                connected.Add(boardHere);
                connected.Add(boardThere);
            }

            /* Step 3 - Connect the Unconnected
             * --------------------------------
             * [EXIT]=[ 01 ]=[ 02 ]
             *  |
             * [ 03 ]=[ 04 ]
             *           |
             * [ 05 ]=[ 06 ] [ 07 ]=[ 08 ]
             *    |             |
             * [ 09 ]=[ 10 ]=[ 11 ]
             *                  |
             *        [GOAL]=[ 13 ]
             */

            for (var i = 0; i < levels.Count; i++)
            {
                for (var j = 0; j < levels[i].Count - 1; j++)
                {
                    //Don't connect if this board AND the right-hand neighbor are already connected.
                    //if (connected.Contains(levels[i][j]) && connected.Contains(levels[i][j + 1]))
                    //	continue;

                    var boardHere  = levels[i][j];
                    var boardThere = levels[i][j + 1];

                    var here  = findWarpSpot(boardHere);
                    var there = findWarpSpot(boardThere);
                    boardHere.Warps.Add(here);
                    boardThere.Warps.Add(there);
                    here.ID            = boardHere.ID + boardHere.Warps.Count;
                    there.ID           = boardThere.ID + boardThere.Warps.Count;
                    here.TargetBoard   = boardThere.BoardNum;
                    there.TargetBoard  = boardHere.BoardNum;
                    here.TargetWarpID  = there.ID;
                    there.TargetWarpID = here.ID;
                    boardHere.SetTile(here.YPosition, here.XPosition, "dungeonSideexit");                     //boardHere.SetTile(here.YPosition, here.XPosition, '\x2261', Color.Gray, Color.Black);
                    boardThere.SetTile(there.YPosition, there.XPosition, "dungeonSideexit");                  //boardThere.SetTile(there.YPosition, there.XPosition, '\x2261', Color.Gray, Color.Black);

                    Program.WriteLine("Connected {0} -- {1}.", boardHere.ID, boardThere.ID);

                    connected.Add(boardHere);
                    connected.Add(boardThere);
                }
            }

            // Step 4 - place sick lewt in goalBoard
            var treasureX = 0;
            var treasureY = 0;

            while (true)
            {
                treasureX = Random.Next(1, goalBoard.Width - 1);
                treasureY = Random.Next(1, goalBoard.Height - 1);

                //2013-03-07: prevent treasure from spawning inside a wall
                if (goalBoard.IsSolid(treasureY, treasureX))
                {
                    continue;
                }
                //2013-03-07: prevent placing warps on same tile as clutter
                if (goalBoard.Entities.FirstOrDefault(e => e.XPosition == treasureX && e.YPosition == treasureY) != null)
                {
                    Program.WriteLine("Tried to place cave treasure below an entity -- rerolling...");
                    continue;
                }

                var sides = 0;
                if (goalBoard.IsSolid(treasureY - 1, treasureX))
                {
                    sides++;
                }
                if (goalBoard.IsSolid(treasureY + 1, treasureX))
                {
                    sides++;
                }
                if (goalBoard.IsSolid(treasureY, treasureX - 1))
                {
                    sides++;
                }
                if (goalBoard.IsSolid(treasureY, treasureX + 1))
                {
                    sides++;
                }
                if (sides < 3 && sides > 1 && goalBoard.Warps.FirstOrDefault(w => w.XPosition == treasureX && w.YPosition == treasureY) == null)
                {
                    break;
                }
            }
            var treasure = DungeonGenerator.GetRandomLoot("container", "dungeon_chest", new Dictionary <string, string>()
            {
                { "biome", BiomeData.Biomes[DungeonGenerator.DungeonGeneratorBiome].Name.ToLowerInvariant() },
            });
            var treasureChest = new Container(i18n.GetString("treasurechest"), treasure)
            {
                Glyph           = 0x14A,
                XPosition       = treasureX,
                YPosition       = treasureY,
                ForegroundColor = Color.FromName("SaddleBrown"),
                BackgroundColor = Color.Black,
                ParentBoard     = goalBoard,
                Blocking        = false,
            };

            goalBoard.Entities.Add(treasureChest);

            if (forTravel)
            {
                originalExit.TargetBoard = -2;                 //causes Travel menu to appear on use.
                return(entranceBoard);
            }

            var entrance = nox.CurrentBoard.Warps.Find(w => w.ID == DungeonGeneratorEntranceWarpID);

            entrance.TargetBoard      = entranceBoard.BoardNum;        //should be this one.
            entrance.TargetWarpID     = originalExit.ID;
            originalExit.TargetBoard  = nox.CurrentBoard.BoardNum;
            originalExit.TargetWarpID = entrance.ID;

            nox.CurrentBoard.EntitiesToRemove.Add(nox.Player);
            nox.CurrentBoard       = entranceBoard;
            nox.Player.ParentBoard = entranceBoard;
            entranceBoard.Entities.Add(nox.Player);
            nox.Player.XPosition = originalExit.XPosition;
            nox.Player.YPosition = originalExit.YPosition;
            entranceBoard.UpdateLightmap(nox.Player, true);
            entranceBoard.Redraw();
            entranceBoard.PlayMusic();
            NoxicoGame.Immediate = true;
            NoxicoGame.Mode      = UserMode.Walkabout;
            NoxicoGame.Me.SaveGame();

            return(entranceBoard);
        }