Attached Files:
|
0001-Translated-pools-layout-code-to-C.patch [^] (82,124 bytes) 2013-04-18 06:00 [Show Content] [Hide Content]From 7c60fba388559ce91fdc33eae51bd83e9a4a170d Mon Sep 17 00:00:00 2001
From: infiniplex <infiniplex@hotmail.com>
Date: Wed, 17 Apr 2013 18:28:53 -0600
Subject: [PATCH] Translated "pools" layout code to C++
---
crawl-ref/source/dat/des/builder/layout.des | 126 +++
.../source/dat/des/builder/layout_gehenna.des | 647 +++++++++++++
crawl-ref/source/dat/des/builder/layout_pools.des | 1023 --------------------
crawl-ref/source/l_dgnbld.cc | 466 +++++++++
4 files changed, 1239 insertions(+), 1023 deletions(-)
create mode 100644 crawl-ref/source/dat/des/builder/layout_gehenna.des
delete mode 100644 crawl-ref/source/dat/des/builder/layout_pools.des
diff --git a/crawl-ref/source/dat/des/builder/layout.des b/crawl-ref/source/dat/des/builder/layout.des
index f36facb..0393aa3 100644
--- a/crawl-ref/source/dat/des/builder/layout.des
+++ b/crawl-ref/source/dat/des/builder/layout.des
@@ -621,6 +621,12 @@ TAGS: overwritable layout allow_dup unrand
MAP
ENDMAP
+##############################################################
+# layout_caves
+#
+# One (sometimes more) large open caverns with irregular
+# walls.
+#
NAME: layout_caves
DEPTH: 9-22, !Dis, !Geh, Orc, Slime
CHANCE: 100% (Orc), 100% (Slime)
@@ -661,6 +667,125 @@ TAGS: overwritable layout allow_dup unrand
MAP
ENDMAP
+##############################################################
+# layout_cave_pools
+#
+# This layout creates an irregular cave with clumps of rock and
+# possibly a few pools of water. There are more pools at
+# deeper depths. Starting at depth 19, there is an increasing
+# chance of lava pools instead of water pools (never mixed).
+#
+NAME: layout_cave_pools
+DEPTH: D:9-
+WEIGHT: 10
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map { width = gxm, height = gym, fill = 'x' }
+
+ layout_type "caves"
+
+ -- without a starting floor patch, spotty_map will crash
+ mapgrd[gxm/2][gym/2] = '.'
+ spotty_map { boxy = false, iterations = 1000 }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ local pool_contents = {}
+ pool_contents["."] = 40
+ pool_contents["x"] = 40 - you.absdepth()
+ if crawl.coinflip() then
+ if you.absdepth() >= 19 + crawl.random2(8) then
+ pool_contents["l"] = you.absdepth() * crawl.random2(100) / 100
+ else
+ pool_contents["w"] = you.absdepth() * crawl.random2(100) / 100
+ end
+ end
+
+ add_pools { replace = ".",
+ pool_size = 10 + crawl.random2(15),
+ contents = pool_contents,
+ frequency = pool_frequency }
+
+ widen_paths { find = "x", percent = 30 }
+ remove_isolated_glyphs { find = "x", percent = 80 }
+ widen_paths { find = "l", percent = 30 }
+ remove_isolated_glyphs { find = "l", percent = 75, boxy = true }
+}}
+MAP
+ENDMAP
+
+#############################################################
+# layout_honeycomb
+#
+# This layout is composed of a series of irregular rooms
+# directly beside each other. They are sometimes connected
+# by doors and sometimes just by holes in the wall.
+#
+NAME: layout_honeycomb
+DEPTH: D:15-
+WEIGHT: 10
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map { width = gxm, height = gym, fill = 'x' }
+
+ layout_type "rooms"
+
+ make_circle { x = gxm/2, y = gym/2, radius = 10 }
+ mapgrd[gxm/2][gym/2] = '.'
+ spotty_map { boxy = true, iterations = 1200 }
+ widen_paths { find = "x", percent = 50 }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ local fill = '.'
+ local border = 'x'
+ local connection = crawl.random_element({[fill] = 1, ["+"] = 2})
+
+ add_pools { replace = ".",
+ contents = {[fill] = 1},
+ pool_size = 25 + crawl.random2(25),
+ border = border }
+
+ -- connect rooms
+ for i = 1, crawl.random_range(800, 1200) do
+ local x = crawl.random_range(1, gxm - 2)
+ local y = crawl.random_range(1, gym - 2)
+
+ if mapgrd[x][y] == border then
+ if mapgrd[x + 1][y] == border and
+ mapgrd[x - 1][y] == border and
+ mapgrd[x][y + 1] == fill and
+ mapgrd[x][y - 1] == fill then
+ mapgrd[x][y] = connection
+ elseif mapgrd[x + 1][y] == fill and
+ mapgrd[x - 1][y] == fill and
+ mapgrd[x][y + 1] == border and
+ mapgrd[x][y - 1] == border then
+ mapgrd[x][y] = connection
+ end
+ end
+ end
+
+ replace_closest { x = gxm/2, y = gym/2, find = fill, replace = '@' }
+ fill_disconnected{wanted = '@'}
+ subst("@ = " .. fill)
+
+ random_wall_material(_G)
+}}
+# Enforce minimum floor size - this is important
+validate {{
+ if count_feature_in_box { feat="."} < 600 then
+ return false
+ else
+ return true
+ end
+}}
+MAP
+ENDMAP
+
+##############################################################
# A long winding cavern of roughly constant width, snaking around all the
# level. It forks from time to time, but never for long.
NAME: layout_twisted_cavern
@@ -689,6 +814,7 @@ TAGS: overwritable layout allow_dup unrand
end
}}
+##############################################################
## This replaces dungeon.cc:_roguey_level.
NAME: layout_roguey
DEPTH: 2-, !Pan, !Zot, !Dis, !Geh
diff --git a/crawl-ref/source/dat/des/builder/layout_gehenna.des b/crawl-ref/source/dat/des/builder/layout_gehenna.des
new file mode 100644
index 0000000..8acca97
--- /dev/null
+++ b/crawl-ref/source/dat/des/builder/layout_gehenna.des
@@ -0,0 +1,647 @@
+##############################################################
+# layout_gehenna.des
+#
+# NOTE: There are other Gehenna layouts in other files.
+#
+# These layouts are long canyons with lava pools in them and
+# rock "pools" to provide cover. The up stairs may be placed
+# randomly or at one end of the canyon, while the down stairs
+# are always placed randomly. Deeper maps have fewer, larger
+# pools, of which more are lava and fewer are rock.
+#
+# The approximate shape the each canyon is shown above the
+# layout vault.
+#
+# Simply put, the algorithm is:
+# 1. Draw the rough layout shape with fill_area
+# 2. Grow a cave map with spotty_map
+# 3. Add the stairs (pools must go around these)
+# 4. Add the lava and rock pools with add_pools
+# 5. Fix up lava and rock pools to look good and have wider
+# paths
+#
+
+
+#
+# Constants and function
+#
+# These are collected together here instead of in the layout
+# vaults because they are each used in more than one.
+#
+# These maps have a small chance of placing the up stairs.
+# This is handlied by always generating the layout as if
+# the stairs were to be placed, but only sometimes adding
+# them.
+#
+
+{{
+ -- Increasing this makes the caves bigger
+ CANYON_SIZE_FACTOR = 100
+
+ -- The distance stairs are placed from the edge of the map
+ STAIRS_FROM_MAP_EDGE = 15
+
+ -- The chance that the up stairs are deliberately placed,
+ -- usually at the canyon end: increasing this makes diving
+ -- longer and thus harder
+ STAIRS_PLACE_PERCENT = 20
+
+ -- The width of the path before the caves are grown is 1 + 2 * size
+ PATH_SIZE_BASIC = 2
+ PATH_SIZE_TRIPLE = 1
+
+ -- The spacing between 3 stairs placed together on the
+ -- _straight, _big_room, _U_turn, _T, and _trident layouts
+ STAIRS_SPACING_X = 3
+ STAIRS_SPACING_Y = 8
+
+ -- The horizontal path in the _corner, U_turn, and _box
+ -- layouts is placed this far from the center of the room
+ BASIC_PATH_OFFSET_Y = 15
+
+ -- The spacing between the three paths on the _parallel and
+ -- _trident layouts
+ TRIPLE_PATH_SPACING = 22
+
+
+
+ -- add and fix up the lava and rock pools
+ function gehenna_layout_epilogue (e)
+ -- you.depth() is the depth in the current branch
+ local branch_depth = dgn.br_depth(you.branch())
+ local depth_fraction = (you.depth() / branch_depth)
+
+ local pool_contents = {}
+ pool_contents["c"] = branch_depth * 2 - you.depth()
+ pool_contents["l"] = branch_depth + you.depth()
+ pool_contents["."] = branch_depth
+ if pool_contents["."] <= 0 then
+ pool_contents["."] = nil
+ end
+
+ e.widen_paths { find = "x", percent = 10 }
+ e.add_pools { replace = ".",
+ pool_size = 60 - 25 * depth_fraction,
+ contents = pool_contents }
+ e.widen_paths { find = "c", percent = 90 }
+ e.subst("c = x")
+ e.remove_isolated_glyphs { find = "x", percent = 75 }
+ e.widen_paths { find = "l", percent = 60 }
+ e.remove_isolated_glyphs { find = "l", percent = 90, boxy = true }
+ end
+}}
+
+
+
+# ( )
+# {+-------+}
+# [ ]
+NAME: layout_gehenna_straight
+DEPTH: Geh
+WEIGHT: 20
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
+ local STAIRS_X_DOWN1 = gxm - STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_DOWN23 = gxm - STAIRS_FROM_MAP_EDGE - STAIRS_SPACING_X
+
+ local STAIRS_Y_1 = gym / 2
+ local STAIRS_Y_2 = STAIRS_Y_1 - STAIRS_SPACING_Y
+ local STAIRS_Y_3 = STAIRS_Y_1 + STAIRS_SPACING_Y
+
+ fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_UP23, y2 = STAIRS_Y_3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
+ x2 = STAIRS_X_DOWN1, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_DOWN23, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_DOWN23, y2 = STAIRS_Y_3,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (4 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
+ mapgrd[STAIRS_X_UP23 ][STAIRS_Y_2] = '('
+ mapgrd[STAIRS_X_UP23 ][STAIRS_Y_3] = '['
+ shuffle("{([")
+
+ -- uncomment to place down stairs at other end
+ --mapgrd[STAIRS_X_DOWN1 ][STAIRS_Y_1] = '}'
+ --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_2] = ')'
+ --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_3] = ']'
+ --shuffle("})]")
+ --shuffle("{([/})]")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# +
+# ( / \ )
+# {+-+ ? +-+}
+# [ \ / ]
+# +
+NAME: layout_gehenna_big_room
+DEPTH: Geh
+WEIGHT: 25
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
+ local STAIRS_X_DOWN1 = gxm - STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_DOWN23 = gxm - STAIRS_FROM_MAP_EDGE - STAIRS_SPACING_X
+
+ local STAIRS_Y_1 = gym / 2
+ local STAIRS_Y_2 = STAIRS_Y_1 - STAIRS_SPACING_Y
+ local STAIRS_Y_3 = STAIRS_Y_1 + STAIRS_SPACING_Y
+
+ local big_room_x = gxm / 2 + crawl.random_range(-2, 2)
+ local big_room_y = gym / 2 + crawl.random_range(-5, 5)
+ local big_room_radius = crawl.random_range(15, 20)
+
+ fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_UP23, y2 = STAIRS_Y_3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
+ x2 = STAIRS_X_DOWN1, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_DOWN23, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_DOWN23, y2 = STAIRS_Y_3,
+ fill = '.' }
+
+ make_diamond { x = big_room_x, y = big_room_y,
+ radius = big_room_radius, fill = '.' }
+
+ if crawl.coinflip() then
+ make_diamond { x = big_room_x, y = big_room_y,
+ radius = big_room_radius - PATH_SIZE_BASIC * 2,
+ fill = 'x' }
+ end
+
+ spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
+ mapgrd[STAIRS_X_UP23 ][STAIRS_Y_2] = '('
+ mapgrd[STAIRS_X_UP23 ][STAIRS_Y_3] = '['
+ shuffle("{([")
+
+ -- uncomment to place down stairs at other end
+ --mapgrd[STAIRS_X_DOWN1 ][STAIRS_Y_1] = '}'
+ --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_2] = ')'
+ --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_3] = ']'
+ --shuffle("})]")
+ --shuffle("{([/})]")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# (
+# {+-------+
+# [ |
+# |
+# (-+-]
+# }
+NAME: layout_gehenna_corner
+DEPTH: Geh
+WEIGHT: 10
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
+ local STAIRS_X_DOWN2 = gxm - STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_DOWN1 = STAIRS_X_DOWN2 - STAIRS_SPACING_Y
+ local STAIRS_X_DOWN3 = STAIRS_X_DOWN1 - STAIRS_SPACING_Y
+
+ local STAIRS_Y_UP1 = gym / 2 - BASIC_PATH_OFFSET_Y
+ local STAIRS_Y_UP2 = STAIRS_Y_UP1 - STAIRS_SPACING_Y
+ local STAIRS_Y_UP3 = STAIRS_Y_UP1 + STAIRS_SPACING_Y
+ local STAIRS_Y_DOWN1 = gym - STAIRS_FROM_MAP_EDGE
+ local STAIRS_Y_DOWN23 = STAIRS_Y_DOWN1 - STAIRS_SPACING_X
+
+ fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_UP2,
+ x2 = STAIRS_X_UP23, y2 = STAIRS_Y_UP3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_UP1 - PATH_SIZE_BASIC,
+ x2 = STAIRS_X_DOWN1, y2 = STAIRS_Y_UP1 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_DOWN1 - PATH_SIZE_BASIC, y1 = STAIRS_Y_UP1,
+ x2 = STAIRS_X_DOWN1 + PATH_SIZE_BASIC, y2 = STAIRS_Y_DOWN1,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_DOWN2, y1 = STAIRS_Y_DOWN23,
+ x2 = STAIRS_X_DOWN3, y2 = STAIRS_Y_DOWN23,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP1 ][STAIRS_Y_UP1] = '{'
+ mapgrd[STAIRS_X_UP23 ][STAIRS_Y_UP2] = '('
+ mapgrd[STAIRS_X_UP23 ][STAIRS_Y_UP3] = '['
+ shuffle("{([")
+
+ -- uncomment to place down stairs at vertical end of canyon
+ --mapgrd[STAIRS_X_DOWN1][STAIRS_Y_DOWN1] = '}'
+ --mapgrd[STAIRS_X_DOWN2][STAIRS_Y_DOWN23] = ')'
+ --mapgrd[STAIRS_X_DOWN3][STAIRS_Y_DOWN23] = ']'
+ --shuffle("})]")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# (
+# {+-------+
+# [ |
+# |
+# ) |
+# }+-------+
+# ]
+NAME: layout_gehenna_U_turn
+DEPTH: Geh
+WEIGHT: 5
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_1 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
+ local ROOM_END_X = gxm - STAIRS_FROM_MAP_EDGE
+
+ local STAIRS_Y_UP1 = gym / 2 - BASIC_PATH_OFFSET_Y
+ local STAIRS_Y_UP2 = STAIRS_Y_UP1 - STAIRS_SPACING_Y
+ local STAIRS_Y_UP3 = STAIRS_Y_UP1 + STAIRS_SPACING_Y
+ local STAIRS_Y_DOWN1 = gym / 2 + BASIC_PATH_OFFSET_Y
+ local STAIRS_Y_DOWN2 = STAIRS_Y_DOWN1 - STAIRS_SPACING_Y
+ local STAIRS_Y_DOWN3 = STAIRS_Y_DOWN1 + STAIRS_SPACING_Y
+
+ fill_area { x1 = STAIRS_X_23, y1 = STAIRS_Y_UP2,
+ x2 = STAIRS_X_23, y2 = STAIRS_Y_UP3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_1, y1 = STAIRS_Y_UP1 - PATH_SIZE_BASIC,
+ x2 = ROOM_END_X, y2 = STAIRS_Y_UP1 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = ROOM_END_X - PATH_SIZE_BASIC, y1 = STAIRS_Y_UP1,
+ x2 = ROOM_END_X + PATH_SIZE_BASIC, y2 = STAIRS_Y_DOWN1,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_1, y1 = STAIRS_Y_DOWN1 - PATH_SIZE_BASIC,
+ x2 = ROOM_END_X, y2 = STAIRS_Y_DOWN1 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_23, y1 = STAIRS_Y_DOWN2,
+ x2 = STAIRS_X_23, y2 = STAIRS_Y_DOWN3,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (7 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_1 ][STAIRS_Y_UP1] = '{'
+ mapgrd[STAIRS_X_23][STAIRS_Y_UP2] = '('
+ mapgrd[STAIRS_X_23][STAIRS_Y_UP3] = '['
+ shuffle("{([")
+
+ -- uncomment to place down stairs on other branch of U
+ --mapgrd[STAIRS_X_1 ][STAIRS_Y_DOWN1] = '}'
+ --mapgrd[STAIRS_X_23][STAIRS_Y_DOWN2] = ')'
+ --mapgrd[STAIRS_X_23][STAIRS_Y_DOWN3] = ']'
+ --shuffle("})]")
+ --shuffle("{([/})]")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# )
+# ( |
+# {+--------}
+# [ |
+# ]
+NAME: layout_gehenna_T
+DEPTH: Geh
+WEIGHT: 10
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
+ local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
+
+ local STAIRS_Y_1 = gym / 2
+ local STAIRS_Y_UP2 = STAIRS_Y_1 - STAIRS_SPACING_Y
+ local STAIRS_Y_UP3 = STAIRS_Y_1 + STAIRS_SPACING_Y
+ local STAIRS_Y_DOWN2 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_Y_DOWN3 = gym - STAIRS_FROM_MAP_EDGE
+
+ fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_UP2,
+ x2 = STAIRS_X_UP23, y2 = STAIRS_Y_UP3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
+ fill = '.' }
+
+ fill_area { x1 = STAIRS_X_DOWN - PATH_SIZE_BASIC, y1 = STAIRS_Y_DOWN2,
+ x2 = STAIRS_X_DOWN + PATH_SIZE_BASIC, y2 = STAIRS_Y_DOWN3,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (4.5 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
+ mapgrd[STAIRS_X_UP23][STAIRS_Y_UP2] = '('
+ mapgrd[STAIRS_X_UP23][STAIRS_Y_UP3] = '['
+ mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
+ mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN2] = ')'
+ mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN3] = ']'
+
+ shuffle("{([")
+ shuffle("})]")
+ shuffle("{([/})]")
+
+ -- remove to place down stairs at other end
+ subst("})] = .")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# ( )
+# | |
+# {---------}
+# | |
+# [ ]
+NAME: layout_gehenna_H
+DEPTH: Geh
+WEIGHT: 5
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
+
+ local STAIRS_Y_1 = gym / 2
+ local STAIRS_Y_2 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_Y_3 = gym - STAIRS_FROM_MAP_EDGE
+
+ fill_area { x1 = STAIRS_X_DOWN - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_DOWN + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_UP + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_2] = '('
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_3] = '['
+ shuffle("{([")
+
+ -- uncomment to place down stairs in canyon branches at other end
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_2] = ')'
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_3] = ']'
+ --shuffle("})]")
+ --shuffle("{([/})]")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# (---------)
+# | |
+# { }
+# | |
+# [---------]
+NAME: layout_gehenna_box
+DEPTH: Geh
+WEIGHT: 10
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
+
+ local STAIRS_Y_1 = gym / 2
+ local STAIRS_Y_2 = STAIRS_Y_1 - BASIC_PATH_OFFSET_Y
+ local STAIRS_Y_3 = STAIRS_Y_1 + BASIC_PATH_OFFSET_Y
+
+ fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_2 - PATH_SIZE_BASIC,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_2 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_3 - PATH_SIZE_BASIC,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_3 + PATH_SIZE_BASIC,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_UP + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_DOWN - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
+ x2 = STAIRS_X_DOWN + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (7.5 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_2] = '('
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_3] = '['
+ shuffle("{([")
+
+ -- uncomment to place down stairs at other side of box
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_2] = ')'
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_3] = ']'
+ --shuffle("})]")
+ --shuffle("{([/})]")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# (-----+---)
+# |
+# {--+--+---}
+# |
+# [--+------]
+NAME: layout_gehenna_parallel
+DEPTH: Geh
+WEIGHT: 5
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
+ local X_LENGTH = STAIRS_X_DOWN - STAIRS_X_UP
+
+ local STAIRS_Y_1 = gym / 2
+ local STAIRS_Y_2 = STAIRS_Y_1 - TRIPLE_PATH_SPACING
+ local STAIRS_Y_3 = STAIRS_Y_1 + TRIPLE_PATH_SPACING
+
+ local branch_x_1 = STAIRS_X_UP +
+ X_LENGTH * crawl.random_range(20, 80) / 100
+ local branch_x_2 = STAIRS_X_UP +
+ X_LENGTH * crawl.random_range(20, 80) / 100
+
+ -- parallel hallways
+ fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_1 - PATH_SIZE_TRIPLE,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_TRIPLE,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_2 - PATH_SIZE_TRIPLE,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_2 + PATH_SIZE_TRIPLE,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_3 - PATH_SIZE_TRIPLE,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_3 + PATH_SIZE_TRIPLE,
+ fill = '.' }
+
+ -- connections
+ fill_area { x1 = branch_x_1 - PATH_SIZE_TRIPLE, y1 = STAIRS_Y_2,
+ x2 = branch_x_1 + PATH_SIZE_TRIPLE, y2 = STAIRS_Y_1,
+ fill = '.' }
+ fill_area { x1 = branch_x_2 - PATH_SIZE_TRIPLE, y1 = STAIRS_Y_1,
+ x2 = branch_x_2 + PATH_SIZE_TRIPLE, y2 = STAIRS_Y_3,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (6 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_2] = '('
+ mapgrd[STAIRS_X_UP ][STAIRS_Y_3] = '['
+ shuffle("{([")
+
+ -- uncomment to place down stairs at other ends of canyons
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_2] = ')'
+ --mapgrd[STAIRS_X_DOWN][STAIRS_Y_3] = ']'
+ --shuffle("})]")
+ --shuffle("{([/})]")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
+
+# +----)
+# ( |
+# {+--------}
+# [ |
+# +----]
+NAME: layout_gehenna_trident
+DEPTH: Geh
+WEIGHT: 10
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand no_rotate
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map{width = gxm, height = gym, fill = 'x'}
+
+ layout_type "caves"
+
+ local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
+ local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
+ local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
+ local BRANCH_X = gxm / 2
+
+ local STAIRS_Y_1 = gym / 2
+ local STAIRS_Y_UP2 = STAIRS_Y_1 - STAIRS_SPACING_Y
+ local STAIRS_Y_UP3 = STAIRS_Y_1 + STAIRS_SPACING_Y
+ local STAIRS_Y_DOWN2 = STAIRS_Y_1 - TRIPLE_PATH_SPACING
+ local STAIRS_Y_DOWN3 = STAIRS_Y_1 + TRIPLE_PATH_SPACING
+
+ fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_UP2,
+ x2 = STAIRS_X_UP23, y2 = STAIRS_Y_UP3,
+ fill = '.' }
+ fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
+ x2 = BRANCH_X, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
+ fill = '.' }
+
+ fill_area { x1 = BRANCH_X - PATH_SIZE_TRIPLE, y1 = STAIRS_Y_DOWN2,
+ x2 = BRANCH_X + PATH_SIZE_TRIPLE, y2 = STAIRS_Y_DOWN3,
+ fill = '.' }
+
+ fill_area { x1 = BRANCH_X, y1 = STAIRS_Y_1 - PATH_SIZE_TRIPLE,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_TRIPLE,
+ fill = '.' }
+ fill_area { x1 = BRANCH_X, y1 = STAIRS_Y_DOWN2 - PATH_SIZE_TRIPLE,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_DOWN2 + PATH_SIZE_TRIPLE,
+ fill = '.' }
+ fill_area { x1 = BRANCH_X, y1 = STAIRS_Y_DOWN3 - PATH_SIZE_TRIPLE,
+ x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_DOWN3 + PATH_SIZE_TRIPLE,
+ fill = '.' }
+
+ spotty_map { boxy = false, iterations = (5.5 * CANYON_SIZE_FACTOR) }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ if crawl.random2(100) < STAIRS_PLACE_PERCENT then
+ mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
+ mapgrd[STAIRS_X_UP23][STAIRS_Y_UP2] = '('
+ mapgrd[STAIRS_X_UP23][STAIRS_Y_UP3] = '['
+ mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
+ mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN2] = ')'
+ mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN3] = ']'
+
+ shuffle("{([")
+ shuffle("})]")
+ shuffle("{([/})]")
+
+ -- remove to place down stairs at other end(s) of canyon
+ subst("})] = .")
+ end
+
+ gehenna_layout_epilogue(_G)
+}}
diff --git a/crawl-ref/source/dat/des/builder/layout_pools.des b/crawl-ref/source/dat/des/builder/layout_pools.des
deleted file mode 100644
index e66419a..0000000
--- a/crawl-ref/source/dat/des/builder/layout_pools.des
+++ /dev/null
@@ -1,1023 +0,0 @@
-###############################################################################
-# layout_pools.des: The "pools" layout vaults go here. These layouts are each
-# a large, irregular open area mostly filled with clumps of
-# some glyph. These are not true vaults, in that the dungeon
-# builder can add other vaults on top of them.
-#
-###############################################################################
-
-{{
- -- replace all cells with the specified glyph bordered by
- -- floor in all four cardinal directions
- function remove_isolated_glyphs (e, replace, percent)
- local gxm, gym = dgn.max_bounds()
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if e.mapgrd[x ][y ] == replace and
- e.mapgrd[x + 1][y ] == '.' and
- e.mapgrd[x - 1][y ] == '.' and
- e.mapgrd[x ][y + 1] == '.' and
- e.mapgrd[x ][y - 1] == '.' and
- crawl.random2(100) < percent then
- e.mapgrd[x][y] = '.'
- end
- end
- end
- end
-
- -- replace all cells with the specified glyph bordered by at
- -- least on floor with floor cells
- function widen_paths (e, replace, percent)
- local gxm, gym = dgn.max_bounds()
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if e.mapgrd[x][y] == replace and
- crawl.random2(100) < percent then
- if e.mapgrd[x - 1][y ] == '.' or
- e.mapgrd[x + 1][y ] == '.' or
- e.mapgrd[x ][y - 1] == '.' or
- e.mapgrd[x ][y + 1] == '.' then
- e.mapgrd[x][y] = '_'
- end
- end
- end
- end
- e.subst("_ = .")
- end
-
-
-
- -- the relative positions of a cell's neighbours
- -- these go with the add_pools function
- local NEIGHBOUR_COUNT = 4
- local NEIGHBOUR_OFFSETS = { { x=1, y=0 },
- { x=-1, y=0 },
- { x=0, y=1 },
- { x=0, y=-1 } }
-
- --
- -- add_pools
- --
- -- Purpose: To fill the portion of the map with the
- -- specified floor glyph with irregular areas of
- -- the specified pool glyphs, seperated by paths
- -- of the floor glyph. There is always a path
- -- around the pools. Border cells are excluded.
- -- Parameter(s):
- -- <1> e: The global enviroment
- -- <2> floor: The floor glyph
- -- <3> pool_elements: The pool glyphs, in the format
- -- required for the
- -- crawl.random_element function
- -- <4> pool_frequency: The number of pools to place,
- -- expressed as a fraction from
- -- 0.0 (no pools) to
- -- 1.0 (1 pool per floor cell)
- -- Precondition(s):
- -- <1> e ~= nil
- -- <2> pool_elements ~= nil
- -- <3> pool_frequency >= 0
- -- <4> pool_frequency <= 1
- -- Returns: N/A
- -- Side Effect: Pools of types choosen randomly from
- -- pool_elements are added to the portion of
- -- mapgrd filled with floor glyphs. A
- -- differant pool type is chosen for each
- -- pool. The number of pools is equal to
- -- pool_fraction times the number fo cells
- -- that originally had glyph floor.
- --
- -- TODO: translate this function to C++
- --
-
- function add_pools (e, floor, pool_elements, pool_frequency)
- assert(e ~= nil, "e cannot be nil")
- assert(pool_elements ~= nil, "pool_elements cannot be nil")
- assert(pool_frequency >= 0, "pool_frequency must be >= 0")
- assert(pool_frequency <= 1, "pool_frequency must be <= 1")
-
- --
- -- The basic ideas here is that we place a number of
- -- pool "seeds" on the map and spread them outward
- -- randomly until they run into each other. We never
- -- fill in the last cell, so they never actually
- -- touch and we get paths between them.
- --
- -- The algorithm we use to spread the pools is like a
- -- depth-/breadth-first search, except that:
- -- 1. We choose a random element from the open list
- -- 2. We have multiple starting locations, each
- -- with its own "closed" value
- -- 3. We mark all cells bordered by 2 (or more)
- -- non-BORDER closed values with special closed
- -- value BORDER
- --
- -- In the end, we used the "closed" values to determine
- -- which pool we are in. The BORDER value indicates
- -- a path between pools.
- --
-
- local NO_POOL = 999997 -- must be lowest constant
- local IN_LIST = 999998
- local BORDER = 999999
- local FORBIDDEN = 1000000
-
- -- The minimum seperation distance for pool seeds
- local MIN_SEED_SEPERATION_DISTANCE = 2
-
- local gxm, gym = dgn.max_bounds()
-
-
-
- -- a helper function to select the pool seed positions
- function getPoolSeedPositions (aa_pool_index,
- pool_frequency,
- min_seperation)
- assert(aa_pool_index ~= nil, "aa_pool_index cannot be nil")
- assert(pool_frequency >= 0, "pool_frequency must be >= 0")
- assert(pool_frequency <= 1, "pool_frequency must be <= 1")
- assert(min_seperation > 0, "min_seperation must be positive")
-
- local gxm, gym = dgn.max_bounds()
-
- -- 1. Find all floor positions
-
- local a_floor_positions = {}
- a_floor_positions.count = 0
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if aa_pool_index[x][y] == NO_POOL then
- a_floor_positions[a_floor_positions.count] = {}
- a_floor_positions[a_floor_positions.count].x = x
- a_floor_positions[a_floor_positions.count].y = y
- a_floor_positions.count = a_floor_positions.count + 1
- end
- end
- end
-
- -- 2. Choose the pool seed positions
-
- local min_seperation_squared = min_seperation * min_seperation
- local pool_count_goal = math.floor(a_floor_positions.count *
- pool_frequency)
-
- local a_seeds = {}
- a_seeds.count = 0
-
- for i = 1, pool_count_goal do
- -- choose a random position
- if a_floor_positions.count <= 0 then
- -- give up if no more positions
- break
- end
-
- local index_chosen = crawl.random2(a_floor_positions.count)
- local x = a_floor_positions[index_chosen].x
- local y = a_floor_positions[index_chosen].y
- a_floor_positions.count = a_floor_positions.count - 1
- a_floor_positions[index_chosen].x =
- a_floor_positions[a_floor_positions.count].x
- a_floor_positions[index_chosen].y =
- a_floor_positions[a_floor_positions.count].y
-
- -- check if it is too close to another seed
- local too_close = false
- for j = 0, a_seeds.count - 1 do
- local diff_x = x - a_seeds[j].x
- local diff_y = y - a_seeds[j].y
- local distance_squared = diff_x * diff_x + diff_y * diff_y
-
- if distance_squared < min_seperation_squared then
- too_close = true
- break
- end
- end
-
- -- if not too close, add it to the list
- if not too_close then
- a_seeds[a_seeds.count] = {}
- a_seeds[a_seeds.count].x = x
- a_seeds[a_seeds.count].y = y
- a_seeds.count = a_seeds.count + 1
- end
- end
-
- -- 3. Return the pool seeds
-
- return a_seeds
- end
-
- -- a helper function to add a cell's neighbours to the open list
- function add_neighbours_to_open_list (aa_pool_index, x, y, a_open_list)
- local gxm, gym = dgn.max_bounds()
-
- for n = 1, NEIGHBOUR_COUNT do
- nx = x + NEIGHBOUR_OFFSETS[n].x
- ny = y + NEIGHBOUR_OFFSETS[n].y
-
- assert(nx >= 0, "nx must be >= 0")
- assert(nx < gxm, "nx must be < gxm")
- assert(ny >= 0, "ny must be >= 0")
- assert(ny < gym, "ny must be < gym")
-
- if aa_pool_index[nx][ny] == NO_POOL then
- aa_pool_index[nx][ny] = IN_LIST
- a_open_list[a_open_list.count] = {}
- a_open_list[a_open_list.count].x = nx
- a_open_list[a_open_list.count].y = ny
- a_open_list.count = a_open_list.count + 1
- end
- end
- end
-
-
-
- -- Step 1: Make a 2D array to store which pool each cell is part of
-
- local aa_pool_index = {}
- for x = 1, gxm - 2 do
- aa_pool_index[x] = {}
-
- for y = 1, gym - 2 do
- if e.mapgrd[x][y] == floor then
- aa_pool_index[x][y] = NO_POOL
- else
- aa_pool_index[x][y] = FORBIDDEN
- end
- end
- end
-
- -- Step 2: Place the pool seeds and add neighbours to the open list
-
- local a_pool_position = getPoolSeedPositions(
- aa_pool_index,
- pool_frequency,
- MIN_SEED_SEPERATION_DISTANCE)
- local a_open_list = {}
- a_open_list.count = 0
-
- for p = 0, a_pool_position.count - 1 do
- local x = a_pool_position[p].x
- local y = a_pool_position[p].y
-
- aa_pool_index[x][y] = p
- add_neighbours_to_open_list(aa_pool_index, x, y, a_open_list)
- end
-
- -- Step 3: Spread out pools as far as possible
-
- while a_open_list.count > 0 do
- -- remove a random position from the open list
- local index_chosen = crawl.random2(a_open_list.count)
- local x = a_open_list[index_chosen].x
- local y = a_open_list[index_chosen].y
- a_open_list.count = a_open_list.count - 1
- a_open_list[index_chosen].x = a_open_list[a_open_list.count].x
- a_open_list[index_chosen].y = a_open_list[a_open_list.count].y
-
- -- choose which neighbouring pool to join
- local chosen_pool = NO_POOL
- for n = 1, NEIGHBOUR_COUNT do
- nx = x + NEIGHBOUR_OFFSETS[n].x
- ny = y + NEIGHBOUR_OFFSETS[n].y
-
- assert(nx >= 0, "nx must be >= 0")
- assert(nx < gxm, "nx must be < gxm")
- assert(ny >= 0, "ny must be >= 0")
- assert(ny < gym, "ny must be < gym")
-
- neighbour_pool = aa_pool_index[nx][ny]
-
- if neighbour_pool < NO_POOL then
- -- valid pool
- if chosen_pool == NO_POOL or
- chosen_pool == neighbour_pool then
- chosen_pool = neighbour_pool
- else
- -- between pools
- chosen_pool = BORDER
- end
- end
-
- if neighbour_pool == FORBIDDEN then
- -- next to a wall
- chosen_pool = BORDER
- end
- end
- -- assert(chosen_pool ~= NO_POOL, "no neighbouring pools")
-
- if chosen_pool ~= NO_POOL then
- -- add this cell to the appropriate pool
- aa_pool_index[x][y] = chosen_pool
- add_neighbours_to_open_list(aa_pool_index, x, y, a_open_list)
- end
- end
-
- -- Step 4: Add the pools to the map
-
- local a_pool_glyph = {}
- for p = 0, a_pool_position.count - 1 do
- a_pool_glyph[p] = crawl.random_element(pool_elements)
- end
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if aa_pool_index[x][y] < NO_POOL then
- e.mapgrd[x][y] = a_pool_glyph[aa_pool_index[x][y]]
- end
- end
- end
- end
-}}
-
-
-
-#
-# Gehenna layout constants and functions
-#
-# These are collected together here instead of in the layout
-# vaults because they are each used in more than one.
-#
-{{
- -- Increasing this makes the caves bigger
- CANYON_SIZE_FACTOR = 100
-
- -- The distance stairs are placed from the edge of the map
- STAIRS_FROM_MAP_EDGE = 15
-
- -- The chance that the up stairs are deliberately placed,
- -- usually at the canyon end: increasing this makes diving
- -- longer and thus harder
- STAIRS_PLACE_PERCENT = 20
-
- -- The width of the path before the caves are grown is 1 + 2 * size
- PATH_SIZE_BASIC = 2
- PATH_SIZE_TRIPLE = 1
-
- -- The spacing between 3 stairs placed together on the
- -- _straight, _big_room, _U_turn, _T, and _trident layouts
- STAIRS_SPACING_X = 3
- STAIRS_SPACING_Y = 8
-
- -- The horizontal path in the _corner, U_turn, and _box
- -- layouts is placed this far from the center of the room
- BASIC_PATH_OFFSET_Y = 15
-
- -- The spacing between the three paths on the _parallel and
- -- _trident layouts
- TRIPLE_PATH_SPACING = 22
-
-
-
- -- add and fix up the lava and rock pools
- function gehenna_layout_epilogue (e)
- -- you.depth() is the depth in the current branch
- local branch_depth = dgn.br_depth(you.branch())
- local depth_fraction = (you.depth() / branch_depth)
-
- local pool_frequency = 0.025 - depth_fraction * 0.01
- if pool_frequency < 0 then
- pool_frequency = 0
- elseif pool_frequency > 1 then
- pool_frequency = 1
- end
-
- local pool_contents = {}
- pool_contents["c"] = branch_depth * 2 - you.depth()
- pool_contents["l"] = branch_depth + you.depth()
- pool_contents["."] = branch_depth
- if pool_contents["."] <= 0 then
- pool_contents["."] = nil
- end
-
- widen_paths(e, 'x', 25)
- add_pools(e, '.', pool_contents, pool_frequency)
- widen_paths(e, 'c', 95)
- e.subst("c = x")
- remove_isolated_glyphs(e, 'x', 75)
- widen_paths(e, 'l', 80)
- remove_isolated_glyphs(e, 'l', 90)
- end
-}}
-
-
-
-##############################################################
-# layout_pools
-#
-# This layout creates an irregular cave with clumps of rock and
-# a few pools of water. There are more pools at deeper depths.
-# Starting at depth 19, there is an increasing chance of lava
-# pools instead of water pools (never mixed).
-#
-NAME: layout_pools
-DEPTH: D:4-
-WEIGHT: 5
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map { width = gxm, height = gym, fill = 'x' }
-
- layout_type "pools"
-
- -- without a starting floor patch, spotty_map will crash
- mapgrd[gxm/2][gym/2] = '.'
- spotty_map { boxy = false, iterations = 1000 }
- remove_isolated_glyphs(_G, 'x', 100)
-
- local pool_frequency = 0.04 + crawl.random2(60) / 1000
- local pool_contents = {}
- pool_contents["w"] = you.absdepth() * crawl.random2(100) / 100
- pool_contents["."] = 40
- pool_contents["x"] = 40 - you.absdepth()
- if you.absdepth() >= 19 + crawl.random2(8) then
- pool_contents["l"] = pool_contents["w"]
- pool_contents["w"] = nil
- end
-
- add_pools(_G, '.', pool_contents, pool_frequency)
- remove_isolated_glyphs(_G, 'x', 80)
- widen_paths(_G, 'x', 60)
- widen_paths(_G, 'l', 80)
- remove_isolated_glyphs(_G, 'l', 75)
-}}
-MAP
-ENDMAP
-
-##############################################################
-# layout_gehenna_???
-#
-# These layouts are long canyons with lava pools in them and
-# rock "pools" to provide cover. The up stairs may be placed
-# randomly or at one end of the canyon, while the down stairs
-# are always placed randomly. Deeper maps have fewer, larger
-# pools, of which more are lava and fewer are rock.
-#
-# The approximate shape the each canyon is shown above the
-# layout vault.
-#
-# Simply put, the algorithm is:
-# 1. Draw the rough layout shape with fill_area
-# 2. Grow a cave map with spotty_map
-# 3. Add the stairs (pools must go around these)
-# 4. Add the lava and rock pools with add_pools
-# 5. Fix up lava and rock pools to look good and have wider
-# paths
-#
-
-# ( )
-# {+-------+}
-# [ ]
-NAME: layout_gehenna_straight
-DEPTH: Geh
-WEIGHT: 20
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
- local STAIRS_X_DOWN1 = gxm - STAIRS_FROM_MAP_EDGE
- local STAIRS_X_DOWN23 = gxm - STAIRS_FROM_MAP_EDGE - STAIRS_SPACING_X
-
- local STAIRS_Y_1 = gym / 2
- local STAIRS_Y_2 = STAIRS_Y_1 - STAIRS_SPACING_Y
- local STAIRS_Y_3 = STAIRS_Y_1 + STAIRS_SPACING_Y
-
- fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_UP23, y2 = STAIRS_Y_3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
- x2 = STAIRS_X_DOWN1, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = STAIRS_X_DOWN23, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_DOWN23, y2 = STAIRS_Y_3,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (4 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
- mapgrd[STAIRS_X_UP23 ][STAIRS_Y_2] = '('
- mapgrd[STAIRS_X_UP23 ][STAIRS_Y_3] = '['
- shuffle("{([")
-
- -- uncomment to place down stairs at other end
- --mapgrd[STAIRS_X_DOWN1 ][STAIRS_Y_1] = '}'
- --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_2] = ')'
- --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_3] = ']'
- --shuffle("})]")
- --shuffle("{([/})]")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# +
-# ( / \ )
-# {+-+ ? +-+}
-# [ \ / ]
-# +
-NAME: layout_gehenna_big_room
-DEPTH: Geh
-WEIGHT: 25
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
- local STAIRS_X_DOWN1 = gxm - STAIRS_FROM_MAP_EDGE
- local STAIRS_X_DOWN23 = gxm - STAIRS_FROM_MAP_EDGE - STAIRS_SPACING_X
-
- local STAIRS_Y_1 = gym / 2
- local STAIRS_Y_2 = STAIRS_Y_1 - STAIRS_SPACING_Y
- local STAIRS_Y_3 = STAIRS_Y_1 + STAIRS_SPACING_Y
-
- local big_room_x = gxm / 2 + crawl.random_range(-2, 2)
- local big_room_y = gym / 2 + crawl.random_range(-5, 5)
- local big_room_radius = crawl.random_range(15, 20)
-
- fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_UP23, y2 = STAIRS_Y_3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
- x2 = STAIRS_X_DOWN1, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = STAIRS_X_DOWN23, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_DOWN23, y2 = STAIRS_Y_3,
- fill = '.' }
-
- make_diamond { x = big_room_x, y = big_room_y,
- radius = big_room_radius, fill = '.' }
-
- if crawl.coinflip() then
- make_diamond { x = big_room_x, y = big_room_y,
- radius = big_room_radius - PATH_SIZE_BASIC * 2,
- fill = 'x' }
- end
-
- spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
- mapgrd[STAIRS_X_UP23 ][STAIRS_Y_2] = '('
- mapgrd[STAIRS_X_UP23 ][STAIRS_Y_3] = '['
- shuffle("{([")
-
- -- uncomment to place down stairs at other end
- --mapgrd[STAIRS_X_DOWN1 ][STAIRS_Y_1] = '}'
- --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_2] = ')'
- --mapgrd[STAIRS_X_DOWN23][STAIRS_Y_3] = ']'
- --shuffle("})]")
- --shuffle("{([/})]")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# (
-# {+-------+
-# [ |
-# |
-# (-+-]
-# }
-NAME: layout_gehenna_corner
-DEPTH: Geh
-WEIGHT: 10
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
- local STAIRS_X_DOWN2 = gxm - STAIRS_FROM_MAP_EDGE
- local STAIRS_X_DOWN1 = STAIRS_X_DOWN2 - STAIRS_SPACING_Y
- local STAIRS_X_DOWN3 = STAIRS_X_DOWN1 - STAIRS_SPACING_Y
-
- local STAIRS_Y_UP1 = gym / 2 - BASIC_PATH_OFFSET_Y
- local STAIRS_Y_UP2 = STAIRS_Y_UP1 - STAIRS_SPACING_Y
- local STAIRS_Y_UP3 = STAIRS_Y_UP1 + STAIRS_SPACING_Y
- local STAIRS_Y_DOWN1 = gym - STAIRS_FROM_MAP_EDGE
- local STAIRS_Y_DOWN23 = STAIRS_Y_DOWN1 - STAIRS_SPACING_X
-
- fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_UP2,
- x2 = STAIRS_X_UP23, y2 = STAIRS_Y_UP3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_UP1 - PATH_SIZE_BASIC,
- x2 = STAIRS_X_DOWN1, y2 = STAIRS_Y_UP1 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = STAIRS_X_DOWN1 - PATH_SIZE_BASIC, y1 = STAIRS_Y_UP1,
- x2 = STAIRS_X_DOWN1 + PATH_SIZE_BASIC, y2 = STAIRS_Y_DOWN1,
- fill = '.' }
- fill_area { x1 = STAIRS_X_DOWN2, y1 = STAIRS_Y_DOWN23,
- x2 = STAIRS_X_DOWN3, y2 = STAIRS_Y_DOWN23,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP1 ][STAIRS_Y_UP1] = '{'
- mapgrd[STAIRS_X_UP23 ][STAIRS_Y_UP2] = '('
- mapgrd[STAIRS_X_UP23 ][STAIRS_Y_UP3] = '['
- shuffle("{([")
-
- -- uncomment to place down stairs at vertical end of canyon
- --mapgrd[STAIRS_X_DOWN1][STAIRS_Y_DOWN1] = '}'
- --mapgrd[STAIRS_X_DOWN2][STAIRS_Y_DOWN23] = ')'
- --mapgrd[STAIRS_X_DOWN3][STAIRS_Y_DOWN23] = ']'
- --shuffle("})]")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# (
-# {+-------+
-# [ |
-# |
-# ) |
-# }+-------+
-# ]
-NAME: layout_gehenna_U_turn
-DEPTH: Geh
-WEIGHT: 5
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_1 = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
- local ROOM_END_X = gxm - STAIRS_FROM_MAP_EDGE
-
- local STAIRS_Y_UP1 = gym / 2 - BASIC_PATH_OFFSET_Y
- local STAIRS_Y_UP2 = STAIRS_Y_UP1 - STAIRS_SPACING_Y
- local STAIRS_Y_UP3 = STAIRS_Y_UP1 + STAIRS_SPACING_Y
- local STAIRS_Y_DOWN1 = gym / 2 + BASIC_PATH_OFFSET_Y
- local STAIRS_Y_DOWN2 = STAIRS_Y_DOWN1 - STAIRS_SPACING_Y
- local STAIRS_Y_DOWN3 = STAIRS_Y_DOWN1 + STAIRS_SPACING_Y
-
- fill_area { x1 = STAIRS_X_23, y1 = STAIRS_Y_UP2,
- x2 = STAIRS_X_23, y2 = STAIRS_Y_UP3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_1, y1 = STAIRS_Y_UP1 - PATH_SIZE_BASIC,
- x2 = ROOM_END_X, y2 = STAIRS_Y_UP1 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = ROOM_END_X - PATH_SIZE_BASIC, y1 = STAIRS_Y_UP1,
- x2 = ROOM_END_X + PATH_SIZE_BASIC, y2 = STAIRS_Y_DOWN1,
- fill = '.' }
- fill_area { x1 = STAIRS_X_1, y1 = STAIRS_Y_DOWN1 - PATH_SIZE_BASIC,
- x2 = ROOM_END_X, y2 = STAIRS_Y_DOWN1 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = STAIRS_X_23, y1 = STAIRS_Y_DOWN2,
- x2 = STAIRS_X_23, y2 = STAIRS_Y_DOWN3,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (7 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_1 ][STAIRS_Y_UP1] = '{'
- mapgrd[STAIRS_X_23][STAIRS_Y_UP2] = '('
- mapgrd[STAIRS_X_23][STAIRS_Y_UP3] = '['
- shuffle("{([")
-
- -- uncomment to place down stairs on other branch of U
- --mapgrd[STAIRS_X_1 ][STAIRS_Y_DOWN1] = '}'
- --mapgrd[STAIRS_X_23][STAIRS_Y_DOWN2] = ')'
- --mapgrd[STAIRS_X_23][STAIRS_Y_DOWN3] = ']'
- --shuffle("})]")
- --shuffle("{([/})]")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# )
-# ( |
-# {+--------}
-# [ |
-# ]
-NAME: layout_gehenna_T
-DEPTH: Geh
-WEIGHT: 10
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
- local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
-
- local STAIRS_Y_1 = gym / 2
- local STAIRS_Y_UP2 = STAIRS_Y_1 - STAIRS_SPACING_Y
- local STAIRS_Y_UP3 = STAIRS_Y_1 + STAIRS_SPACING_Y
- local STAIRS_Y_DOWN2 = STAIRS_FROM_MAP_EDGE
- local STAIRS_Y_DOWN3 = gym - STAIRS_FROM_MAP_EDGE
-
- fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_UP2,
- x2 = STAIRS_X_UP23, y2 = STAIRS_Y_UP3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
- fill = '.' }
-
- fill_area { x1 = STAIRS_X_DOWN - PATH_SIZE_BASIC, y1 = STAIRS_Y_DOWN2,
- x2 = STAIRS_X_DOWN + PATH_SIZE_BASIC, y2 = STAIRS_Y_DOWN3,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (4.5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
- mapgrd[STAIRS_X_UP23][STAIRS_Y_UP2] = '('
- mapgrd[STAIRS_X_UP23][STAIRS_Y_UP3] = '['
- mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
- mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN2] = ')'
- mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN3] = ']'
-
- shuffle("{([")
- shuffle("})]")
- shuffle("{([/})]")
-
- -- remove to place down stairs at other end
- subst("})] = .")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# ( )
-# | |
-# {---------}
-# | |
-# [ ]
-NAME: layout_gehenna_H
-DEPTH: Geh
-WEIGHT: 5
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
-
- local STAIRS_Y_1 = gym / 2
- local STAIRS_Y_2 = STAIRS_FROM_MAP_EDGE
- local STAIRS_Y_3 = gym - STAIRS_FROM_MAP_EDGE
-
- fill_area { x1 = STAIRS_X_DOWN - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_DOWN + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_UP + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
- mapgrd[STAIRS_X_UP ][STAIRS_Y_2] = '('
- mapgrd[STAIRS_X_UP ][STAIRS_Y_3] = '['
- shuffle("{([")
-
- -- uncomment to place down stairs in canyon branches at other end
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_2] = ')'
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_3] = ']'
- --shuffle("})]")
- --shuffle("{([/})]")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# (---------)
-# | |
-# { }
-# | |
-# [---------]
-NAME: layout_gehenna_box
-DEPTH: Geh
-WEIGHT: 10
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
-
- local STAIRS_Y_1 = gym / 2
- local STAIRS_Y_2 = STAIRS_Y_1 - BASIC_PATH_OFFSET_Y
- local STAIRS_Y_3 = STAIRS_Y_1 + BASIC_PATH_OFFSET_Y
-
- fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_2 - PATH_SIZE_BASIC,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_2 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_3 - PATH_SIZE_BASIC,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_3 + PATH_SIZE_BASIC,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_UP + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_DOWN - PATH_SIZE_BASIC, y1 = STAIRS_Y_2,
- x2 = STAIRS_X_DOWN + PATH_SIZE_BASIC, y2 = STAIRS_Y_3,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (7.5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
- mapgrd[STAIRS_X_UP ][STAIRS_Y_2] = '('
- mapgrd[STAIRS_X_UP ][STAIRS_Y_3] = '['
- shuffle("{([")
-
- -- uncomment to place down stairs at other side of box
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_2] = ')'
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_3] = ']'
- --shuffle("})]")
- --shuffle("{([/})]")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# (-----+---)
-# |
-# {--+--+---}
-# |
-# [--+------]
-NAME: layout_gehenna_parallel
-DEPTH: Geh
-WEIGHT: 5
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
- local X_LENGTH = STAIRS_X_DOWN - STAIRS_X_UP
-
- local STAIRS_Y_1 = gym / 2
- local STAIRS_Y_2 = STAIRS_Y_1 - TRIPLE_PATH_SPACING
- local STAIRS_Y_3 = STAIRS_Y_1 + TRIPLE_PATH_SPACING
-
- local branch_x_1 = STAIRS_X_UP +
- X_LENGTH * crawl.random_range(20, 80) / 100
- local branch_x_2 = STAIRS_X_UP +
- X_LENGTH * crawl.random_range(20, 80) / 100
-
- -- parallel hallways
- fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_1 - PATH_SIZE_TRIPLE,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_TRIPLE,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_2 - PATH_SIZE_TRIPLE,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_2 + PATH_SIZE_TRIPLE,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP, y1 = STAIRS_Y_3 - PATH_SIZE_TRIPLE,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_3 + PATH_SIZE_TRIPLE,
- fill = '.' }
-
- -- connections
- fill_area { x1 = branch_x_1 - PATH_SIZE_TRIPLE, y1 = STAIRS_Y_2,
- x2 = branch_x_1 + PATH_SIZE_TRIPLE, y2 = STAIRS_Y_1,
- fill = '.' }
- fill_area { x1 = branch_x_2 - PATH_SIZE_TRIPLE, y1 = STAIRS_Y_1,
- x2 = branch_x_2 + PATH_SIZE_TRIPLE, y2 = STAIRS_Y_3,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (6 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
- mapgrd[STAIRS_X_UP ][STAIRS_Y_2] = '('
- mapgrd[STAIRS_X_UP ][STAIRS_Y_3] = '['
- shuffle("{([")
-
- -- uncomment to place down stairs at other ends of canyons
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_2] = ')'
- --mapgrd[STAIRS_X_DOWN][STAIRS_Y_3] = ']'
- --shuffle("})]")
- --shuffle("{([/})]")
- end
-
- gehenna_layout_epilogue(_G)
-}}
-
-# +----)
-# ( |
-# {+--------}
-# [ |
-# +----]
-NAME: layout_gehenna_trident
-DEPTH: Geh
-WEIGHT: 10
-ORIENT: encompass
-TAGS: overwritable layout allow_dup unrand no_rotate
-{{
- local gxm, gym = dgn.max_bounds()
- extend_map{width = gxm, height = gym, fill = 'x'}
-
- layout_type "pools"
-
- local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
- local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
- local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
- local BRANCH_X = gxm / 2
-
- local STAIRS_Y_1 = gym / 2
- local STAIRS_Y_UP2 = STAIRS_Y_1 - STAIRS_SPACING_Y
- local STAIRS_Y_UP3 = STAIRS_Y_1 + STAIRS_SPACING_Y
- local STAIRS_Y_DOWN2 = STAIRS_Y_1 - TRIPLE_PATH_SPACING
- local STAIRS_Y_DOWN3 = STAIRS_Y_1 + TRIPLE_PATH_SPACING
-
- fill_area { x1 = STAIRS_X_UP23, y1 = STAIRS_Y_UP2,
- x2 = STAIRS_X_UP23, y2 = STAIRS_Y_UP3,
- fill = '.' }
- fill_area { x1 = STAIRS_X_UP1, y1 = STAIRS_Y_1 - PATH_SIZE_BASIC,
- x2 = BRANCH_X, y2 = STAIRS_Y_1 + PATH_SIZE_BASIC,
- fill = '.' }
-
- fill_area { x1 = BRANCH_X - PATH_SIZE_TRIPLE, y1 = STAIRS_Y_DOWN2,
- x2 = BRANCH_X + PATH_SIZE_TRIPLE, y2 = STAIRS_Y_DOWN3,
- fill = '.' }
-
- fill_area { x1 = BRANCH_X, y1 = STAIRS_Y_1 - PATH_SIZE_TRIPLE,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_1 + PATH_SIZE_TRIPLE,
- fill = '.' }
- fill_area { x1 = BRANCH_X, y1 = STAIRS_Y_DOWN2 - PATH_SIZE_TRIPLE,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_DOWN2 + PATH_SIZE_TRIPLE,
- fill = '.' }
- fill_area { x1 = BRANCH_X, y1 = STAIRS_Y_DOWN3 - PATH_SIZE_TRIPLE,
- x2 = STAIRS_X_DOWN, y2 = STAIRS_Y_DOWN3 + PATH_SIZE_TRIPLE,
- fill = '.' }
-
- spotty_map { boxy = false, iterations = (5.5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
-
- if crawl.random2(100) < STAIRS_PLACE_PERCENT then
- mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
- mapgrd[STAIRS_X_UP23][STAIRS_Y_UP2] = '('
- mapgrd[STAIRS_X_UP23][STAIRS_Y_UP3] = '['
- mapgrd[STAIRS_X_DOWN][STAIRS_Y_1] = '}'
- mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN2] = ')'
- mapgrd[STAIRS_X_DOWN][STAIRS_Y_DOWN3] = ']'
-
- shuffle("{([")
- shuffle("})]")
- shuffle("{([/})]")
-
- -- remove to place down stairs at other end(s) of canyon
- subst("})] = .")
- end
-
- gehenna_layout_epilogue(_G)
-}}
diff --git a/crawl-ref/source/l_dgnbld.cc b/crawl-ref/source/l_dgnbld.cc
index 2d507a6..1d996f4 100644
--- a/crawl-ref/source/l_dgnbld.cc
+++ b/crawl-ref/source/l_dgnbld.cc
@@ -6,6 +6,7 @@
#include "AppHdr.h"
#include <cmath>
+#include <vector>
#include "dungeon.h"
#include "dgn-delve.h"
@@ -220,6 +221,128 @@ static int _count_passable_neighbors(lua_State *ls, map_lines &lines, coord_def
return _count_passable_neighbors(ls, lines, point.x, point.y, passable);
}
+static vector<coord_def> _get_pool_seed_positions(
+ vector<vector<int> > pool_index,
+ int pool_size,
+ int min_seperation)
+{
+ const int NO_POOL = 999997; // must match dgn_add_pools
+
+ if(pool_size < 1)
+ pool_size = 1;
+
+ // 1. Find all floor positions
+
+ vector<coord_def> floor_positions;
+
+ for(unsigned int x = 0; x < pool_index.size(); x++)
+ for(unsigned int y = 0; y < pool_index[x].size(); y++)
+ {
+ if(pool_index[x][y] == NO_POOL)
+ floor_positions.push_back(coord_def(x, y));
+ }
+
+ // 2. Choose the pool seed positions
+
+ int min_seperation_squared = min_seperation * min_seperation;
+ int pool_count_goal = (floor_positions.size() + random2(pool_size))
+ / pool_size;
+
+ vector<coord_def> seeds;
+
+ for (int i = 0; i < pool_count_goal; i++)
+ {
+ if (floor_positions.empty())
+ {
+ // give up if no more positions
+ break;
+ }
+
+ // choose a random position
+ int chosen_index = random2(floor_positions.size());
+ coord_def chosen_coord = floor_positions[chosen_index];
+ floor_positions[chosen_index] = floor_positions.back();
+ floor_positions.pop_back();
+
+ // check if it is too close to another seed
+ bool too_close = false;
+ for (unsigned int j = 0; j < seeds.size(); j++)
+ {
+ int diff_x = chosen_coord.x - seeds[j].x;
+ int diff_y = chosen_coord.y - seeds[j].y;
+ int distance_squared = diff_x * diff_x + diff_y * diff_y;
+
+ if (distance_squared < min_seperation_squared)
+ {
+ too_close = true;
+ break;
+ }
+ }
+
+ // if not too close, add it to the list
+ if (!too_close)
+ seeds.push_back(chosen_coord);
+ }
+
+ // 3. Return the pool seeds
+
+ return seeds;
+}
+
+// This function assumes the table is on the top of the lua stack.
+static vector<char> _pool_fill_glyphs_from_table(lua_State *ls,
+ const char *name)
+{
+ // We will go through the table and put each possible pool
+ // fill glyph in a vector once for each weight. This will
+ // make it easy to select random ones with the correct
+ // distribution when we need to.
+ vector<char> fill_glyphs;
+
+ lua_pushstring(ls, name);
+ lua_gettable(ls, -2);
+ if (!lua_isnil(ls, -1) && lua_istable(ls, -1))
+ {
+ // For some reason, LUA requires us to have a dummy
+ // value to remove from the stack whenever we do a
+ // table lookup. Here is the first one
+ lua_pushnil(ls);
+
+ // table is now at -2
+ while (lua_next(ls, -2) != 0)
+ {
+ // uses 'key' (at index -2) and 'value' (at index -1)
+ if(lua_type(ls, -2) == LUA_TSTRING
+ && lua_type(ls, -1) == LUA_TNUMBER)
+ {
+ // we use first character of string as glyph
+ char glyph = (lua_tostring(ls, -2))[0];
+
+ int count = lua_tointeger(ls, -1);
+ // sanity-check
+ if(count > 10000)
+ count = 10000;
+
+ if(glyph != '\0')
+ {
+ for(int i = 0; i < count; i++)
+ fill_glyphs.push_back(glyph);
+ }
+ }
+
+ // removes 'value'; keeps 'key' for next iteration
+ lua_pop(ls, 1);
+ }
+ }
+ lua_pop(ls, 1);
+
+ // We might have not got anything, if so, use floor
+ if(fill_glyphs.size() == 0)
+ fill_glyphs.push_back('.');
+
+ return fill_glyphs;
+}
+
LUAFN(dgn_count_feature_in_box)
{
@@ -695,6 +818,114 @@ LUAFN(dgn_octa_room)
return 0;
}
+LUAFN(dgn_remove_isolated_glyphs)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_STR(ls, find, "");
+ TABLE_CHAR(ls, replace, '.');
+ TABLE_INT(ls, percent, 100);
+ TABLE_BOOL(ls, boxy, false);
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ // we never change the border
+ if(x1 < 1)
+ x1 = 1;
+ if(x2 >= lines.width() - 1)
+ x2 = lines.width() - 2;
+ if(y1 < 1)
+ y1 = 1;
+ if(y2 >= lines.height() - 1)
+ y2 = lines.height() - 2;
+
+ for (int y = y1; y <= y2; ++y)
+ for (int x = x1; x <= x2; ++x)
+ if (strchr(find, lines(x, y)) && x_chance_in_y(percent, 100))
+ {
+ bool do_replace = true;
+ for (radius_iterator ri(coord_def(x, y), 1,
+ (boxy ? C_SQUARE : C_POINTY),
+ NULL, true); ri; ++ri)
+ {
+ if (_valid_coord(ls, lines, ri->x, ri->y, false))
+ if (strchr(find, lines(*ri)))
+ {
+ do_replace = false;
+ break;
+ }
+ }
+ if(do_replace)
+ lines(x, y) = replace;
+ }
+
+ return 0;
+}
+
+LUAFN(dgn_widen_paths)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_STR(ls, find, "");
+ TABLE_CHAR(ls, replace, '.');
+ TABLE_STR(ls, passable, traversable_glyphs);
+ TABLE_INT(ls, percent, 100);
+ TABLE_BOOL(ls, boxy, false);
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ // we never change the border
+ if(x1 < 1)
+ x1 = 1;
+ if(x2 >= lines.width() - 1)
+ x2 = lines.width() - 2;
+ if(y1 < 1)
+ y1 = 1;
+ if(y2 >= lines.height() - 1)
+ y2 = lines.height() - 2;
+
+ float antifraction_each = 1.0 - percent / 100.0f;
+ float antifraction_current = 1.0;
+ int percent_for_neighbours[9];
+ for (int i = 0; i < 9; i++)
+ {
+ percent_for_neighbours[i] = 100 - (int)(antifraction_current * 100);
+ antifraction_current *= antifraction_each;
+ }
+
+ // We do not replace this as we go to avoid favouring some directions.
+ vector<coord_def> coord_to_replace;
+
+ for (int y = y1; y <= y2; ++y)
+ for (int x = x1; x <= x2; ++x)
+ if (strchr(find, lines(x, y)))
+ {
+ int neighbour_count = 0;
+ for (radius_iterator ri(coord_def(x, y), 1,
+ (boxy ? C_SQUARE : C_POINTY),
+ NULL, true); ri; ++ri)
+ {
+ if (_valid_coord(ls, lines, ri->x, ri->y, false))
+ if (strchr(passable, lines(*ri)))
+ neighbour_count++;
+ }
+
+ // store this coordinate if needed
+ if(x_chance_in_y(percent_for_neighbours[neighbour_count], 100))
+ coord_to_replace.push_back(coord_def(x, y));
+ }
+
+ // now go through and actually replace the positions
+ for (unsigned int i = 0; i < coord_to_replace.size(); i++)
+ lines(coord_to_replace[i]) = replace;
+
+ return 0;
+}
+
LUAFN(dgn_replace_area)
{
LINES(ls, 1, lines);
@@ -793,6 +1024,69 @@ LUAFN(dgn_replace_random)
return 0;
}
+LUAFN(dgn_replace_closest)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_INT(ls, x, 0);
+ TABLE_INT(ls, y, 0);
+ TABLE_CHAR(ls, find, '\0');
+ TABLE_CHAR(ls, replace, '\0');
+ TABLE_BOOL(ls, required, false);
+
+ coord_def center(x, y);
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ int count = (x2 - x1 + 1) * (y2 - y1 + 1);
+ if (!count)
+ {
+ if (required)
+ luaL_error(ls, "%s", "No elements to replace");
+ return 0;
+ }
+
+ vector<coord_def> loc;
+ loc.reserve(count);
+
+ int best_distance = 10000;
+ unsigned int best_count = 0;
+ coord_def best_coord;
+
+ for (int this_y = y1; this_y <= y2; ++this_y)
+ for (int this_x = x1; this_x <= x2; ++this_x)
+ if (lines(this_x, this_y) == find)
+ {
+ coord_def here(this_x, this_y);
+ int distance = here.distance_from(center);
+ if(distance < best_distance)
+ {
+ best_distance = distance;
+ best_count = 1;
+ best_coord = here;
+ }
+ else if (distance == best_distance)
+ {
+ best_count++;
+ if(one_chance_in(best_count))
+ best_coord = here;
+ }
+ }
+
+ if (best_count == 0)
+ {
+ if (required)
+ return luaL_error(ls, "Could not find '%c'", find);
+ return 0;
+ }
+
+ lines(best_coord) = replace;
+
+ return 0;
+}
+
LUAFN(dgn_smear_map)
{
LINES(ls, 1, lines);
@@ -898,6 +1192,174 @@ LUAFN(dgn_spotty_map)
return 0;
}
+LUAFN(dgn_add_pools)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_STR(ls, replace, ".");
+ TABLE_CHAR(ls, border, '.');
+ TABLE_INT(ls, pool_size, 100);
+ TABLE_INT(ls, seed_seperation, 2);
+
+ vector<char> fill_glyphs = _pool_fill_glyphs_from_table(ls, "contents");
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ int size_x = x2 - x1 + 1;
+ int size_y = y2 - y1 + 1;
+
+ //
+ // The basic ideas here is that we place a number of
+ // pool "seeds" on the map and spread them outward
+ // randomly until they run into each other. We never
+ // fill in the last cell, so they never actually
+ // touch and we get paths between them.
+ //
+ // The algorithm we use to spread the pools is like a
+ // depth-/breadth-first search, except that:
+ // 1. We choose a random element from the open list
+ // 2. We have multiple starting locations, each
+ // with its own "closed" value
+ // 3. We mark all cells bordered by 2 (or more)
+ // distinct non-BORDER closed values with special
+ // closed value BORDER
+ //
+ // In the end, we used the "closed" values to determine
+ // which pool we are in. The BORDER value indicates
+ // a path between pools.
+ //
+
+ // NO_POOL
+ // -> must be lowest constant
+ // -> must match _get_pool_seed_positions
+ const int NO_POOL = 999997;
+ const int IN_LIST = 999998;
+ const int BORDER = 999999;
+ const int FORBIDDEN = 1000000;
+
+ // Step 1: Make a 2D array to store which pool each cell is part of
+ // -> We use nested vectors to store this. We cannot use
+ // a fixedarray because we don't know the size at
+ // compile time.
+
+ vector<vector<int> > pool_index(size_x, vector<int>(size_y, FORBIDDEN));
+ for(int x = 0; x < size_x; x++)
+ for(int y = 0; y < size_y; y++)
+ {
+ if(strchr(replace, lines(x + x1, y + y1)))
+ pool_index[x][y] = NO_POOL;
+ }
+
+ // Step 2: Place the pool seeds and add their neighbours to the open list
+
+ vector<coord_def> pool_seeds = _get_pool_seed_positions(pool_index,
+ pool_size,
+ seed_seperation);
+ vector<coord_def> open_list;
+
+ for(unsigned int pool = 0; pool < pool_seeds.size(); pool++)
+ {
+ int x = pool_seeds[pool].x;
+ int y = pool_seeds[pool].y;
+
+ pool_index[x][y] = pool;
+
+ // add neighbours to open list
+ for (orth_adjacent_iterator ai(pool_seeds[pool]); ai; ++ai)
+ if (_valid_coord(ls, lines, ai->x, ai->y, false))
+ {
+ pool_index[ai->x][ai->y] = IN_LIST;
+ open_list.push_back(*ai);
+ }
+ }
+
+ // Step 3: Spread out pools as far as possible
+
+ while(!open_list.empty())
+ {
+ // remove a random position from the open list
+ int index_chosen = random2(open_list.size());
+ coord_def chosen_coord = open_list[index_chosen];
+ open_list[index_chosen] = open_list.back();
+ open_list.pop_back();
+
+ // choose which neighbouring pool to join
+ int chosen_pool = NO_POOL;
+ for (adjacent_iterator ai(chosen_coord); ai; ++ai)
+ if (_valid_coord(ls, lines, ai->x, ai->y, false))
+ {
+ int neighbour_pool = pool_index[ai->x][ai->y];
+ if(neighbour_pool < NO_POOL)
+ {
+ // this is a valid pool, consider it
+ if(chosen_pool == NO_POOL)
+ chosen_pool = neighbour_pool;
+ else if(chosen_pool == neighbour_pool)
+ ; // already correct
+ else
+ {
+ // this is the path between pools
+ chosen_pool = BORDER;
+ break;
+ }
+ }
+ else if (neighbour_pool == FORBIDDEN)
+ {
+ // next to a wall
+ chosen_pool = BORDER;
+ break;
+ }
+ }
+
+ if(chosen_pool != NO_POOL)
+ {
+ // add this cell to the appropriate pool
+ pool_index[chosen_coord.x][chosen_coord.y] = chosen_pool;
+
+ // add neighbours to open list
+ for (orth_adjacent_iterator ai(chosen_coord); ai; ++ai)
+ if (_valid_coord(ls, lines, ai->x, ai->y, false)
+ && pool_index[ai->x][ai->y] == NO_POOL)
+ {
+ pool_index[ai->x][ai->y] = IN_LIST;
+ open_list.push_back(*ai);
+ }
+ }
+ else
+ {
+ // a default, although I do not know why we ever get here
+ pool_index[chosen_coord.x][chosen_coord.y] = NO_POOL;
+ }
+ }
+
+ // Step 4: Add the pools to the map
+
+ vector<char> pool_glyphs(pool_seeds.size(), '\0');
+ for(unsigned int i = 0; i < pool_glyphs.size(); i++)
+ pool_glyphs[i] = fill_glyphs[random2(fill_glyphs.size())];
+
+ for(int x = 0; x < size_x; x++)
+ for(int y = 0; y < size_y; y++)
+ {
+ int index = pool_index[x][y];
+ if(index < (int)(pool_glyphs.size()))
+ lines(x + x1, y + y1) = pool_glyphs[index];
+ else if(index == NO_POOL || index == BORDER)
+ lines(x + x1, y + y1) = border;
+ else if(index == FORBIDDEN)
+ ; // leave it alone
+ else
+ {
+ return luaL_error(ls, "Invalid pool index %i/%i at (%i, %i)",
+ index, pool_glyphs.size(), x + x1, y + y1);
+ }
+ }
+
+ return 0;
+}
+
static int dgn_width(lua_State *ls)
{
LINES(ls, 1, lines);
@@ -1037,11 +1499,15 @@ const struct luaL_reg dgn_build_dlib[] =
{ "make_box_doors", &dgn_make_box_doors },
{ "mapgrd_table", dgn_mapgrd_table },
{ "octa_room", &dgn_octa_room },
+ { "remove_isolated_glyphs", &dgn_remove_isolated_glyphs },
+ { "widen_paths", &dgn_widen_paths },
{ "replace_area", &dgn_replace_area },
{ "replace_first", &dgn_replace_first },
{ "replace_random", &dgn_replace_random },
+ { "replace_closest", &dgn_replace_closest },
{ "smear_map", &dgn_smear_map },
{ "spotty_map", &dgn_spotty_map },
+ { "add_pools", &dgn_add_pools },
{ "delve", &dgn_delve },
{ "width", dgn_width },
{ "layout_type", &dgn_layout_type },
--
1.8.1.2
layout_honeycomb.png [^] (8,459 bytes) 2013-04-18 06:00
0001-Translated-pools-layout-code-to-C2.patch [^] (45,052 bytes) 2013-04-23 05:20 [Show Content] [Hide Content]From b0fe1de5817b8bbbc1d613dc838ad1f01d3fd688 Mon Sep 17 00:00:00 2001
From: infiniplex <infiniplex@hotmail.com>
Date: Wed, 17 Apr 2013 18:28:53 -0600
Subject: [PATCH] Translated "pools" layout code to C++
---
crawl-ref/source/dat/des/builder/layout.des | 8 +
crawl-ref/source/dat/des/builder/layout_pools.des | 521 ++++++----------------
crawl-ref/source/l_dgnbld.cc | 466 +++++++++++++++++++
3 files changed, 613 insertions(+), 382 deletions(-)
diff --git a/crawl-ref/source/dat/des/builder/layout.des b/crawl-ref/source/dat/des/builder/layout.des
index f36facb..2111625 100644
--- a/crawl-ref/source/dat/des/builder/layout.des
+++ b/crawl-ref/source/dat/des/builder/layout.des
@@ -621,6 +621,12 @@ TAGS: overwritable layout allow_dup unrand
MAP
ENDMAP
+##############################################################
+# layout_caves
+#
+# One (sometimes more) large open caverns with irregular
+# walls.
+#
NAME: layout_caves
DEPTH: 9-22, !Dis, !Geh, Orc, Slime
CHANCE: 100% (Orc), 100% (Slime)
@@ -661,6 +667,7 @@ TAGS: overwritable layout allow_dup unrand
MAP
ENDMAP
+##############################################################
# A long winding cavern of roughly constant width, snaking around all the
# level. It forks from time to time, but never for long.
NAME: layout_twisted_cavern
@@ -689,6 +696,7 @@ TAGS: overwritable layout allow_dup unrand
end
}}
+##############################################################
## This replaces dungeon.cc:_roguey_level.
NAME: layout_roguey
DEPTH: 2-, !Pan, !Zot, !Dis, !Geh
diff --git a/crawl-ref/source/dat/des/builder/layout_pools.des b/crawl-ref/source/dat/des/builder/layout_pools.des
index e66419a..1b8f1c3 100644
--- a/crawl-ref/source/dat/des/builder/layout_pools.des
+++ b/crawl-ref/source/dat/des/builder/layout_pools.des
@@ -1,346 +1,28 @@
-###############################################################################
-# layout_pools.des: The "pools" layout vaults go here. These layouts are each
-# a large, irregular open area mostly filled with clumps of
-# some glyph. These are not true vaults, in that the dungeon
-# builder can add other vaults on top of them.
+##############################################################
+# layout_pools.des
+#
+# These layouts are based on the add_pools function. They
+# divide the map into a bunch of irregular areas jammed aginst
+# each other. The layout may use either the areas themsleves
+# are the paths between them. These are not true vaults, in
+# that the dungeon builder can add other vaults on top of them.
#
-###############################################################################
-
-{{
- -- replace all cells with the specified glyph bordered by
- -- floor in all four cardinal directions
- function remove_isolated_glyphs (e, replace, percent)
- local gxm, gym = dgn.max_bounds()
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if e.mapgrd[x ][y ] == replace and
- e.mapgrd[x + 1][y ] == '.' and
- e.mapgrd[x - 1][y ] == '.' and
- e.mapgrd[x ][y + 1] == '.' and
- e.mapgrd[x ][y - 1] == '.' and
- crawl.random2(100) < percent then
- e.mapgrd[x][y] = '.'
- end
- end
- end
- end
-
- -- replace all cells with the specified glyph bordered by at
- -- least on floor with floor cells
- function widen_paths (e, replace, percent)
- local gxm, gym = dgn.max_bounds()
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if e.mapgrd[x][y] == replace and
- crawl.random2(100) < percent then
- if e.mapgrd[x - 1][y ] == '.' or
- e.mapgrd[x + 1][y ] == '.' or
- e.mapgrd[x ][y - 1] == '.' or
- e.mapgrd[x ][y + 1] == '.' then
- e.mapgrd[x][y] = '_'
- end
- end
- end
- end
- e.subst("_ = .")
- end
-
-
-
- -- the relative positions of a cell's neighbours
- -- these go with the add_pools function
- local NEIGHBOUR_COUNT = 4
- local NEIGHBOUR_OFFSETS = { { x=1, y=0 },
- { x=-1, y=0 },
- { x=0, y=1 },
- { x=0, y=-1 } }
-
- --
- -- add_pools
- --
- -- Purpose: To fill the portion of the map with the
- -- specified floor glyph with irregular areas of
- -- the specified pool glyphs, seperated by paths
- -- of the floor glyph. There is always a path
- -- around the pools. Border cells are excluded.
- -- Parameter(s):
- -- <1> e: The global enviroment
- -- <2> floor: The floor glyph
- -- <3> pool_elements: The pool glyphs, in the format
- -- required for the
- -- crawl.random_element function
- -- <4> pool_frequency: The number of pools to place,
- -- expressed as a fraction from
- -- 0.0 (no pools) to
- -- 1.0 (1 pool per floor cell)
- -- Precondition(s):
- -- <1> e ~= nil
- -- <2> pool_elements ~= nil
- -- <3> pool_frequency >= 0
- -- <4> pool_frequency <= 1
- -- Returns: N/A
- -- Side Effect: Pools of types choosen randomly from
- -- pool_elements are added to the portion of
- -- mapgrd filled with floor glyphs. A
- -- differant pool type is chosen for each
- -- pool. The number of pools is equal to
- -- pool_fraction times the number fo cells
- -- that originally had glyph floor.
- --
- -- TODO: translate this function to C++
- --
-
- function add_pools (e, floor, pool_elements, pool_frequency)
- assert(e ~= nil, "e cannot be nil")
- assert(pool_elements ~= nil, "pool_elements cannot be nil")
- assert(pool_frequency >= 0, "pool_frequency must be >= 0")
- assert(pool_frequency <= 1, "pool_frequency must be <= 1")
-
- --
- -- The basic ideas here is that we place a number of
- -- pool "seeds" on the map and spread them outward
- -- randomly until they run into each other. We never
- -- fill in the last cell, so they never actually
- -- touch and we get paths between them.
- --
- -- The algorithm we use to spread the pools is like a
- -- depth-/breadth-first search, except that:
- -- 1. We choose a random element from the open list
- -- 2. We have multiple starting locations, each
- -- with its own "closed" value
- -- 3. We mark all cells bordered by 2 (or more)
- -- non-BORDER closed values with special closed
- -- value BORDER
- --
- -- In the end, we used the "closed" values to determine
- -- which pool we are in. The BORDER value indicates
- -- a path between pools.
- --
-
- local NO_POOL = 999997 -- must be lowest constant
- local IN_LIST = 999998
- local BORDER = 999999
- local FORBIDDEN = 1000000
-
- -- The minimum seperation distance for pool seeds
- local MIN_SEED_SEPERATION_DISTANCE = 2
-
- local gxm, gym = dgn.max_bounds()
-
-
-
- -- a helper function to select the pool seed positions
- function getPoolSeedPositions (aa_pool_index,
- pool_frequency,
- min_seperation)
- assert(aa_pool_index ~= nil, "aa_pool_index cannot be nil")
- assert(pool_frequency >= 0, "pool_frequency must be >= 0")
- assert(pool_frequency <= 1, "pool_frequency must be <= 1")
- assert(min_seperation > 0, "min_seperation must be positive")
-
- local gxm, gym = dgn.max_bounds()
-
- -- 1. Find all floor positions
-
- local a_floor_positions = {}
- a_floor_positions.count = 0
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if aa_pool_index[x][y] == NO_POOL then
- a_floor_positions[a_floor_positions.count] = {}
- a_floor_positions[a_floor_positions.count].x = x
- a_floor_positions[a_floor_positions.count].y = y
- a_floor_positions.count = a_floor_positions.count + 1
- end
- end
- end
-
- -- 2. Choose the pool seed positions
-
- local min_seperation_squared = min_seperation * min_seperation
- local pool_count_goal = math.floor(a_floor_positions.count *
- pool_frequency)
-
- local a_seeds = {}
- a_seeds.count = 0
-
- for i = 1, pool_count_goal do
- -- choose a random position
- if a_floor_positions.count <= 0 then
- -- give up if no more positions
- break
- end
-
- local index_chosen = crawl.random2(a_floor_positions.count)
- local x = a_floor_positions[index_chosen].x
- local y = a_floor_positions[index_chosen].y
- a_floor_positions.count = a_floor_positions.count - 1
- a_floor_positions[index_chosen].x =
- a_floor_positions[a_floor_positions.count].x
- a_floor_positions[index_chosen].y =
- a_floor_positions[a_floor_positions.count].y
-
- -- check if it is too close to another seed
- local too_close = false
- for j = 0, a_seeds.count - 1 do
- local diff_x = x - a_seeds[j].x
- local diff_y = y - a_seeds[j].y
- local distance_squared = diff_x * diff_x + diff_y * diff_y
-
- if distance_squared < min_seperation_squared then
- too_close = true
- break
- end
- end
-
- -- if not too close, add it to the list
- if not too_close then
- a_seeds[a_seeds.count] = {}
- a_seeds[a_seeds.count].x = x
- a_seeds[a_seeds.count].y = y
- a_seeds.count = a_seeds.count + 1
- end
- end
-
- -- 3. Return the pool seeds
-
- return a_seeds
- end
-
- -- a helper function to add a cell's neighbours to the open list
- function add_neighbours_to_open_list (aa_pool_index, x, y, a_open_list)
- local gxm, gym = dgn.max_bounds()
-
- for n = 1, NEIGHBOUR_COUNT do
- nx = x + NEIGHBOUR_OFFSETS[n].x
- ny = y + NEIGHBOUR_OFFSETS[n].y
-
- assert(nx >= 0, "nx must be >= 0")
- assert(nx < gxm, "nx must be < gxm")
- assert(ny >= 0, "ny must be >= 0")
- assert(ny < gym, "ny must be < gym")
-
- if aa_pool_index[nx][ny] == NO_POOL then
- aa_pool_index[nx][ny] = IN_LIST
- a_open_list[a_open_list.count] = {}
- a_open_list[a_open_list.count].x = nx
- a_open_list[a_open_list.count].y = ny
- a_open_list.count = a_open_list.count + 1
- end
- end
- end
-
-
-
- -- Step 1: Make a 2D array to store which pool each cell is part of
-
- local aa_pool_index = {}
- for x = 1, gxm - 2 do
- aa_pool_index[x] = {}
-
- for y = 1, gym - 2 do
- if e.mapgrd[x][y] == floor then
- aa_pool_index[x][y] = NO_POOL
- else
- aa_pool_index[x][y] = FORBIDDEN
- end
- end
- end
-
- -- Step 2: Place the pool seeds and add neighbours to the open list
-
- local a_pool_position = getPoolSeedPositions(
- aa_pool_index,
- pool_frequency,
- MIN_SEED_SEPERATION_DISTANCE)
- local a_open_list = {}
- a_open_list.count = 0
-
- for p = 0, a_pool_position.count - 1 do
- local x = a_pool_position[p].x
- local y = a_pool_position[p].y
-
- aa_pool_index[x][y] = p
- add_neighbours_to_open_list(aa_pool_index, x, y, a_open_list)
- end
-
- -- Step 3: Spread out pools as far as possible
-
- while a_open_list.count > 0 do
- -- remove a random position from the open list
- local index_chosen = crawl.random2(a_open_list.count)
- local x = a_open_list[index_chosen].x
- local y = a_open_list[index_chosen].y
- a_open_list.count = a_open_list.count - 1
- a_open_list[index_chosen].x = a_open_list[a_open_list.count].x
- a_open_list[index_chosen].y = a_open_list[a_open_list.count].y
-
- -- choose which neighbouring pool to join
- local chosen_pool = NO_POOL
- for n = 1, NEIGHBOUR_COUNT do
- nx = x + NEIGHBOUR_OFFSETS[n].x
- ny = y + NEIGHBOUR_OFFSETS[n].y
-
- assert(nx >= 0, "nx must be >= 0")
- assert(nx < gxm, "nx must be < gxm")
- assert(ny >= 0, "ny must be >= 0")
- assert(ny < gym, "ny must be < gym")
-
- neighbour_pool = aa_pool_index[nx][ny]
-
- if neighbour_pool < NO_POOL then
- -- valid pool
- if chosen_pool == NO_POOL or
- chosen_pool == neighbour_pool then
- chosen_pool = neighbour_pool
- else
- -- between pools
- chosen_pool = BORDER
- end
- end
-
- if neighbour_pool == FORBIDDEN then
- -- next to a wall
- chosen_pool = BORDER
- end
- end
- -- assert(chosen_pool ~= NO_POOL, "no neighbouring pools")
-
- if chosen_pool ~= NO_POOL then
- -- add this cell to the appropriate pool
- aa_pool_index[x][y] = chosen_pool
- add_neighbours_to_open_list(aa_pool_index, x, y, a_open_list)
- end
- end
-
- -- Step 4: Add the pools to the map
-
- local a_pool_glyph = {}
- for p = 0, a_pool_position.count - 1 do
- a_pool_glyph[p] = crawl.random_element(pool_elements)
- end
-
- for x = 1, gxm - 2 do
- for y = 1, gym - 2 do
- if aa_pool_index[x][y] < NO_POOL then
- e.mapgrd[x][y] = a_pool_glyph[aa_pool_index[x][y]]
- end
- end
- end
- end
-}}
+##############################################################
#
# Gehenna layout constants and functions
#
# These are collected together here instead of in the layout
# vaults because they are each used in more than one.
#
+# These maps have a small chance of placing the up stairs.
+# This is handlied by always generating the layout as if
+# the stairs were to be placed, but only sometimes adding
+# them.
+#
+
{{
-- Increasing this makes the caves bigger
CANYON_SIZE_FACTOR = 100
@@ -378,13 +60,6 @@
local branch_depth = dgn.br_depth(you.branch())
local depth_fraction = (you.depth() / branch_depth)
- local pool_frequency = 0.025 - depth_fraction * 0.01
- if pool_frequency < 0 then
- pool_frequency = 0
- elseif pool_frequency > 1 then
- pool_frequency = 1
- end
-
local pool_contents = {}
pool_contents["c"] = branch_depth * 2 - you.depth()
pool_contents["l"] = branch_depth + you.depth()
@@ -393,13 +68,15 @@
pool_contents["."] = nil
end
- widen_paths(e, 'x', 25)
- add_pools(e, '.', pool_contents, pool_frequency)
- widen_paths(e, 'c', 95)
+ e.widen_paths { find = "x", percent = 10 }
+ e.add_pools { replace = ".",
+ pool_size = 60 - 25 * depth_fraction,
+ contents = pool_contents }
+ e.widen_paths { find = "c", percent = 90 }
e.subst("c = x")
- remove_isolated_glyphs(e, 'x', 75)
- widen_paths(e, 'l', 80)
- remove_isolated_glyphs(e, 'l', 90)
+ e.remove_isolated_glyphs { find = "x", percent = 75 }
+ e.widen_paths { find = "l", percent = 60 }
+ e.remove_isolated_glyphs { find = "l", percent = 90, boxy = true }
end
}}
@@ -409,47 +86,127 @@
# layout_pools
#
# This layout creates an irregular cave with clumps of rock and
-# a few pools of water. There are more pools at deeper depths.
-# Starting at depth 19, there is an increasing chance of lava
-# pools instead of water pools (never mixed).
+# possibly a few pools of water. There are more pools at
+# deeper depths. Starting at depth 19, there is an increasing
+# chance of lava pools instead of water pools (never mixed).
#
NAME: layout_pools
-DEPTH: D:4-
-WEIGHT: 5
+DEPTH: D:9-
+WEIGHT: 10
ORIENT: encompass
TAGS: overwritable layout allow_dup unrand
{{
local gxm, gym = dgn.max_bounds()
extend_map { width = gxm, height = gym, fill = 'x' }
- layout_type "pools"
+ layout_type "caves"
-- without a starting floor patch, spotty_map will crash
mapgrd[gxm/2][gym/2] = '.'
spotty_map { boxy = false, iterations = 1000 }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
- local pool_frequency = 0.04 + crawl.random2(60) / 1000
local pool_contents = {}
- pool_contents["w"] = you.absdepth() * crawl.random2(100) / 100
pool_contents["."] = 40
pool_contents["x"] = 40 - you.absdepth()
- if you.absdepth() >= 19 + crawl.random2(8) then
- pool_contents["l"] = pool_contents["w"]
- pool_contents["w"] = nil
+ if crawl.coinflip() then
+ if you.absdepth() >= 19 + crawl.random2(8) then
+ pool_contents["l"] = you.absdepth() * crawl.random2(100) / 100
+ else
+ pool_contents["w"] = you.absdepth() * crawl.random2(100) / 100
+ end
end
- add_pools(_G, '.', pool_contents, pool_frequency)
- remove_isolated_glyphs(_G, 'x', 80)
- widen_paths(_G, 'x', 60)
- widen_paths(_G, 'l', 80)
- remove_isolated_glyphs(_G, 'l', 75)
+ add_pools { replace = ".",
+ pool_size = 10 + crawl.random2(15),
+ contents = pool_contents,
+ frequency = pool_frequency }
+
+ widen_paths { find = "x", percent = 30 }
+ remove_isolated_glyphs { find = "x", percent = 80 }
+ widen_paths { find = "l", percent = 30 }
+ remove_isolated_glyphs { find = "l", percent = 75, boxy = true }
+}}
+MAP
+ENDMAP
+
+#############################################################
+# layout_honeycomb
+#
+# This layout is composed of a series of irregular rooms
+# directly beside each other. They are sometimes connected
+# by doors and sometimes just by holes in the wall.
+#
+NAME: layout_honeycomb
+DEPTH: D:15-
+WEIGHT: 10
+ORIENT: encompass
+TAGS: overwritable layout allow_dup unrand
+{{
+ local gxm, gym = dgn.max_bounds()
+ extend_map { width = gxm, height = gym, fill = 'x' }
+
+ layout_type "rooms"
+
+ make_circle { x = gxm/2, y = gym/2, radius = 10 }
+ mapgrd[gxm/2][gym/2] = '.'
+ spotty_map { boxy = true, iterations = 1200 }
+ widen_paths { find = "x", percent = 50 }
+ remove_isolated_glyphs { find = "x", percent = 100 }
+
+ local fill = '.'
+ local border = 'x'
+ local connection = crawl.random_element({[fill] = 1, ["+"] = 2})
+
+ add_pools { replace = ".",
+ contents = {[fill] = 1},
+ pool_size = 25 + crawl.random2(25),
+ border = border }
+
+ -- connect rooms
+ for i = 1, crawl.random_range(800, 1200) do
+ local x = crawl.random_range(1, gxm - 2)
+ local y = crawl.random_range(1, gym - 2)
+
+ if mapgrd[x][y] == border then
+ if mapgrd[x + 1][y] == border and
+ mapgrd[x - 1][y] == border and
+ mapgrd[x][y + 1] == fill and
+ mapgrd[x][y - 1] == fill then
+ mapgrd[x][y] = connection
+ elseif mapgrd[x + 1][y] == fill and
+ mapgrd[x - 1][y] == fill and
+ mapgrd[x][y + 1] == border and
+ mapgrd[x][y - 1] == border then
+ mapgrd[x][y] = connection
+ end
+ end
+ end
+
+ replace_closest { x = gxm/2, y = gym/2, find = fill, replace = '@' }
+ fill_disconnected{wanted = '@'}
+ subst("@ = " .. fill)
+
+ -- This is the random_wall_material function from layout.des
+ if crawl.one_chance_in(20) then
+ e.subst('x : ccv')
+ end
+}}
+# Enforce minimum floor size - this is important
+validate {{
+ if count_feature_in_box { feat="."} < 600 then
+ return false
+ else
+ return true
+ end
}}
MAP
ENDMAP
##############################################################
-# layout_gehenna_???
+# Gehenna layouts
+#
+# NOTE: There are other Gehenna layouts in other files.
#
# These layouts are long canyons with lava pools in them and
# rock "pools" to provide cover. The up stairs may be placed
@@ -481,7 +238,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
@@ -503,7 +260,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (4 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
@@ -536,7 +293,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
@@ -571,7 +328,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
end
spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
@@ -605,7 +362,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
@@ -633,7 +390,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP1 ][STAIRS_Y_UP1] = '{'
@@ -667,7 +424,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_1 = STAIRS_FROM_MAP_EDGE
local STAIRS_X_23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
@@ -697,7 +454,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (7 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_1 ][STAIRS_Y_UP1] = '{'
@@ -730,7 +487,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
@@ -754,7 +511,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (4.5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
@@ -789,7 +546,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
@@ -809,7 +566,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
@@ -842,7 +599,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
@@ -865,7 +622,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (7.5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
@@ -898,7 +655,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP = STAIRS_FROM_MAP_EDGE
local STAIRS_X_DOWN = gxm - STAIRS_FROM_MAP_EDGE
@@ -933,7 +690,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (6 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP ][STAIRS_Y_1] = '{'
@@ -966,7 +723,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
local gxm, gym = dgn.max_bounds()
extend_map{width = gxm, height = gym, fill = 'x'}
- layout_type "pools"
+ layout_type "caves"
local STAIRS_X_UP1 = STAIRS_FROM_MAP_EDGE
local STAIRS_X_UP23 = STAIRS_FROM_MAP_EDGE + STAIRS_SPACING_X
@@ -1001,7 +758,7 @@ TAGS: overwritable layout allow_dup unrand no_rotate
fill = '.' }
spotty_map { boxy = false, iterations = (5.5 * CANYON_SIZE_FACTOR) }
- remove_isolated_glyphs(_G, 'x', 100)
+ remove_isolated_glyphs { find = "x", percent = 100 }
if crawl.random2(100) < STAIRS_PLACE_PERCENT then
mapgrd[STAIRS_X_UP1 ][STAIRS_Y_1] = '{'
diff --git a/crawl-ref/source/l_dgnbld.cc b/crawl-ref/source/l_dgnbld.cc
index 2d507a6..1d996f4 100644
--- a/crawl-ref/source/l_dgnbld.cc
+++ b/crawl-ref/source/l_dgnbld.cc
@@ -6,6 +6,7 @@
#include "AppHdr.h"
#include <cmath>
+#include <vector>
#include "dungeon.h"
#include "dgn-delve.h"
@@ -220,6 +221,128 @@ static int _count_passable_neighbors(lua_State *ls, map_lines &lines, coord_def
return _count_passable_neighbors(ls, lines, point.x, point.y, passable);
}
+static vector<coord_def> _get_pool_seed_positions(
+ vector<vector<int> > pool_index,
+ int pool_size,
+ int min_seperation)
+{
+ const int NO_POOL = 999997; // must match dgn_add_pools
+
+ if(pool_size < 1)
+ pool_size = 1;
+
+ // 1. Find all floor positions
+
+ vector<coord_def> floor_positions;
+
+ for(unsigned int x = 0; x < pool_index.size(); x++)
+ for(unsigned int y = 0; y < pool_index[x].size(); y++)
+ {
+ if(pool_index[x][y] == NO_POOL)
+ floor_positions.push_back(coord_def(x, y));
+ }
+
+ // 2. Choose the pool seed positions
+
+ int min_seperation_squared = min_seperation * min_seperation;
+ int pool_count_goal = (floor_positions.size() + random2(pool_size))
+ / pool_size;
+
+ vector<coord_def> seeds;
+
+ for (int i = 0; i < pool_count_goal; i++)
+ {
+ if (floor_positions.empty())
+ {
+ // give up if no more positions
+ break;
+ }
+
+ // choose a random position
+ int chosen_index = random2(floor_positions.size());
+ coord_def chosen_coord = floor_positions[chosen_index];
+ floor_positions[chosen_index] = floor_positions.back();
+ floor_positions.pop_back();
+
+ // check if it is too close to another seed
+ bool too_close = false;
+ for (unsigned int j = 0; j < seeds.size(); j++)
+ {
+ int diff_x = chosen_coord.x - seeds[j].x;
+ int diff_y = chosen_coord.y - seeds[j].y;
+ int distance_squared = diff_x * diff_x + diff_y * diff_y;
+
+ if (distance_squared < min_seperation_squared)
+ {
+ too_close = true;
+ break;
+ }
+ }
+
+ // if not too close, add it to the list
+ if (!too_close)
+ seeds.push_back(chosen_coord);
+ }
+
+ // 3. Return the pool seeds
+
+ return seeds;
+}
+
+// This function assumes the table is on the top of the lua stack.
+static vector<char> _pool_fill_glyphs_from_table(lua_State *ls,
+ const char *name)
+{
+ // We will go through the table and put each possible pool
+ // fill glyph in a vector once for each weight. This will
+ // make it easy to select random ones with the correct
+ // distribution when we need to.
+ vector<char> fill_glyphs;
+
+ lua_pushstring(ls, name);
+ lua_gettable(ls, -2);
+ if (!lua_isnil(ls, -1) && lua_istable(ls, -1))
+ {
+ // For some reason, LUA requires us to have a dummy
+ // value to remove from the stack whenever we do a
+ // table lookup. Here is the first one
+ lua_pushnil(ls);
+
+ // table is now at -2
+ while (lua_next(ls, -2) != 0)
+ {
+ // uses 'key' (at index -2) and 'value' (at index -1)
+ if(lua_type(ls, -2) == LUA_TSTRING
+ && lua_type(ls, -1) == LUA_TNUMBER)
+ {
+ // we use first character of string as glyph
+ char glyph = (lua_tostring(ls, -2))[0];
+
+ int count = lua_tointeger(ls, -1);
+ // sanity-check
+ if(count > 10000)
+ count = 10000;
+
+ if(glyph != '\0')
+ {
+ for(int i = 0; i < count; i++)
+ fill_glyphs.push_back(glyph);
+ }
+ }
+
+ // removes 'value'; keeps 'key' for next iteration
+ lua_pop(ls, 1);
+ }
+ }
+ lua_pop(ls, 1);
+
+ // We might have not got anything, if so, use floor
+ if(fill_glyphs.size() == 0)
+ fill_glyphs.push_back('.');
+
+ return fill_glyphs;
+}
+
LUAFN(dgn_count_feature_in_box)
{
@@ -695,6 +818,114 @@ LUAFN(dgn_octa_room)
return 0;
}
+LUAFN(dgn_remove_isolated_glyphs)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_STR(ls, find, "");
+ TABLE_CHAR(ls, replace, '.');
+ TABLE_INT(ls, percent, 100);
+ TABLE_BOOL(ls, boxy, false);
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ // we never change the border
+ if(x1 < 1)
+ x1 = 1;
+ if(x2 >= lines.width() - 1)
+ x2 = lines.width() - 2;
+ if(y1 < 1)
+ y1 = 1;
+ if(y2 >= lines.height() - 1)
+ y2 = lines.height() - 2;
+
+ for (int y = y1; y <= y2; ++y)
+ for (int x = x1; x <= x2; ++x)
+ if (strchr(find, lines(x, y)) && x_chance_in_y(percent, 100))
+ {
+ bool do_replace = true;
+ for (radius_iterator ri(coord_def(x, y), 1,
+ (boxy ? C_SQUARE : C_POINTY),
+ NULL, true); ri; ++ri)
+ {
+ if (_valid_coord(ls, lines, ri->x, ri->y, false))
+ if (strchr(find, lines(*ri)))
+ {
+ do_replace = false;
+ break;
+ }
+ }
+ if(do_replace)
+ lines(x, y) = replace;
+ }
+
+ return 0;
+}
+
+LUAFN(dgn_widen_paths)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_STR(ls, find, "");
+ TABLE_CHAR(ls, replace, '.');
+ TABLE_STR(ls, passable, traversable_glyphs);
+ TABLE_INT(ls, percent, 100);
+ TABLE_BOOL(ls, boxy, false);
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ // we never change the border
+ if(x1 < 1)
+ x1 = 1;
+ if(x2 >= lines.width() - 1)
+ x2 = lines.width() - 2;
+ if(y1 < 1)
+ y1 = 1;
+ if(y2 >= lines.height() - 1)
+ y2 = lines.height() - 2;
+
+ float antifraction_each = 1.0 - percent / 100.0f;
+ float antifraction_current = 1.0;
+ int percent_for_neighbours[9];
+ for (int i = 0; i < 9; i++)
+ {
+ percent_for_neighbours[i] = 100 - (int)(antifraction_current * 100);
+ antifraction_current *= antifraction_each;
+ }
+
+ // We do not replace this as we go to avoid favouring some directions.
+ vector<coord_def> coord_to_replace;
+
+ for (int y = y1; y <= y2; ++y)
+ for (int x = x1; x <= x2; ++x)
+ if (strchr(find, lines(x, y)))
+ {
+ int neighbour_count = 0;
+ for (radius_iterator ri(coord_def(x, y), 1,
+ (boxy ? C_SQUARE : C_POINTY),
+ NULL, true); ri; ++ri)
+ {
+ if (_valid_coord(ls, lines, ri->x, ri->y, false))
+ if (strchr(passable, lines(*ri)))
+ neighbour_count++;
+ }
+
+ // store this coordinate if needed
+ if(x_chance_in_y(percent_for_neighbours[neighbour_count], 100))
+ coord_to_replace.push_back(coord_def(x, y));
+ }
+
+ // now go through and actually replace the positions
+ for (unsigned int i = 0; i < coord_to_replace.size(); i++)
+ lines(coord_to_replace[i]) = replace;
+
+ return 0;
+}
+
LUAFN(dgn_replace_area)
{
LINES(ls, 1, lines);
@@ -793,6 +1024,69 @@ LUAFN(dgn_replace_random)
return 0;
}
+LUAFN(dgn_replace_closest)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_INT(ls, x, 0);
+ TABLE_INT(ls, y, 0);
+ TABLE_CHAR(ls, find, '\0');
+ TABLE_CHAR(ls, replace, '\0');
+ TABLE_BOOL(ls, required, false);
+
+ coord_def center(x, y);
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ int count = (x2 - x1 + 1) * (y2 - y1 + 1);
+ if (!count)
+ {
+ if (required)
+ luaL_error(ls, "%s", "No elements to replace");
+ return 0;
+ }
+
+ vector<coord_def> loc;
+ loc.reserve(count);
+
+ int best_distance = 10000;
+ unsigned int best_count = 0;
+ coord_def best_coord;
+
+ for (int this_y = y1; this_y <= y2; ++this_y)
+ for (int this_x = x1; this_x <= x2; ++this_x)
+ if (lines(this_x, this_y) == find)
+ {
+ coord_def here(this_x, this_y);
+ int distance = here.distance_from(center);
+ if(distance < best_distance)
+ {
+ best_distance = distance;
+ best_count = 1;
+ best_coord = here;
+ }
+ else if (distance == best_distance)
+ {
+ best_count++;
+ if(one_chance_in(best_count))
+ best_coord = here;
+ }
+ }
+
+ if (best_count == 0)
+ {
+ if (required)
+ return luaL_error(ls, "Could not find '%c'", find);
+ return 0;
+ }
+
+ lines(best_coord) = replace;
+
+ return 0;
+}
+
LUAFN(dgn_smear_map)
{
LINES(ls, 1, lines);
@@ -898,6 +1192,174 @@ LUAFN(dgn_spotty_map)
return 0;
}
+LUAFN(dgn_add_pools)
+{
+ LINES(ls, 1, lines);
+
+ TABLE_STR(ls, replace, ".");
+ TABLE_CHAR(ls, border, '.');
+ TABLE_INT(ls, pool_size, 100);
+ TABLE_INT(ls, seed_seperation, 2);
+
+ vector<char> fill_glyphs = _pool_fill_glyphs_from_table(ls, "contents");
+
+ int x1, y1, x2, y2;
+ if (!_coords(ls, lines, x1, y1, x2, y2))
+ return 0;
+
+ int size_x = x2 - x1 + 1;
+ int size_y = y2 - y1 + 1;
+
+ //
+ // The basic ideas here is that we place a number of
+ // pool "seeds" on the map and spread them outward
+ // randomly until they run into each other. We never
+ // fill in the last cell, so they never actually
+ // touch and we get paths between them.
+ //
+ // The algorithm we use to spread the pools is like a
+ // depth-/breadth-first search, except that:
+ // 1. We choose a random element from the open list
+ // 2. We have multiple starting locations, each
+ // with its own "closed" value
+ // 3. We mark all cells bordered by 2 (or more)
+ // distinct non-BORDER closed values with special
+ // closed value BORDER
+ //
+ // In the end, we used the "closed" values to determine
+ // which pool we are in. The BORDER value indicates
+ // a path between pools.
+ //
+
+ // NO_POOL
+ // -> must be lowest constant
+ // -> must match _get_pool_seed_positions
+ const int NO_POOL = 999997;
+ const int IN_LIST = 999998;
+ const int BORDER = 999999;
+ const int FORBIDDEN = 1000000;
+
+ // Step 1: Make a 2D array to store which pool each cell is part of
+ // -> We use nested vectors to store this. We cannot use
+ // a fixedarray because we don't know the size at
+ // compile time.
+
+ vector<vector<int> > pool_index(size_x, vector<int>(size_y, FORBIDDEN));
+ for(int x = 0; x < size_x; x++)
+ for(int y = 0; y < size_y; y++)
+ {
+ if(strchr(replace, lines(x + x1, y + y1)))
+ pool_index[x][y] = NO_POOL;
+ }
+
+ // Step 2: Place the pool seeds and add their neighbours to the open list
+
+ vector<coord_def> pool_seeds = _get_pool_seed_positions(pool_index,
+ pool_size,
+ seed_seperation);
+ vector<coord_def> open_list;
+
+ for(unsigned int pool = 0; pool < pool_seeds.size(); pool++)
+ {
+ int x = pool_seeds[pool].x;
+ int y = pool_seeds[pool].y;
+
+ pool_index[x][y] = pool;
+
+ // add neighbours to open list
+ for (orth_adjacent_iterator ai(pool_seeds[pool]); ai; ++ai)
+ if (_valid_coord(ls, lines, ai->x, ai->y, false))
+ {
+ pool_index[ai->x][ai->y] = IN_LIST;
+ open_list.push_back(*ai);
+ }
+ }
+
+ // Step 3: Spread out pools as far as possible
+
+ while(!open_list.empty())
+ {
+ // remove a random position from the open list
+ int index_chosen = random2(open_list.size());
+ coord_def chosen_coord = open_list[index_chosen];
+ open_list[index_chosen] = open_list.back();
+ open_list.pop_back();
+
+ // choose which neighbouring pool to join
+ int chosen_pool = NO_POOL;
+ for (adjacent_iterator ai(chosen_coord); ai; ++ai)
+ if (_valid_coord(ls, lines, ai->x, ai->y, false))
+ {
+ int neighbour_pool = pool_index[ai->x][ai->y];
+ if(neighbour_pool < NO_POOL)
+ {
+ // this is a valid pool, consider it
+ if(chosen_pool == NO_POOL)
+ chosen_pool = neighbour_pool;
+ else if(chosen_pool == neighbour_pool)
+ ; // already correct
+ else
+ {
+ // this is the path between pools
+ chosen_pool = BORDER;
+ break;
+ }
+ }
+ else if (neighbour_pool == FORBIDDEN)
+ {
+ // next to a wall
+ chosen_pool = BORDER;
+ break;
+ }
+ }
+
+ if(chosen_pool != NO_POOL)
+ {
+ // add this cell to the appropriate pool
+ pool_index[chosen_coord.x][chosen_coord.y] = chosen_pool;
+
+ // add neighbours to open list
+ for (orth_adjacent_iterator ai(chosen_coord); ai; ++ai)
+ if (_valid_coord(ls, lines, ai->x, ai->y, false)
+ && pool_index[ai->x][ai->y] == NO_POOL)
+ {
+ pool_index[ai->x][ai->y] = IN_LIST;
+ open_list.push_back(*ai);
+ }
+ }
+ else
+ {
+ // a default, although I do not know why we ever get here
+ pool_index[chosen_coord.x][chosen_coord.y] = NO_POOL;
+ }
+ }
+
+ // Step 4: Add the pools to the map
+
+ vector<char> pool_glyphs(pool_seeds.size(), '\0');
+ for(unsigned int i = 0; i < pool_glyphs.size(); i++)
+ pool_glyphs[i] = fill_glyphs[random2(fill_glyphs.size())];
+
+ for(int x = 0; x < size_x; x++)
+ for(int y = 0; y < size_y; y++)
+ {
+ int index = pool_index[x][y];
+ if(index < (int)(pool_glyphs.size()))
+ lines(x + x1, y + y1) = pool_glyphs[index];
+ else if(index == NO_POOL || index == BORDER)
+ lines(x + x1, y + y1) = border;
+ else if(index == FORBIDDEN)
+ ; // leave it alone
+ else
+ {
+ return luaL_error(ls, "Invalid pool index %i/%i at (%i, %i)",
+ index, pool_glyphs.size(), x + x1, y + y1);
+ }
+ }
+
+ return 0;
+}
+
static int dgn_width(lua_State *ls)
{
LINES(ls, 1, lines);
@@ -1037,11 +1499,15 @@ const struct luaL_reg dgn_build_dlib[] =
{ "make_box_doors", &dgn_make_box_doors },
{ "mapgrd_table", dgn_mapgrd_table },
{ "octa_room", &dgn_octa_room },
+ { "remove_isolated_glyphs", &dgn_remove_isolated_glyphs },
+ { "widen_paths", &dgn_widen_paths },
{ "replace_area", &dgn_replace_area },
{ "replace_first", &dgn_replace_first },
{ "replace_random", &dgn_replace_random },
+ { "replace_closest", &dgn_replace_closest },
{ "smear_map", &dgn_smear_map },
{ "spotty_map", &dgn_spotty_map },
+ { "add_pools", &dgn_add_pools },
{ "delve", &dgn_delve },
{ "width", dgn_width },
{ "layout_type", &dgn_layout_type },
--
1.8.1.2
|