############################################################################### # 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. # ############################################################################### {{ -- Call func num times around a circle of radius centered at (x, y) function apply_circle(x, y, num, radius, scale_x, scale_y, func) radius = math.floor(radius) for n = 1, num do local rad = n * 2 * math.pi / num local rx = math.floor(math.cos(rad) * radius * scale_x + 0.5) local ry = math.floor(math.sin(rad) * radius * scale_y + 0.5) func(x + rx, y + ry) end 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() extend_map{width=gxm, height=gym, fill='x'} fill_area{fill='x'} local width = (10 - crawl.random2(7)) local floor = '.' local wall = 'x' -- construct donut fill_area{x1=10, y1=10, x2=gxm-10, y2=10+width, fill=floor} fill_area{x1=10, y1=60-width, x2=gxm-10, y2=gym-10, fill=floor} fill_area{x1=10, y1=10, x2=10+width, y2=gym-10, fill=floor} fill_area{x1=60-width, y1=10, x2=gxm-10, y2=gym-10, fill=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) fill_area{x1=10, y1=gym/2-width2, x2=gxm-10, y2=gym/2+width2, fill=floor} fill_area{x1=gxm/2-width2, y1=10, x2=gxm/2+width2, y2=gym-10, fill=floor} -- sometimes add a small octagon room if crawl.coinflip() then local obl = 0 if crawl.coinflip() then obl = 5 + crawl.random2(20) end local fill = crawl.random_element({ ["."] = 10, ["w"] = 5, ["l"] = 1, }) octa_room{x1=25, y1=25, x2=gxm-25, y2=gym-25, oblique=obl, replace='x', inside=fill} -- decrease spotty chance spotty = crawl.one_chance_in(5) end end local spotty_boxy = crawl.coinflip() local smear_boxy = crawl.coinflip() if spotty then spotty_map{boxy=spotty_boxy} end if not spotty and crawl.one_chance_in(4) or spotty then smear_map{iterations=smears, smear='x', onto='.', boxy=smear_boxy} 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 gxm, gym = dgn.max_bounds() extend_map{width = gxm, height = gym, fill = 'x'} local floor = '.' local wall = 'x' local width = 5 - crawl.random2(5) local height = 5 - crawl.random2(5) -- 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 then if crawl.coinflip() then wall = 'l' else wall = 'w' end end fill_area{fill=wall} -- create window if window then local clear = 'm' fill_area{x1=10, y1=gym/2-height-1, x2=gxm-10, y2=gym/2-height-1, fill=clear} fill_area{x1=10, y1=gym/2+height+1, x2=gxm-10, y2=gym/2+height+1, fill=clear} fill_area{x1=gxm/2-width-1, y1=10, x2=gxm/2-width-1, y2=gym-10, fill=clear} fill_area{x1=gxm/2+width+1, y1=10, x2=gxm/2+width+1, y2=gym-10, fill=clear} end -- create a cross fill_area{x1=10, y1=gym/2-height, x2=gxm-10, y2=gym/2+height, fill=floor} fill_area{x1=gxm/2-width, y1=10, x2=gxm/2+width, y2=gym-10, fill=floor} if not crawl.one_chance_in(4) then spotty_map{boxy = 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 {{ -- Step 1: Big octagon. local gxm, gym = dgn.max_bounds() extend_map{width = gxm, height = gym, fill = 'x'} fill_area{fill = 'x'} local oblique = 10 + crawl.random2(20) octa_room{ x1 = 10, y1 = 10, x2 = gxm-10, y2 = gym-10, oblique = oblique, replace = 'x', inside = '.'} local do_smear = crawl.coinflip() if do_smear then local iterations = 100 + crawl.random2(800) smear_map{iterations = iterations, boxy = false} --Fill in disconnected zones now, prior to adding the stairs. --Temporarily set a (passable) unique symbol in the middle of the map, --to guarantee everything is connected to it after smearing. mapgrd[gxm/2][gym/2] = '@' fill_disconnected{wanted = '@'} mapgrd[gxm/2][gym/2] = '.' end -- Step 2: Add pillars -- pillar types and relative weights local pillar_fill = { ["x"] = 15, ["b"] = 5, ["v"] = 4, ["m"] = 3, ["w"] = 2, ["l"] = 1, } if (you.in_branch("lair")) then pillar_fill["t"] = 15 end -- Potential pillar drawing routines local pillar_func = { make_circle, make_diamond, make_square, 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 pfunc = pillar_func[crawl.random2(#pillar_func) + 1] pfunc = make_diamond 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 local fill = crawl.random_element(pillar_fill) -- beautification hack: no "circle" pillars of radius 1 if pfunc == make_circle and pillar_radius == 1 then fill = crawl.random_element({"G", "X", "t"}) kfeat("X = stone_arch") end -- Finally, make the pillars local make_pillar = function(x, y) return pfunc({ x = x, y = y, radius = pillar_radius, fill = fill}) end apply_circle(gxm/2, gym/2, num, circle_radius, 1, 1, make_pillar) -- 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 = {"{", "(", "["} local down_stairs = {"}", ")", "]"} 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] if loc == 0 then replace_random({find = ".", replace = st, required = true}) elseif loc == 1 then mapgrd[gxm/2 + i - 2][gym/2 + 1 - math.abs(i - 2)] = st elseif loc == 2 then replace_first({ required = true, x = gxm/2 + i - 2, y = 0, xdir = 0, ydir = 1, find = ".", replace = st}) elseif loc == 3 then replace_first({ required = true, x = gxm - 1, y = gym/2 + i - 2, xdir = -1, ydir = 0, find = ".", replace = st}) elseif loc == 4 then replace_first({ required = true, x = gxm/2 + i - 2, y = gym - 1, xdir = 0, ydir = -1, find = ".", replace = st}) elseif loc == 5 then replace_first({ required = true, x = 0, y = gym/2 + i - 2, xdir = 1, ydir = 0, find = ".", replace = st}) end end end }} MAP ENDMAP ############################################################## # layout_rooms # # This replaces dungeon.cc:_plan_3(). # NAME: layout_rooms ORIENT: encompass TAGS: layout allow_dup {{ function 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 join_the_dots_p(start, finish) return join_the_dots({ x1 = start.x, y1 = start.y, x2 = finish.x, y2 = finish.y}) end local gxm, gym = dgn.max_bounds() extend_map{width = gxm, height = gym, fill = 'x'} fill_area{fill = 'x'} 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 = count_antifeature_in_box({ x1 = new_room.x1, y1 = new_room.y1, x2 = new_room.x2, y2 = new_room.y2, feat = "x"}) if (not exclusive or not_walls == 0) then replace_area({ x1 = new_room.x1, y1 = new_room.y1, x2 = new_room.x2, y2 = new_room.y2, find = "x", replace = "."}) if #rooms > 0 and not exclusive2 then join_the_dots_p(random_room_point(new_room), 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 join_the_dots_p(random_room_point(rooms[i]), random_room_point(rooms[i - 1])) end end }} MAP ENDMAP ############################################################## # layout_city # # This replaces dungeon.cc:_city_level(). # NAME: layout_city ORIENT: encompass TAGS: layout allow_dup {{ function treasure_area (x1, y1, x2, y2) x2 = x2 + 1 y2 = y2 + 1 if x2 <= x2 or y2 <= y2 then return false end if (x2 - x1) * (y2 - y1) >= 40 then return false end local tl = dgn.point(x1, y1) local br = dgn.point(x2 - 1, y2 - 1) for point in iter.rect_iterator(tl, br) do if is_valid_coord {x = point.x, y = point.y } then if is_passable_coord { x=point.x, y=point.y } or crawl.coinflip() then mapgrd[point.x][point.y] = "|" end end end return true end local gxm, gym = dgn.max_bounds() extend_map{width = gxm, height = gym, fill = 'x'} fill_area{fill = 'x'} local temp_rand = crawl.random2(8) local wall_type_room local wall_type local rooms = {} local xs = 0 local ys = 0 local ax1 = 0 local bx2 = 0 local ay1 = 0 local by2 = 0 local i, j if temp_rand > 4 then wall_type = 'x' elseif temp_rand > 2 then wall_type = 'c' else wall_type = 'v' end if crawl.one_chance_in(100) then wall_type = 'b' end fill_area { x1=8, y1=8, x2=gxm-9, y2=gym-9, fill="." } for i = 0, 5 do for j = 0, 4 do xs = 8 + (i * 13) ys = 8 + (j * 14) a1 = xs + crawl.random2avg(5, 2); a2 = ys + crawl.random2avg(5, 2); b1 = xs + 11 - crawl.random2avg(5, 2); b2 = ys + 11 - crawl.random2avg(5, 2); temp_rand = crawl.random2(280); if temp_rand > 39 and is_valid_coord {x=a1, y=a2} and is_valid_coord{x=b1, y=b2} then if temp_rand > 63 then wall_type_room = wall_type elseif temp_rand > 54 then wall_type_room = "c" elseif temp_rand > 45 then wall_type_room = "x" else wall_type_room = "v" end if crawl.one_chance_in(250) then wall_type_room = "b" end table.insert(rooms, {a1, a2, b1, b2}) make_box { x1=a1, y1=a2, x2=b1, y2=b2, wall=wall_type_room } if b1 - a1 > 5 and b2 - a2 > 5 and crawl.one_chance_in(8) then table.insert(rooms, {a1+2, a2+2, b1-2, b2-2}) make_box { x1=a1+2, y1=a2+2, x2=b1-2, y2=b2-2, wall=wall_type_room } if crawl.one_chance_in(3) then treasure_area(a1+3, a2+3, b1-3, b2-3) end end end end end for _, room in ipairs(rooms) do local doors = 1 + crawl.random2(5) - crawl.random2(3) if doors < 1 then doors = 1 end if doors > 3 and crawl.one_chance_in(3) then doors = 2 end make_box_doors {x1=room[1], y1=room[2], x2=room[3], y2=room[4], number=doors} end }} MAP ENDMAP