diff options
-rw-r--r-- | crawl-ref/source/dat/clua/loadmaps.lua | 5 | ||||
-rw-r--r-- | crawl-ref/source/dat/layout.des | 303 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.cc | 64 | ||||
-rw-r--r-- | crawl-ref/source/maps.cc | 2 |
4 files changed, 327 insertions, 47 deletions
diff --git a/crawl-ref/source/dat/clua/loadmaps.lua b/crawl-ref/source/dat/clua/loadmaps.lua index c462002101..ae1bb54600 100644 --- a/crawl-ref/source/dat/clua/loadmaps.lua +++ b/crawl-ref/source/dat/clua/loadmaps.lua @@ -8,8 +8,9 @@ local des_files = { "altar.des", "bazaar.des", "entry.des", "elf.des", "float.des", "hells.des", - "hive.des", "lab.des", "lair.des", "large.des", "mini.des", "orc.des", - "pan.des", "portal.des", "temple.des", "vaults.des", "crypt.des", "zot.des" + "hive.des", "lab.des", "lair.des", "large.des", "layout.des", "mini.des", + "orc.des", "pan.des", "portal.des", "temple.des", "vaults.des", "crypt.des", + "zot.des" } for _, file in ipairs(des_files) do diff --git a/crawl-ref/source/dat/layout.des b/crawl-ref/source/dat/layout.des new file mode 100644 index 0000000000..0727074e79 --- /dev/null +++ b/crawl-ref/source/dat/layout.des @@ -0,0 +1,303 @@ +############################################################################### +# 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. +# +############################################################################### + +lua {{ + function fill_area(x1, y1, x2, y2, feature) + for x = x1, x2 do + for y = y1, y2 do + dgn.grid(x, y, feature) + end + end + end + + function octa_room(x1, y1, x2, y2, oblique, floor) + local ob_temp = oblique + + local rock_wall = dgn.feature_number("rock_wall") + local shallow_water = dgn.feature_number("shallow_water") + + for x = x1, x2 do + for y = y1 + ob_temp, y2 - ob_temp do + if dgn.grid(x, y) == rock_wall then + dgn.grid(x, y, floor) + end + if dgn.grid(x, y) == floor and floor == shallow_water then + dgn.grid(x, y, shallow_water) + end + end + + if x > x2 - oblique then + ob_temp = ob_temp + 1 + elseif ob_temp > 0 then + ob_temp = ob_temp - 1 + end + end + end + + function pillars(center_x, center_y, num, flip_x, big_radius, + pillar_radius, pillar_routine, fill) + for i = 0, num - 1 do + local angle = i * 2 * math.pi / num + local x = math.floor(math.cos(angle) * big_radius * flip_x + 0.5) + local y = math.floor(math.sin(angle) * big_radius + 0.5) + + pillar_routine(center_x + x, center_y + y, pillar_radius, fill) + end + end + + -- begin pillar functions + function pillar_square(center_x, center_y, radius, fill) + for x = -radius, radius do + for y = -radius, radius do + dgn.grid(center_x + x, center_y + y, fill) + end + end + end + + function pillar_rounded_square(center_x, center_y, radius, fill) + for x = -radius, radius do + for y = -radius, radius do + if math.abs(x) ~= radius or math.abs(y) ~= radius then + dgn.grid(center_x + x, center_y + y, fill) + end + end + end + end + + function pillar_circle(center_x, center_y, radius, fill) + for x = -radius, radius do + for y = -radius, radius do + if x * x + y * y < radius * radius then + dgn.grid(center_x + x, center_y + y, fill) + end + end + end + end + -- end pillar functions + + function select_from_weighted_table(tb) + local value = nil + local rollsize = 0 + for temp_val, temp_weight in pairs (tb) do + if rollsize == 0 then + value = temp_val + rollsize = temp_weight + else + rollsize = rollsize + temp_weight + if crawl.random2(rollsize) < temp_weight then + value = temp_val + end + end + end + + return value + end + + -- Randomly selects a grid with feature 'search' and sets it to 'replace' + function replace_random(search, replace) + local gxm, gym = dgn.max_bounds() + + local feature = nil, x, y + while feature ~= search do + x = crawl.random2(gxm) + y = crawl.random2(gym) + feature = dgn.grid(x, y) + end + + dgn.grid(x, y, replace) + end + + function valid(x, y) + local gxm, gym = dgn.max_bounds() + return (x >= 0 and y >= 0 and x < gxm and y < gym) + end + + -- Walks from x, y along dx,dy until it finds 'search' + function replace_first(x, y, dx, dy, search, replace) + + local feature = dgn.grid(x, y) + + while feature ~= search and valid(x,y) do + x = x + dx + y = y + dy + feature = dgn.grid(x, y) + end + + if valid(x, y) then + dgn.grid(x, y, replace) + return true + else + return false + end + end +}} + +############################################################## +# 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 + fill_area(0, 0, gxm-1, gym-1, wall) + + -- create window + if window then + local clear = dgn.feature_number("clear_rock_wall") + fill_area(10, gym/2 - height - 1, gxm - 10, gym/2 - height - 1, clear) + fill_area(10, gym/2 + height + 1, gxm - 10, gym/2 + height + 1, clear) + fill_area(gxm/2 - width - 1, 10, gxm/2 - width - 1, gym - 10, clear) + fill_area(gxm/2 + width + 1, 10, gxm/2 + width + 1, gym - 10, clear) + end + + -- create a cross + fill_area(10, gym/2 - height, gxm - 10, gym/2 + height, floor) + fill_area(gxm/2 - width, 10, gxm/2 + width, gym - 10, floor) + + -- TODO enne - add lua function for spotty() +}} +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) + + -- Step 1: Create octagon + fill_area(0, 0, gxm - 1, gym - 1, wall) + octa_room(10, 10, gxm - 10, gym - 10, oblique, floor) + + -- 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(select_from_weighted_table(pillar_fill)) + + -- Potential pillar drawing routines + local pillar_func = {pillar_circle, pillar_square, pillar_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 + 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 + 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 = replace_first(gxm/2 + i - 2, 0, 0, 1, floor, st) + elseif loc == 3 then + ret = replace_first(gxm - 1, gym/2 + i - 2, -1, 0, floor, st) + elseif loc == 4 then + ret = replace_first(gxm/2 + i - 2, gym - 1, 0, -1, floor, st) + elseif loc == 5 then + ret = replace_first(0, gym/2 + i - 2, 1, 0, floor, st) + end + + assert(ret) + end + end +}} +MAP +. +ENDMAP diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 443a62e419..0e74a08826 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -169,7 +169,7 @@ static void _spotty_level(bool seeded, int iterations, bool boxy); static void _bigger_room(); static void _plan_main(int level_number, int force_plan); static char _plan_1(); -static char _plan_2(); +static char _plan_2(int level_number); static char _plan_3(); static char _plan_4(char forbid_x1, char forbid_y1, char forbid_x2, char forbid_y2, dungeon_feature_type force_wall); @@ -639,7 +639,9 @@ static void _register_place(const vault_placement &place) { _dgn_register_vault(place.map); - _mask_vault(place, MMT_VAULT | MMT_NO_DOOR); + if (!place.map.has_tag("layout")) + _mask_vault(place, MMT_VAULT | MMT_NO_DOOR); + if (place.map.has_tag("no_monster_gen")) _mask_vault(place, MMT_NO_MONS); @@ -4273,9 +4275,11 @@ static bool _build_vaults(int level_number, int force_vault, int rune_subst, mapgen_report_map_use(place.map); #endif + bool is_layout = place.map.has_tag("layout"); + // If the map takes the whole screen or we were only requested to // build the vault, our work is done. - if (gluggy == MAP_ENCOMPASS || build_only) + if (gluggy == MAP_ENCOMPASS && !is_layout || build_only) return (true); // Does this level require Dis treatment (metal wallification)? @@ -4299,7 +4303,7 @@ static bool _build_vaults(int level_number, int force_vault, int rune_subst, { _plan_4(v1x, v1y, v2x, v2y, DNGN_METAL_WALL); } - else + else if (!is_layout) { dgn_region_list excluded_regions; excluded_regions.push_back( dgn_region::absolute(v1x, v1y, v2x, v2y) ); @@ -5767,7 +5771,7 @@ static void _plan_main(int level_number, int force_plan) force_plan = 1 + random2(12); do_stairs = ((force_plan == 1) ? _plan_1() : - (force_plan == 2) ? _plan_2() : + (force_plan == 2) ? _plan_2(level_number) : (force_plan == 3) ? _plan_3() : (force_plan == 4) ? _plan_4(0, 0, 0, 0, NUM_FEATURES) : (force_plan == 5) ? (one_chance_in(9) ? _plan_5() @@ -5864,19 +5868,17 @@ static char _plan_1() return (one_chance_in(5) ? 3 : 2); } // end plan_1() -// just a cross: -static char _plan_2() +static char _plan_2(int level_number) { dgn_Build_Method = "plan_2"; - char width2 = (5 - random2(5)); // value range of [1,5] {dlb} + const int vault = random_map_for_tag("layout", false, true); + ASSERT(vault != -1); - _replace_area(10, (35 - width2), (GXM - 10), (35 + width2), - DNGN_ROCK_WALL, DNGN_FLOOR); - _replace_area((40 - width2), 10, (40 + width2), (GYM - 10), - DNGN_ROCK_WALL, DNGN_FLOOR); + bool success = _build_vaults(level_number, vault); + _ensure_vault_placed(success); - return (one_chance_in(4) ? 2 : 3); + return (one_chance_in(4) ? 0 : 1); } // end plan_2() static char _plan_3() @@ -6100,39 +6102,11 @@ static char _plan_6(int level_number) { dgn_Build_Method = "plan_6"; - spec_room sr; + const int vault = random_map_for_tag("layout", false, true); + ASSERT(vault != -1); - // circle of standing stones (well, kind of) - sr.x1 = 10; - sr.x2 = (GXM - 10); - sr.y1 = 10; - sr.y2 = (GYM - 10); - - _octa_room(sr, 14, DNGN_FLOOR); - - _replace_area(23, 23, 26, 26, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(23, 47, 26, 50, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(55, 23, 58, 26, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(55, 47, 58, 50, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(39, 20, 43, 23, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(39, 50, 43, 53, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(20, 30, 23, 33, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(20, 40, 23, 43, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(58, 30, 61, 33, DNGN_FLOOR, DNGN_STONE_WALL); - _replace_area(58, 40, 61, 43, DNGN_FLOOR, DNGN_STONE_WALL); - - grd[35][32] = DNGN_STONE_WALL; - grd[46][32] = DNGN_STONE_WALL; - grd[35][40] = DNGN_STONE_WALL; - grd[46][40] = DNGN_STONE_WALL; - - grd[69][34] = DNGN_STONE_STAIRS_DOWN_I; - grd[69][35] = DNGN_STONE_STAIRS_DOWN_II; - grd[69][36] = DNGN_STONE_STAIRS_DOWN_III; - - grd[10][34] = DNGN_STONE_STAIRS_UP_I; - grd[10][35] = DNGN_STONE_STAIRS_UP_II; - grd[10][36] = DNGN_STONE_STAIRS_UP_III; + bool success = _build_vaults(level_number, vault); + _ensure_vault_placed(success); // This "back door" is often one of the easier ways to get out of // pandemonium... the easiest is to use the banish spell. diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc index 665c8e22ad..044ae2a47f 100644 --- a/crawl-ref/source/maps.cc +++ b/crawl-ref/source/maps.cc @@ -361,6 +361,7 @@ int random_map_for_place(const level_id &place, bool want_minivault) // We also accept tagged levels here. if (vdefs[i].place == place && vdefs[i].is_minivault() == want_minivault + && !vdefs[i].has_tag("layout") && vault_unforbidden(vdefs[i])) { rollsize += vdefs[i].chance; @@ -398,6 +399,7 @@ int random_map_in_depth(const level_id &place, bool want_minivault) && !vdefs[i].has_tag("pan") && !vdefs[i].has_tag("unrand") && !vdefs[i].has_tag("bazaar") + && !vdefs[i].has_tag("layout") && vault_unforbidden(vdefs[i])) { rollsize += vdefs[i].chance; |