From 227c7f40fc0ba8f2a15af767c30976d14f9e4ad6 Mon Sep 17 00:00:00 2001 From: David Ploog Date: Sun, 8 Nov 2009 06:23:50 +0100 Subject: Split up level_design.txt into smaller files. Namely introduction.txt, syntax.txt, advanced.txt all inside of docs/develop/levels. --- crawl-ref/docs/develop/level_design.txt | 2173 ------------------------ crawl-ref/docs/develop/levels/advanced.txt | 894 ++++++++++ crawl-ref/docs/develop/levels/introduction.txt | 349 ++++ crawl-ref/docs/develop/levels/syntax.txt | 1031 +++++++++++ 4 files changed, 2274 insertions(+), 2173 deletions(-) delete mode 100644 crawl-ref/docs/develop/level_design.txt create mode 100644 crawl-ref/docs/develop/levels/advanced.txt create mode 100644 crawl-ref/docs/develop/levels/introduction.txt create mode 100644 crawl-ref/docs/develop/levels/syntax.txt (limited to 'crawl-ref/docs') diff --git a/crawl-ref/docs/develop/level_design.txt b/crawl-ref/docs/develop/level_design.txt deleted file mode 100644 index 08edd20a1a..0000000000 --- a/crawl-ref/docs/develop/level_design.txt +++ /dev/null @@ -1,2173 +0,0 @@ ------------------------------------------------ -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 "_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 -================ - -Terrain -------- - x - rock wall (DNGN_ROCK_WALL) - X - permanent rock wall - always undiggable (DNGN_PERMAROCK_WALL) - c - stone wall - only affected by Shatter (DNGN_STONE_WALL) - m - clear rock wall (DNGN_CLEAR_ROCK_WALL) - n - clear stone wall - only affected by Shatter (DNGN_CLEAR_STONE_WALL) - o - clear permanent rock wall - always undiggable (DNGN_CLEAR_PERMAROCK_WALL) - v - metal wall - grounds electricity (DNGN_METAL_WALL) - b - crystal wall - reflects cold and fire (DNGN_GREEN_CRYSTAL_WALL) - a - wax wall - can melt (DNGN_WAX_WALL) - t - trees - a single square doesn't block LOS (DNGN_TREES) - - . - floor (DNGN_FLOOR) - + - closed door (DNGN_CLOSED_DOOR) - = - secret door (DNGN_SECRET_DOOR) - - W - shallow water - w - deep water - can be randomly turned into shallow water by the - level-builder; you can prevent this conversion with the no_pool_fixup TAG. - Also, water may automatically receive water creatures! For entry - vaults, avoid this with the no_monster_gen TAG or KMASK. - l - lava - again, use the no_monster_gen TAG or KMASK for entry vaults! - -Features --------- - @ - entry point - must be on outside edge. If you use ORIENT: float, and do - not use any @, the dungeon builder will connect at least one floorspace on - the edge of your map to the rest of the level; if there is no floorspace - on the edge of your map, it will be isolated. - }{ - Stone stairs - You must be able to reach these from each other. The - { upstair is also the stair on which the player will enter the - dungeon for entry vaults. - )( - Stone stairs, set 2. - ][ - Stone stairs, set 3. - - >< - escape hatches - you can leave the level by these but will usually - not land on stairs/hatches - - I - orcish idol (does nothing) - - ^ - random trap. - ~ - random trap suitable for the branch and depth the map is being used. - - A - Vestibule gateway (opened by Horn). - B - Altar. These are assigned specific types (e.g. of Zin etc) in dungeon.cc, - in order. - C - Random Altar. - - G - Granite statue (does nothing) - you can see through but not walk through. - Also, sight-based effects like smiting work past granite statues, as does - apportation. - - NOTE: F used to put down a granite Statue most of the time but occasionally - Orange or Silver or Ice statues (1 in 100). You can reproduce this by using - F on the map together with - SUBST: F = G:100 F:1 - KMONS: F = orange crystal statue / silver statue / ice statue - - T - Water fountain - U - Magic fountain - V - Permanently dry fountain - Y - Blood fountain (use sparingly!) - -Items ------ - $ - gold - % - normal item - * - higher level item (good) - | - acquirement-level item (almost guaranteed excellent) - O - place an appropriate rune here. For portal vaults, place the portal here. - d-k - item array item. See section below on ITEM: arrays for more info. - -NOTE: The P (place a rune here with 1/3 chance) and R (place a honeycomb with - 2/3 chance or else a royal jelly) symbols have been deprecated. You can - (and should) produce the desired behaviour using - SUBST: P = O.. - KITEM: R = w:2 honeycomb / w:1 royal jelly - -Monsters --------- - 0 - normal monster - 9 - +5 depth monster - 8 - (+2) * 2 depth monster (aargh!). Can get golden dragons and titans - this way. - 1-7 - monster array monster. See section below on MONS: arrays for more - information - - -D. Header information -======================= - -(All declarations apart from NAME: are translated to Lua function calls -behind the scenes. See the Lua reference for more information.) - -Try to respect line lengths of 80 characters. Should some line exceed that -(which is quite possible, especially for ITEM and MONS lines), you can use -the \ symbol to break a line. You can break a line anywhere, with the -exception of comma-separated lists, where you cannot start a new line with -a comma. See the end of this section for examples. - -NAME: a_string - Each map must have a unique name. Underscores and digits are ok. - -ORIENT: (float |encompass | north | northwest | ... | southeast) - - Some kind of ORIENT: line is mandatory for vaults; skipping - ORIENT: makes your map a minivault. As a rule of thumb, if - you're writing a small random map, skip the ORIENT: line and - make it a minivault. - - * "float": The dungeon builder puts your vault wherever it wants to. - * "some_direction": The vault lies along that side of the map: - xxxxxxxxxx xxxxxxxxxxxxx - xORIENT:Nx xORIENT:NW|.. - x.VAULT..x x.VAULT...|.. - x--------x x---------|.. - xrest....x xrest........ - x...of...x x.....of..... - x...levelx x.......level - - ORIENT: float vaults give a lot of flexibility to the dungeon - generator; float should generally be preferred to other ORIENT: - settings for new vaults. - -DEPTH: For random vaults, branch entry vaults, and minivaults, this - specifies the range of levels where the vault may be placed - in the dungeon. E.g. - - DEPTH: 7-20 - - DEPTH: does not force a map to be placed in a particular place; it - applies only when the dungeon builder is looking for a random vault - or minivault, so you can control at what depths your vault gets - placed. - - A simple DEPTH: declaration that does not specify a branch - applies to all branches. A map declared with depth 7-20 could - be used in the Lair, for instance. (Lair:1 will be treated as - a depth of 12 if the Lair entrance is on D:11.) - - You can constrain a map by branch: - - DEPTH: Lair:3-6 - - (Anywhere between levels 3-6 of the Lair, inclusive.) - - You can apply multiple constraints in one DEPTH line, - comma-separated: - - DEPTH: 7-20, !12-14 - - (Anywhere in the dungeon between depths 7-20, but not on levels - 12-14.) - - DEPTH: 7-20, !Orc - - (Anywhere in the dungeon between depths 7-20, but never in the Orcish - Mines.) - - DEPTH: Lair:* - - (Anywhere in the Lair. Can also be expressed as "DEPTH: Lair".) - - Maps that do not specify a DEPTH: attribute will inherit their depth - constraints from the closest preceding default-depth: line. If there - is no preceding default-depth directive in the .des file, the map will - have no DEPTH: constraint. Note that maps without a DEPTH: constraint - cannot be selected as random vaults or minivaults. - -CHANCE: : or - - CHANCE allows you to control the probability that your map - is used on any given level with an absolute roll. - - There are two ways to specify the CHANCE roll: - - CHANCE: 500 - or - CHANCE: 5% - - If specified as a raw number, the chance of selecting the - vault is in 10000. If specified as a percentage, - the chance of selecting the vault is * 100 in 10000. - Note that CHANCE accepts only integers, no fractions or - decimals. - - For any map with alternatives, a CHANCE influences how - likely the map is to be picked instead of the alternatives. - If a map has a CHANCE, Crawl will roll a random number in - the range 1-10000, and select the map if the CHANCE is >= - the rolled random number. - - If there are multiple alternative maps with CHANCE, they - will be tested in an unspecified order; the first map that - makes the CHANCE roll will be used. If you'd like to specify - an order of testing CHANCEs, specify a CHANCE with a - priority: - - CHANCE: 10 : 20% - - This specifies a CHANCE of 20%, with a priority of 10, which - means this vault will be checked before any other vault with - a lower priority (the default priority is 0). - - If no map with a CHANCE is picked, Crawl will select a map - based on WEIGHT, ignoring vaults with a CHANCE set. - - Note that the Lua equivalent for CHANCE is a two-argument - function: - - : chance(, ) - - These lines are all equivalent: - CHANCE: 5% - CHANCE: 500 - CHANCE: 0 : 5% - CHANCE: 0 : 500 - : chance(0, 500) - - A common case when using CHANCE is to assign a CHANCE to a - set of maps. For instance, if you have a set of portal vault - entries, and you want one of the set to be used on 5% of all - levels, you can do this: - - NAME: portal_a - CHANCE: 50 : 5% - TAGS: chance_portal_group - ... - - NAME: portal_b - CHANCE: 50 : 5% - TAGS: chance_portal_group - ... - - That is, if you have a set of maps that use CHANCE and are - tagged chance_xxx, then one map of that set will be used - when the chance is met. - -WEIGHT: (number with 10 being default) - For entry vaults and any other vaults randomly picked from among - a set, this type of line affects the likelihood of the given vault - being picked in a given game. The default WEIGHT: is 10. The - likelihood of a vault getting picked is: - [vault's WEIGHT: / sum of all WEIGHT:s of vaults of that type] - -PLACE: Used to specify certain special levels. Existing special levels - include most branch ends. - The branches need to use the official abbreviations also used e.g. in - the overmap (Ctrl-O): D, Temple, Orc, Elf, Lair, Swamp, Shoal, Slime, - Snake, Hive, Vault, Blade, Crypt, Tomb, Hell, Dis, Geh, Coc, Tar, Zot. - - PLACE can also be used to specify arbitrary places, like D:3, which - will force the map (or one of the maps with PLACE: D:3) to be picked - when D:3 is generated. - - PLACE cannot be used to specify places in the Abyss, Pandemonium, - or Labyrinths. - - PLACE can be used with random vaults and minivaults for testing them. - -TAGS: Tags go an a TAGS: line and are space-separated. You can have several - TAGS: lines, or use \ for very long ones. Valid tags are: - * "allow_dup": Vaults are normally used only once per game. If you - have a vault that can be used more than once, use allow_dup to tell - the dungeon builder that the vault can be reused. - * "chance_FOO": Maps can be tagged chance_ with any unique suffix - to indicate that if the map's CHANCE roll is made, one of the maps - tagged chance_FOO should be picked. - * "dummy": this tag indicates that the vault is a stub; if the dungeon - builder picks a dummy vault, it pretends no vault was selected. - Dummies are used to reduce the probability of other vaults at the - same depth / place. - * "entry": this tag MUST be there for a vault to be pickable as an - entry vault. - * "extra": requests that the dungeon builder treat this as - an extra vault and try to immediately place another vault of the - same type it was trying to place when it placed this vault. - "extra" is good to use for things like labyrinth entries - that should not affect the chance of other minivaults on the level. - If you use "extra", you probably want to use one of the - "luniq" tags as well if your map is tagged "allow_dup". - * "generate_awake": Monsters placed (using MONS, KMONS) in this vault - will be generated awake. - * "patrolling": Monsters placed (using MONS, KMONS) in this vault - will be generated with their starting position as patrol point. - If not otherwise occupied (fighting, seeking) they will patrol - the area. - * "no_item_gen": Prevents random item generation in the vault. - Items explicitly placed by the vault are not affected. - * "mini_float": applicable only to minivaults, requests that - the dungeon builder pick random exits from the minivault and - connect it to the rest of the level, similar to the exit behaviour - for floating vaults. - * "no_monster_gen": Prevents random monster generation at the time of - the vault's creation. Highly advised for entry vaults with a - player-hostile geography, MUST-HAVE for those with water/lava. - Can be applied only to particular symbols with KMASK. - * "no_pool_fixup": prevents water squares next to land from being - randomly converted from deep water (the default) to shallow. - * "no_wall_fixup": In Dis, the Vaults and the Crypt a vault's - rock walls will be changed to be the same as the wall type of - the rest of the level. If you don't want that to happen then - use this tag. - * "uniq_BAR": (uniq_ with any suffix) specifies that only one of - the vaults with this tag can be used in a game. - * "luniq": specifies that this vault can be used only once on a - given level. "luniq" is only relevant when used with "allow_dup". - * "luniq_BAR": (luniq_ with any suffix) specifies that only one - of the vaults with this tag can be used on any given level. - "luniq_BAR" is only relevant when used with "allow_dup". - * "branch_entry" eg. "orc_entry", "lair_entry" etc. - If chosen, these maps will contain the stairs for that branch. - Use "O" to place the stairs. If a branch has very few entries, - a dummy entry is advisable to make sure the player doesn't get - bored of the same few entries recycled ad nauseam. - Note: if any TAG argument contains an "entry", the vault will - be no longer eligible for random placement. (Currently, - this just affects your choice of BAR when using uniq_BAR.) - * "mnoleg" or the name of some other pandemonium lord. This makes - the map eligible for said pan lord's lair. See pan.des. - * "minotaur" turns this into a labyrinth exit vault. - "lab" turns this into an additional labyrinth flavour vault. - See lab.des for examples and details. - * "no_rotate": Normally, the dungeon builder can, at its whim, - rotate your vault. This flag tells it, "hey, don't do that to my - vault!" - * "no_hmirror": Like no_rotate, but for horizontal mirroring. - * "no_vmirror": Like no_rotate, but for vertical mirroring. - * "layout": Lua code that dungeon.cc uses for generating level - layouts. Do *NOT* use or mess with unless you know what - you're doing. - * "layout_foo": Indicates what sort of level layouts this vault is - compatible with, for vaults that don't fit in with all layouts; - the absence of this type of tags means it can go with any layout. - Multiple layout_foo tags can be used if it can be used with - multiple layouts. Current values for "foo" are: rooms, city, - open, caves, cross, shoals, swamp, labyrinth (though currently - random vaults aren't placed in the last three). - * "trowel_portal": This vault can be created by the Trowel card. - This tag should be used exclusively for the generic (one tile) - entries to portal vaults, like bazaars and labyrinths. Other - portal vaults may be eligible for Trowel, too. - * "no_dump": Don't dump out this vault's name in the list of - vaults generated during the game. Use this if the vault - is predictable (like the Vault:8 and Slime:6 vaults) or - are for weird internal uses (like the shoalhut vaults). - -LFLAGS: Persistent, changeable per-level flags which affect game behaviour - (FLAGS just controls how the vault is placed); should only be used - for vaults with ORIENT encompass or with PLACE. Causes a level's - flags to be set when the level is first created. These flags can - later be altered using Lua markers; for examples, look at the slime - pit vault in lair.des, and the vaults in hell.des and elf.des. - - Valid flags are: - * no_tele_control - prevents the player from using teleport control - * not_mappable - prevents the player from remembering where - they've been (like in the Abyss) - * no_magic_map - which prevents magic mapping from working. - -BFLAGS: Persistent, changeable per-*branch* flags which affect game - behaviour; should only be used for vaults which go on the first - level of a particular branch. These flags can later be altered - using Lua markers; see the Tomb vaults in vaults.lua for an - example. - - Valid flags are: - * no_tele_control - prevents the player from using teleport control - * not_mappable - prevents the player from remembering where - they've been (like in the Abyss) - * no_magic_map - which prevents magic mapping from working. - -LFLOORCOL: blue - LFLOORCOL: allows you to set the floor colour for the level the - vault appears in. Should only be used for bazaars and other - portal vaults. - -LROCKCOL: yellow - LROCKCOL: allows you to set the colour of rock walls for the level - the vault appears in. Should only be used for bazaars and other - portal vaults. - -LFLOORTILE: (tile name string, e.g. "floor_tomb") - Like LFLOORCOL, this overrides the default floor tiles used for - this level. If the tile specified has variations, those will be - used automatically. - -LROCKTILE: (tile name string, e.g. "wall_hive") - Same as LFLOORTILE, but for rock walls. - -ITEM: (list of items, separated by comma) - These are used to help place specified items at specific places - within a vault. They create an array with up to 8 positions. What's - in the first position in the array will be used when the dungeon - builder sees a "d" in the vault definition, the second will be used - for "e"s, etc. Positions are comma-separated; several ITEM: lines - are possible as well. The following defines letters 'd' - 'g': - ITEM: stone, ring mail, meat ration, ring of hunger - - Positions can contain multiple possibilities, one of which the - builder will choose randomly. Separate such multiple possibilities - using a slash. Note that "nothing" (without the quotes) is a valid - possibility. The random choice is done for each individual occurence - of the letter. You can also give possibilities a "weight," which - affects their chance of being picked. The default weight is 10. You - can abbreviate "weight:30" by "w:30". The chance to pick a - possibility is - [possibility's weight: / sum of all weight:s in that array position] - - For example, the following line makes letter 'd' into a bread ration - with 50% chance, or apple or orange with 25% chance each: - - ITEM: bread ration / w:5 apple / w:5 orange - - Modifiers: - * "q:N" sets the item quantity to N (if N > 0). Does nothing - if the item is not stackable. - * "no_uniq" prevents the item from being turned into an artefact. - * "good_item" makes the builder try to make the item a good one - (acquirement quality). - * "acquire" requests the use of the acquirement code itself, - ensuring that the player gets wearable armour, etc. You can - also use acquire: to request that the acquired item be - treated as a god gift. Examples: "acquire any", "acquire armour", - "acquire:sif_muna book", "acquire:trog weapon". - * "level:N" sets the object's item level (can't be used with - "good_item"). If set to -2 then the object's item level will - be the same as a "*" symbol item (five plus twice the - vault's level number). - * "damaged" sets the item plusses to -1..-4. - * "cursed" gets a curse plus plusses as in "damaged". - * "any" by itself gives a random choice; you can combine "any" with - "good_item." - * "any book", "any misc" etc. gives a random item of that class. - Valid item class names are: gold, weapon, missile, armour, wand, - food, scroll, jewelry, potion, book, staff, orb, misc, carrion. - All of these are usable in map definitions, apart from "orb" and - "carrion". - * "race:race_name", where "race_name" is "elven", "dwarven" or - "orcish"; it can also be "none" or "no_race" to prevent the item - from being randomly being made racial. Has no effect if the item - can't take that kind of racial setting. - NOTE: Can result in a non-racial item if used with "any" and the - chosen item isn't compatible with the desired race. - * "ego:ego_name", where "ego_name" is something like "running" or - "fire_resistance", and so on; "none" can be used to prevent the - item from getting an ego. The item must be fully specified, so - trying "any weapon ego:vorpal" or "any armour ego:positive_energy" - will result in an error. Trying to give an ego to something which - can't accept an ego will also result in an error. - * "unrand:item_name" will make a given unrandom by a given name, - like "long sword unrand:singing_sword". Omit any apostrophes - in the name (e.g, unrand:vampires_tooth). If the name has - something between double quotes then use that string (e.g, - unrand:bloodbane). If the unique already exists, the base item - will be given instead. - * "randart" will force a randart. Most of the above modifiers - will be ignored, except for "ego" (for weapons only). - - WARNING: While checks are done to make sure that an armour ego - isn't given to a weapon, a weapon ego to a missile, and so on, and - also to make sure that egos are only given to armours, weapons and - missiles, no other checking is done. Thus it is possible to create - a demonic weapon of holy wrath or a helmet of running. - - Limitations: You can't specify specific pluses or number of charges. - You also can't lay down corpses, skeletons, or chunks. - - You can place multiple items on the same square by using the KITEM - directive. See that section for more information. - -MONS: (list of monsters) - These are used to help place specific monsters at specific places - in a vault. They create an array with up to 7 positions. What's in - the first position in the array will be used when the dungeon - builder sees a "1" in the vault definition, the second for "2," - etc. Note that if, for example, you place a 3 on the map, but your - MONS: line has no third position, the 3 will be filled with - RANDOM_MONSTER. Also note that for entry vaults (D:1), all monsters - in sight of the hero are removed. This does not hold for plants. - You can use weights as for ITEM: lines. - - A hydra can be given a specific number of heads by calling it - an "n-headed hydra" (with a maximum of 20 heads): - MONS: four-headed hydra - - A slime creature's size can be set to other than normal using - the prefixes "large", "very large", "enormous" or "titanic": - MONS: very large slime creature - - Individual monsters may be prefixed with the "generate_awake" - (without the quotes). Use this sparingly: - MONS: generate_awake giant beetle - - Individual monsters may be prefixed with the "patrolling" - (without the quotes). Use this sparingly: - MONS: patrolling naga guardian - - Monsters can also be given colours that override their default - colour. Use this *very* sparingly: - MONS: col:darkgrey fungus - - Note that 8, 9, 0 also place monsters (see the table). - - If you want to place a random monster suitable for the level - the map is generated on, you can use - MONS: random - - If you want to place a random monster suitable for some other - place, you can use a place: tag in the monster spec: - MONS: place:Abyss - or - MONS: place:Slime:6 - - Using place: with MONS implies that you want a random monster. - You can also request zombies from random monsters suitable - for some other depth as: - MONS: place:Elf:7 zombie - or - MONS: place:Zot:5 simulacrum - or - MONS: place:Vault:8 spectre - - The available modifiers are "zombie", "skeleton", - "simulacrum" and "spectre". - - If a monster is a member of a band, you can request that it - be eligible for band members by adding the keyword "band" to - the name. For instance: - MONS: orc warlord band - - Specifying "band" doesn't force bands to be placed - it - requests that the game use the normal chances of creating a - band. If you use "band", leave some empty space around the - monster for its band members to be placed. - - A monster can be given specific items by following the monster - name with a semi-colon and then with an item list as described - in ITEM:, but with slashes replaced with pipes and commas replaced - with periods. For example: - MONS: orc ; katana | quick blade . chain mail | scale mail - - will generate an orc wielding either a katana or a quick blade - and wearing either a chain mail or a scale mail. Randarts are - never generated, and ego items are only generated if the ego - is explicitly stated. Note that any items that the monster was - originally generated with will be removed and destroyed. This - can be used to force a monster to have no items whatsoever: - MONS: orc; nothing - - Items given to an orc or an elf will be made orcish or elven - unless the item's race type is explicitly set otherwise. - - Limitations: If an item in the item list has alternatives, - there's no way to force all monsters dervied from that monster - spec to choose the same alternative. If a monster is given - a random launcher, there is no way to force the ammo type to - match the launcher type. - - Individual monsters can be given names as follows: - MONS: kobold name:Durwent - - This will cause the monster to appear as "Durwent the kobold". - Spaces can be placed in the name by substituting them with the _ - symbol. It is worth noting that "the " will be appended - to all names, which should be considered when coming up with them. - - The name tag is also useable in KMONS. It should be used carefully - to avoid having multiple monsters named the same (ie, as above, - and then using the glyph '1' multiple times will result in multiple - "Durwent the Kobold"s). - - There are three different modifiers that by used on a name: - name_adjective, name_suffix and name_replace. name_adjective - makes the name act as an adjective. For example: - MONS: kobold name:ugly name_adjective - - Will cause "An ugly kobold", "The ugly kobold hits you", - and so on. - - name_suffix does the same, but after the monster's base name: - MONS: kobold name:wearing_mittens name_suffix - - Will give "A kobold wearing mittens", "The kobold wearing - mittens hits you", and so on. - - name_replace causes the base name to be replaced by given - name, as if the monster was a unique: - MONS: kobold name:Durwent name_replace - - Will result in "Durwent" rather than "Durwent the Kobold". - - Monster names should be used very sparingly. - - Overriding Monster Spells: - -------------------------- - Monster spell sets can be overridden with a spells: tag, - used as follows: - - MONS: goblin spells:throw_flame - MONS: ancient lich spells:symbol_of_torment;ice_storm;ice_storm - - (a list of spell names, spaces replaced with underscores, - and names separated by ';' with no spaces around the ';' or - after the spell: prefix) - - Monster spells currently use a limited spell-slot system, - with these slots: - 1. Bolt spell - 2. Enchantment - 3. Self-enchantment - 4. Misc(1) - 5. Misc(2) - 6. Emergency/escape - - These slots are not hard and fast rules, but it is sometimes - useful to drop a spell in a specific slot, for instance the - emergency/escape slot: - MONS: hobgoblin spells:.;.;.;.;.;teleport_self - - Spell names must exactly match the names in spl-data.h, with - spaces replaced by underscores. You may use "." or an empty - string to specify that a slot should be left empty. You can - force a spell-less monster with: - MONS: orc wizard spells:. - (although why you'd want to do this is open to question.) - - If you define spells for a monster that cannot cast spells - normally, you may want to mark the monster as a real - spellcaster with 'actual_spells': - MONS: goblin spells:throw_flame actual_spells - - Or as a priestly (divine) caster with 'priest_spells': - MONS: goblin spells:smiting priest_spells - - Real spellcasters and priests can be silenced and will - trigger appropriate conducts (Trog will appreciate killing - spellcasters, Beogh will appreciate killing priests). If you - define spells without specifying 'actual_spells' or - 'priest_spells', and the monster cannot cast spells - normally, the spells will be treated as innate abilities, so - the monster can use these spells even when silenced. - Treating spells as innate abilities may produce odd casting - message (such as: "the rat throws fire at you"). If you find - the messages you get unsatisfactory, add suitable entries to - source/dat/database/monspell.txt. - - -COLOUR: . = green / blue:5 / red / none - COLOUR: allows you to attach explicit colours to any feature. - Explicit colours will override the default colour for that - feature. The example shown above colours all . (floor) in the - map green, blue, red, or unchanged (use the default colour). - - You can use : to specify that all glyphs get the same colour: - COLOUR: x : red / blue - will colour all rock walls in the map red, or all rock - walls blue. - - COLOUR: should be used very sparingly, and only for features - where it won't cause confusion (i.e.: never re-colour features - like lava or traps unless you really know what you do!) - - If you apply COLOUR to a glyph and then apply a SUBST, - the COLOUR will transfer to the resulting transformed glyph. - - There are two types of colour available: base and "elemental". - Available base colours are as follows: blue, green, cyan, - red, magenta, brown, lightgrey, darkgrey, lightblue, lightgreen, - lightcyan, lightred, lightmagenta, yellow and white. - - Elemental colours are: fire, ice, earth, electricity, air, poison, - water, magic, mutagenic, warp, enchant, heal, holy, dark, death, - necro, unholy, vehumet, beogh, crystal, blood, smoke, slime, jewel, - elven, dwarven, orcish, gila, mist, shimmer_blue, decay, silver, - gold, iron, bone, random. See view.h for comments on each. - - Even more so than base colours, elemental colours should be used - very, very, very sparingly. - -FTILE: . = floor_grass:20 / floor_dirt / none - Similar to COLOUR, FTILE allows you to attach explicit floor - tiles to any glyph. In non-tiles builds, this does nothing. - If the tile specified has variations, those will be used - automatically. Only tiles from the dungeon image can be used. - - This will not (necessarily) replace the feature tile itself, - only the floor. If you set the FTILE on a fountain glyph, - then the fountain will still appear normally, but the floor - underneath it will be the tile that was specified. - - If a feature that normally covers the floor (e.g. rock walls) is - destroyed, this floor tile will be used in place of the normal - floor. Thus, it can be useful even for non-floor features. - - Like COLOUR, this should be used sparingly. - -RTILE: x = wall_hive:15 / wall_lair / none - Identical to FTILE, but for rock walls. Not useful for anything - but the rock wall feature. - -SHUFFLE: def, 12/3? - This allows you to randomly permute glyphs on the map. There are - two ways: - - SHUFFLE: 123w (i.e. list of glyphs, NOT slash-separated) - could, for example, swap all occurences of "1" with "2", as well as - swapping all "3" with "w" (or any other of the 24 possibilities). - - SHUFFLE: 12/3w (i.e. list of slash-separated blocks of same size) - will either do nothing or swap all "1" with "3" and then also swap - "2" with "w" everywhere. - - Several SHUFFLE: lines can be used, and mixed with SUBST:, and the - shuffles and substitutions will be applied in order. You can also - put multiple SHUFFLEs on one line, comma-separated. Shuffles cannot - use , or /. All spaces are stripped before shuffling. - -SUBST: ?=xc, !:bv, 1=2 1:100 - The SUBST: directive allows you to specify a placeholder symbol - that is replaced with a random glyph from a set. For instance: - - SUBST: ? = TUV - replaces occurrences of ? with one of TUV. Since whitespaces are - irrelevant, this is the same as - SUBST: ? = T U V - - SUBST: ? = T:20 U V - makes T twice as likely to be used as U or V (the default weight - is 10). Note that there has to be at least one space before and - after T:20 and that whitespace in T:20 is not permitted. - - SUBST: ? : TUV - replaces occurrences of ? with one of TUV, and guarantees that all - occurrences of ? will get the same replacement symbol. - - The placeholder and replacement symbols can be any non-space, - printable character, including : and =, apart from commas. For - example, the following is valid: - SUBST: = = +=:123def" - - SUBST: lines can safely replace symbols with themselves, as in: - SUBST: w = wW - - Multiple SUBST: lines can be used, and mixed with SHUFFLE:, and - will be applied in order. Multiple substitutions can be performed - on one line, using commas. - -NSUBST: ? = 3:w / *:l - - NSUBST is similar to SUBST, replacing placeholders with - replacement values. Unlike SUBST, however, it allows you to - replace different instances of the same placeholder with - completely different substitutions. For instance: - - ? = 3:w / *:l - - replaces three occurrences (randomly selected) of ? with w - and all others with l. - - You can use complex SUBST specifications: - - ? = 3= w .:15 A / *: =+CF - - This is equivalent to SUBST: ? = w .:15 A for three ? and - SUBST: ? : =+CF for all the others. - - You can use any number of NSUBST specifiers: - - ? = wW / l / A / 1234 - - Each specifier is preceded by the number of symbols to apply - it to, followed by : or = (: to use one substitution for all - occurrences, = to randomly pick for each occurrence). If you - omit the initial N: or N=, then 1= is assumed, except for the - last spec where *= is assumed. - -KFEAT: G = C / needle trap / antique armour shop / altar_zin - The KFEAT: directive allows you to specify a placeholder symbol - that is replaced with another symbol, named feature, trap, or - shop. For example, the line above will replace occurrences of G - with C (random altar), a needle trap, an antique armour shop, or - an altar of Zin. Different instances of G may receive different - replacements. To force a single replacement for all G, use: - - KFEAT: G : C / needle trap / antique armour shop - - You'll notice that 'G' is the symbol of a granite statue. Kxxx - directives allow you to assign arbitrary definitions to any symbol. - - KFEAT features are specified as a feature name (see section I - for a full list of feature names). As another example, you can - place a portal to the Abyss as: - - KFEAT: A = enter_abyss - - If you want no feature as an option in a KFEAT line, use '.' or - 'floor'. If you do not want to specify the type of shop, use - 'any shop' or 'random shop'. - - If you want a trap to start out known to the player, add "known" - to the trap name: - - KFEAT: A = known needle trap - - The placeholder used by KFEAT can be shared by KITEM and KMONS; - see below. If the placeholder is shared, all defined Kxxxx - operations for the placeholder are performed. Also, all Kxxx - lines accept weights as for MONS or ITEM. - -KMONS: ? = orc priest / w:3 deep elf priest - - KMONS: allows you to specify a placeholder symbol that indicates - the position of a monster (or monsters). - Using KMONS: allows you to exceed the 7 slot limit for monsters. - It is also useful if you want to place a monster on a non-floor - square (used in association with a KFEAT:). For example, - KFEAT: Z = W - KMONS: Z = rat - places a rat on a shallow water square for all occurrences of Z. - - KMONS: also allows you to specify alternative monsters if the - primary monster you want to place is unavailable (because it - is a unique that was already generated). For instance, if you want - to generate one of Terence, Michael or Erica or a generic human - (whoever is available, in that order, you can use): - KMONS: n = Terence, Michael, Erica, human - Or if you want to pick randomly: - KMONS: n = Terence / Michael / Erica, human - -KMASK: Z = no_monster_gen - - KMASK allows you set or unset various masks for particular - symbols, rather than for the entire vault like if you did it - with TAGS. Valid masks are - - * "no_item_gen": Prevents random item on that symbol. Items - explicitly placed on that symbol aren't affected. - * "no_monster_gen": Prevents random monster generation on that - symbol. MUST-HAVE for those with water/lava symbols in - entry vaults. - * "no_pool_fixup": prevents a water square next to land from being - randomly converted from deep water (the default) to shallow. - * "no_secret_doors": prevents a door from randomly being turned - into a secret door. - - For example - - KMASK: W = no_monster_gen - - will prevent monsters from randomly being generated on shallow water - squares. Note that if shuffling and substitutions cause W to end up - as water 10% of the time and floor 90% of the time, then those floor - squares will still have no_monster_gen set, but that's still a higher - degree of control than you get with TAGS. - - If TAGS has been used to set a mask for the entire vault, you can use - KMASK to remove that mask from particular symbols. For instance: - - TAGS: no_monster_gen - KMASK: W = !no_monster_gen - - would make it so that monsters are only randomly generated on shallow - water squares. - -KPROP: x = bloody - KPROP: allows you to assign a specific property to a feature. Like - KFEAT: and KMONS:, it can be combined with these for the same place- - holder. - - Available properties are: - - * "bloody": Causes features to appear as though splattered with - blood. This should be used very, very sparingly! - * "force_exclude": Forces a single grid square or feature to be an - exclusion in auto-explore and automatic travel. Will be coloured - red in the overmap. - * "no_cloud_gen": Prevents clouds from being generated over this - feature (usually lava). Does not stop fog generators or clouds - entering from nearby squares. - * "no_rtele_into": Prevents random teleport from chosing to use this - square. Should be used sparingly. - -KITEM: ? = potion of healing / potion of restore abilities - KITEM: places the specified item at all occurrences of the - placeholder. It can be combined with KFEAT: and KMONS: lines for - the same placeholder. - - You can use "gold" or "$" to place gold: - KITEM: ? = nothing / gold - KITEM: ? = nothing / $ - - You can use q: to specify quantities: - KITEM: ? = q:100 gold - - KITEM: allows you to place multiple items on the same square: - KITEM: ? = bread ration, potion of water, potion of porridge - -MARKER: A = feat: or lua: - - A marker ties a square on the map to a game-trigger of some sort - (which depends on the marker and what feature it is on). - - The portals to the Hells in the Vestibule of Hell are each annotated - with feature markers like this: - - MARKER: D=feat:enter_dis, G=feat:enter_gehenna - - When the horn is sounded, the stone arch at D becomes the portal to - Dis, the arch at G becomes the portal to Gehenna. This behaviour - applies only to the Vestibule of Hell. - - Lua markers are used for more complex triggers, such as for bazaar - and labyrinth gates, rune pickup triggers for the branches of Hell, - fog generators, etc. - - Here's a Lua marker that creates a cloud generator (for a - full explanation of the various parameters, read the header - of dat/clua/lm_fog.lua): - - MARKER: A = lua:fog_machine { \ - pow_max = 15, delay_min = 100, delay_max = 150, \ - size = 1, size_buildup_amnt = 29, \ - size_buildup_time = 1000 } - - Feature names used in markers must be names matching the names in - the source code. There's a full list of feature names in section I - (Feature names) at the end of this document. - - An important note about markers is that they are also considered map - transforms along with SUBST, NSUBST and SHUFFLE. You usually want - to place a MARKER line after all SUBST, NSUBST and SHUFFLE lines so - that the final position of the marker key is used. For instance, if - you want to attach a marker to the rune in a map which randomises - the position of the rune, this is a mistake: - - MARKER: O = lua: - SHUFFLE: Oa/|c - - because the marker will be placed at O (the rune), then O may be - shuffled to a different position. The correct order in this case is: - - SHUFFLE: Oa/|c - MARKER: O = lua: - -Handling long lines -------------------- - -For most map headers, you can split long lines by ending the line that will be -continued on the next line with \ as: - -KMONS: * = orc ; katana | quick blade . chain mail | scale mail / \ - goblin ; dagger - -If you're using continuation lines for comma-separated lists of monsters or -items, split your line after the comma, not before. For example: - -Wrong: - ITEM: potion of healing \ - , potion of speed -Right: - ITEM: potion of healing, \ - potion of speed - -But in general, it is preferable to use multiple ITEM or MONS lines if you're -splitting comma-separated values: - -Preferred: - ITEM: potion of healing - ITEM: potion of speed - -Spaces before the \ of the continued line are significant, leading spaces of -the next (continuing) line are not. In other words, given: - -ITEM: potion of\ - healing - -Crawl will see "potion ofhealing", not "potion of healing". - -Assigning multiple glyphs at once ---------------------------------- - -Declarations that modify glyphs allow multiple glyphs to be assigned -simultaneously as a convenience. For example, the following declaration will -assign floor_orc as the tile to be used for all up stair cases and floor: - - FTILE: .[{( = floor_orc - -This case is identical to the longer syntax: - - FTILE: . = floor_orc - FTILE: [ = floor_orc - FTILE: { = floor_orc - FTILE: ( = floor_orc - -Using : instead of = while assigning glyphs will assign the same value to all -glyphs. In the following example, the glyphs A, B, and C will either all -contain gold or all contain nothing: - - KITEM: ABC : gold / nothing - -Note: The number of items assigned in an NSUBST expression applies to the -entire group of glyphs being assigned. For example: - - # Among all A, B, and C glyphs, make one a floor and the rest walls. - NSUBST: ABC = 1:. / *:x - - # Make one A glyph floor, one B glyph floor, and one C glyph floor. - # Make the rest of the A, B, and C glyphs walls. - 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: - is translated into kfeat(""). - -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(, "no_rotate") - -Where is the C++ map object to which the tag should be added. -Since calling dgn.(, ) 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 (...) - dgn.(, ...) - end - -i.e. for every function in the 'dgn' table, we define a new -function that just calls dgn.() 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(, "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 {{ }} - or - lua {{ - - }} - The "lua" word is optional; you can also use: - {{ }} - and - {{ - - }} - -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 {{ }} - or - prelude {{ - - }} - -* Lua blocks for the validate chunk: - validate {{ }} - or - validate {{ - - }} - -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 ." - -* 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 "." 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/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: + is translated into kfeat(""). + +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(, "no_rotate") + +Where is the C++ map object to which the tag should be added. +Since calling dgn.(, ) 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 (...) + dgn.(, ...) + end + +i.e. for every function in the 'dgn' table, we define a new +function that just calls dgn.() 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(, "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 {{ }} + or + lua {{ + + }} + The "lua" word is optional; you can also use: + {{ }} + and + {{ + + }} + +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 {{ }} + or + prelude {{ + + }} + +* Lua blocks for the validate chunk: + validate {{ }} + or + validate {{ + + }} + +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 ." + +* 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 "." 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 "_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/levels/syntax.txt b/crawl-ref/docs/develop/levels/syntax.txt new file mode 100644 index 0000000000..bd3e8b5000 --- /dev/null +++ b/crawl-ref/docs/develop/levels/syntax.txt @@ -0,0 +1,1031 @@ +----------------------------------------------- +How to make levels for Dungeon Crawl Stone Soup +----------------------------------------------- + +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 +------- + x - rock wall (DNGN_ROCK_WALL) + X - permanent rock wall - always undiggable (DNGN_PERMAROCK_WALL) + c - stone wall - only affected by Shatter (DNGN_STONE_WALL) + m - clear rock wall (DNGN_CLEAR_ROCK_WALL) + n - clear stone wall - only affected by Shatter (DNGN_CLEAR_STONE_WALL) + o - clear permanent rock wall - always undiggable (DNGN_CLEAR_PERMAROCK_WALL) + v - metal wall - grounds electricity (DNGN_METAL_WALL) + b - crystal wall - reflects cold and fire (DNGN_GREEN_CRYSTAL_WALL) + a - wax wall - can melt (DNGN_WAX_WALL) + t - trees - a single square doesn't block LOS (DNGN_TREES) + + . - floor (DNGN_FLOOR) + + - closed door (DNGN_CLOSED_DOOR) + = - secret door (DNGN_SECRET_DOOR) + + W - shallow water + w - deep water - can be randomly turned into shallow water by the + level-builder; you can prevent this conversion with the no_pool_fixup TAG. + Also, water may automatically receive water creatures! For entry + vaults, avoid this with the no_monster_gen TAG or KMASK. + l - lava - again, use the no_monster_gen TAG or KMASK for entry vaults! + +Features +-------- + @ - entry point - must be on outside edge. If you use ORIENT: float, and do + not use any @, the dungeon builder will connect at least one floorspace on + the edge of your map to the rest of the level; if there is no floorspace + on the edge of your map, it will be isolated. + }{ - Stone stairs - You must be able to reach these from each other. The + { upstair is also the stair on which the player will enter the + dungeon for entry vaults. + )( - Stone stairs, set 2. + ][ - Stone stairs, set 3. + + >< - escape hatches - you can leave the level by these but will usually + not land on stairs/hatches + + I - orcish idol (does nothing) + + ^ - random trap. + ~ - random trap suitable for the branch and depth the map is being used. + + A - Vestibule gateway (opened by Horn). + B - Altar. These are assigned specific types (e.g. of Zin etc) in dungeon.cc, + in order. + C - Random Altar. + + G - Granite statue (does nothing) - you can see through but not walk through. + Also, sight-based effects like smiting work past granite statues, as does + apportation. + + NOTE: F used to put down a granite Statue most of the time but occasionally + Orange or Silver or Ice statues (1 in 100). You can reproduce this by using + F on the map together with + SUBST: F = G:100 F:1 + KMONS: F = orange crystal statue / silver statue / ice statue + + T - Water fountain + U - Magic fountain + V - Permanently dry fountain + Y - Blood fountain (use sparingly!) + +Items +----- + $ - gold + % - normal item + * - higher level item (good) + | - acquirement-level item (almost guaranteed excellent) + O - place an appropriate rune here. For portal vaults, place the portal here. + d-k - item array item. See section below on ITEM: arrays for more info. + +NOTE: The P (place a rune here with 1/3 chance) and R (place a honeycomb with + 2/3 chance or else a royal jelly) symbols have been deprecated. You can + (and should) produce the desired behaviour using + SUBST: P = O.. + KITEM: R = w:2 honeycomb / w:1 royal jelly + +Monsters +-------- + 0 - normal monster + 9 - +5 depth monster + 8 - (+2) * 2 depth monster (aargh!). Can get golden dragons and titans + this way. + 1-7 - monster array monster. See section below on MONS: arrays for more + information + + +H. Header information +======================= + +(All declarations apart from NAME: are translated to Lua function calls +behind the scenes. See the Lua reference for more information.) + +Try to respect line lengths of 80 characters. Should some line exceed that +(which is quite possible, especially for ITEM and MONS lines), you can use +the \ symbol to break a line. You can break a line anywhere, with the +exception of comma-separated lists, where you cannot start a new line with +a comma. See the end of this section for examples. + +NAME: a_string + Each map must have a unique name. Underscores and digits are ok. + +ORIENT: (float |encompass | north | northwest | ... | southeast) + + Some kind of ORIENT: line is mandatory for vaults; skipping + ORIENT: makes your map a minivault. As a rule of thumb, if + you're writing a small random map, skip the ORIENT: line and + make it a minivault. + + * "float": The dungeon builder puts your vault wherever it wants to. + * "some_direction": The vault lies along that side of the map: + xxxxxxxxxx xxxxxxxxxxxxx + xORIENT:Nx xORIENT:NW|.. + x.VAULT..x x.VAULT...|.. + x--------x x---------|.. + xrest....x xrest........ + x...of...x x.....of..... + x...levelx x.......level + + ORIENT: float vaults give a lot of flexibility to the dungeon + generator; float should generally be preferred to other ORIENT: + settings for new vaults. + +DEPTH: For random vaults, branch entry vaults, and minivaults, this + specifies the range of levels where the vault may be placed + in the dungeon. E.g. + + DEPTH: 7-20 + + DEPTH: does not force a map to be placed in a particular place; it + applies only when the dungeon builder is looking for a random vault + or minivault, so you can control at what depths your vault gets + placed. + + A simple DEPTH: declaration that does not specify a branch + applies to all branches. A map declared with depth 7-20 could + be used in the Lair, for instance. (Lair:1 will be treated as + a depth of 12 if the Lair entrance is on D:11.) + + You can constrain a map by branch: + + DEPTH: Lair:3-6 + + (Anywhere between levels 3-6 of the Lair, inclusive.) + + You can apply multiple constraints in one DEPTH line, + comma-separated: + + DEPTH: 7-20, !12-14 + + (Anywhere in the dungeon between depths 7-20, but not on levels + 12-14.) + + DEPTH: 7-20, !Orc + + (Anywhere in the dungeon between depths 7-20, but never in the Orcish + Mines.) + + DEPTH: Lair:* + + (Anywhere in the Lair. Can also be expressed as "DEPTH: Lair".) + + Maps that do not specify a DEPTH: attribute will inherit their depth + constraints from the closest preceding default-depth: line. If there + is no preceding default-depth directive in the .des file, the map will + have no DEPTH: constraint. Note that maps without a DEPTH: constraint + cannot be selected as random vaults or minivaults. + +CHANCE: : or + + CHANCE allows you to control the probability that your map + is used on any given level with an absolute roll. + + There are two ways to specify the CHANCE roll: + + CHANCE: 500 + or + CHANCE: 5% + + If specified as a raw number, the chance of selecting the + vault is in 10000. If specified as a percentage, + the chance of selecting the vault is * 100 in 10000. + Note that CHANCE accepts only integers, no fractions or + decimals. + + For any map with alternatives, a CHANCE influences how + likely the map is to be picked instead of the alternatives. + If a map has a CHANCE, Crawl will roll a random number in + the range 1-10000, and select the map if the CHANCE is >= + the rolled random number. + + If there are multiple alternative maps with CHANCE, they + will be tested in an unspecified order; the first map that + makes the CHANCE roll will be used. If you'd like to specify + an order of testing CHANCEs, specify a CHANCE with a + priority: + + CHANCE: 10 : 20% + + This specifies a CHANCE of 20%, with a priority of 10, which + means this vault will be checked before any other vault with + a lower priority (the default priority is 0). + + If no map with a CHANCE is picked, Crawl will select a map + based on WEIGHT, ignoring vaults with a CHANCE set. + + Note that the Lua equivalent for CHANCE is a two-argument + function: + + : chance(, ) + + These lines are all equivalent: + CHANCE: 5% + CHANCE: 500 + CHANCE: 0 : 5% + CHANCE: 0 : 500 + : chance(0, 500) + + A common case when using CHANCE is to assign a CHANCE to a + set of maps. For instance, if you have a set of portal vault + entries, and you want one of the set to be used on 5% of all + levels, you can do this: + + NAME: portal_a + CHANCE: 50 : 5% + TAGS: chance_portal_group + ... + + NAME: portal_b + CHANCE: 50 : 5% + TAGS: chance_portal_group + ... + + That is, if you have a set of maps that use CHANCE and are + tagged chance_xxx, then one map of that set will be used + when the chance is met. + +WEIGHT: (number with 10 being default) + For entry vaults and any other vaults randomly picked from among + a set, this type of line affects the likelihood of the given vault + being picked in a given game. The default WEIGHT: is 10. The + likelihood of a vault getting picked is: + [vault's WEIGHT: / sum of all WEIGHT:s of vaults of that type] + +PLACE: Used to specify certain special levels. Existing special levels + include most branch ends. + The branches need to use the official abbreviations also used e.g. in + the overmap (Ctrl-O): D, Temple, Orc, Elf, Lair, Swamp, Shoal, Slime, + Snake, Hive, Vault, Blade, Crypt, Tomb, Hell, Dis, Geh, Coc, Tar, Zot. + + PLACE can also be used to specify arbitrary places, like D:3, which + will force the map (or one of the maps with PLACE: D:3) to be picked + when D:3 is generated. + + PLACE cannot be used to specify places in the Abyss, Pandemonium, + or Labyrinths. + + PLACE can be used with random vaults and minivaults for testing them. + +TAGS: Tags go an a TAGS: line and are space-separated. You can have several + TAGS: lines, or use \ for very long ones. Valid tags are: + * "allow_dup": Vaults are normally used only once per game. If you + have a vault that can be used more than once, use allow_dup to tell + the dungeon builder that the vault can be reused. + * "chance_FOO": Maps can be tagged chance_ with any unique suffix + to indicate that if the map's CHANCE roll is made, one of the maps + tagged chance_FOO should be picked. + * "dummy": this tag indicates that the vault is a stub; if the dungeon + builder picks a dummy vault, it pretends no vault was selected. + Dummies are used to reduce the probability of other vaults at the + same depth / place. + * "entry": this tag MUST be there for a vault to be pickable as an + entry vault. + * "extra": requests that the dungeon builder treat this as + an extra vault and try to immediately place another vault of the + same type it was trying to place when it placed this vault. + "extra" is good to use for things like labyrinth entries + that should not affect the chance of other minivaults on the level. + If you use "extra", you probably want to use one of the + "luniq" tags as well if your map is tagged "allow_dup". + * "generate_awake": Monsters placed (using MONS, KMONS) in this vault + will be generated awake. + * "patrolling": Monsters placed (using MONS, KMONS) in this vault + will be generated with their starting position as patrol point. + If not otherwise occupied (fighting, seeking) they will patrol + the area. + * "no_item_gen": Prevents random item generation in the vault. + Items explicitly placed by the vault are not affected. + * "mini_float": applicable only to minivaults, requests that + the dungeon builder pick random exits from the minivault and + connect it to the rest of the level, similar to the exit behaviour + for floating vaults. + * "no_monster_gen": Prevents random monster generation at the time of + the vault's creation. Highly advised for entry vaults with a + player-hostile geography, MUST-HAVE for those with water/lava. + Can be applied only to particular symbols with KMASK. + * "no_pool_fixup": prevents water squares next to land from being + randomly converted from deep water (the default) to shallow. + * "no_wall_fixup": In Dis, the Vaults and the Crypt a vault's + rock walls will be changed to be the same as the wall type of + the rest of the level. If you don't want that to happen then + use this tag. + * "uniq_BAR": (uniq_ with any suffix) specifies that only one of + the vaults with this tag can be used in a game. + * "luniq": specifies that this vault can be used only once on a + given level. "luniq" is only relevant when used with "allow_dup". + * "luniq_BAR": (luniq_ with any suffix) specifies that only one + of the vaults with this tag can be used on any given level. + "luniq_BAR" is only relevant when used with "allow_dup". + * "branch_entry" eg. "orc_entry", "lair_entry" etc. + If chosen, these maps will contain the stairs for that branch. + Use "O" to place the stairs. If a branch has very few entries, + a dummy entry is advisable to make sure the player doesn't get + bored of the same few entries recycled ad nauseam. + Note: if any TAG argument contains an "entry", the vault will + be no longer eligible for random placement. (Currently, + this just affects your choice of BAR when using uniq_BAR.) + * "mnoleg" or the name of some other pandemonium lord. This makes + the map eligible for said pan lord's lair. See pan.des. + * "minotaur" turns this into a labyrinth exit vault. + "lab" turns this into an additional labyrinth flavour vault. + See lab.des for examples and details. + * "no_rotate": Normally, the dungeon builder can, at its whim, + rotate your vault. This flag tells it, "hey, don't do that to my + vault!" + * "no_hmirror": Like no_rotate, but for horizontal mirroring. + * "no_vmirror": Like no_rotate, but for vertical mirroring. + * "layout": Lua code that dungeon.cc uses for generating level + layouts. Do *NOT* use or mess with unless you know what + you're doing. + * "layout_foo": Indicates what sort of level layouts this vault is + compatible with, for vaults that don't fit in with all layouts; + the absence of this type of tags means it can go with any layout. + Multiple layout_foo tags can be used if it can be used with + multiple layouts. Current values for "foo" are: rooms, city, + open, caves, cross, shoals, swamp, labyrinth (though currently + random vaults aren't placed in the last three). + * "trowel_portal": This vault can be created by the Trowel card. + This tag should be used exclusively for the generic (one tile) + entries to portal vaults, like bazaars and labyrinths. Other + portal vaults may be eligible for Trowel, too. + * "no_dump": Don't dump out this vault's name in the list of + vaults generated during the game. Use this if the vault + is predictable (like the Vault:8 and Slime:6 vaults) or + are for weird internal uses (like the shoalhut vaults). + +LFLAGS: Persistent, changeable per-level flags which affect game behaviour + (FLAGS just controls how the vault is placed); should only be used + for vaults with ORIENT encompass or with PLACE. Causes a level's + flags to be set when the level is first created. These flags can + later be altered using Lua markers; for examples, look at the slime + pit vault in lair.des, and the vaults in hell.des and elf.des. + + Valid flags are: + * no_tele_control - prevents the player from using teleport control + * not_mappable - prevents the player from remembering where + they've been (like in the Abyss) + * no_magic_map - which prevents magic mapping from working. + +BFLAGS: Persistent, changeable per-*branch* flags which affect game + behaviour; should only be used for vaults which go on the first + level of a particular branch. These flags can later be altered + using Lua markers; see the Tomb vaults in vaults.lua for an + example. + + Valid flags are: + * no_tele_control - prevents the player from using teleport control + * not_mappable - prevents the player from remembering where + they've been (like in the Abyss) + * no_magic_map - which prevents magic mapping from working. + +LFLOORCOL: blue + LFLOORCOL: allows you to set the floor colour for the level the + vault appears in. Should only be used for bazaars and other + portal vaults. + +LROCKCOL: yellow + LROCKCOL: allows you to set the colour of rock walls for the level + the vault appears in. Should only be used for bazaars and other + portal vaults. + +LFLOORTILE: (tile name string, e.g. "floor_tomb") + Like LFLOORCOL, this overrides the default floor tiles used for + this level. If the tile specified has variations, those will be + used automatically. + +LROCKTILE: (tile name string, e.g. "wall_hive") + Same as LFLOORTILE, but for rock walls. + +ITEM: (list of items, separated by comma) + These are used to help place specified items at specific places + within a vault. They create an array with up to 8 positions. What's + in the first position in the array will be used when the dungeon + builder sees a "d" in the vault definition, the second will be used + for "e"s, etc. Positions are comma-separated; several ITEM: lines + are possible as well. The following defines letters 'd' - 'g': + ITEM: stone, ring mail, meat ration, ring of hunger + + Positions can contain multiple possibilities, one of which the + builder will choose randomly. Separate such multiple possibilities + using a slash. Note that "nothing" (without the quotes) is a valid + possibility. The random choice is done for each individual occurence + of the letter. You can also give possibilities a "weight," which + affects their chance of being picked. The default weight is 10. You + can abbreviate "weight:30" by "w:30". The chance to pick a + possibility is + [possibility's weight: / sum of all weight:s in that array position] + + For example, the following line makes letter 'd' into a bread ration + with 50% chance, or apple or orange with 25% chance each: + + ITEM: bread ration / w:5 apple / w:5 orange + + Modifiers: + * "q:N" sets the item quantity to N (if N > 0). Does nothing + if the item is not stackable. + * "no_uniq" prevents the item from being turned into an artefact. + * "good_item" makes the builder try to make the item a good one + (acquirement quality). + * "acquire" requests the use of the acquirement code itself, + ensuring that the player gets wearable armour, etc. You can + also use acquire: to request that the acquired item be + treated as a god gift. Examples: "acquire any", "acquire armour", + "acquire:sif_muna book", "acquire:trog weapon". + * "level:N" sets the object's item level (can't be used with + "good_item"). If set to -2 then the object's item level will + be the same as a "*" symbol item (five plus twice the + vault's level number). + * "damaged" sets the item plusses to -1..-4. + * "cursed" gets a curse plus plusses as in "damaged". + * "any" by itself gives a random choice; you can combine "any" with + "good_item." + * "any book", "any misc" etc. gives a random item of that class. + Valid item class names are: gold, weapon, missile, armour, wand, + food, scroll, jewelry, potion, book, staff, orb, misc, carrion. + All of these are usable in map definitions, apart from "orb" and + "carrion". + * "race:race_name", where "race_name" is "elven", "dwarven" or + "orcish"; it can also be "none" or "no_race" to prevent the item + from being randomly being made racial. Has no effect if the item + can't take that kind of racial setting. + NOTE: Can result in a non-racial item if used with "any" and the + chosen item isn't compatible with the desired race. + * "ego:ego_name", where "ego_name" is something like "running" or + "fire_resistance", and so on; "none" can be used to prevent the + item from getting an ego. The item must be fully specified, so + trying "any weapon ego:vorpal" or "any armour ego:positive_energy" + will result in an error. Trying to give an ego to something which + can't accept an ego will also result in an error. + * "unrand:item_name" will make a given unrandom by a given name, + like "long sword unrand:singing_sword". Omit any apostrophes + in the name (e.g, unrand:vampires_tooth). If the name has + something between double quotes then use that string (e.g, + unrand:bloodbane). If the unique already exists, the base item + will be given instead. + * "randart" will force a randart. Most of the above modifiers + will be ignored, except for "ego" (for weapons only). + + WARNING: While checks are done to make sure that an armour ego + isn't given to a weapon, a weapon ego to a missile, and so on, and + also to make sure that egos are only given to armours, weapons and + missiles, no other checking is done. Thus it is possible to create + a demonic weapon of holy wrath or a helmet of running. + + Limitations: You can't specify specific pluses or number of charges. + You also can't lay down corpses, skeletons, or chunks. + + You can place multiple items on the same square by using the KITEM + directive. See that section for more information. + +MONS: (list of monsters) + These are used to help place specific monsters at specific places + in a vault. They create an array with up to 7 positions. What's in + the first position in the array will be used when the dungeon + builder sees a "1" in the vault definition, the second for "2," + etc. Note that if, for example, you place a 3 on the map, but your + MONS: line has no third position, the 3 will be filled with + RANDOM_MONSTER. Also note that for entry vaults (D:1), all monsters + in sight of the hero are removed. This does not hold for plants. + You can use weights as for ITEM: lines. + + A hydra can be given a specific number of heads by calling it + an "n-headed hydra" (with a maximum of 20 heads): + MONS: four-headed hydra + + A slime creature's size can be set to other than normal using + the prefixes "large", "very large", "enormous" or "titanic": + MONS: very large slime creature + + Individual monsters may be prefixed with the "generate_awake" + (without the quotes). Use this sparingly: + MONS: generate_awake giant beetle + + Individual monsters may be prefixed with the "patrolling" + (without the quotes). Use this sparingly: + MONS: patrolling naga guardian + + Monsters can also be given colours that override their default + colour. Use this *very* sparingly: + MONS: col:darkgrey fungus + + Note that 8, 9, 0 also place monsters (see the table). + + If you want to place a random monster suitable for the level + the map is generated on, you can use + MONS: random + + If you want to place a random monster suitable for some other + place, you can use a place: tag in the monster spec: + MONS: place:Abyss + or + MONS: place:Slime:6 + + Using place: with MONS implies that you want a random monster. + You can also request zombies from random monsters suitable + for some other depth as: + MONS: place:Elf:7 zombie + or + MONS: place:Zot:5 simulacrum + or + MONS: place:Vault:8 spectre + + The available modifiers are "zombie", "skeleton", + "simulacrum" and "spectre". + + If a monster is a member of a band, you can request that it + be eligible for band members by adding the keyword "band" to + the name. For instance: + MONS: orc warlord band + + Specifying "band" doesn't force bands to be placed - it + requests that the game use the normal chances of creating a + band. If you use "band", leave some empty space around the + monster for its band members to be placed. + + A monster can be given specific items by following the monster + name with a semi-colon and then with an item list as described + in ITEM:, but with slashes replaced with pipes and commas replaced + with periods. For example: + MONS: orc ; katana | quick blade . chain mail | scale mail + + will generate an orc wielding either a katana or a quick blade + and wearing either a chain mail or a scale mail. Randarts are + never generated, and ego items are only generated if the ego + is explicitly stated. Note that any items that the monster was + originally generated with will be removed and destroyed. This + can be used to force a monster to have no items whatsoever: + MONS: orc; nothing + + Items given to an orc or an elf will be made orcish or elven + unless the item's race type is explicitly set otherwise. + + Limitations: If an item in the item list has alternatives, + there's no way to force all monsters dervied from that monster + spec to choose the same alternative. If a monster is given + a random launcher, there is no way to force the ammo type to + match the launcher type. + + Individual monsters can be given names as follows: + MONS: kobold name:Durwent + + This will cause the monster to appear as "Durwent the kobold". + Spaces can be placed in the name by substituting them with the _ + symbol. It is worth noting that "the " will be appended + to all names, which should be considered when coming up with them. + + The name tag is also useable in KMONS. It should be used carefully + to avoid having multiple monsters named the same (ie, as above, + and then using the glyph '1' multiple times will result in multiple + "Durwent the Kobold"s). + + There are three different modifiers that by used on a name: + name_adjective, name_suffix and name_replace. name_adjective + makes the name act as an adjective. For example: + MONS: kobold name:ugly name_adjective + + Will cause "An ugly kobold", "The ugly kobold hits you", + and so on. + + name_suffix does the same, but after the monster's base name: + MONS: kobold name:wearing_mittens name_suffix + + Will give "A kobold wearing mittens", "The kobold wearing + mittens hits you", and so on. + + name_replace causes the base name to be replaced by given + name, as if the monster was a unique: + MONS: kobold name:Durwent name_replace + + Will result in "Durwent" rather than "Durwent the Kobold". + + Monster names should be used very sparingly. + + Overriding Monster Spells: + -------------------------- + Monster spell sets can be overridden with a spells: tag, + used as follows: + + MONS: goblin spells:throw_flame + MONS: ancient lich spells:symbol_of_torment;ice_storm;ice_storm + + (a list of spell names, spaces replaced with underscores, + and names separated by ';' with no spaces around the ';' or + after the spell: prefix) + + Monster spells currently use a limited spell-slot system, + with these slots: + 1. Bolt spell + 2. Enchantment + 3. Self-enchantment + 4. Misc(1) + 5. Misc(2) + 6. Emergency/escape + + These slots are not hard and fast rules, but it is sometimes + useful to drop a spell in a specific slot, for instance the + emergency/escape slot: + MONS: hobgoblin spells:.;.;.;.;.;teleport_self + + Spell names must exactly match the names in spl-data.h, with + spaces replaced by underscores. You may use "." or an empty + string to specify that a slot should be left empty. You can + force a spell-less monster with: + MONS: orc wizard spells:. + (although why you'd want to do this is open to question.) + + If you define spells for a monster that cannot cast spells + normally, you may want to mark the monster as a real + spellcaster with 'actual_spells': + MONS: goblin spells:throw_flame actual_spells + + Or as a priestly (divine) caster with 'priest_spells': + MONS: goblin spells:smiting priest_spells + + Real spellcasters and priests can be silenced and will + trigger appropriate conducts (Trog will appreciate killing + spellcasters, Beogh will appreciate killing priests). If you + define spells without specifying 'actual_spells' or + 'priest_spells', and the monster cannot cast spells + normally, the spells will be treated as innate abilities, so + the monster can use these spells even when silenced. + Treating spells as innate abilities may produce odd casting + message (such as: "the rat throws fire at you"). If you find + the messages you get unsatisfactory, add suitable entries to + source/dat/database/monspell.txt. + + +COLOUR: . = green / blue:5 / red / none + COLOUR: allows you to attach explicit colours to any feature. + Explicit colours will override the default colour for that + feature. The example shown above colours all . (floor) in the + map green, blue, red, or unchanged (use the default colour). + + You can use : to specify that all glyphs get the same colour: + COLOUR: x : red / blue + will colour all rock walls in the map red, or all rock + walls blue. + + COLOUR: should be used very sparingly, and only for features + where it won't cause confusion (i.e.: never re-colour features + like lava or traps unless you really know what you do!) + + If you apply COLOUR to a glyph and then apply a SUBST, + the COLOUR will transfer to the resulting transformed glyph. + + There are two types of colour available: base and "elemental". + Available base colours are as follows: blue, green, cyan, + red, magenta, brown, lightgrey, darkgrey, lightblue, lightgreen, + lightcyan, lightred, lightmagenta, yellow and white. + + Elemental colours are: fire, ice, earth, electricity, air, poison, + water, magic, mutagenic, warp, enchant, heal, holy, dark, death, + necro, unholy, vehumet, beogh, crystal, blood, smoke, slime, jewel, + elven, dwarven, orcish, gila, mist, shimmer_blue, decay, silver, + gold, iron, bone, random. See view.h for comments on each. + + Even more so than base colours, elemental colours should be used + very, very, very sparingly. + +FTILE: . = floor_grass:20 / floor_dirt / none + Similar to COLOUR, FTILE allows you to attach explicit floor + tiles to any glyph. In non-tiles builds, this does nothing. + If the tile specified has variations, those will be used + automatically. Only tiles from the dungeon image can be used. + + This will not (necessarily) replace the feature tile itself, + only the floor. If you set the FTILE on a fountain glyph, + then the fountain will still appear normally, but the floor + underneath it will be the tile that was specified. + + If a feature that normally covers the floor (e.g. rock walls) is + destroyed, this floor tile will be used in place of the normal + floor. Thus, it can be useful even for non-floor features. + + Like COLOUR, this should be used sparingly. + +RTILE: x = wall_hive:15 / wall_lair / none + Identical to FTILE, but for rock walls. Not useful for anything + but the rock wall feature. + +SHUFFLE: def, 12/3? + This allows you to randomly permute glyphs on the map. There are + two ways: + + SHUFFLE: 123w (i.e. list of glyphs, NOT slash-separated) + could, for example, swap all occurences of "1" with "2", as well as + swapping all "3" with "w" (or any other of the 24 possibilities). + + SHUFFLE: 12/3w (i.e. list of slash-separated blocks of same size) + will either do nothing or swap all "1" with "3" and then also swap + "2" with "w" everywhere. + + Several SHUFFLE: lines can be used, and mixed with SUBST:, and the + shuffles and substitutions will be applied in order. You can also + put multiple SHUFFLEs on one line, comma-separated. Shuffles cannot + use , or /. All spaces are stripped before shuffling. + +SUBST: ?=xc, !:bv, 1=2 1:100 + The SUBST: directive allows you to specify a placeholder symbol + that is replaced with a random glyph from a set. For instance: + + SUBST: ? = TUV + replaces occurrences of ? with one of TUV. Since whitespaces are + irrelevant, this is the same as + SUBST: ? = T U V + + SUBST: ? = T:20 U V + makes T twice as likely to be used as U or V (the default weight + is 10). Note that there has to be at least one space before and + after T:20 and that whitespace in T:20 is not permitted. + + SUBST: ? : TUV + replaces occurrences of ? with one of TUV, and guarantees that all + occurrences of ? will get the same replacement symbol. + + The placeholder and replacement symbols can be any non-space, + printable character, including : and =, apart from commas. For + example, the following is valid: + SUBST: = = +=:123def" + + SUBST: lines can safely replace symbols with themselves, as in: + SUBST: w = wW + + Multiple SUBST: lines can be used, and mixed with SHUFFLE:, and + will be applied in order. Multiple substitutions can be performed + on one line, using commas. + +NSUBST: ? = 3:w / *:l + + NSUBST is similar to SUBST, replacing placeholders with + replacement values. Unlike SUBST, however, it allows you to + replace different instances of the same placeholder with + completely different substitutions. For instance: + + ? = 3:w / *:l + + replaces three occurrences (randomly selected) of ? with w + and all others with l. + + You can use complex SUBST specifications: + + ? = 3= w .:15 A / *: =+CF + + This is equivalent to SUBST: ? = w .:15 A for three ? and + SUBST: ? : =+CF for all the others. + + You can use any number of NSUBST specifiers: + + ? = wW / l / A / 1234 + + Each specifier is preceded by the number of symbols to apply + it to, followed by : or = (: to use one substitution for all + occurrences, = to randomly pick for each occurrence). If you + omit the initial N: or N=, then 1= is assumed, except for the + last spec where *= is assumed. + +KFEAT: G = C / needle trap / antique armour shop / altar_zin + The KFEAT: directive allows you to specify a placeholder symbol + that is replaced with another symbol, named feature, trap, or + shop. For example, the line above will replace occurrences of G + with C (random altar), a needle trap, an antique armour shop, or + an altar of Zin. Different instances of G may receive different + replacements. To force a single replacement for all G, use: + + KFEAT: G : C / needle trap / antique armour shop + + You'll notice that 'G' is the symbol of a granite statue. Kxxx + directives allow you to assign arbitrary definitions to any symbol. + + KFEAT features are specified as a feature name (see section I + for a full list of feature names). As another example, you can + place a portal to the Abyss as: + + KFEAT: A = enter_abyss + + If you want no feature as an option in a KFEAT line, use '.' or + 'floor'. If you do not want to specify the type of shop, use + 'any shop' or 'random shop'. + + If you want a trap to start out known to the player, add "known" + to the trap name: + + KFEAT: A = known needle trap + + The placeholder used by KFEAT can be shared by KITEM and KMONS; + see below. If the placeholder is shared, all defined Kxxxx + operations for the placeholder are performed. Also, all Kxxx + lines accept weights as for MONS or ITEM. + +KMONS: ? = orc priest / w:3 deep elf priest + + KMONS: allows you to specify a placeholder symbol that indicates + the position of a monster (or monsters). + Using KMONS: allows you to exceed the 7 slot limit for monsters. + It is also useful if you want to place a monster on a non-floor + square (used in association with a KFEAT:). For example, + KFEAT: Z = W + KMONS: Z = rat + places a rat on a shallow water square for all occurrences of Z. + + KMONS: also allows you to specify alternative monsters if the + primary monster you want to place is unavailable (because it + is a unique that was already generated). For instance, if you want + to generate one of Terence, Michael or Erica or a generic human + (whoever is available, in that order, you can use): + KMONS: n = Terence, Michael, Erica, human + Or if you want to pick randomly: + KMONS: n = Terence / Michael / Erica, human + +KMASK: Z = no_monster_gen + + KMASK allows you set or unset various masks for particular + symbols, rather than for the entire vault like if you did it + with TAGS. Valid masks are + + * "no_item_gen": Prevents random item on that symbol. Items + explicitly placed on that symbol aren't affected. + * "no_monster_gen": Prevents random monster generation on that + symbol. MUST-HAVE for those with water/lava symbols in + entry vaults. + * "no_pool_fixup": prevents a water square next to land from being + randomly converted from deep water (the default) to shallow. + * "no_secret_doors": prevents a door from randomly being turned + into a secret door. + + For example + + KMASK: W = no_monster_gen + + will prevent monsters from randomly being generated on shallow water + squares. Note that if shuffling and substitutions cause W to end up + as water 10% of the time and floor 90% of the time, then those floor + squares will still have no_monster_gen set, but that's still a higher + degree of control than you get with TAGS. + + If TAGS has been used to set a mask for the entire vault, you can use + KMASK to remove that mask from particular symbols. For instance: + + TAGS: no_monster_gen + KMASK: W = !no_monster_gen + + would make it so that monsters are only randomly generated on shallow + water squares. + +KPROP: x = bloody + KPROP: allows you to assign a specific property to a feature. Like + KFEAT: and KMONS:, it can be combined with these for the same place- + holder. + + Available properties are: + + * "bloody": Causes features to appear as though splattered with + blood. This should be used very, very sparingly! + * "force_exclude": Forces a single grid square or feature to be an + exclusion in auto-explore and automatic travel. Will be coloured + red in the overmap. + * "no_cloud_gen": Prevents clouds from being generated over this + feature (usually lava). Does not stop fog generators or clouds + entering from nearby squares. + * "no_rtele_into": Prevents random teleport from chosing to use this + square. Should be used sparingly. + +KITEM: ? = potion of healing / potion of restore abilities + KITEM: places the specified item at all occurrences of the + placeholder. It can be combined with KFEAT: and KMONS: lines for + the same placeholder. + + You can use "gold" or "$" to place gold: + KITEM: ? = nothing / gold + KITEM: ? = nothing / $ + + You can use q: to specify quantities: + KITEM: ? = q:100 gold + + KITEM: allows you to place multiple items on the same square: + KITEM: ? = bread ration, potion of water, potion of porridge + +MARKER: A = feat: or lua: + + A marker ties a square on the map to a game-trigger of some sort + (which depends on the marker and what feature it is on). + + The portals to the Hells in the Vestibule of Hell are each annotated + with feature markers like this: + + MARKER: D=feat:enter_dis, G=feat:enter_gehenna + + When the horn is sounded, the stone arch at D becomes the portal to + Dis, the arch at G becomes the portal to Gehenna. This behaviour + applies only to the Vestibule of Hell. + + Lua markers are used for more complex triggers, such as for bazaar + and labyrinth gates, rune pickup triggers for the branches of Hell, + fog generators, etc. + + Here's a Lua marker that creates a cloud generator (for a + full explanation of the various parameters, read the header + of dat/clua/lm_fog.lua): + + MARKER: A = lua:fog_machine { \ + pow_max = 15, delay_min = 100, delay_max = 150, \ + size = 1, size_buildup_amnt = 29, \ + size_buildup_time = 1000 } + + Feature names used in markers must be names matching the names in + the source code. There's a full list of feature names in section I + (Feature names) at the end of this document. + + An important note about markers is that they are also considered map + transforms along with SUBST, NSUBST and SHUFFLE. You usually want + to place a MARKER line after all SUBST, NSUBST and SHUFFLE lines so + that the final position of the marker key is used. For instance, if + you want to attach a marker to the rune in a map which randomises + the position of the rune, this is a mistake: + + MARKER: O = lua: + SHUFFLE: Oa/|c + + because the marker will be placed at O (the rune), then O may be + shuffled to a different position. The correct order in this case is: + + SHUFFLE: Oa/|c + MARKER: O = lua: + +Handling long lines +------------------- + +For most map headers, you can split long lines by ending the line that will be +continued on the next line with \ as: + +KMONS: * = orc ; katana | quick blade . chain mail | scale mail / \ + goblin ; dagger + +If you're using continuation lines for comma-separated lists of monsters or +items, split your line after the comma, not before. For example: + +Wrong: + ITEM: potion of healing \ + , potion of speed +Right: + ITEM: potion of healing, \ + potion of speed + +But in general, it is preferable to use multiple ITEM or MONS lines if you're +splitting comma-separated values: + +Preferred: + ITEM: potion of healing + ITEM: potion of speed + +Spaces before the \ of the continued line are significant, leading spaces of +the next (continuing) line are not. In other words, given: + +ITEM: potion of\ + healing + +Crawl will see "potion ofhealing", not "potion of healing". + +Assigning multiple glyphs at once +--------------------------------- + +Declarations that modify glyphs allow multiple glyphs to be assigned +simultaneously as a convenience. For example, the following declaration will +assign floor_orc as the tile to be used for all up stair cases and floor: + + FTILE: .[{( = floor_orc + +This case is identical to the longer syntax: + + FTILE: . = floor_orc + FTILE: [ = floor_orc + FTILE: { = floor_orc + FTILE: ( = floor_orc + +Using : instead of = while assigning glyphs will assign the same value to all +glyphs. In the following example, the glyphs A, B, and C will either all +contain gold or all contain nothing: + + KITEM: ABC : gold / nothing + +Note: The number of items assigned in an NSUBST expression applies to the +entire group of glyphs being assigned. For example: + + # Among all A, B, and C glyphs, make one a floor and the rest walls. + NSUBST: ABC = 1:. / *:x + + # Make one A glyph floor, one B glyph floor, and one C glyph floor. + # Make the rest of the A, B, and C glyphs walls. + NSUBST: A = 1:. / *:x + NSUBST: B = 1:. / *:x + NSUBST: C = 1:. / *:x -- cgit v1.2.3-54-g00ecf