summaryrefslogtreecommitdiffstats
path: root/crawl-ref/docs/develop/levels/advanced.txt
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/docs/develop/levels/advanced.txt')
-rw-r--r--crawl-ref/docs/develop/levels/advanced.txt894
1 files changed, 894 insertions, 0 deletions
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.