summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ploog <dploog@users.sourceforge.net>2009-11-08 06:23:50 +0100
committerDavid Ploog <dploog@users.sourceforge.net>2009-11-08 06:25:44 +0100
commit227c7f40fc0ba8f2a15af767c30976d14f9e4ad6 (patch)
tree8ce072cc6e07182053059f44aed1c586f3fbd648
parent1c0a611a9e00fc789a8e71f1423e48bec7dd5020 (diff)
downloadcrawl-ref-227c7f40fc0ba8f2a15af767c30976d14f9e4ad6.tar.gz
crawl-ref-227c7f40fc0ba8f2a15af767c30976d14f9e4ad6.zip
Split up level_design.txt into smaller files.
Namely introduction.txt, syntax.txt, advanced.txt all inside of docs/develop/levels.
-rw-r--r--crawl-ref/README.pdfbin73217 -> 74722 bytes
-rw-r--r--crawl-ref/README.txt4
-rw-r--r--crawl-ref/docs/develop/levels/advanced.txt894
-rw-r--r--crawl-ref/docs/develop/levels/introduction.txt349
-rw-r--r--crawl-ref/docs/develop/levels/syntax.txt (renamed from crawl-ref/docs/develop/level_design.txt)1170
-rw-r--r--crawl-ref/source/dat/database/FAQ.txt2
-rw-r--r--crawl-ref/source/enum.h2
-rw-r--r--crawl-ref/source/util/docs/README.tex2
8 files changed, 1262 insertions, 1161 deletions
diff --git a/crawl-ref/README.pdf b/crawl-ref/README.pdf
index 7044917ad3..a801b4e06a 100644
--- a/crawl-ref/README.pdf
+++ b/crawl-ref/README.pdf
Binary files differ
diff --git a/crawl-ref/README.txt b/crawl-ref/README.txt
index 097efda10d..ad4c59b64a 100644
--- a/crawl-ref/README.txt
+++ b/crawl-ref/README.txt
@@ -125,8 +125,8 @@ them at the homepage, http://crawl-ref.sourceforge.net.
Crawl uses many hand-drawn (but often randomised) maps. Making them is fun and
easy. It's best to start with simple entry vaults (glance through
dat/entry.des for a first impression). Later, you may want to read
-docs/level_design.txt for the full power. If you're ambitious, new maps for
-branch ends are possible, as well.
+docs/develop/levels/introduction.txt. If you're ambitious, new maps for branch
+ends are possible, as well.
If you've made some maps, you can test them on your system (no compiling
needed) and then just mail them to the mailing list.
diff --git a/crawl-ref/docs/develop/levels/advanced.txt b/crawl-ref/docs/develop/levels/advanced.txt
new file mode 100644
index 0000000000..361116cc6c
--- /dev/null
+++ b/crawl-ref/docs/develop/levels/advanced.txt
@@ -0,0 +1,894 @@
+-----------------------------------------------
+How to make levels for Dungeon Crawl Stone Soup
+-----------------------------------------------
+
+Part III: Advanced Methods
+ ================
+
+Contents: I. Conditionalising levels
+ J. Validating levels
+ K. Portal vaults
+ L. Lua reference
+ M. Feature names
+ N. Map statistics
+ O. Map generation
+
+This document describes the advanced features of vault making. This includes
+usage of lua and how to create portal vaults.
+
+
+I. Conditionalising levels
+=============================
+
+Crawl translates level (.des) files into Lua code chunks and runs these chunks
+to produce the final level that is generated. While you don't need to use Lua
+for most levels, using Lua allows you to conditionalise or randomise levels
+with greater control.
+
+Let's take a simple example of randomisation:
+
+NAME: random_test
+# Put it on D:1 so it's easy to test.
+PLACE: D:1
+ORIENT: float
+MAP
+xxxxxxxxxxxxxxxxxxx
+x........{........x
+xxxAxxxxxBxxxxxCxxx
+xxx.xxxxx.xxxxx.xxx
+xxx@xxxxx@xxxxx@xxx
+ENDMAP
+
+Now let's say you want A, B, and C to be randomly rock or floor, but B should
+be floor if both A and C are rock. Here's one way to do it (add these lines
+to the map definition):
+
+: local asolid, csolid
+: if crawl.random2(2) == 0 then
+: asolid = true
+: subst("A = x")
+: else
+: subst("A = .")
+: end
+: if crawl.random2(2) == 0 then
+: csolid = true
+: subst("C = x")
+: else
+: subst("C = .")
+: end
+: if asolid and csolid then
+: subst("B = .")
+: else
+: subst("B = .x")
+: end
+
+This code uses crawl.random2(N) which returns a number from 0 to N-1
+(in this case, returns 0 or 1). So we give A a 50% chance of being
+rock, and the same for C. If we made both A and C rock, we force B to
+be floor, otherwise we use a subst that gives B the same 50% chance of
+being rock.
+
+You can conditionalise on various factors, such as player experience
+level:
+
+NAME: condition_002
+DEPTH: 1-27
+ORIENT: float
+: if you.xl() > 18 then
+MONS: greater mummy
+: else
+MONS: deep elf priest / deep elf sorcerer / deep elf demonologist
+: end
+MAP
+xxxxxx
+x1...x
+x1...+
+x1...x
+xxxxxx
+ENDMAP
+
+Or based on where the map is being generated:
+
+NAME: condition_003
+DEPTH: Elf:*, Orc:*
+ORIENT: float
+: if you.branch() == "Orc" then
+MONS: orc priest, orc high priest
+: else
+MONS: deep elf priest, deep elf high priest
+: end
+MAP
+xxxxxx
+x1...x
+x2...+
+x1...x
+xxxxxx
+ENDMAP
+
+When conditionalising maps, remember that your Lua code executes in
+two contexts:
+
+1) An initial compilation phase before the game starts.
+2) The actual mapgen phase when the dungeon builder is at work.
+
+In context (1), you will not get useful answers from the Crawl Lua API
+in general, because the game hasn't started. This is generally
+ignorable (as in the case above) because the compilation phase just
+checks the syntax of your Lua code. If you conditionalise your map,
+however, you may run into compile failures. Take this variant, which
+(incorrectly) attempts to conditionalise the map:
+
+NAME: condition_004
+DEPTH: Elf:*, Orc:*
+ORIENT: float
+: if you.branch() == "Orc" then
+MONS: orc priest, orc high priest
+MAP
+xxxxxx
+x1...x
+x2.I.+
+x1...x
+xxxxxx
+ENDMAP
+: elseif you.branch() == "Elf" then
+MONS: deep elf priest, deep elf high priest
+MAP
+xxxxxx
+x1...x
+x2.U.+
+x1...x
+xxxxxx
+ENDMAP
+: end
+
+This map will break the compile with the cryptic message "Must define
+map." (to compound the confusion, the line number for this error will
+be the first line number of the map following the buggy map).
+
+This error is because although the map is Elf or Orc only, at compile
+time, the branch is *neither* Elf nor Orc, so the level-compiler
+thinks you've neglected to define a map.
+
+Lua code can detect the compile phase using crawl.game_started() which
+returns true only when the player has started a game (and will return
+false when the map is being initially compiled).
+
+For more details on the available Lua API and syntax, see the Lua
+reference section.
+
+
+J. Validating levels
+=======================
+
+If you have a map with lots of transforms (SUBST and SHUFFLE), and
+want to guarantee that the map is sane after the transforms, you can
+use a validation hook.
+
+To take a very contrived example:
+
+NAME: contrived_001
+PLACE: D:2
+ORIENT: float
+TAGS: no_pool_fixup
+SUBST: .=.w
+SUBST: c=x.
+MAP
+xxxxxx
+x{.+.c
+x..+>x
+xxxxxx
+ENDMAP
+
+This map has a chance of leaving the player stuck on the upstair
+without access to the rest of the level if the two floor squares near
+the doors are substituted with deep water (from the SUBST line), or
+the 'c' glyph is substituted with rock. Since a cut-off vault is
+uncool, you can force connectedness with the rest of the level:
+
+validate {{ return has_exit_from_glyph('{') }}
+
+The has_exit_from_glyph() function returns true if it is possible to
+leave the vault (without digging, etc.) from the position of the {
+glyph. (This takes things like the merfolk ability to swim into
+account, so a merfolk character may see deep water between the stair
+and door.)
+
+The validate Lua returns false (or nil) to indicate that the map is
+invalid, which will force the dungeon builder to reapply transforms
+(SUBST and SHUFFLE) and validate the map again. If the map fails
+validation enough times, the dungeon builder will discard the entire
+level and retry (this may cause a different map to be selected,
+bypassing the buggy map).
+
+Going back to the example, if you just want to ensure that the player
+can reach the > downstair, you can use:
+
+validate {{ return glyphs_connected('{', '>') }}
+
+NOTE: You cannot use the colon-prefixed syntax for validation Lua. If
+you have a big block of code, use the multiline syntax:
+
+validate {{
+ -- This level is always cool.
+ crawl.mpr("This level is guaranteed perfect!")
+ return true
+}}
+
+
+K. Portal Vaults
+==================
+
+Portal vaults are vaults accessed by portals in the dungeon (labyrinths
+and bazaars are special cases of portal vaults). You can create custom
+portal vaults in the following steps (no compilation is necessary):
+
+* Create a new file name.des in the dat/ folder. Rules:
+ The "name" should be descriptive of the vault you're adding.
+ The "name" should not exceed eight letters.
+ The ending must be "des".
+* Add "name.des" to the list of local files in dat/clua/loadmaps.lua.
+* "name.des" should contain a comment at the top, explaining flavour and
+ gameplay goals of the portal vault (and perhaps additional ideas etc.)
+* Define at least one vault containing the portal (see below).
+* Define at least one destination map (see below).
+* Add a short in-game description for the string "desc" (see below) to
+ dat/descript/features.txt.
+
+Before going into the details of portal vault creation, some words about
+their uses: Portal vaults are different from branches in that they are
+not guaranteed. Also, there is only one go at a portal vault - if you
+leave, it's gone for good. You can apply special rules to a portal vault,
+like enforcing maprot.
+
+Portal vaults can be particulary thematic, using specialised monster
+sets, fitting loot, coloured dungeon features etc. Avoid death traps; it
+is no fun to enter a vault, being unable to leave and be killed outright.
+In order to provide fun and reduce spoiler effects, randomise. For portal
+vaults, it is desirable to have several different layouts (ideally each
+of the maps has some randomisation on its own). Often, it is a good idea
+to skew the map distribution: e.g. with four destination vaults, weights
+like 40,30,20,10 might be more interesting than 25,25,25,25.
+
+In order to test a portal vault, you can either use PLACE: D:2 for an
+entry vault, or use the wizard mode command &L for conjuring up the entry.
+
+Define a vault to hold the portal itself
+----------------------------------------
+
+# Bare-bones portal vault entry
+NAME: portal_generic_entry
+TAGS: allow_dup
+ORIENT: float
+MARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \
+ dst = "generic_portal" }
+KFEAT: O = enter_portal_vault
+MAP
+O
+ENDMAP
+
+Portal entries must contain a portal vault entry (enter_portal_vault).
+This feature must always have a marker that provides the portal with a
+description ("A portal to places unknown") and a destination
+("generic_portal").
+
+In case you want to make sure that the portal vault entry is only used
+once, you add a TAGS: uniq_BAR line. It should be noted that the label
+BAR may *not* end in _entry (otherwise the level builder assumes that
+the vault is a branch entry).
+
+If you want the place name displayed while in the vault to be different
+than the destination name, then you can give one_way_stair() a "dstname"
+parameter. If you want the place origin for items in a character
+dump to be different than the default you can give one_way_stair a
+"dstorigin" parameter (i.e., dstname = "garden", dstorigin = "in the gardens").
+If you want the place name abbreviation used when displaying notes to be
+different than than the default you can use the "dstname_abbrev" parameter.
+
+You can dynamically change the origin string using the lua function
+dgn.set_level_type_origin(), and dynamically change the place name
+abbreviation with dgn.set_set_level_name_abbrev().
+
+Known portal vault entries will be displayed on the overmap. By default
+the name shown on the overmap will be the "dstname" parameter, or if
+that isn't present the "dst" paremeter. It can be set to something else
+with the "overmap" parameter. A note can be made to accompany the
+portal's position on the overmap with the "overmap_note" parameter.
+
+Bones files for characters killed in the portal vault will normally
+use an extension derived from the first three letters of the 'dst'
+property. You can override this by setting the 'dstext' property to
+your preferred extension.
+
+This will produce a portal, but attempting to use it will trigger an
+ASSERT since there's no map for the destination. So we create a
+destination map like so:
+
+Define a destination map
+------------------------
+
+NAME: portal_generic_generic
+# Tag must match dst value of portal in entry.
+TAGS: generic_portal allow_dup
+ORIENT: encompass
+MONS: ancient lich
+KFEAT: > = exit_portal_vault
+MAP
+xxxxxxxxxxx
+x111111111x
+x1A111111>x
+x111111111x
+xxxxxxxxxxx
+ENDMAP
+
+Note that the entry point into the map will be a stone arch. You must
+provide an exit to the dungeon explicitly (KFEAT: > = exit_portal_vault)
+or the player will not be able to leave.
+
+Stairs will not work right in portal vaults, do not use them.
+
+You can use multiple maps with the destination tag (generic_portal),
+and the dungeon builder will pick one at random.
+
+The MARKER parameters
+---------------------
+
+The lines
+ MARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \
+ dst = "generic_portal" }
+ KFEAT: O = enter_portal_vault
+ensure that an 'O' glyph will be turned into a portal. Upon leaving the portal
+vault, you will be placed on its entry which has been turned into a floor. You
+can turn it into something different (usually an empty stone arch), by adding
+ floor = 'stone_arch'
+to the lua:one_way_stair parameters.
+
+Note that the desc string is what you will see upon examining the portal.
+The dst string is used for Crawl's right hand stat area; it will show
+ Place: generic portal
+in the above example. Here is a lost of the parameters that can be used
+within one_way_stair (taken from icecave.des):
+ desc = "A frozen archway", # description of the portal before entry
+ dst = "ice_cave", # label used for maps and entry vaults
+ dstname = "Ice Cave", # used for PLACE: on the main screen
+ dstname_abbrev = "IceCv", # used in the notes
+ dstorigin = "in an ice cave", # appendix for items picked up there
+ overmap = "frozen archway", # used on the overmap (X)
+ floor = "stone_arch" # feature left after escaping the portal
+
+The dst string is also used to link the destination maps to the entry maps.
+In case dstname is missing, dst will be used.
+
+You can replace lua:one_way_stair by lua:timed_marker in order to make timed
+portal vaults (which will disappear after some time). bazaar.des and lab.des
+contain examples. For timed portals, you may want to add messages to the file
+dat/clua/lm_tmsg.lua.
+
+Using lua functions as shortcuts
+--------------------------------
+
+If you are making several entry and destination vaults, you will note a
+lot of duplicated header statements. This can be lessened using lua.
+Define a lua block right at the top (after your comments) as follows:
+
+{{
+function generic_portal(e)
+ e.marker([[O = lua:one_way_stair { desc = "A portal to places unknown",
+ dst = "generic_portal",
+ floor = "stone_arch" }]])
+ e.kfeat("O = enter_portal_vault")
+ e.colour("O = magenta")
+end
+}}
+
+Instead of the MARKER and KFEAT lines introduced above you now just use
+ :generic_portal(_G)
+and the resulting portal glyphs will even be magenta!
+
+Defining a random monster set
+-----------------------------
+
+Portal vaults require a defined random monster set to make the Shadow
+Creatures spell work. This is done by calling dgn.set_random_mon_list()
+manually. Here's an example from ice_cave_small_02 in icecave.des:
+ : dgn.set_random_mon_list("ice beast w:90 / ice dragon / nothing")
+You can use "nothing" to have the spell fail sometimes.
+
+If you are using the same random monster list in several destination maps,
+you can define a lua block and call it from the destination map definition.
+This example is from sewer.des:
+
+{{
+function sewer_random_monster_list(e)
+ e.set_random_mon_list("giant bat w:20 / giant newt w:20 / small snake / \
+ ooze / worm / snake / giant mosquito w:15")
+end
+}}
+
+You can then use this line in the map definition to execute the lua block:
+ : sewer_random_monster_list(_G)
+
+You can also set env.spawn_random_rate() to have monsters generated from the
+list during play.
+
+Milestones for portal vaults
+----------------------------
+
+This example is from icecave.des, defined in the lua preludes:
+
+{{
+function ice_cave_milestone(e)
+ crawl.mark_milestone("br.enter", "entered an Ice Cave.")
+end
+}}
+
+The function is called from each of the destination map definitions:
+
+: ice_cave_milestone(_G)
+
+This marks down entering the portal vault in the milestones. When the portal
+is entered, the destination map is chosen and the call to crawl.mark_milestone
+is executed along with the rest of the map definition.
+
+Adding milestones in a .des does have the slight catch of creating multiple
+milestones if the map fails validation for some reason, so it's best used
+in maps that will never fail validation.
+
+
+L. Lua reference
+===================
+
+How maps are processed
+----------------------
+
+Under the hood, Crawl translates everything in a .des file to Lua. You
+don't need to know what the underlying Lua looks like to design
+levels, but it helps.
+
+Crawl uses Lua 5.1 from http://www.lua.org (the site has information
+on the Lua language). Let's examine how Crawl converts a map
+definition into Lua code with an example map:
+
+NAME: statue_in_pool
+TAGS: no_rotate no_pool_fixup
+: if you.absdepth() < 7 then
+MONS: plant
+: else
+MONS: oklob plant
+: end
+MAP
+1...1
+.www.
+.wGw.
+.www.
+1...1
+ENDMAP
+
+Crawl will convert this map into the following Lua code, wrapped in an
+anonymous function (this is called a Lua chunk):
+
+function ()
+ tags("no_rotate")
+ tags("no_pool_fixup")
+ if you.absdepth() < 7 then
+ mons("plant")
+ else
+ mons("oklob plant")
+ end
+ map(".....")
+ map(".www.")
+ map(".wGw.")
+ map(".www.")
+ map(".....")
+end
+
+If your level defines prelude or validation Lua code, such code is
+extracted into separate prelude and validation chunks. The prelude and
+validation chunks are empty unless specified.
+
+Apart from the special NAME map header, every map header translates to
+a Lua function with the same name in lowercase. For instance, KFEAT:
+<xyz> is translated into kfeat("<xyz>").
+
+If you have a space or comma separated list (such as TAGS, MONS, ITEM,
+etc.), then each space/comma separated item is passed into a separate
+call to the corresponding Lua function. For instance:
+
+TAGS: no_rotate no_pool_fixup
+->
+tags("no_rotate")
+tags("no_pool_fixup")
+
+MONS: orc, gnoll
+->
+mons("orc")
+mons("gnoll")
+
+Knowing what the generated Lua looks like under the hood is useful
+because it allows you to extract repeated boilerplate in similar
+vaults into a Lua function in the .des file's prelude. For instance,
+if you were planning to write a whole slew of vaults featuring statues
+in water guarded by plants, you could extract the common code into the
+top of the .des file as:
+
+# This block has to be placed before any other vault in the .des file.
+{{
+function statue_pool_map(e)
+ e.tags("no_rotate")
+ e.tags("no_pool_fixup")
+ if you.absdepth() < 7 then
+ e.mons("plant")
+ else
+ e.mons("oklob plant")
+ end
+end
+}}
+
+NAME: statue_in_pool
+# Pass in the Lua environment global _G to the prelude function.
+: statue_pool_map(_G)
+MAP
+1...1
+.www.
+.wGw.
+.www.
+1...1
+ENDMAP
+
+You can also use arbitrary Lua directly in vault definitions, which is
+handy when randomizing things:
+
+NAME: statue_in_pool
+: local plant_weight = crawl.random_range(1,10)
+: mons("plant w:" .. plant_weight ..
+: " / oklob plant w:" .. (10 - plant_weight))
+MAP
+1...1
+.www.
+.wGw.
+.www.
+1...1
+ENDMAP
+
+How Lua chunks are associated with a C++ map object
+---------------------------------------------------
+
+A map's Lua chunk consists of calls to functions such as tags(),
+mons(), etc. These functions are defined in the dgn table (see the Lua
+API reference below), and they expect to act on an instance of Crawl's
+C++ mapdef object. Given:
+
+tags("no_rotate")
+
+the actual Lua call needs to be:
+
+dgn.tags(<map>, "no_rotate")
+
+Where <map> is the C++ map object to which the tag should be added.
+Since calling dgn.<foo>(<map>, <xxx>) is tedious, dat/clua/dungeon.lua
+wraps the Lua chunk for the map into an environment that defines
+wrappers for all the functions in 'dgn' as:
+
+ function <xyz>(...)
+ dgn.<xyz>(<map>, ...)
+ end
+
+i.e. for every function <xyz> in the 'dgn' table, we define a new
+function <xyz> that just calls dgn.<xyz>() with the current map as the
+first parameter, and the other parameters as passed in. Thus Lua code
+that you write as:
+
+tags("no_rotate")
+
+is translated to the correct dgn.tags(<map>, "no_rotate").
+
+While this is done automatically for map code, if you need to call Lua
+code that was not defined in the scope of the map, as in the example
+statue_pool_map() function, you need to pass in the map environment to
+that function if you want it to modify the map. Thus the call to
+statue_pool_map looks like:
+
+: statue_pool_map(_G)
+
+Steps involved in processing .des files
+---------------------------------------
+
+* Level files are compiled into a series of Lua chunks. Each map can
+ have one or more Lua chunks associated with it: the prelude, the
+ body, and a validation chunk. The body is mandatory, but validation
+ and prelude chunks are necessary only if your map needs validation
+ or fancy selection criteria.
+
+* When first compiling a .des file, Crawl compiles each map's Lua
+ chunks, then compiles and runs the prelude, body and validation
+ immediately to verify that the Lua code is not broken. Lua errors at
+ this stage will cause Crawl to exit with an error message (hopefully
+ relevant). Note that the validation Lua chunk's return code is
+ completely ignored at this stage - it is only run to check for
+ syntax errors in the code.
+
+* When a new game is started, Crawl will run the Lua preludes for all
+ maps (most maps should have no prelude - map preludes slow the game
+ down). At this point, preludes can change the map's placement or
+ availability.
+
+* When the dungeon builder selects a map (based on TAGS, DEPTH,
+ PLACE), it re-runs the map prelude and the map body, applies
+ transforms (SUBST, SHUFFLE) if any, then calls the map's validation
+ Lua. If the map passes validation, the dungeon builder continues
+ with level-generation; otherwise, it restarts from the map prelude.
+
+The global prelude
+------------------
+
+Every .des file can have (at the start of the file) Lua code that is
+not associated with any specific map, but with all maps in the file.
+This is called the global prelude. The global prelude is run before
+running any other Lua code in the file, once during compilation, and
+once at start of game.
+
+You can use the global prelude to define functions and set up globals
+that the rest of the maps in the .des file use. If you have a lot of
+common code, you should probably add it to dungeon.lua instead.
+
+Syntax for using Lua in .des files
+----------------------------------
+
+* Colon-prefixed lines are individual Lua lines, extending to the end
+ of the line. E.g.
+
+ : crawl.mpr("Hello")
+
+ Colon-prefixed lines are always in the main Lua chunk, unless they occur
+ before any map definitions, in which case they go to the global prelude.
+
+* Lua blocks for the main (body) Lua
+ lua {{ <code> }}
+ or
+ lua {{
+ <code>
+ }}
+ The "lua" word is optional; you can also use:
+ {{ <code> }}
+ and
+ {{
+ <code>
+ }}
+
+NOTE: Colon-prefixed lines, or lua {{ }} blocks defined before any
+map's NAME: directive will add the Lua code to the global prelude.
+
+* Lua blocks for the prelude:
+ prelude {{ <code> }}
+ or
+ prelude {{
+ <code>
+ }}
+
+* Lua blocks for the validate chunk:
+ validate {{ <code> }}
+ or
+ validate {{
+ <code>
+ }}
+
+Debugging Lua
+-------------
+
+Since Lua action happens in the guts of Crawl, it can be hard to tell
+what's going on. Lua debugging involves the time-honoured method of
+peppering your code with print statements:
+
+* Use error() or print() for compile-time work (i.e. when Crawl reads
+ the .des file). Note that print() just writes to the terminal and
+ keeps going, while error() forces Crawl to exit immediately (at
+ compile time; errors during level-generation are handled
+ differently).
+
+* Use crawl.mpr() for output when the game has started (at
+ level-generation time).
+
+It's very important that your finished level never croaks during
+level-generation. A Lua error at this stage is considered a validation
+failure.
+
+Special dungeon-related Lua marker properties
+---------------------------------------------
+
+There are several properties a Lua marker can have which will affect the
+dungeon cell which they are on:
+
+* connected_exclude: Consider the cell to be separate from neighboring
+ cells with identical or similar features. Currently only useful
+ for preventing adjacent doors from grouping together into a gate,
+ forcing them to open and close as separate doors. See the Evil
+ Zoo (minivault_9) in dat/mini.des for an example.
+
+* door_description_suffix: A string to append to the description of
+ any door the marker is on. This should be used for doors
+ rather than the feature_description property since it elemintates
+ the need to track if the door is opened or closed, plus it will
+ have no effect on secret doors which have yet to be detected.
+
+* feature_description: What to use as the short description of the
+ cell's feature.
+
+* feature_description_long: What to use as the long description of the
+ cell's feature.
+
+* stop_explore: If set to anything, and placed on a cell with a statue
+ or orcish idol, will cause auto-explore to stop with the message
+ "Found <whatever>."
+
+* stop_explore_msg: Like stop_explore, but when auto-explore is stopped
+ the content of the property will be printed out as a message.
+
+* veto_disintegrate: If this property is set to "veto" then the cell
+ will be immune to disintegration.
+
+* veto_fragmentation: If this proprety is set to "veto" then the cell
+ will be unaffected by fragmentation (Lee's Rapid Deconstruction
+ spell).
+
+* veto_shatter: If this property is set to "veto" then the cell will
+ be unaffected by the Shatter spell.
+
+Lua API reference
+-----------------
+a. The Map.
+b. Global game state.
+c. Character information.
+
+
+Lua API - the Map
+-----------------
+
+Lua functions dealing with the map are mostly grouped under the "dgn"
+module. For convenience, .des file Lua chunks are run in an environment
+such that function calls written as:
+
+ fn(x, y, ...)
+
+are translated to
+
+ dgn.fn(map, x, y, ...)
+
+where "map" is the reference to the map that the currently executing
+Lua chunk belongs to. This is only for Lua chunks that belong to a
+map, Lua code in the global prelude does not get this treatment
+(because the global prelude is not associated with any map).
+
+Functions in the dgn module:
+
+default_depth, name, depth, place, tags, tags_remove, chance, weight,
+orient, shuffle, shuffle_remove, subst, subst_remove, map, mons, item,
+kfeat, kitem, kmons, grid, points_connected, gly_point, gly_points,
+original_map, glyphs_connected, orig_glyphs_connected, orig_gly_point,
+orig_gly_points, load_des_file, feature_number, feature_name,
+dgn_event_type, register_listener, remove_listener, remove_marker,
+num_matching_markers, feature_desc, feature_desc_at, item_from_index,
+mons_from_index, change_level_flags, change_branch_flags,
+set_random_mon_list
+
+
+Additionally, the dgn module provides a global "mapgrd" variable that
+can access the current map glyphs. The top left symbol in the map
+can be assigned like this:
+
+ mapgrd[1][1] = 'x'
+
+The bottom right symbol can be assigned like this:
+
+ mapgrd[width()][height()] = "."
+
+
+Lua API - global game state
+---------------------------
+
+The "crawl" module provides functions that describe the game state or
+provide utility methods.
+
+mpr, mesclr, random2, coinflip, one_chance_in, redraw_screen,
+input_line, c_input_line, getch, kbhit, flush_input, sendkeys,
+playsound, runmacro, bindkey, setopt, msgch_num, msgch_name, regex,
+message_filter, trim, split, game_started, err_trace, args,
+mark_milestone
+
+
+Lua API - character information
+-------------------------------
+
+The "you" module provides functions that describe the player character.
+
+turn_is_over, spells, abilities, name, race, class, god, hp, mp,
+hunger, strength, intelligence, dexterity, xl, exp, res_poison,
+res_fire, res_cold, res_draining, res_shock, res_statdrain,
+res_mutation, res_slowing, gourmand, levitating, flying, transform,
+stop_activity, floor_items, where, branch, subdepth, absdepth
+
+
+M. Feature Names
+==================
+
+These are the feature names usable in MARKER declarations:
+
+unseen, rock_wall, stone_wall, closed_door, metal_wall, secret_door,
+green_crystal_wall, orcish_idol, wax_wall, permarock_wall,
+silver_statue, granite_statue, orange_crystal_statue,
+statue_reserved_1, statue_reserved_2, lava, deep_water, shallow_water,
+water_stuck, floor, exit_hell, enter_hell, open_door, trap_mechanical,
+trap_magical, trap_iii, undiscovered_trap, enter_shop,
+enter_labyrinth, stone_stairs_down_i, stone_stairs_down_ii,
+stone_stairs_down_iii, escape_hatch_down, stone_stairs_up_i,
+stone_stairs_up_ii, stone_stairs_up_iii, escape_hatch_up, enter_dis,
+enter_gehenna, enter_cocytus, enter_tartarus, enter_abyss, exit_abyss,
+stone_arch, enter_pandemonium, exit_pandemonium, transit_pandemonium,
+builder_special_wall, builder_special_floor, enter_orcish_mines,
+enter_hive, enter_lair, enter_slime_pits, enter_vaults, enter_crypt,
+enter_hall_of_blades, enter_zot, enter_temple, enter_snake_pit,
+enter_elven_halls, enter_tomb, enter_swamp, enter_shoals,
+enter_reserved_2, enter_reserved_3, enter_reserved_4,
+return_from_orcish_mines, return_from_hive, return_from_lair,
+return_from_slime_pits, return_from_vaults, return_from_crypt,
+return_from_hall_of_blades, return_from_zot, return_from_temple,
+return_from_snake_pit, return_from_elven_halls, return_from_tomb,
+return_from_swamp, return_from_shoals, return_reserved_2,
+return_reserved_3, return_reserved_4, enter_portal_vault,
+exit_portal_vault, altar_zin, altar_shining_one, altar_kikubaaqudgha,
+altar_yredelemnul, altar_xom, altar_vehumet, altar_okawaru,
+altar_makhleb, altar_sif_muna, altar_trog, altar_nemelex_xobeh,
+altar_elyvilon, altar_lugonu, altar_beogh, fountain_blue,
+fountain_sparkling, fountain_blood, dry_fountain_blue,
+dry_fountain_sparkling, dry_fountain_blood, permadry_fountain
+
+
+N. Map Statistics
+===================
+
+Full-debug Crawl builds (this does not include normal Crawl builds
+that have wizard-mode - you must build Crawl with "make debug", not
+"make wizard") can produce map generation statistics. To generate
+statistics, run crawl from the command-line as:
+
+crawl -mapstat
+
+This will generate 100 Crawl dungeons and report on the maps used in a
+file named "mapgen.log" in the working directory.
+
+You can change the number of dungeons to generate:
+
+crawl -mapstat 10
+
+Will generate 10 dungeons. If you merely want statistics on the
+probabilities of the random map on each level, use:
+
+crawl -mapstat 1
+
+
+O. Map Generation
+===================
+
+Full-debug Crawl builds (see above for more information) include a test for
+generating specific vaults and outputting a copy of the map to a text file for
+inspection. This is most useful for portal and other encompass vaults which
+use randomisation heavily.
+
+To use the test, you must edit source/test/vault_generation.lua. Fill in the
+following variables:
+
+ * map_to_test: The exact name of the vault you want to generate.
+ * checks: How many times to generate the vault. Default value is 10.
+ * output_to: The basic filename to output the results of generation to. This
+ will have ".<iteration>" appended. For example, "volcano.map" will
+ result in files named "volcano.map.1", "volcano.map.2", etc.
+ * need_to_load_des: If the file is not included in one of the .des files that
+ are listed in source/dat/clua/loadmaps.lua, this should be set to true,
+ and the following variable should be set.
+ * des_file: The name of the file to load. The file should be located in the
+ source/dat folder.
+
+Once you have saved your changes, run crawl:
+
+ crawl -test vault_generation
+
+Once all of the tests have been finished successfully you should find the
+relevant files in your working directory.
diff --git a/crawl-ref/docs/develop/levels/introduction.txt b/crawl-ref/docs/develop/levels/introduction.txt
new file mode 100644
index 0000000000..1066c11583
--- /dev/null
+++ b/crawl-ref/docs/develop/levels/introduction.txt
@@ -0,0 +1,349 @@
+-----------------------------------------------
+How to make levels for Dungeon Crawl Stone Soup
+-----------------------------------------------
+
+Part I: INTRODUCTION
+ ============
+
+Contents: A. Introduction
+ B. Sample map
+ C. The .des files
+ D. Kinds of vaults
+ E. Hints for level makers
+ F. Principles of vault making
+
+This document explains some basics of vault making. For actual vault work,
+you will need to look at syntax.txt. However, by simply looking at the
+example provided here and looking through entry.des, you should be able to
+make changes or small vaults on your own.
+
+
+A. Introduction
+=================
+
+A game like Crawl generally uses random content. This also applies to maps,
+which are made in various ways, but all with a large random component.
+However, for several reasons, it is also useful to have handmade maps: they
+can provide challenges random levels would rarely come up with; they can be
+especially thematic, for example on branch ends. Simple pre-made pieces of
+maps are called "vaults", these can provide challenge, loot, flavour or
+just make the rather big levels of Crawl more interesting.
+
+These vaults come in all sizes, from mere 3x3 to level encompassing maps.
+Section B contains an example vault (not to be used somewhere), giving you
+an idea of how vaults are defined.
+
+Since predefined and fixed content clashes with the philosophy of randomly
+generated content, vaults can be randomised in many ways. The other way to
+help lessen the effect of deja vu is by having lots of vaults. Therefore,
+new vaults are always appreciated.
+
+
+B. Sample Map
+===============
+
+Before going into the technical details of the level-file syntax, it might be
+a good idea to look at an example - a branch entry for the Ecumenical Temple -
+to see what a map definition looks like.
+
+# name below:
+NAME: useless_temple_entry
+# header section below:
+ORIENT: float # "ORIENT: float" tells the level builder that
+ # this entry can be anywhere on the level.
+TAGS: temple_entry # "TAGS: temple_entry" turns the 'O' on the
+MONS: butterfly, plant # map into stairs to the Temple.
+ITEM: stone
+# actual map below: # The symbols on the map:
+MAP # x - rock wall
+xx.d.xx # . - floor
+x..1..x # @ - entry point (
+@d2O2d. # O - stairs to the Temple
+x..1..x # 1 - first monster from list (here butterfly)
+xx.d.xx # 2 - second monster from list (here plant)
+ENDMAP # d - first item from the list (here stones)
+
+Every map consists of a name, a header and the actual map (the order is not
+important as long as the name comes first, but try to stick to this order for
+consistency).
+
+Lines starting with # are comments. The keywords available are explained
+in detail in the syntax.txt file.
+
+
+C. The .des files
+===================
+
+All fixed level information resides in various .des files to be found in the
+dat directory. If you are interested in adding some vaults, say, start with
+the existing ones and modify them. If you are new to vault making, look at
+
+ entry.des - entry vaults (each game - but not tutorial games - uses one of
+ these premade maps for the vicinity of the entrance)
+ float.des - floating vaults
+ large.des - all regular vaults which have ORIENT:encompass/northwest etc
+ mini.des - minivaults (no ORIENT line at all)
+
+The following contain vaults for special branches:
+
+ crypt.des - random vaults for Crypt, the Crypt:5 branch ends, and the
+ predefined maps for Tomb:1, Tomb:2 and Tomb:3
+ elf.des - arrival and random vaults for Elf, and Elf:7 branch ends
+ hells.des - hell entrances, Geryon's vestibule, Coc:7, Tar:7, Dis:7, Geh:7
+ hive.des - hive entrances, random hive vaults, Hive:2
+ lair.des - lair entrances, random vaults for lair proper and sub-branches,
+ and the branch ends: Shoals:5, Swamp:5, Snake:5, Slime:6
+ orc.des - orcish mine entrances, orc only vaults
+ pan.des - vaults of the Pan demon lords, Pan minivaults
+ temple.des - Ecumenical Temples, and Temple entrances
+ vaults.des - entrances for the Vaults, Vaults-specific vaults, the
+ Hall of Blades, and Vaults:8
+ zot.des - vaults for the Zot branch and the maps for Zot:5
+
+There are a number of portal vaults. The following files contain a lot more
+technology. Look into them if you want to make portal vaults of your own, or
+just see lua applied.
+
+ altar.des - minivaults containing altars
+ bailey.des - the bailey portal vault
+ bazaar.des - entrances to bazaar portal vaults, and bazaars proper
+ icecave.des - the ice cave portal vault
+ lab.des - labyrinths exits and flavour vaults
+ ossuary.des - the ossuary portal vault
+ sewer.des - the sewer portal vault
+ shrine.des - the shrine portal vault
+ volcano.des - the volcano portal vault
+ ziggurat.des - the ziggurat entry vaults, pillars and arenas
+
+The following .des files are rather special. Look, don't touch.
+
+ arena.des - arenas for the arena mode
+ didact.des - lua and vaults for syntax checking - not used in-game
+ dummy.des - global dummy balancers
+ layout.des - level layout code that has been moved from dungeon.cc and
+ rewritten in Lua.
+ rooms.des - special monster rooms, such as orc, kobold and jelly rooms
+
+
+D. Kinds of Vaults
+====================
+
+The different kinds of vaults used by Crawl are described below.
+
+Entry vault:
+ A map designed for D:1, which (usually) contains the primary upstair {
+and is always tagged "entry". A player starting a new game will usually land
+in an entry vault.
+
+Branch entry vault, or branch portal vault:
+ A map containing the entry to a branch - either a branch stair (such as
+the stair to the Orcish Mines), or a branch portal (a portal to Hell, say).
+Always tagged "<branchname>_entry".
+
+Special level:
+ A map for a location of significance in the game, such as the Ecumenical
+Temple, or the end of branches such as level 5 of the Snake Pit (Snake:5).
+Special level maps usually have a PLACE: attribute.
+
+Random vaults:
+ Random vaults may be randomly generated at any level in the dungeon.
+Random vault maps are selected by the dungeon builder based on their DEPTH:
+attributes.
+
+Random minivaults:
+ Random minivaults are small maps that are placed onto a level that the
+dungeon builder has already constructed fully otherwise (the level may
+include other vaults).
+
+Minivaults are distinguished from normal vaults by the absence of an
+ORIENT: declaration. Any map without a specified ORIENT: is a
+minivault. Minivaults are handled like floating vaults (ORIENT: float
+vaults) in most respects. The differences are:
+
+1. Floating vaults may be placed before the rest of the level layout
+ is generated, and the rest of the level may be built around the floating
+ vault. This is never the case for minivaults.
+
+2. Floating vaults may be placed anywhere in the map, including places
+ completely separated from the rest of the level by rock. The
+ dungeon builder will then connect the exits from the floating vault
+ to the rest of the level, usually producing obvious "passages" from
+ the floating vault to the main body of the level.
+
+ In contrast, minivaults are placed such that at least one square of
+ the minivault overlaps with an existing part of the level, and are
+ thus more likely to look like part of the level. Unlike floating
+ vaults, the dungeon builder assumes that any one square of overlap
+ is enough to connect the minivault to the rest of the level and
+ makes no effort to connect exits from the minivault to the level.
+ You can ask the dungeon builder to connect exits from your
+ minivault with the "mini_float" tag.
+
+
+E. Hints for level makers
+===========================
+
+Stairs
+------
+You do not have to place all of the stairs unless the level is full
+screen, in which case you must place all except the extra stairs (these
+are glyphs > and < and produce escape hatches). Any of the other stairs
+which are not present in the vault will be randomly placed outside it.
+
+Also generally try to avoid rooms with no exit (you can use > or < to
+make it possible for players to get away, although there are other,
+more elaborate options like teleporation traps, etc.). However, unless
+needed for the purpose, escape hatches are generally not interesting.
+If you do use them, > is almost always better than <.
+
+Entry points
+------------
+Minivaults can use explicit @ exits, or be completely surrounded by
+one space of floor for accessibility. Alternatively, you can request
+that the dungeon builder pick appropriate exits as it does for
+floating vaults by using the "mini_float" tag.
+
+The entry point '@' must be present for all vaults (except for
+full-screen vaults where it must not, and for floating vaults and
+minivaults where it is optional). All @ will be connected to floor
+space in the rest of the map (multiple @ close together may merge
+into the same exit corridor). Make sure that no part of your entry
+level can be cut off! If no @ is present in a floating vault (and
+there are no doors on the edge of the map, see below), the level
+builder will use one or more random floor spaces '.' or doors at the
+circumference as exits. Note that it is not possible to predict
+which spaces the level builder will choose to connect; if you need
+predictability, use explicit @ exits on the edge.
+
+The level-builder will also implicitly treat doors and secret doors
+on the edge of a map as explicit exits (the same as using @) and
+connect them to the rest of the level.
+
+Not using @ and allowing the level-builder to pick exits is
+acceptable in floating vaults, but when you use no @'s with this
+feature in mind, please add comments stating this - else somebody
+may just add @'s later on. :)
+
+Minivaults vs. random vaults
+----------------------------
+Minivaults are handled very differently from regular vaults and special
+levels. They're placed *after* normal map generation, whereas normal
+vaults are placed before generating the rest of the level. There's no
+way to guarantee generation of a minivault on a particular level, although
+using a PLACE: attribute makes the dungeon builder try very hard to place
+the minivault on the specified level. Regular vaults can always be forced to
+appear using a PLACE: attribute.
+
+Technically, you make a minivault like a normal floating vault but
+without an ORIENT: line. Note that minivaults used to be exclusively of
+size 12x12 but this restriction is gone. Still, the smaller the better.
+
+Where possible, use minivaults instead of regular vaults, because the dungeon
+builder has greater freedom with the rest of the level layout when using
+minivaults.
+
+levdes.vim
+----------
+If you use vim, the levdes.vim syntax highlighting script (provided
+in the dat directory) can make level-editing far more pleasant by colouring
+different features in maps and syntax-highlighting .des-file syntax. vim is
+available for nearly all operating systems, including Windows.
+
+
+F. Principles of vault making
+===============================
+
+Small is good!
+--------------
+This applies mostly to entry vaults and minivaults. Especially entry vaults
+should be rather small. Their intention is to provide some atmosphere for
+the starting room, not to get a grip on the whole of D:1. Minivaults should
+be rather small, as well, in order to increase the chances they may actually
+be chosen during level generation.
+
+Randomise!
+----------
+The level making syntax is very supportive for making a single map appear
+in many versions. Use the SHUFFLE: and SUBST: and NSUBST: directives and
+look at the existing entry vaults. Besides reducing tedium, this avoids
+giving veterans a spoiled edge. As an example, if a secret chamber with
+loot is always at the same place, it's a no-brainer for those who know.
+The same goes for traps. This is much less so if there are several places
+for the chamber (or trap) and there's even a chance it doesn't exist.
+
+You can also use WEIGHT to create modified versions of the same map. In
+order to do this, make several maps and endow each with a chance such
+that the sum of chances add up to 10.
+
+Randomisation does not just apply to layout: you could also have
+different monster population sets (for example make a branch end skewed
+for either melee or ranged opponents), or perhaps couple difficulty to
+loot.
+
+Not too much loot!
+------------------
+For example, entry vaults should in general have very little loot - in
+particular no good_xxx or '*' items lest they might give incentive for
+start-scumming. For random vaults, there needn't be loot at all and, in
+any case, there shouldn't be too much of it. Compare with the branch ends
+rich in treasure (Tomb:3, Cocytus etc.) to get a feeling for this.
+
+It is very easy to fall into the power spiral trap: making newer vaults
+harder than the old ones, but handing out more loot. Be strong, don't
+give in to that temptation.
+
+Have a theme.
+-------------
+It is often worthwhile (for me at least) to have a theme in mind before
+making the actual level. For entry vaults, something simple like 'forest'
+or 'fortress' may be enough. For later (or larger) maps, try to think of
+distinguishing features your map may have. Being cool can be good enough,
+but possessing some gameplay value (for example by being easier for
+particular skills/capabilities like ranged attacks or Traps & Doors or
+necromancy) is even better.
+
+Testing your maps.
+------------------
+This is easy for entry vaults. Temporarily introducing either
+ WEIGHT: 50000 or
+ PLACE: D:1
+will make your entry appear almost always. For other vaults, you can
+for the moment declare them as entry vaults with a huge WEIGHT: as
+above (and preferably in wizard mode).
+
+In wizmode, you can use the following commands
+ &L "map name" (creates that vault on the current level)
+ &P "map name" (for playtesting portal vaults)
+ &~ (for jumping to a branch end).
+For both &L and &P, you don't need to specify the full name of the vault,
+a substring which uniquely determines the vault is enough. If a branch end
+has several alternatives, you may want to use a high WEIGHT: again.
+
+Minivaults can also be tested by adding a PLACE: to the definition, which
+makes it very likely that the minivault will appear in the chosen level.
+
+If the .des file syntax is incorrect, Crawl will tell you on which line of
+which des file it found the syntax error, making for easier debugging.
+
+Be fair!
+--------
+Crawl is hard but try to balance your monsters. While it is true that Orc:1
+can show an orcish knight, this is very rare. Hence it's probably a bad idea
+to use orcish knights for an entry to the Orcish Mines.
+
+Phrased more generally, do not use OOD (out-of-depth) monsters unless you
+really know what you want.
+
+Be especially fair when creating entry vaults. If your entry is too hard,
+it might get just trashed. Keep in mind that your vault will be played
+very very often, so even small chances of something stupid happening
+(like creation of a really nasty monster) will kick in often enough.
+
+Glass, colours, names: use sparingly!
+-------------------------------------
+It can be very tempting to use the cool new features all over the place:
+transparent walls for looking through, colouring walls and floor in exotic
+ways, giving monsters special names.
+Each of these have their uses, but ask yourself each time if the vaults
+really benefits from this. If all vaults use colours, actual flavour has
+been lost.
diff --git a/crawl-ref/docs/develop/level_design.txt b/crawl-ref/docs/develop/levels/syntax.txt
index 08edd20a1a..bd3e8b5000 100644
--- a/crawl-ref/docs/develop/level_design.txt
+++ b/crawl-ref/docs/develop/levels/syntax.txt
@@ -2,152 +2,19 @@
How to make levels for Dungeon Crawl Stone Soup
-----------------------------------------------
-Contents: A. Introduction
- B. Sample map
- C. Map symbols
- D. Header information
- E. Conditionalising levels
- F. Validating levels
- G. Hints for level makers
- H. Portal vaults
- I. Lua reference
- J. Feature names
- K. Map statistics
- L. Map generation
-
-
-A. Introduction
-=================
-
-All fixed level information resides in various .des files to be found in the
-dat directory. If you are interested in adding some vaults, say, start with
-the existing ones and modify them. Currently, the following .des files are in
-use:
-
- altar.des - minivaults containing altars
- arena.des - arenas for the arena mode
- bailey.des - the bailey portal vault
- bazaar.des - entrances to bazaar portal vaults, and bazaars proper
- crypt.des - random vaults for Crypt, the Crypt:5 branch ends, and the
- predefined maps for Tomb:1, Tomb:2 and Tomb:3
- didact.des - lua and vaults for syntax checking - not used in-game
- dummy.des - global dummy balancers
- elf.des - arrival and random vaults for Elf, and Elf:7 branch ends
- entry.des - entry vaults (each game - but not tutorial games - uses one of
- these premade maps for the vicinity of the entrance)
- float.des - floating vaults
- hells.des - hell entrances, Geryon's vestibule, Coc:7, Tar:7, Dis:7, Geh:7
- hive.des - hive entrances, random hive vaults, Hive:2
- icecave.des - the ice cave portal vault
- lab.des - labyrinths exits and flavour vaults
- lair.des - lair entrances, random vaults for lair proper and sub-branches,
- and the branch ends: Shoals:5, Swamp:5, Snake:5, Slime:6
- large.des - all regular vaults which have ORIENT:encompass/northwest etc
- layout.des - level layout code that has been moved from dungeon.cc and
- rewritten in Lua.
- mini.des - minivaults (no ORIENT line at all)
- orc.des - orcish mine entrances, orc only vaults
- ossuary.des - the ossuary portal vault
- pan.des - vaults of the Pan demon lords, Pan minivaults
- rooms.des - special monster rooms, such as orc, kobold and jelly rooms
- sewer.des - the sewer portal vault
- shrine.des - the shrine portal vault
- temple.des - Ecumenical Temples, and Temple entrances
- vaults.des - entrances for the Vaults, Vaults-specific vaults, the
- Hall of Blades, and Vaults:8
- volcano.des - the volcano portal vault
- ziggurat.des - the ziggurat entry vaults, pillars and arenas
- zot.des - vaults for the Zot branch and the maps for Zot:5
-
-Kinds of Vaults
----------------
-The different kinds of vaults used by Crawl are described briefly below.
-
-Entry vault:
- A map designed for D:1, which (usually) contains the primary upstair {
-and is always tagged "entry". A player starting a new game will usually land
-in an entry vault.
-
-Branch entry vault, or branch portal vault:
- A map containing the entry to a branch - either a branch stair (such as
-the stair to the Orcish Mines), or a branch portal (a portal to Hell, say).
-Always tagged "<branchname>_entry".
-
-Special level:
- A map for a location of significance in the game, such as the Ecumenical
-Temple, or the end of branches such as level 5 of the Snake Pit (Snake:5).
-Special level maps usually have a PLACE: attribute.
-
-Random vaults:
- Random vaults may be randomly generated at any level in the dungeon.
-Random vault maps are selected by the dungeon builder based on their DEPTH:
-attributes.
-
-Random minivaults:
- Random minivaults are small maps that are placed onto a level that the
-dungeon builder has already constructed fully otherwise (the level may
-include other vaults).
-
-Minivaults are distinguished from normal vaults by the absence of an
-ORIENT: declaration. Any map without a specified ORIENT: is a
-minivault. Minivaults are handled like floating vaults (ORIENT: float
-vaults) in most respects. The differences are:
-
-1. Floating vaults may be placed before the rest of the level layout
- is generated, and the rest of the level may be built around the floating
- vault. This is never the case for minivaults.
-
-2. Floating vaults may be placed anywhere in the map, including places
- completely separated from the rest of the level by rock. The
- dungeon builder will then connect the exits from the floating vault
- to the rest of the level, usually producing obvious "passages" from
- the floating vault to the main body of the level.
-
- In contrast, minivaults are placed such that at least one square of
- the minivault overlaps with an existing part of the level, and are
- thus more likely to look like part of the level. Unlike floating
- vaults, the dungeon builder assumes that any one square of overlap
- is enough to connect the minivault to the rest of the level and
- makes no effort to connect exits from the minivault to the level.
- You can ask the dungeon builder to connect exits from your
- minivault with the "mini_float" tag.
-
-
-
-B. Sample Map
-===============
-
-Before going into the technical details of the level-file syntax, let's look
-at an example - a branch entry for the Ecumenical Temple - to see what a map
-definition looks like.
-
-# name below:
-NAME: useless_temple_entry
-# header section below:
-ORIENT: float # "ORIENT: float" tells the level builder that
- # this entry can be anywhere on the level.
-TAGS: temple_entry # "TAGS: temple_entry" turns the 'O' on the
-MONS: butterfly, plant # map into stairs to the Temple.
-ITEM: stone
-# actual map below: # The symbols on the map:
-MAP # x - rock wall
-xx.d.xx # . - floor
-x..1..x # @ - entry point (
-@d2O2d. # O - stairs to the Temple
-x..1..x # 1 - first monster from list (here butterfly)
-xx.d.xx # 2 - second monster from list (here plant)
-ENDMAP # d - first item from the list (here stones)
-
-Every map consists of a name, a header and the actual map (the order is not
-important as long as the name comes first, but try to stick to this order for
-consistency).
-
-Lines starting with # are comments. The keywords available are explained
-in detail in the following sections.
-
-
-C. Map symbols
-================
+Part II: SYNTAX
+ ======
+
+Contents: G. Glyphs
+ H. Header information
+
+This document contains the syntax needed for making maps and vaults. It
+does not say anything about principles of vault making; for this, see
+introduction.txt. For more technical aspects, including tests, lua and
+portal vaults, refer to advanced.txt.
+
+G. Glyphs
+===========
Terrain
-------
@@ -238,7 +105,7 @@ Monsters
information
-D. Header information
+H. Header information
=======================
(All declarations apart from NAME: are translated to Lua function calls
@@ -1162,1012 +1029,3 @@ entire group of glyphs being assigned. For example:
NSUBST: A = 1:. / *:x
NSUBST: B = 1:. / *:x
NSUBST: C = 1:. / *:x
-
-E. Conditionalising levels
-=============================
-
-Crawl translates level (.des) files into Lua code chunks and runs these chunks
-to produce the final level that is generated. While you don't need to use Lua
-for most levels, using Lua allows you to conditionalise or randomise levels
-with greater control.
-
-Let's take a simple example of randomisation:
-
-NAME: random_test
-# Put it on D:1 so it's easy to test.
-PLACE: D:1
-ORIENT: float
-MAP
-xxxxxxxxxxxxxxxxxxx
-x........{........x
-xxxAxxxxxBxxxxxCxxx
-xxx.xxxxx.xxxxx.xxx
-xxx@xxxxx@xxxxx@xxx
-ENDMAP
-
-Now let's say you want A, B, and C to be randomly rock or floor, but B should
-be floor if both A and C are rock. Here's one way to do it (add these lines
-to the map definition):
-
-: local asolid, csolid
-: if crawl.random2(2) == 0 then
-: asolid = true
-: subst("A = x")
-: else
-: subst("A = .")
-: end
-: if crawl.random2(2) == 0 then
-: csolid = true
-: subst("C = x")
-: else
-: subst("C = .")
-: end
-: if asolid and csolid then
-: subst("B = .")
-: else
-: subst("B = .x")
-: end
-
-This code uses crawl.random2(N) which returns a number from 0 to N-1
-(in this case, returns 0 or 1). So we give A a 50% chance of being
-rock, and the same for C. If we made both A and C rock, we force B to
-be floor, otherwise we use a subst that gives B the same 50% chance of
-being rock.
-
-You can conditionalise on various factors, such as player experience
-level:
-
-NAME: condition_002
-DEPTH: 1-27
-ORIENT: float
-: if you.xl() > 18 then
-MONS: greater mummy
-: else
-MONS: deep elf priest / deep elf sorcerer / deep elf demonologist
-: end
-MAP
-xxxxxx
-x1...x
-x1...+
-x1...x
-xxxxxx
-ENDMAP
-
-Or based on where the map is being generated:
-
-NAME: condition_003
-DEPTH: Elf:*, Orc:*
-ORIENT: float
-: if you.branch() == "Orc" then
-MONS: orc priest, orc high priest
-: else
-MONS: deep elf priest, deep elf high priest
-: end
-MAP
-xxxxxx
-x1...x
-x2...+
-x1...x
-xxxxxx
-ENDMAP
-
-When conditionalising maps, remember that your Lua code executes in
-two contexts:
-
-1) An initial compilation phase before the game starts.
-2) The actual mapgen phase when the dungeon builder is at work.
-
-In context (1), you will not get useful answers from the Crawl Lua API
-in general, because the game hasn't started. This is generally
-ignorable (as in the case above) because the compilation phase just
-checks the syntax of your Lua code. If you conditionalise your map,
-however, you may run into compile failures. Take this variant, which
-(incorrectly) attempts to conditionalise the map:
-
-NAME: condition_004
-DEPTH: Elf:*, Orc:*
-ORIENT: float
-: if you.branch() == "Orc" then
-MONS: orc priest, orc high priest
-MAP
-xxxxxx
-x1...x
-x2.I.+
-x1...x
-xxxxxx
-ENDMAP
-: elseif you.branch() == "Elf" then
-MONS: deep elf priest, deep elf high priest
-MAP
-xxxxxx
-x1...x
-x2.U.+
-x1...x
-xxxxxx
-ENDMAP
-: end
-
-This map will break the compile with the cryptic message "Must define
-map." (to compound the confusion, the line number for this error will
-be the first line number of the map following the buggy map).
-
-This error is because although the map is Elf or Orc only, at compile
-time, the branch is *neither* Elf nor Orc, so the level-compiler
-thinks you've neglected to define a map.
-
-Lua code can detect the compile phase using crawl.game_started() which
-returns true only when the player has started a game (and will return
-false when the map is being initially compiled).
-
-For more details on the available Lua API and syntax, see the Lua
-reference section.
-
-
-F. Validating levels
-=======================
-
-If you have a map with lots of transforms (SUBST and SHUFFLE), and
-want to guarantee that the map is sane after the transforms, you can
-use a validation hook.
-
-To take a very contrived example:
-
-NAME: contrived_001
-PLACE: D:2
-ORIENT: float
-TAGS: no_pool_fixup
-SUBST: .=.w
-SUBST: c=x.
-MAP
-xxxxxx
-x{.+.c
-x..+>x
-xxxxxx
-ENDMAP
-
-This map has a chance of leaving the player stuck on the upstair
-without access to the rest of the level if the two floor squares near
-the doors are substituted with deep water (from the SUBST line), or
-the 'c' glyph is substituted with rock. Since a cut-off vault is
-uncool, you can force connectedness with the rest of the level:
-
-validate {{ return has_exit_from_glyph('{') }}
-
-The has_exit_from_glyph() function returns true if it is possible to
-leave the vault (without digging, etc.) from the position of the {
-glyph. (This takes things like the merfolk ability to swim into
-account, so a merfolk character may see deep water between the stair
-and door.)
-
-The validate Lua returns false (or nil) to indicate that the map is
-invalid, which will force the dungeon builder to reapply transforms
-(SUBST and SHUFFLE) and validate the map again. If the map fails
-validation enough times, the dungeon builder will discard the entire
-level and retry (this may cause a different map to be selected,
-bypassing the buggy map).
-
-Going back to the example, if you just want to ensure that the player
-can reach the > downstair, you can use:
-
-validate {{ return glyphs_connected('{', '>') }}
-
-NOTE: You cannot use the colon-prefixed syntax for validation Lua. If
-you have a big block of code, use the multiline syntax:
-
-validate {{
- -- This level is always cool.
- crawl.mpr("This level is guaranteed perfect!")
- return true
-}}
-
-
-G. Hints for level makers
-============================
-
-* Technical stuff:
-
- You do not have to place all of the stairs unless the level is full
- screen, in which case you must place all except the extra stairs (> and
- <). The <> stairs can be put anywhere and in any quantities but do not
- have to be there. Any of the other stairs which are not present in the
- vault will be randomly placed outside it. Also generally try to avoid
- rooms with no exit (use at least > or < to make it possible for players
- to get away).
-
- Minivaults can use explicit @ exits, or be completely surrounded by
- one space of floor for accessibility. Alternatively, you can request
- that the dungeon builder pick appropriate exits as it does for
- floating vaults by using the "mini_float" tag.
-
- The entry point '@' must be present for all vaults (except
- full-screen vaults where it must not, and floating vaults and
- minivaults where it is optional). All @ will be connected to floor
- space in the rest of the map (multiple @ close together may merge
- into the same exit corridor). Make sure that no part of your entry
- level can be cut off! If no @ is present in a floating vault (and
- there are no doors on the edge of the map, see below), the level
- builder will use one or more random floor spaces '.' or doors at the
- circumference as exits. Note that it is not possible to predict
- which spaces the level builder will choose to connect; if you need
- predictability, use explicit @ exits on the edge.
-
- The level-builder will also implicitly treat doors and secret doors
- on the edge of a map as explicit exits (the same as using @) and
- connect them to the rest of the level.
-
- Not using @ and allowing the level-builder to pick exits is
- acceptable in floating vaults, but when you use no @'s with this
- feature in mind, please add comments stating this - else somebody
- may just add @'s later on. :)
-
- Entry levels should be rather small. Their intention is to provide some
- atmosphere for the starting room, not to get a grip on the whole of D:1.
- Minivaults should be rather small, as well, in order to increase the
- chances they may actually be chosen during level generation.
-
-* Randomise!
- The level making syntax is very supportive for making a single map appear
- in many versions. Use the SHUFFLE: and SUBST: and NSUBST: directives and
- look at the existing entry vaults. Besides reducing tedium, this avoids
- giving veterans a spoiled edge. As an example, if a secret chamber with
- loot is always at the same place, it's a no-brainer for those who know.
- The same goes for traps. This is much less so if there are several places
- for the chamber (or trap) and there's even a chance it doesn't exist.
-
- You can also use WEIGHT to create modified versions of the same map. In
- order to do this, make several maps and endow each with a chance such
- that the sum of chances add up to 10.
-
- Randomisation does not just apply to layout: you could also have
- different monster population sets (for example make a branch end skewed
- for either melee or ranged opponents), or perhaps couple difficulty to
- loot.
-
-* Not too much loot.
- For example, entry vaults should in general have very little loot - in
- particular no good_xxx or '*' items lest they might give incentive for
- start-scumming. For random vaults, there needn't be loot at all and, in
- any case, there shouldn't be too much of it. Compare with the branch ends
- rich in treasure (Tomb:3, Cocytus etc.) to get a feeling for this.
-
-* Have a theme.
- It is often worthwhile (for me at least) to have a theme in mind before
- making the actual level. For entry vaults, something simple like 'forest'
- or 'fortress' may be enough. For later (or larger) maps, try to think of
- distinguishing features your map may have. Being cool can be good enough,
- but possessing some gameplay value (for example by being easier for
- particular skills/capabilities like ranged attacks or Traps & Doors or
- necromancy) is even better.
-
-* Testing your maps.
- This is easy for entry vaults. Temporarily introducing a WEIGHT: 50000
- will make your entry appear almost always. For other vaults, you can
- for the moment declare them as entry vaults with a huge WEIGHT: as
- above (and preferably in wizard mode). For more intricate things like
- new branch ends, you have to resort to wizard mode and use the &~ command
- to go directly to the place where the map is used, say Snake:5. You may want
- to use a high WEIGHT: again, if the map has alternatives (like Snake:5, or
- Coc:7). Minivaults can also be tested by adding a PLACE: to the definition,
- which makes it very likely that the minivault will appear in the chosen
- level.
-
- Vaults can be conjured up in wizard mode using the &L command. You don't
- need to specify the full name of the vault, a substring which uniquely
- determines the vault is enough. You can playtest portal vaults using the &P
- wizard command. Branch ends can be conveniently tested with the &~ command.
-
- If the .des file syntax is incorrect, Crawl will tell you on which line of
- which des file it found the syntax error, making for easier debugging.
-
-* Be fair!
- Crawl is hard but try to balance your monsters. While it is true that Orc:1
- can show an orcish knight, this is very rare. Hence it's probably a bad idea
- to use orcish knights for an entry to the Orcish Mines.
-
- Phrased more generally, do not use OOD (out-of-depth) monsters unless you
- really know what you want.
-
- Be especially fair when creating entry vaults. If your entry is too hard,
- it might get just trashed. Keep in mind that your vault will be played
- very very often, so even small chances of something stupid happening
- (like creation of a really nasty monster) will kick in often enough.
-
-* Minivaults vs. random vaults.
- Minivaults are handled very differently from regular vaults and special
- levels. They're placed *after* normal map generation, whereas normal
- vaults are placed before generating the rest of the level. There's no
- way to guarantee generation of a minivault on a particular level, although
- using a PLACE: attribute makes the dungeon builder try very hard to place
- the minivault on the specified level. Regular vaults can always be forced to
- appear using a PLACE: attribute.
-
- Technically, you make a minivault like a normal floating vault but
- without an ORIENT: line. Note that minivaults used to be exclusively of
- size 12x12 but this restriction is gone. Still, the smaller the better.
-
- Where possible, use minivaults instead of regular vaults, because the dungeon
- builder has greater freedom with the rest of the level layout when using
- minivaults.
-
-* levdes.vim.
- If you use vim, the levdes.vim syntax highlighting script (provided
- in the dat directory) can make level-editing far more pleasant by colouring
- different features in maps and syntax-highlighting .des-file syntax. vim is
- available for nearly all operating systems, including Windows.
-
-
-H. Portal Vaults
-==================
-
-Portal vaults are vaults accessed by portals in the dungeon (labyrinths
-and bazaars are special cases of portal vaults). You can create custom
-portal vaults in the following steps (no compilation is necessary):
-
-* Create a new file name.des in the dat/ folder. Rules:
- The "name" should be descriptive of the vault you're adding.
- The "name" should not exceed eight letters.
- The ending must be "des".
-* Add "name.des" to the list of local files in dat/clua/loadmaps.lua.
-* "name.des" should contain a comment at the top, explaining flavour and
- gameplay goals of the portal vault (and perhaps additional ideas etc.)
-* Define at least one vault containing the portal (see below).
-* Define at least one destination map (see below).
-* Add a short in-game description for the string "desc" (see below) to
- dat/descript/features.txt.
-
-Before going into the details of portal vault creation, some words about
-their uses: Portal vaults are different from branches in that they are
-not guaranteed. Also, there is only one go at a portal vault - if you
-leave, it's gone for good. You can apply special rules to a portal vault,
-like enforcing maprot.
-
-Portal vaults can be particulary thematic, using specialised monster
-sets, fitting loot, coloured dungeon features etc. Avoid death traps; it
-is no fun to enter a vault, being unable to leave and be killed outright.
-In order to provide fun and reduce spoiler effects, randomise. For portal
-vaults, it is desirable to have several different layouts (ideally each
-of the maps has some randomisation on its own). Often, it is a good idea
-to skew the map distribution: e.g. with four destination vaults, weights
-like 40,30,20,10 might be more interesting than 25,25,25,25.
-
-In order to test a portal vault, you can either use PLACE: D:2 for an
-entry vault, or use the wizard mode command &L for conjuring up the entry.
-
-Define a vault to hold the portal itself
-----------------------------------------
-
-# Bare-bones portal vault entry
-NAME: portal_generic_entry
-TAGS: allow_dup
-ORIENT: float
-MARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \
- dst = "generic_portal" }
-KFEAT: O = enter_portal_vault
-MAP
-O
-ENDMAP
-
-Portal entries must contain a portal vault entry (enter_portal_vault).
-This feature must always have a marker that provides the portal with a
-description ("A portal to places unknown") and a destination
-("generic_portal").
-
-In case you want to make sure that the portal vault entry is only used
-once, you add a TAGS: uniq_BAR line. It should be noted that the label
-BAR may *not* end in _entry (otherwise the level builder assumes that
-the vault is a branch entry).
-
-If you want the place name displayed while in the vault to be different
-than the destination name, then you can give one_way_stair() a "dstname"
-parameter. If you want the place origin for items in a character
-dump to be different than the default you can give one_way_stair a
-"dstorigin" parameter (i.e., dstname = "garden", dstorigin = "in the gardens").
-If you want the place name abbreviation used when displaying notes to be
-different than than the default you can use the "dstname_abbrev" parameter.
-
-You can dynamically change the origin string using the lua function
-dgn.set_level_type_origin(), and dynamically change the place name
-abbreviation with dgn.set_set_level_name_abbrev().
-
-Known portal vault entries will be displayed on the overmap. By default
-the name shown on the overmap will be the "dstname" parameter, or if
-that isn't present the "dst" paremeter. It can be set to something else
-with the "overmap" parameter. A note can be made to accompany the
-portal's position on the overmap with the "overmap_note" parameter.
-
-Bones files for characters killed in the portal vault will normally
-use an extension derived from the first three letters of the 'dst'
-property. You can override this by setting the 'dstext' property to
-your preferred extension.
-
-This will produce a portal, but attempting to use it will trigger an
-ASSERT since there's no map for the destination. So we create a
-destination map like so:
-
-Define a destination map
-------------------------
-
-NAME: portal_generic_generic
-# Tag must match dst value of portal in entry.
-TAGS: generic_portal allow_dup
-ORIENT: encompass
-MONS: ancient lich
-KFEAT: > = exit_portal_vault
-MAP
-xxxxxxxxxxx
-x111111111x
-x1A111111>x
-x111111111x
-xxxxxxxxxxx
-ENDMAP
-
-Note that the entry point into the map will be a stone arch. You must
-provide an exit to the dungeon explicitly (KFEAT: > = exit_portal_vault)
-or the player will not be able to leave.
-
-Stairs will not work right in portal vaults, do not use them.
-
-You can use multiple maps with the destination tag (generic_portal),
-and the dungeon builder will pick one at random.
-
-The MARKER parameters
----------------------
-
-The lines
- MARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \
- dst = "generic_portal" }
- KFEAT: O = enter_portal_vault
-ensure that an 'O' glyph will be turned into a portal. Upon leaving the portal
-vault, you will be placed on its entry which has been turned into a floor. You
-can turn it into something different (usually an empty stone arch), by adding
- floor = 'stone_arch'
-to the lua:one_way_stair parameters.
-
-Note that the desc string is what you will see upon examining the portal.
-The dst string is used for Crawl's right hand stat area; it will show
- Place: generic portal
-in the above example. Here is a lost of the parameters that can be used
-within one_way_stair (taken from icecave.des):
- desc = "A frozen archway", # description of the portal before entry
- dst = "ice_cave", # label used for maps and entry vaults
- dstname = "Ice Cave", # used for PLACE: on the main screen
- dstname_abbrev = "IceCv", # used in the notes
- dstorigin = "in an ice cave", # appendix for items picked up there
- overmap = "frozen archway", # used on the overmap (X)
- floor = "stone_arch" # feature left after escaping the portal
-
-The dst string is also used to link the destination maps to the entry maps.
-In case dstname is missing, dst will be used.
-
-You can replace lua:one_way_stair by lua:timed_marker in order to make timed
-portal vaults (which will disappear after some time). bazaar.des and lab.des
-contain examples. For timed portals, you may want to add messages to the file
-dat/clua/lm_tmsg.lua.
-
-Using lua functions as shortcuts
---------------------------------
-
-If you are making several entry and destination vaults, you will note a
-lot of duplicated header statements. This can be lessened using lua.
-Define a lua block right at the top (after your comments) as follows:
-
-{{
-function generic_portal(e)
- e.marker([[O = lua:one_way_stair { desc = "A portal to places unknown",
- dst = "generic_portal",
- floor = "stone_arch" }]])
- e.kfeat("O = enter_portal_vault")
- e.colour("O = magenta")
-end
-}}
-
-Instead of the MARKER and KFEAT lines introduced above you now just use
- :generic_portal(_G)
-and the resulting portal glyphs will even be magenta!
-
-Defining a random monster set
------------------------------
-
-Portal vaults require a defined random monster set to make the Shadow
-Creatures spell work. This is done by calling dgn.set_random_mon_list()
-manually. Here's an example from ice_cave_small_02 in icecave.des:
- : dgn.set_random_mon_list("ice beast w:90 / ice dragon / nothing")
-You can use "nothing" to have the spell fail sometimes.
-
-If you are using the same random monster list in several destination maps,
-you can define a lua block and call it from the destination map definition.
-This example is from sewer.des:
-
-{{
-function sewer_random_monster_list(e)
- e.set_random_mon_list("giant bat w:20 / giant newt w:20 / small snake / \
- ooze / worm / snake / giant mosquito w:15")
-end
-}}
-
-You can then use this line in the map definition to execute the lua block:
- : sewer_random_monster_list(_G)
-
-You can also set env.spawn_random_rate() to have monsters generated from the
-list during play.
-
-Milestones for portal vaults
-----------------------------
-
-This example is from icecave.des, defined in the lua preludes:
-
-{{
-function ice_cave_milestone(e)
- crawl.mark_milestone("br.enter", "entered an Ice Cave.")
-end
-}}
-
-The function is called from each of the destination map definitions:
-
-: ice_cave_milestone(_G)
-
-This marks down entering the portal vault in the milestones. When the portal
-is entered, the destination map is chosen and the call to crawl.mark_milestone
-is executed along with the rest of the map definition.
-
-Adding milestones in a .des does have the slight catch of creating multiple
-milestones if the map fails validation for some reason, so it's best used
-in maps that will never fail validation.
-
-I. Lua reference
-===================
-
-How maps are processed
-----------------------
-
-Under the hood, Crawl translates everything in a .des file to Lua. You
-don't need to know what the underlying Lua looks like to design
-levels, but it helps.
-
-Crawl uses Lua 5.1 from http://www.lua.org (the site has information
-on the Lua language). Let's examine how Crawl converts a map
-definition into Lua code with an example map:
-
-NAME: statue_in_pool
-TAGS: no_rotate no_pool_fixup
-: if you.absdepth() < 7 then
-MONS: plant
-: else
-MONS: oklob plant
-: end
-MAP
-1...1
-.www.
-.wGw.
-.www.
-1...1
-ENDMAP
-
-Crawl will convert this map into the following Lua code, wrapped in an
-anonymous function (this is called a Lua chunk):
-
-function ()
- tags("no_rotate")
- tags("no_pool_fixup")
- if you.absdepth() < 7 then
- mons("plant")
- else
- mons("oklob plant")
- end
- map(".....")
- map(".www.")
- map(".wGw.")
- map(".www.")
- map(".....")
-end
-
-If your level defines prelude or validation Lua code, such code is
-extracted into separate prelude and validation chunks. The prelude and
-validation chunks are empty unless specified.
-
-Apart from the special NAME map header, every map header translates to
-a Lua function with the same name in lowercase. For instance, KFEAT:
-<xyz> is translated into kfeat("<xyz>").
-
-If you have a space or comma separated list (such as TAGS, MONS, ITEM,
-etc.), then each space/comma separated item is passed into a separate
-call to the corresponding Lua function. For instance:
-
-TAGS: no_rotate no_pool_fixup
-->
-tags("no_rotate")
-tags("no_pool_fixup")
-
-MONS: orc, gnoll
-->
-mons("orc")
-mons("gnoll")
-
-Knowing what the generated Lua looks like under the hood is useful
-because it allows you to extract repeated boilerplate in similar
-vaults into a Lua function in the .des file's prelude. For instance,
-if you were planning to write a whole slew of vaults featuring statues
-in water guarded by plants, you could extract the common code into the
-top of the .des file as:
-
-# This block has to be placed before any other vault in the .des file.
-{{
-function statue_pool_map(e)
- e.tags("no_rotate")
- e.tags("no_pool_fixup")
- if you.absdepth() < 7 then
- e.mons("plant")
- else
- e.mons("oklob plant")
- end
-end
-}}
-
-NAME: statue_in_pool
-# Pass in the Lua environment global _G to the prelude function.
-: statue_pool_map(_G)
-MAP
-1...1
-.www.
-.wGw.
-.www.
-1...1
-ENDMAP
-
-You can also use arbitrary Lua directly in vault definitions, which is
-handy when randomizing things:
-
-NAME: statue_in_pool
-: local plant_weight = crawl.random_range(1,10)
-: mons("plant w:" .. plant_weight ..
-: " / oklob plant w:" .. (10 - plant_weight))
-MAP
-1...1
-.www.
-.wGw.
-.www.
-1...1
-ENDMAP
-
-How Lua chunks are associated with a C++ map object
----------------------------------------------------
-
-A map's Lua chunk consists of calls to functions such as tags(),
-mons(), etc. These functions are defined in the dgn table (see the Lua
-API reference below), and they expect to act on an instance of Crawl's
-C++ mapdef object. Given:
-
-tags("no_rotate")
-
-the actual Lua call needs to be:
-
-dgn.tags(<map>, "no_rotate")
-
-Where <map> is the C++ map object to which the tag should be added.
-Since calling dgn.<foo>(<map>, <xxx>) is tedious, dat/clua/dungeon.lua
-wraps the Lua chunk for the map into an environment that defines
-wrappers for all the functions in 'dgn' as:
-
- function <xyz>(...)
- dgn.<xyz>(<map>, ...)
- end
-
-i.e. for every function <xyz> in the 'dgn' table, we define a new
-function <xyz> that just calls dgn.<xyz>() with the current map as the
-first parameter, and the other parameters as passed in. Thus Lua code
-that you write as:
-
-tags("no_rotate")
-
-is translated to the correct dgn.tags(<map>, "no_rotate").
-
-While this is done automatically for map code, if you need to call Lua
-code that was not defined in the scope of the map, as in the example
-statue_pool_map() function, you need to pass in the map environment to
-that function if you want it to modify the map. Thus the call to
-statue_pool_map looks like:
-
-: statue_pool_map(_G)
-
-Steps involved in processing .des files
----------------------------------------
-
-* Level files are compiled into a series of Lua chunks. Each map can
- have one or more Lua chunks associated with it: the prelude, the
- body, and a validation chunk. The body is mandatory, but validation
- and prelude chunks are necessary only if your map needs validation
- or fancy selection criteria.
-
-* When first compiling a .des file, Crawl compiles each map's Lua
- chunks, then compiles and runs the prelude, body and validation
- immediately to verify that the Lua code is not broken. Lua errors at
- this stage will cause Crawl to exit with an error message (hopefully
- relevant). Note that the validation Lua chunk's return code is
- completely ignored at this stage - it is only run to check for
- syntax errors in the code.
-
-* When a new game is started, Crawl will run the Lua preludes for all
- maps (most maps should have no prelude - map preludes slow the game
- down). At this point, preludes can change the map's placement or
- availability.
-
-* When the dungeon builder selects a map (based on TAGS, DEPTH,
- PLACE), it re-runs the map prelude and the map body, applies
- transforms (SUBST, SHUFFLE) if any, then calls the map's validation
- Lua. If the map passes validation, the dungeon builder continues
- with level-generation; otherwise, it restarts from the map prelude.
-
-The global prelude
-------------------
-
-Every .des file can have (at the start of the file) Lua code that is
-not associated with any specific map, but with all maps in the file.
-This is called the global prelude. The global prelude is run before
-running any other Lua code in the file, once during compilation, and
-once at start of game.
-
-You can use the global prelude to define functions and set up globals
-that the rest of the maps in the .des file use. If you have a lot of
-common code, you should probably add it to dungeon.lua instead.
-
-Syntax for using Lua in .des files
-----------------------------------
-
-* Colon-prefixed lines are individual Lua lines, extending to the end
- of the line. E.g.
-
- : crawl.mpr("Hello")
-
- Colon-prefixed lines are always in the main Lua chunk, unless they occur
- before any map definitions, in which case they go to the global prelude.
-
-* Lua blocks for the main (body) Lua
- lua {{ <code> }}
- or
- lua {{
- <code>
- }}
- The "lua" word is optional; you can also use:
- {{ <code> }}
- and
- {{
- <code>
- }}
-
-NOTE: Colon-prefixed lines, or lua {{ }} blocks defined before any
-map's NAME: directive will add the Lua code to the global prelude.
-
-* Lua blocks for the prelude:
- prelude {{ <code> }}
- or
- prelude {{
- <code>
- }}
-
-* Lua blocks for the validate chunk:
- validate {{ <code> }}
- or
- validate {{
- <code>
- }}
-
-Debugging Lua
--------------
-
-Since Lua action happens in the guts of Crawl, it can be hard to tell
-what's going on. Lua debugging involves the time-honoured method of
-peppering your code with print statements:
-
-* Use error() or print() for compile-time work (i.e. when Crawl reads
- the .des file). Note that print() just writes to the terminal and
- keeps going, while error() forces Crawl to exit immediately (at
- compile time; errors during level-generation are handled
- differently).
-
-* Use crawl.mpr() for output when the game has started (at
- level-generation time).
-
-It's very important that your finished level never croaks during
-level-generation. A Lua error at this stage is considered a validation
-failure.
-
-Special dungeon-related Lua marker properties
----------------------------------------------
-
-There are several properties a Lua marker can have which will affect the
-dungeon cell which they are on:
-
-* connected_exclude: Consider the cell to be separate from neighboring
- cells with identical or similar features. Currently only useful
- for preventing adjacent doors from grouping together into a gate,
- forcing them to open and close as separate doors. See the Evil
- Zoo (minivault_9) in dat/mini.des for an example.
-
-* door_description_suffix: A string to append to the description of
- any door the marker is on. This should be used for doors
- rather than the feature_description property since it elemintates
- the need to track if the door is opened or closed, plus it will
- have no effect on secret doors which have yet to be detected.
-
-* feature_description: What to use as the short description of the
- cell's feature.
-
-* feature_description_long: What to use as the long description of the
- cell's feature.
-
-* stop_explore: If set to anything, and placed on a cell with a statue
- or orcish idol, will cause auto-explore to stop with the message
- "Found <whatever>."
-
-* stop_explore_msg: Like stop_explore, but when auto-explore is stopped
- the content of the property will be printed out as a message.
-
-* veto_disintegrate: If this property is set to "veto" then the cell
- will be immune to disintegration.
-
-* veto_fragmentation: If this proprety is set to "veto" then the cell
- will be unaffected by fragmentation (Lee's Rapid Deconstruction
- spell).
-
-* veto_shatter: If this property is set to "veto" then the cell will
- be unaffected by the Shatter spell.
-
-Lua API reference
------------------
-a. The Map.
-b. Global game state.
-c. Character information.
-
-
-Lua API - the Map
------------------
-
-Lua functions dealing with the map are mostly grouped under the "dgn"
-module. For convenience, .des file Lua chunks are run in an environment
-such that function calls written as:
-
- fn(x, y, ...)
-
-are translated to
-
- dgn.fn(map, x, y, ...)
-
-where "map" is the reference to the map that the currently executing
-Lua chunk belongs to. This is only for Lua chunks that belong to a
-map, Lua code in the global prelude does not get this treatment
-(because the global prelude is not associated with any map).
-
-Functions in the dgn module:
-
-default_depth, name, depth, place, tags, tags_remove, chance, weight,
-orient, shuffle, shuffle_remove, subst, subst_remove, map, mons, item,
-kfeat, kitem, kmons, grid, points_connected, gly_point, gly_points,
-original_map, glyphs_connected, orig_glyphs_connected, orig_gly_point,
-orig_gly_points, load_des_file, feature_number, feature_name,
-dgn_event_type, register_listener, remove_listener, remove_marker,
-num_matching_markers, feature_desc, feature_desc_at, item_from_index,
-mons_from_index, change_level_flags, change_branch_flags,
-set_random_mon_list
-
-
-Additionally, the dgn module provides a global "mapgrd" variable that
-can access the current map glyphs. The top left symbol in the map
-can be assigned like this:
-
- mapgrd[1][1] = 'x'
-
-The bottom right symbol can be assigned like this:
-
- mapgrd[width()][height()] = "."
-
-
-Lua API - global game state
----------------------------
-
-The "crawl" module provides functions that describe the game state or
-provide utility methods.
-
-mpr, mesclr, random2, coinflip, one_chance_in, redraw_screen,
-input_line, c_input_line, getch, kbhit, flush_input, sendkeys,
-playsound, runmacro, bindkey, setopt, msgch_num, msgch_name, regex,
-message_filter, trim, split, game_started, err_trace, args,
-mark_milestone
-
-
-Lua API - character information
--------------------------------
-
-The "you" module provides functions that describe the player character.
-
-turn_is_over, spells, abilities, name, race, class, god, hp, mp,
-hunger, strength, intelligence, dexterity, xl, exp, res_poison,
-res_fire, res_cold, res_draining, res_shock, res_statdrain,
-res_mutation, res_slowing, gourmand, levitating, flying, transform,
-stop_activity, floor_items, where, branch, subdepth, absdepth
-
-
-J. Feature Names
-==================
-
-These are the feature names usable in MARKER declarations:
-
-unseen, rock_wall, stone_wall, closed_door, metal_wall, secret_door,
-green_crystal_wall, orcish_idol, wax_wall, permarock_wall,
-silver_statue, granite_statue, orange_crystal_statue,
-statue_reserved_1, statue_reserved_2, lava, deep_water, shallow_water,
-water_stuck, floor, exit_hell, enter_hell, open_door, trap_mechanical,
-trap_magical, trap_iii, undiscovered_trap, enter_shop,
-enter_labyrinth, stone_stairs_down_i, stone_stairs_down_ii,
-stone_stairs_down_iii, escape_hatch_down, stone_stairs_up_i,
-stone_stairs_up_ii, stone_stairs_up_iii, escape_hatch_up, enter_dis,
-enter_gehenna, enter_cocytus, enter_tartarus, enter_abyss, exit_abyss,
-stone_arch, enter_pandemonium, exit_pandemonium, transit_pandemonium,
-builder_special_wall, builder_special_floor, enter_orcish_mines,
-enter_hive, enter_lair, enter_slime_pits, enter_vaults, enter_crypt,
-enter_hall_of_blades, enter_zot, enter_temple, enter_snake_pit,
-enter_elven_halls, enter_tomb, enter_swamp, enter_shoals,
-enter_reserved_2, enter_reserved_3, enter_reserved_4,
-return_from_orcish_mines, return_from_hive, return_from_lair,
-return_from_slime_pits, return_from_vaults, return_from_crypt,
-return_from_hall_of_blades, return_from_zot, return_from_temple,
-return_from_snake_pit, return_from_elven_halls, return_from_tomb,
-return_from_swamp, return_from_shoals, return_reserved_2,
-return_reserved_3, return_reserved_4, enter_portal_vault,
-exit_portal_vault, altar_zin, altar_shining_one, altar_kikubaaqudgha,
-altar_yredelemnul, altar_xom, altar_vehumet, altar_okawaru,
-altar_makhleb, altar_sif_muna, altar_trog, altar_nemelex_xobeh,
-altar_elyvilon, altar_lugonu, altar_beogh, fountain_blue,
-fountain_sparkling, fountain_blood, dry_fountain_blue,
-dry_fountain_sparkling, dry_fountain_blood, permadry_fountain
-
-
-K. Map Statistics
-===================
-
-Full-debug Crawl builds (this does not include normal Crawl builds
-that have wizard-mode - you must build Crawl with "make debug", not
-"make wizard") can produce map generation statistics. To generate
-statistics, run crawl from the command-line as:
-
-crawl -mapstat
-
-This will generate 100 Crawl dungeons and report on the maps used in a
-file named "mapgen.log" in the working directory.
-
-You can change the number of dungeons to generate:
-
-crawl -mapstat 10
-
-Will generate 10 dungeons. If you merely want statistics on the
-probabilities of the random map on each level, use:
-
-crawl -mapstat 1
-
-L. Map Generation
-===================
-
-Full-debug Crawl builds (see above for more information) include a test for
-generating specific vaults and outputting a copy of the map to a text file for
-inspection. This is most useful for portal and other encompass vaults which
-use randomisation heavily.
-
-To use the test, you must edit source/test/vault_generation.lua. Fill in the
-following variables:
-
- * map_to_test: The exact name of the vault you want to generate.
- * checks: How many times to generate the vault. Default value is 10.
- * output_to: The basic filename to output the results of generation to. This
- will have ".<iteration>" appended. For example, "volcano.map" will
- result in files named "volcano.map.1", "volcano.map.2", etc.
- * need_to_load_des: If the file is not included in one of the .des files that
- are listed in source/dat/clua/loadmaps.lua, this should be set to true,
- and the following variable should be set.
- * des_file: The name of the file to load. The file should be located in the
- source/dat folder.
-
-Once you have saved your changes, run crawl:
-
- crawl -test vault_generation
-
-Once all of the tests have been finished successfully you should find the
-relevant files in your working directory.
diff --git a/crawl-ref/source/dat/database/FAQ.txt b/crawl-ref/source/dat/database/FAQ.txt
index 25f9ceaa46..a8f26e309b 100644
--- a/crawl-ref/source/dat/database/FAQ.txt
+++ b/crawl-ref/source/dat/database/FAQ.txt
@@ -360,7 +360,7 @@ A:help
A: There are several areas where you can get creative and outside help is
much appreciated. These are:
-* the maps/vaults (see dat/ folder, docs/level_design.txt)
+* the maps/vaults (see dat/ folder, docs/develop/levels/introduction.txt)
* monster speech (see dat/database/, docs/monster_speech.txt)
* monster/item/spell descriptions (see dat/descript/)
* tiles (see source/rltiles/, docs/tiles_creation.txt)
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 64fa660478..dcdc5968cd 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -961,7 +961,7 @@ enum dungeon_char_type
// * Any: edit dungeon.cc and add a symbol to map_feature() and
// vault_grid() for the feature, if you want vault maps to
// be able to use it. If you do, also update
-// docs/level_design.txt with the new symbol.
+// docs/develop/levels/syntax.txt with the new symbol.
// * Any: edit l_dgngrd.cc and add the feature's name to the dngn_feature_names
// array, if you want vault map Lua code to be able to use the
// feature, and/or you want to be able to create the feature
diff --git a/crawl-ref/source/util/docs/README.tex b/crawl-ref/source/util/docs/README.tex
index 79b30d479c..007edb5cbc 100644
--- a/crawl-ref/source/util/docs/README.tex
+++ b/crawl-ref/source/util/docs/README.tex
@@ -188,7 +188,7 @@ be added and discussed on the homepage, \key{http://crawl-ref.sourceforge.net}.
Crawl uses many hand-drawn (but often randomised) maps. Making them is fun
and easy. It's best to start with simple entry vaults (glance through
\key{dat/entry.des} for a first impression). Later, you may want to read
-\key{docs/level\_design.txt} for the full power. If you're ambitious, new
+\key{docs/develop/levels/introduction.txt}. If you're ambitious, new
maps for branch ends are possible, as well.
If you've made some maps, you can test them on your system (no compiling
needed) and then just mail them to the mailing list.