###############################################################################
# layout.des: All large layout vaults go here.  These are defined by having
#             both ORIENT: encompass and TAGS: layout.  These are not true
#             vaults, in that the dungeon builder can add other vaults on
#             top of them.
#
###############################################################################

{{
    function dgn.random_room_point(room)
      return dgn.point(room.x1 + crawl.random2(room.x2 - room.x1),
                       room.y1 + crawl.random2(room.y2 - room.y1))
    end

    function dgn.join_the_dots_p(start, finish)
      return dgn.join_the_dots(start.x, start.y, finish.x, finish.y)
    end
}}

##############################################################
# layout_forbidden_doughnut
#
# This replaces dungeon.cc:_plan_1().  It usually creates a
# room with a large hole in the middle.
#
NAME:   layout_forbidden_donut
ORIENT: encompass
TAGS:   layout allow_dup

{{
    local gxm, gym = dgn.max_bounds()
    local wall = dgn.feature_number("rock_wall")
    local floor = dgn.feature_number("floor")
    dgn.fill_area(0, 0, gxm - 1, gym - 1, wall)

    local width = (10 - crawl.random2(7))

    -- construct donut
    dgn.fill_area(10, 10, gxm - 10, 10 + width, floor)
    dgn.fill_area(10, 60 - width, gxm - 10, gym - 10, floor)
    dgn.fill_area(10, 10, 10 + width, gym - 10, floor)
    dgn.fill_area(60 - width, 10, gxm - 10, gym - 10, floor)

    local spotty = crawl.coinflip()
    local smears = crawl.random2(300)

    -- sometimes add a hallway cross through center
    if crawl.coinflip() then
        local width2 = 1 + crawl.random2(5)

        dgn.fill_area(10, gym/2 - width2, gxm - 10, gym/2 + width2, floor)
        dgn.fill_area(gxm/2 - width2, 10, gxm/2 + width2, gym - 10, floor)

        -- sometimes add a small octagon room
        if crawl.coinflip() and crawl.random2(15) > 7 then
            local oblique = 0
            if crawl.coinflip() then
                oblique = 5 + crawl.random2(20)
            end

            local feature_name = crawl.random_element({
                ["floor"]      = 5,
                ["deep_water"] = 1,
                ["lava"]       = 1,
            })
            dgn.octa_room(25, 25, gxm - 25, gym - 25, oblique, feature_name)

            -- decrease spotty chance
            spotty = crawl.one_chance_in(5)
        end
    end

    local spotty_boxy = crawl.coinflip()
    local smear_boxy = crawl.coinflip()

    if spotty then
        dgn.spotty_level(true, 0, spotty_boxy)
    end
    if not spotty and crawl.one_chance_in(4) or spotty then
        dgn.smear_feature(smears, smear_boxy, wall, 0, 0, gxm - 1, gym - 1)
    end
}}
MAP
ENDMAP

##############################################################
# layout_cross
#
# This replaces dungeon.cc:_plan_2().  It creates a large cross
# of varying width.
#
NAME:    layout_cross
ORIENT:  encompass
TAGS:    layout allow_dup

{{
    local width = 5 - crawl.random2(5)
    local height = 5 - crawl.random2(5)

    local gxm, gym = dgn.max_bounds()

    local wall = dgn.feature_number("rock_wall")
    local floor = dgn.feature_number("floor")

    -- Include a small possibility of adding windows around the cross.
    -- This layout can get used with spotty_level, so don't make this
    -- chance too large as lava/water prevents that from happening.
    local window = crawl.one_chance_in(20)

    if window or crawl.one_chance_in(20) then
        if crawl.coinflip() then
            wall = dgn.feature_number("lava")
        else
            wall = dgn.feature_number("deep_water")
        end
    end

    -- fill with rock
    dgn.fill_area(0, 0, gxm-1, gym-1, wall)

    -- create window
    if window then
        local clear = dgn.feature_number("clear_rock_wall")
        dgn.fill_area(10, gym/2 - height - 1, gxm - 10, gym/2 - height - 1, clear)
        dgn.fill_area(10, gym/2 + height + 1, gxm - 10, gym/2 + height + 1, clear)
        dgn.fill_area(gxm/2 - width - 1, 10, gxm/2 - width - 1, gym - 10, clear)
        dgn.fill_area(gxm/2 + width + 1, 10, gxm/2 + width + 1, gym - 10, clear)
    end

    -- create a cross
    dgn.fill_area(10, gym/2 - height, gxm - 10, gym/2 + height, floor)
    dgn.fill_area(gxm/2 - width, 10, gxm/2 + width, gym - 10, floor)

    if not crawl.one_chance_in(4) then
        dgn.spotty_level(true, 0, crawl.coinflip())
    end
}}
MAP
ENDMAP

#############################################################
# layout_big_octagon
#
# This replaces dungeon.cc:_plan_6().  It has an octagonal
# room with some number of pillars in the middle.  The stairs
# are generally all grouped together.
#

NAME: layout_big_octagon
ORIENT:  encompass
TAGS:    layout allow_dup

