diff options
Diffstat (limited to 'crawl-ref/docs/develop/levels/advanced.txt')
-rw-r--r-- | crawl-ref/docs/develop/levels/advanced.txt | 894 |
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. |