summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-17 03:49:50 +0000
committerennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-17 03:49:50 +0000
commit3e02b2afba0e18c584f423ab303cbb24ba4ef313 (patch)
tree4d0b996775c7e98d7dca8e351e6cb71d92c6f7d9
parentad41d5694a9a1c298965910184fefe6ac3e677db (diff)
downloadcrawl-ref-3e02b2afba0e18c584f423ab303cbb24ba4ef313.tar.gz
crawl-ref-3e02b2afba0e18c584f423ab303cbb24ba4ef313.zip
Outsourced the cross and the large octagon room to the (new) layout.des file. The octagon room is especially more random now, with different types, sizes, and numbers of pillars as well as more interesting stair placement.
Vaults with the "layout" tag: 1) Aren't ever chosen as a random vault. 2) Are treated as normal level, so that other vaults can be placed over top. 3) Should probably be encompassing. 4) Currently only occur with the same frequency as the cross/octagon did. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5096 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/dat/clua/loadmaps.lua5
-rw-r--r--crawl-ref/source/dat/layout.des303
-rw-r--r--crawl-ref/source/dungeon.cc64
-rw-r--r--crawl-ref/source/maps.cc2
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;