{{
    local gxm, gym = dgn.max_bounds()
    local wall = dgn.feature_number("rock_wall")
    local floor = dgn.feature_number("floor")

    local oblique = 10 + crawl.random2(20)

    dgn.fill_area(0, 0, gxm - 1, gym - 1, "rock_wall")
    dgn.octa_room(10, 10, gxm - 10, gym - 10, oblique, "floor")

    local smear = crawl.coinflip()
    if smear then
        local iterations = 100 + crawl.random2(500 - oblique * 12)
        dgn.smear_feature(iterations, false, wall, 0, 0, gxm - 1, gym - 1)
    end

    -- Step 2: Add pillars

    -- pillar types and relative weights
    local pillar_fill = {
        ["rock_wall"]          = 15,
        ["green_crystal_wall"] = 5,
        ["metal_wall"]         = 4,
        ["clear_rock_wall"]    = 3,
        ["deep_water"]         = 2,
        ["lava"]               = 1,
    }
    local fill = dgn.feature_number(crawl.random_element(pillar_fill))

    -- Potential pillar drawing routines
    local pillar_func = {
        dgn.make_circle,
        dgn.make_square,
        dgn.make_rounded_square
    }

    -- Pillar size params
    -- NOTE: Be careful about tweaking the ranges here.  Pillars that are
    -- too large, close, or large in number can entirely surround the center.
    local type = crawl.random2(#pillar_func) + 1
    local num = 3 + crawl.random2(9)
    local pillar_radius = 1 + crawl.random2(3)
    local circle_radius = 2 + crawl.random2(6) + pillar_radius * 2 + num / 2


    -- beautification hack: no "circle" pillars of radius 1
    if type == 1 and pillar_radius == 1 then
        fill = dgn.feature_number("stone_arch")
    end

    -- Finally, make the pillars
    dgn.make_pillars(gxm/2, gym/2, num, 1, circle_radius, pillar_radius,
                     pillar_func[type], fill)

    -- Step 3: Create stairs

    -- Potential stair locations
    -- 0) random
    -- 1) inside
    -- 2) up
    -- 3) right
    -- 4) down
    -- 5) left

    local up_loc = crawl.random2(6)
    local down_loc = crawl.random2(6)
    while up_loc == down_loc do
        down_loc = crawl.random2(6)
    end

    local up_stairs = {
        dgn.feature_number("stone_stairs_up_i"),
        dgn.feature_number("stone_stairs_up_ii"),
        dgn.feature_number("stone_stairs_up_iii"),
    }
    local down_stairs = {
        dgn.feature_number("stone_stairs_down_i"),
        dgn.feature_number("stone_stairs_down_ii"),
        dgn.feature_number("stone_stairs_down_iii"),
    }
    local full_stair_set = {[up_loc] = up_stairs, [down_loc] = down_stairs}

    for loc, stair_list in pairs (full_stair_set) do
        for i = 1, #stair_list do
            local st = stair_list[i]
            local ret = true

            if loc == 0 then
                dgn.replace_random(floor, stair_list[i])
            elseif loc == 1 then
                dgn.grid(gxm/2 + i - 2, gym/2 + 1 - math.abs(i - 2), st)
            elseif loc == 2 then
                ret = dgn.replace_first(gxm/2 + i-2, 0, 0, 1, floor, st)
            elseif loc == 3 then
                ret = dgn.replace_first(gxm - 1, gym/2 + i-2, -1, 0, floor, st)
            elseif loc == 4 then
                ret = dgn.replace_first(gxm/2 + i-2, gym - 1, 0, -1, floor, st)
            elseif loc == 5 then
                ret = dgn.replace_first(0, gym/2 + i-2, 1, 0, floor, st)
            end

            assert(ret)
        end
    end

    if smear then
        dgn.fill_disconnected_zones(0, 0, gxm - 1, gym - 1, wall)
    end
}}
MAP
ENDMAP

##############################################################
# layout_rooms
#
# This replaces dungeon.cc:_plan_3().
#
NAME: layout_rooms
ORIENT: encompass
TAGS: layout allow_dup
{{
    local wall = dgn.feature_number("rock_wall")
    local floor = dgn.feature_number("floor")

    local num_rooms = 30 + crawl.random2(90)
    local exclusive = not crawl.one_chance_in(10)
    local exclusive2 = crawl.coinflip()

    local rooms = {}

    for i = 0, num_rooms do
      local new_room = {
        x1 = 10 + crawl.random2(50),
        y1 = 10 + crawl.random2(40)
      }
      new_room.x2 = new_room.x1 + 2 + crawl.random2(8)
      new_room.y2 = new_room.y1 + 2 + crawl.random2(8)

      local not_walls = dgn.count_antifeature_in_box(new_room.x1 - 1,
                    new_room.y1 - 1, new_room.x2 + 1, new_room.y2 + 1, wall)
      if (not exclusive or not_walls == 0) then
        dgn.replace_area(new_room.x1, new_room.y1, new_room.x2,
                         new_room.y2, wall, floor);

        if #rooms > 0 and not exclusive2 then
          dgn.join_the_dots_p(dgn.random_room_point(new_room),
                              dgn.random_room_point(rooms[#rooms]))
        end

        table.insert(rooms, new_room)
        if #rooms >= 30 then
          break
        end
      end
    end

    if exclusive2 then
      for i = 2, #rooms do
        dgn.join_the_dots_p(dgn.random_room_point(rooms[i]),
                            dgn.random_room_point(rooms[i - 1]))
      end
    end
}}
MAP
ENDMAP