git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7496 c06c8d41-db1a-0410-9941-cceddc491573
BPPMLLPJLP6W2LZSPAMOMYA7YWCIFJTNNL3XBWU2MRHAQBZ5M4XAC A4WHP5XZMXDCFMGRPS43OVHXHMU5KJBZKF4IRIO6F3KTXNHKAERQC 6I5MNJV4MZTMTCUO5ON5XB7J6WPFKP7LNHUENGCHCUM2XJT66KMAC WE3JT43OR4L6675GINGU4B3YDBMURJZHDDYY3VLHUJEBAKH2HYEAC R6XS2HO5QX2FJUGL5UQQRNETKCMYWTUFPHPPS5SYWK3OQA4UDUQQC AFE345BJ7IX2YYYX3I5I6RYLXNWJCFE4WMH6F5JMIR6X7WUP75CAC BTZ3QR6G7FV4DJCEG2CTDFH6YSUM4Y7NXM7NTAKBRLBOUIPKZM4QC RLARLENIGHKWCS2X7NOUYUWYYZ5H2TJLTIH42YQURZLQFQTPBBVAC ZTDYCQQQQSLWGFJOUB3HKGHMJLNY6UHF4OOC2XVVHXSZTTZK5A5AC MXOCLQAUGWLOS7AOTYZ46JZDMRL4EVRK5YN4JJUQ76GLKBOBHEVAC K6ELQ4HEZYDROC7CJFLPJS64AAJQ4G6RVLL4GBRUG6FJMKSBDDIQC ILN2K6ASDZSMEHOPJ22IZLZJUO6DDGZTKAKXM3YXG6JZZHJNLX4AC S74D5KQSRSDBHFN6OTSQQTLUEGNA3FZQMG7IPR5JXDUXJ3AOL2UAC ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC TLA5UN6LZPXGKERI27EFY4HKIIU3VU5Y7ZU54WXL6ANBUV2VOTMQC EH4VJW3I5Y4V6DT3YMLNDA3NW2DEAV4LRE4T5IEXAVB4WB3JJMGAC TPZWAV3USKO7RX4IGHLZKVPRN36K33PJPSZYL6FZMX4XBHTYOQYAC ANVCMXEDN6Y62OGEKKQQYNHJKJVI3TMGQM6KD7SJJIQC46G2SSIQC All fixed level information resides in various .des files to be found in thedat directory. If you are interested in adding some vaults, say, start with
All fixed level information resides in various .des files to be found in thedat directory. If you are interested in adding some vaults, say, start with
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
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
A map containing the entry to a branch - either a branch stair (such asthe stair to the Orcish Mines), or a branch portal (a portal to Hell, say).
A map containing the entry to a branch - either a branch stair (such asthe stair to the Orcish Mines), or a branch portal (a portal to Hell, say).
Random minivaults are small maps that are placed onto a level that thedungeon builder has already constructed fully otherwise (the level may
Random minivaults are small maps that are placed onto a level that thedungeon builder has already constructed fully otherwise (the level may
Similarly, the most of the other feature glyphs can be replaced with KFEAT:lines. The same goes for some item glyphs ('R', 'Z') which could be replaced
Similarly, the most of the other feature glyphs can be replaced with KFEAT:lines. The same goes for some item glyphs ('R', 'Z') which could be replaced
PLACE: Used to specify certain special levels. Existing special levels are:Temple, Hell, Dis:7, Geh:7, Coc:7, Tar:7, Hive:4, Vault:8, Snake:5,Elf:7, Slime:6, Blade, Zot:5, Tomb:1, Tomb:2, Tomb:3, Swamp:5, Crypt:4
PLACE: Used to specify certain special levels. Existing special levelsinclude most branch ends.
for vaults with ORIENT encompass or with PLACE. Causes a level'sflags to be set when the level is first created. These flags can
for vaults with ORIENT encompass or with PLACE. Causes a level'sflags to be set when the level is first created. These flags can
look at the existing entry vaults. Besides reducing tedium, this avoidsgiving veterans a spoiled edge. As an example, if a secret chamber withloot is always at the same place, it's a no-brainer for those who know.
look at the existing entry vaults. Besides reducing tedium, this avoidsgiving veterans a spoiled edge. As an example, if a secret chamber withloot is always at the same place, it's a no-brainer for those who know.
Vaults can be conjured up in wizard mode using the &L command. You don'tneed to specify the full name of the vault, a substring which uniquely
Vaults can be conjured up in wizard mode using the &L command. You don'tneed to specify the full name of the vault, a substring which uniquely
H. Lua reference
H. Portal Vaults==================Portal vaults are vaults accessed by portals in the dungeon (labyrinthsand bazaars are special cases of portal vaults). You can create customportal 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 andgameplay 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) todat/descript/features.txt.Before going into the details of portal vault creation, some words abouttheir uses: Portal vaults are different from branches in that they arenot guaranteed. Furthermore, there is only one go at a portal vault - ifyou leave, it's gone for good. Finally, you can apply special rules to aportal vault, like disabling mapping. Bazaars and labyrinths are typicalexamples.In order to test a portal vault, you can either use PLACE: D:2 for anentry 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 entryNAME: portal_generic_entryTAGS: allow_dupORIENT: floatMARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \dst = "generic_portal" }KFEAT: O = enter_portal_vaultMAPOENDMAPPortal entries must contain a portal vault entry (enter_portal_vault).This feature must always have a marker that provides the portal with adescription ("A portal to places unknown") and a destination("generic_portal").In case you want to make sure that the portal vault entry is only usedonce, you add a TAGS: uniq_BAR line. It should be noted that the labelBAR may *not* end in _uniq (otherwise the level builder assumes that thevault is a branch entry).This will produce a portal, but attempting to use it will trigger anASSERT since there's no map for the destination. So we create adestination map like so:Define a destination map------------------------NAME: portal_generic_generic# Tag must match dst value of portal in entry.TAGS: generic_portal allow_dupORIENT: encompassMONS: ancient lichKFEAT: > = exit_portal_vaultMAPxxxxxxxxxxxx111111111xx1A111111>xx111111111xxxxxxxxxxxxENDMAPNote that the entry point into the map will be a stone arch. You mustprovide 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 linesMARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \dst = "generic_portal" }KFEAT: O = enter_portal_vaultensure that an 'O' glyph will be turned into a portal. Upon leaving the portalvault, you will be placed on its entry which has been turned into a floor. Youcan turn it into something different (usually an empty stone arch), by addingfloor = '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 showPlace: generic portalin the above example. The dst string is also used to link the destination mapsto the entry maps.You can replace lua:one_way_stair by lua:timed_marker in order to make timedportal vaults (which will disappear after some time). bazaar.des and lab.descontain examples.Using lua functions as shortcuts--------------------------------If you are making several entry and destination vaults, you will note alot 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!I. Lua reference
Under the hood, Crawl translates everything in a .des file to Lua. Youdon't need to know what the underlying Lua looks like to designlevels, but it helps.Crawl uses Lua 5.1 from http://www.lua.org (the site has informationon the Lua language). Let's examine how Crawl converts a mapdefinition into Lua code with an example map:NAME: statue_in_poolTAGS: no_rotate no_pool_fixup: if you.absdepth() < 7 thenMONS: plant: elseMONS: oklob plant: endMAP1...1.www..wGw..www.1...1ENDMAP
Crawl uses Lua heavily when dealing with .des files:
Crawl will convert this map into the following Lua code, wrapped in ananonymous function (this is called a Lua chunk):function ()tags("no_rotate")tags("no_pool_fixup")if you.absdepth() < 7 thenmons("plant")elsemons("oklob plant")endmap(".....")map(".www.")map(".wGw.")map(".www.")map(".....")endIf your level defines prelude or validation Lua code, such code isextracted into separate prelude and validation chunks. The prelude andvalidation chunks are empty unless specified.Apart from the special NAME map header, every map header translates toa Lua function with the same name in lowercase. For instance, KFEAT:<xyz> is translated into kfeat("<xyz>").If you have a space or comma separated list (such as TAGS, MONS, ITEM,etc.), then each space/comma separated item is passed into a separatecall 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 usefulbecause it allows you to extract repeated boilerplate in similarvaults into a Lua function in the .des file's prelude. For instance,if you were planning to write a whole slew of vaults featuring statuesin water guarded by plants, you could extract the common code into thetop 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 thene.mons("plant")elsee.mons("oklob plant")endend}}NAME: statue_in_pool# Pass in the Lua environment global _G to the prelude function.: statue_pool_map(_G)MAP1...1.www..wGw..www.1...1ENDMAPYou can also use arbitrary Lua directly in vault definitions, which ishandy 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))MAP1...1.www..wGw..www.1...1ENDMAPHow 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 LuaAPI reference below), and they expect to act on an instance of Crawl'sC++ mapdef object. Given:tags("no_rotate")the actual Lua call needs to be:dgn.tags(<map>, "no_rotate")Where <map> is the C++ map object to which the tag should be added.Since calling dgn.<foo>(<map>, <xxx>) is tedious, dat/clua/dungeon.luawraps the Lua chunk for the map into an environment that defineswrappers for all the functions in 'dgn' as:function <xyz>(...)dgn.<xyz>(<map>, ...)endi.e. for every function <xyz> in the 'dgn' table, we define a newfunction <xyz> that just calls dgn.<xyz>() with the current map as thefirst parameter, and the other parameters as passed in. Thus Lua codethat you write as:tags("no_rotate")is translated to the correct dgn.tags(<map>, "no_rotate").
While this is done automatically for map code, if you need to call Luacode that was not defined in the scope of the map, as in the examplestatue_pool_map() function, you need to pass in the map environment tothat function if you want it to modify the map. Thus the call tostatue_pool_map looks like:: statue_pool_map(_G)Steps involved in processing .des files---------------------------------------
body, and a validation chunk. The body is mandatory, but prelude andvalidation chunks are necessary only if your map needs validation orfancy selection criteria.
body, and a validation chunk. The body is mandatory, but validationand prelude chunks are necessary only if your map needs validationor fancy selection criteria.
that have wizard-mode) can produce map generation statistics. Togenerate statistics, run crawl from the command-line as:
that have wizard-mode - you must build Crawl with "make debug", not"make wizard") can produce map generation statistics. To generatestatistics, run crawl from the command-line as:
K. Portal Vaults==================Portal vaults are vaults accessed by portals in the dungeon (labyrinthsand bazaars are special cases of portal vaults). You can create customportal 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 andgameplay 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) todat/descript/features.txt.Before going into the details of portal vault creation, some words abouttheir uses: Portal vaults are different from branches in that they arenot guaranteed. Furthermore, there is only one go at a portal vault - ifyou leave, it's gone for good. Finally, you can apply special rules to aportal vault, like disabling mapping. Bazaars and labyrinths are typicalexamples.In order to test a portal vault, you can either use PLACE: D:2 for anentry 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 entryNAME: portal_generic_entryTAGS: allow_dupORIENT: floatMARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \dst = "generic_portal" }KFEAT: O = enter_portal_vaultMAPOENDMAPPortal entries must contain a portal vault entry (enter_portal_vault).This feature must always have a marker that provides the portal with adescription ("A portal to places unknown") and a destination("generic_portal").In case you want to make sure that the portal vault entry is only usedonce, you add a TAGS: uniq_BAR line. It should be noted that the labelBAR may *not* end in _uniq (otherwise the level builder assumes that thevault is a branch entry).This will produce a portal, but attempting to use it will trigger anASSERT since there's no map for the destination. So we create adestination map like so:Define a destination map------------------------NAME: portal_generic_generic# Tag must match dst value of portal in entry.TAGS: generic_portal allow_dupORIENT: encompassMONS: ancient lichKFEAT: > = exit_portal_vaultMAPxxxxxxxxxxxx111111111xx1A111111>xx111111111xxxxxxxxxxxxENDMAPNote that the entry point into the map will be a stone arch. You mustprovide 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 linesMARKER: O = lua:one_way_stair { desc = "A portal to places unknown", \dst = "generic_portal" }KFEAT: O = enter_portal_vaultensure that an 'O' glyph will be turned into a portal. Upon leaving the portalvault, you will be placed on its entry which has been turned into a floor. Youcan turn it into something different (usually an empty stone arch), by addingfloor = '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 showPlace: generic portalin the above example. The dst string is also used to link the destination mapsto the entry maps.You can replace lua:one_way_stair by lua:timed_marker in order to make timedportal vaults (which will disappear after some time). bazaar.des and lab.descontain examples.Using lua functions as shortcuts--------------------------------If you are making several entry and destination vaults, you will note alot 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!