# des-file format (UnNetHack)

Contents

1 Comments
2 Header statements

2.1 FUNCTION
2.2 INCLUDE

3 Level definitions

3.1 LEVEL
3.2 FLAGS

4 Level statements

4.1 MESSAGE
4.2 INIT_MAP
4.3 ALTAR
4.4 GRAVE
4.5 MON_GENERATION
4.6 SOUNDS
4.7 BRANCH
4.8 CORRIDOR
4.9 SHUFFLE
4.10 NON_DIGGABLE
4.11 NON_PASSWALL
4.12 ROOMDOOR
4.13 DOOR
4.14 WALLWALK
4.15 DRAWBRIDGE
4.16 ENGRAVING
4.17 FOUNTAIN
4.18 POOL
4.19 SINK
4.20 TERRAIN
4.21 REPLACE_TERRAIN
4.22 SPILL
4.23 PORTAL
4.24 RANDOM_CORRIDORS
4.25 MINERALIZE
4.26 REGION
4.27 ROOM
4.28 SUBROOM
4.29 GOLD
4.30 LADDER
4.31 STAIR
4.32 TELEPORT_REGION
4.33 TRAP
4.34 WALLIFY
4.35 NOMAP
4.36 GEOMETRY
4.37 MAP
4.38 MAZEWALK
4.39 MONSTER
4.40 OBJECT
4.41 CONTAINER

5 Flow control

5.1 SWITCH
5.2 FOR
5.3 LOOP
5.4 IF
5.5 EXIT
5.6 BREAK

6 Variables and Types

6.1 variable
6.2 array variable
6.3 coord or variable
6.4 strings
6.5 region or variable
6.6 map character or variable
6.7 mathematical expression
6.8 selection

6.8.1 coordinate
6.8.2 rectangle
6.8.3 filled rectangle
6.8.4 line
6.8.5 random line
6.8.6 grow
6.8.7 filter
6.8.8 floodfill
6.8.9 circle
6.8.10 ellipse
6.8.11 gradient
6.8.12 complement
6.8.13 rndcoord

7 Predefined functions and constants

7.1 Map characters
7.2 Trap names
7.3 Room types

This documents the des-file format used by UnNetHack.
UnNethack (like Sporkhack) started with the new level compiler patch, and then added most of the changes from Spork.
A des-file consists of any number of Header statements, and one or more of Level definitions.
Unlike vanilla format, the UnNetHack one is closer to a real programming language, the statements are executed in order, and there is some flow control.

Comments
All lines beginning with # are comments and are ignored by the level compiler, except between MAP and ENDMAP.
Example:

# This is a comment.

Header statements
FUNCTION
FUNCTION name() { Level statements }
FUNCTION name([$paramname:paramtype [, ...]]) { Level statements }

Defines a function.
The level statements defined inside the function body will be executed when the function is called.
Function must be defined before it can be called. Function name can contain alphanumeric characters (a-z, A-Z and 0-9) and full stops (.)
Call the function by using it's name, for example name()
Variables defined outside the function cannot be accessed, and variables defined inside the function are gone when the function finishes.
Functions can have any number of named parameters separated by commas. Supported parameter types are "string" and "integer".
Example:

FUNCTION foobar() {
  OBJECT:'?', random
}
foobar()
FUNCTION bazqux($foo:integer, $bar:string) {
  MESSAGE: $bar
  OBJECT:'$', random, quantity: $foo
}
bazqux(12345, "Fee Fie Foe Foo")

INCLUDE
INCLUDE "filename.des"

Includes the contents of the file in the current file.

Level definitions
A level definition consists of LEVEL, followed by an optional FLAGS and any number of Level statements.

LEVEL
LEVEL:"name"

The level is saved as name.lev file. The name can be up to 14 characters long.
Using a %i in the filename will be replaced with a sequential number, starting from 1, and counting upwards, for every LEVEL in that des-file that has a such variable.
Allows number characters between the '%' and 'i' - those will be handled as per printf formatting.
For example:

LEVEL:"bigrm-%i"

FLAGS
FLAGS:noteleport,mazelevel

Defines special flags for the whole level. Parameters are a comma-separated list of flags:

noteleport: Player cannot teleport within the level.
sheol: Level is a Sheol-type level, with special rules.
hardfloor: The floor is too hard to dig.
nommap: magic mapping does not work.
arboreal: supposedly an outdoor map. Solid walls and secret corridors will be shown as trees, digging makes floor instead of corridor and randomly created corridors are made out of floor instead of corridor.
shortsighted: Monsters cannot see you from far away.
noflipx, noflipy and noflip prevent the level from being flipped horizontally, vertically and both.
mazelevel: level is a "maze" type level. Digging a wall turns it into room floor and mimics prefer mimicing a statue.
premapped: The level map is automatically known by player (a la Sokoban).
shroud: Magic mapping doesn't reveal the map permanently.
stormy: Clouds randomly emit lightning bolts, a la Plane of Air.
graveyard: Reduced chances of undead corpses.
sky: Level is open to the sky, so has no ceiling.
Level statements
Level statements include the following commands, variable definitions, FUNCTION definitions, function calls, and Flow control commands.

MESSAGE
MESSAGE:"string"

The message string is shown when player first enters the level. Each message line gets separated with a --more-- -prompt in the game.
Example:

MESSAGE: "Well done, mortal!"
$foo = "Hello, World!"
MESSAGE: $foo

INIT_MAP
INIT_MAP:solidfill, terrain_type
INIT_MAP:mazegrid,'-'
INIT_MAP:sheollev
INIT_MAP:rogue
INIT_MAP:mines, '.' , ' ', true, true, random, true

Initializes the map with different algorithm.

solidfill: Fills the level with the specified map character. Can also take a map character with light-state wrapped in parenthesis: ('.', lit)
mazegrid: Generates a grid of solid walls and the specified map characters. Use MAZEWALK to carve a maze into it.
sheollev: Generates a Sheol level. No parameters.
rogue: Generates a Rogue level. No parameters.
mines: Creates Gnomish Mines-style levels. Takes several parameters: foreground, background, smoothed, joined, light_state, walled [, filling ]
foreground: The "foreground" fill map character. This should be something the player can walk on, as the walkable part will be made out of this.
background: The "background" fill map character. This will surround the foreground area, so can be solid or harmful to player.
smoothed: is either true or false, and denotes whether the level will be "smoothed". This means that any foreground character surrounded by fewer than 3 foreground characters is changed to background character.
joined: is either true or false, and denotes whether the level will be "joined", so that all parts are accessible by walking.
light_state: is either lit, unlit, or random.
walled: is either true or false. This is equivalent of using a WALLIFY -command.
filling: optional fill map character. The "outside" parts of the level will be filled with this.
ALTAR
ALTAR:coord or variable, alignment, altartype

Create an altar.

alignment is one of law, noalign, neutral, chaos, coaligned, noncoaligned, align[0], align[1], align[2] or random.
altartype is one of sanctum (with a high priest), shrine (with an aligned priest), altar or random.
Example:

ALTAR:(50,14),chaos,altar

GRAVE
GRAVE:coord or variable, "Any epitaph message"
GRAVE:coord or variable, random
GRAVE:coord or variable

Creates a grave at given location, with a given epitaph, a random epitaph, or with no text.

MON_GENERATION
Change the monster generation chances for this level.

MON_GENERATION:75%, (9, 'a'), (1, "fire giant")

75% of randomly generated monsters are either ants (90% chance), or fire giants (10% chance).

SOUNDS
Random sounds on this level.

SOUNDS:200, (hear, "falling rocks."), (pline, "Kaboom!"), (verbal, "Mwahahah!"), (feel, "hot!")

1/200 chance each turn to get one of the sounds defined. In this case, "You hear falling rocks.", "Kaboom!", "Mwahahah!", or "You feel hot!"

BRANCH
BRANCH:(x1,y1,x2,y2), (x3,y3,x4,y4)
BRANCH:levregion(x1,y1,x2,y2), levregion(x3,y3,x4,y4)

Places stairs or a magical portal to a dungeon branch within an area covered by (x1,y1,x2,y2) and not covered by (x3,y3,x4,y4).
If the area is prefixed with levregion then the coordinates are relative to the whole level, otherwise the coordinates are relative to the last-defined MAP.
Example:

BRANCH:levregion(51,2,77,18),(0,0,40,20)

CORRIDOR
CORRIDOR:(room_number, direction, door_position), (room_number, direction, door_position)
CORRIDOR:(room_number, direction, door_position), any_integer

Create a corridor from room to another room. direction is one of north, south, west, or east and tells which wall the corridor starts from and ends to. door_position is an integer value and tells how far from the top left of the room the corridor starts/ends. any_integer is a room number. There must be a door (or at least a doorway) in the starting wall position.

SHUFFLE
SHUFFLE:any_array_variable

Shuffles the array elements. The predefined alignment array align is shuffled automatically at the start of the level code, and cannot be reshuffled.
Example:

$foo = monster:{ 'd', 'T', 'e', 'L' }
SHUFFLE: $foo

NON_DIGGABLE
NON_DIGGABLE:region_or_variable

Sets the walls inside the region as non-diggable. 
Example:

NON_DIGGABLE:(00,00,13,12)

NON_PASSWALL
NON_PASSWALL:region_or_variable

Players and monsters cannot phase through the walls inside the region.
Example:

NON_PASSWALL:(00,00,13,12)

ROOMDOOR
ROOMDOOR:secret, door_state, door_wall, door_pos

Creates a door with certain state on the previously defined ROOM or SUBROOM.

secret can be one of true, false, or random.
door_state can be one of open, closed, locked, nodoor, broken, secret, or random.
door_wall can be one of north, south, west, or east, a pipe-delimited list of those, or random, and tells on what wall of the room the door will be created.
door_pos is a positive integer value and tells how far from the top or left the door will be.
Example:

ROOMDOOR: false, closed, north|south, random

DOOR
DOOR:door_state, selection

Puts a door on the map.

door_state can be one of open, closed, locked, nodoor, broken, secret, or random.
WALLWALK
WALLWALK:coord or variable, map character or variable
WALLWALK:coord or variable, map character or variable, 50%
WALLWALK:coord or variable, map character or variable, map character or variable
WALLWALK:coord or variable, map character or variable, map character or variable, 50%

DRAWBRIDGE
DRAWBRIDGE:coord or variable, dir, state

dir is one of the following: north, east, south or west
state is either closed, open or random.
Note that the drawbridge placement is different from door placement; the coordinates must be a place where the drawbridge would be when it's open, and from that place towards the direction there should be a wall, where the portcullis will be.
Example:

DRAWBRIDGE:(25,18), north, closed

ENGRAVING
ENGRAVING:coord or variable, engraving_type, "string"
ENGRAVING:coord or variable, engraving_type, $stringvariable

Creates an engraving on the floor.
engraving_type can be one of dust, engrave, burn, mark, blood, or random.
For example:

ENGRAVING:(12,03), engrave, "You are now entering the Gnome King's wine cellar."

FOUNTAIN
FOUNTAIN:selection

Create a fountain at each pair of coordinates in the selection.

POOL
POOL:selection

Create a pool at each pair of coordinates in the selection.

SINK
SINK:selection

Create a sink at each pair of coordinates in the selection.

TERRAIN
TERRAIN:selection, map_character_or_variable

Set the terrain at each pair of coordinates in the selection.
Example:

TERRAIN:random, 'L'
TERRAIN:line(1,1)-(40,11), ('T', lit)

REPLACE_TERRAIN
REPLACE_TERRAIN:region_or_variable, map_character_or_variable, map_character_or_variable, percentage

Replace percentage amount of the first terrain in the region to the second terrain.
For example, replace 25% of '.' in the area with 'L':

REPLACE_TERRAIN:(1,1,50,20), '.', 'L', 25%

SPILL
SPILL:coord or variable, terrain_type, direction, length

Create random "pool-like" globs of terrain, starting from coordinates, generally moving towards direction, and at a maximum of length positions.
Coordinates, terrain_type and length can be variables of the appropriate type.
For example:

SPILL: random, 'L', north, 20
SPILL: random, ('.', lit), north, 10

PORTAL
PORTAL:(x1,y1,x2,y2), (x3,y3,x4,y4), "levelname"
PORTAL:levregion(x1,y1,x2,y2), levregion(x3,y3,x4,y4), "levelname"

Places a magical portal within an area covered by (x1,y1,x2,y2) and not covered by (x3,y3,x4,y4). The portal will level teleport player to the level with the name "levelname".
If the area is prefixed with levregion then the coordinates are relative to the whole level, otherwise the coordinates are relative to the last-defined MAP.
Example:

PORTAL:levregion(57,01,78,19),(0,0,0,0),"fire"
PORTAL:(0,0,75,19),(65,13,75,19),"air"

RANDOM_CORRIDORS
RANDOM_CORRIDORS
RANDOM_CORRIDORS:style

Create random corridors joining the rooms.
style is random, or one of the following values:

1 = at least one corridor leaves from each room and goes to random room
2 = circular path: room1 -&gt; room2 -&gt; room3 -&gt; ... -&gt; room1
3 = all roads lead to rome. or to the first room.
any other value (or leaving style off) will generate normal style corridors.
MINERALIZE
MINERALIZE
MINERALIZE: kelp_pool, kelp_moat, gold_prob, gem_prob

Puts kelp in pools and moats, and gold and gems in solid walls.
Without parameters uses the same chances as normal Dungeons of Doom mineralize.

kelp_pool and kelp_moat are integer values and is the 1-in-n chances of a pool or a moat having kelp in it. Using -1 or below uses the default chances.
gold_prob and gem_prob are integer values and is the n/1000 chances of a diggable solid wall containing gold and gems. Using -1 or below uses the default chances.
Example:

MINERALIZE:0,0,0,1000  # Put gems in every solid wall

REGION
REGION:region_or_variable, lightstate, roomtype [, filled][, irregular][, joined]
REGION:region_or_variable, lightstate, roomtype [, filled][, irregular][, joined] { Level statements }

Define a region on the map with certain light-state and type. This allows defining irregularly-shaped rooms. See also ROOM and SUBROOM. BREAK is allowed within the level statements.

lightstate is lit, unlit, or random.
roomtype is either random, or one of the special room names, eg. "morgue"
filled is optional, either filled or unfilled, and tells whether the room should get stocked with random stuff.
irregular is optional, either irregular or regular and tells whether the room is irregularly shaped. If the room is irregular, only the first pair of coordinates defining the region must be inside the room, and the room must be closed off from other areas with non-floor map characters. Use the boundary symbol 'B' in the MAP to enclose an irregular room; it will be converted to floor symbol '.' after the level has been created.
joined is an optional joined or unjoined, and tells whether any randomly generated corridors connect to the region.
Example:

REGION:(01,04,09,05),lit,"barracks"

ROOM
ROOM:roomtype, [ chance, ] lightstate, pos, align, size [, filled] [, joined] { Level statements }

Creates a room, with walls and floor. The room will be placed on a position defined both by pos and align. pos defines the rough position (in a 5-by-5 grid on the screen), and align defines the room position within that. BREAK is allowed within the level statements.
NOTE: Creation of a randomly located room may fail, especially if there's little free space to fit it on the level. The level statements of a failed room won't be executed.

roomtype is either random, or one of the special room names, eg. "morgue"
chance is optional percentage of the room being the special room; otherwise the room is ordinary.
lightstate is lit, unlit, or random.
pos can be either random or an approximate location in the form of (1,3) - this is not an absolute position, but an approximate position on the map - the number ranges are 1..5
align is either random or an approximate adjustment to the location in the form of (horiz, vert), where
horiz is one of left, half-left, center, half-right, or right.
vert is one of top, center, or bottom.
size is either random or an exact width and height in the form of (3,5).
filled is an optional filled or unfilled. unfilled means the room should get stocked with random stuff.
joined is an optional joined or unjoined, and tells whether any randomly generated corridors connect to the room.
The contents (and SUBROOMs) of the room can be defined using the level statements.
See also SUBROOM and REGION.

SUBROOM
SUBROOM:"roomtype", [ chance, ] lightstate, position, size [, filled] [, joined] { Level statements }

Creates a room within a ROOM, with walls and floor. BREAK is allowed within the level statements block.

roomtype is either random, or one of the special room names, eg. "morgue"
chance is optional percentage of the room being the special room; otherwise the room is ordinary.
lightstate is lit, unlit, or random.
position is either random, or an exact position of the room inside the outer room in the form of (4,3).
size is either random or an exact width and height in the form of (3,5).
filled is an optional filled or unfilled. unfilled means the room should get stocked with random stuff.
joined is an optional joined or unjoined, and tells whether any randomly generated corridors connect to the room.
The contents (and SUBROOMs) of the room can be defined using the level statements.
See also ROOM and REGION.

GOLD
GOLD:mathematical expression, coord or variable

Create a pile of gold.
Example:

GOLD: 400 + 10d100, (01,05)

LADDER
LADDER:coord or variable, direction

Creates a ladder.
direction is one of up or down.

STAIR
STAIR:coord or variable, direction

Creates stairs.
direction is one of up or down.

TELEPORT_REGION
TELEPORT_REGION:(x1,y1,x2,y2), (x3,y3,x4,y4) [, up_or_down ]

Restricts the area where player can end up on the level when he level teleports or falls in there. Player will end up within an area covered by (x1,y1,x2,y2) and not covered by (x3,y3,x4,y4).
If the area is prefixed with levregion then the coordinates are relative to the whole level, otherwise the coordinates are relative to the last-defined MAP.
You can also add an optional direction parameter, either up or down, which will tell when this rule is applied; when player is coming from below or above.
Example:

TELEPORT_REGION:(69,16,69,16),(0,0,0,0)
TELEPORT_REGION:levregion(56,00,79,20),levregion(01,00,55,20),down

TRAP
TRAP:"falling rock", coord or variable
TRAP:random, coord or variable

Create a trap at the given location.

WALLIFY
WALLIFY
WALLIFY:selection

Turns walls (in the whole map, or in the defined selection) completely surrounded by other walls into solid stone ' '.
Example:

WALLIFY:fillrect(5,5, 40,15)

NOMAP
NOMAP

Instead of GEOMETRY and MAP, you use this if you think that INIT_MAP creates a good enough random map and you don't want to use any fixed map-parts.
See also MAP

GEOMETRY
This must be immediately followed by a MAP definition. It tells the location of the MAP-part on the level.
Two types of GEOMETRY, one takes an approximation of MAP alignment, the other takes an exact coordinate or variable.

GEOMETRY:horiz,vert
GEOMETRY:coord or variable

horiz is one of left, half-left, center, half-right, or right.
vert is one of top, center, or bottom.
Both types take an optional boolean value. If it's true, the commands following the map are restricted into that map.

GEOMETRY:center,center,true

MAP

MAP
...
...
...
ENDMAP

This must be immediately preceded by a GEOMETRY definition.
You define a map-part by "drawing" with map characters between the MAP and ENDMAP. The map can be up to 21 lines high and each line can be up to 76 chars long. Each line must also be the same length. You can also use numbers inside the map, but those will be ignored; they're considered as line numbers.
The top left point of the MAP is represented by the coordinates (0,0).
See also NOMAP.

MAZEWALK
MAZEWALK:coord or variable, direction
MAZEWALK:coord or variable, direction, stocked
MAZEWALK:coord or variable, direction, stocked, '.'

Creates a random maze, starting from the coordinates.
stocked is an optional boolean value and tells whether the maze should get stocked with random loot and monsters.
The optional map character is used to "draw" the maze.
Mazewalk turns map grids with solid stone (' ') into floor ('.'), or the given map character. From the starting position, it checks the mapgrid in the direction given, and if it's solid stone, it will move there, and turn that place into floor. Then it will choose a random direction, jump over the nearest mapgrid in that direction, and check the next mapgrid for solid stone. If there is solid stone, mazewalk will move that direction, changing that place and the intervening mapgrid to floor. Normally the generated maze will not have any loops.
For example

MAP
TTTTTTT
T T T T
TTTTTTT
T T T T
TTTTTTT
ENDMAP

Pointing mazewalk at that will create a small maze of trees, but unless the map (at the place where it's put into the level) is surrounded by something else than solid stone, mazewalk will get out of that MAP.  Substituting floor characters for some of the trees "in the maze" will make loops in the maze, which are not otherwise possible. Substituting floor characters for some of the trees at the edges of the map will make maze entrances and exits at those places.
If the total area NOT covered by all maze-parts in the level is greater than 1/10 of the total area of the level, then the mazes in the level will get stocked with maze-specific stuff, such as minotaurs, traps and items, proportionally to the amount of space not covered by MAPs.
Mazewalk will only work if the solid stone mapgrids in the level (where the MAP was put down) are on odd-numbered squares, both horizontally and vertically. You don't have to worry about this unless your MAP is 21 rows high or 76 columns wide, in which case you'll have to either make the MAP smaller, or move the places where the solid stone squares are.
Also, MAZEWALK will fail in certain types of MAP-parts if you use WALLIFY before MAZEWALK.
Example:

MAZEWALK:(00,06),west

MONSTER
MONSTER:'d', coord or variable
MONSTER:"hill giant", coord or variable
MONSTER:('i', "imp"), coord or variable
MONSTER:random, coord or variable
$foo = monster:'d'
MONSTER:$foo, (5,5)
$arr = monster:{ 'd', 'T', 'y' }
MONSTER:$arr[0], (5,5)

The monster definition can also take a number of optional parameters, separated by commas:

MONSTER:'d', (4,4), "Idefix", peaceful, asleep, law, m_feature "boulder", female, invisible, cancelled, revived, avenge, stunned, confused, fleeing: 40, blinded: 20, paralyzed: 10, seen_traps: all

"Idefix" is the name of the monster.
Instead of peaceful, could use hostile.
Instead of asleep, could use awake.
Instead of law, could use noalign, neutral, chaos, coaligned, noncoaligned, align[0], align[1], align[2] or align:random.
m_feature tells the monster to mimic a dungeon feature, a boulder in this case. could also use m_monster or m_object.
female, invisible, cancelled, revived, avenge, stunned and confused set monster status bits.
fleeing, blinded and paralyzed set the number of turns the monster will flee, is blinded or is paralyzed, respectively. Parameter is an integer value in the range of 0-127.
seen_traps tells which traps the monster has seen; parameter is either all or quoted strings of trap names separated by pipe characters (eg. "falling boulder", or "arrow"|"dart"|"bear")
OBJECT
OBJECT:"elven cloak", (5,5)
OBJECT:'?', (5,5)
OBJECT:('/', "wishing"), (5,5)
OBJECT:random, (5,5)
$foo = object:'/'
OBJECT:$foo, (5,5)
$arr = object:{ '/', '?', '!' }
OBJECT:$arr[2], (5,5)

The object definition can also take a number of optional parameters, separated by commas:

OBJECT:'?', (5,5), blessed, montype:('d', "little dog"), +4, name:"foobar", quantity: 20, buried, invisible, lit, greased, locked, trapped, eroded:2, erodeproof, recharged:3

blessed can be replaced with uncursed or cursed.
montype tells eg. what monster statue it is.
any integer value sets the plusses or minuses for eg. armor or weapon.
name gives the item a name. can also take a variable of string type as a parameter.
quantity set the number of items.
buried, trapped, invisible, greased set object states.
lit or unlit for lamps.
eroded sets the erosion. Don't use with erodeproof.
locked (or broken) set the lock state for lockable objects.
recharged sets the number of times eg. a wand has been recharged.
CONTAINER
CONTAINER:"large chest", (5,5) { Level statements }

Takes the same parameters as OBJECT, but allows defining the contents inside the curly braces.
For the contents, use a subset of level statements: OBJECTs, CONTAINERs and flow control commands; anything else causes undefined behaviour.

Flow control
The following commands affect the order in which commands are executed.

SWITCH

SWITCH [ integer_or_variable ] {
  CASE integer:
     Level statements
  DEFAULT:
     Level statements
} 

The SWITCH behaviour is modeled after the C switch-statement.
Using the BREAK keyword is allowed; without it the execution falls through to the next case.
If the integer value in the switch is a static number, it is automatically wrapped in rnd(). If a dice-notation or a variable is used, then the value is used as-is. For example the statements below are functionally the same:

SWITCH [ 3 ] { ... }
SWITCH [ rnd(3) ] { ... }
SWITCH [ 1d3 - 1 ] { ... }

FOR
FOR $x = math_expr TO math_expr { Level statements }

Executes the level statements as many times as it takes to increase (or decrease) the variable from the first integer value to the second. BREAK is allowed within the loop.
Example:

FOR $x = 2 TO 40 {
  FOR $y = 2+1 TO 2*10 {
    OBJECT:random, coord($x, $y)
  }
}

LOOP
LOOP [ integer_or_variable ] { Level statements }

Executes the level statements as many times (but at least once) as the value inside square brackets says. If an integer variable is used, the value of the variable does not change. BREAK is allowed within the loop.
Example:

LOOP [ 10 ] { OBJECT:random,random }

IF

IF [ percentage ] { Level statements }
IF [ math_expression_or_variable compare_operator math_expression_or_variable ] { Level statements }
IF [ math_expression_or_variable ] { Level statements }

Execute the level statements, but only if matching some condition. You can also add an optional ELSE { Level statements } block.
In the third form the statements will be executed if the math expression or variable is non-zero. Using BREAK is not allowed within the statements, unless the IF-block is inside a command where BREAK is allowed. In that case the BREAK will make the execution jump to the end of the containing command.
There's also a degenerate case [50%]: one_level_statement.
For example:

IF [ 25% ] { Level statements }
IF [ 25% ] { Level statements } ELSE { Level statements }
IF [ 2*2 == 4 ] { Level statements }
IF [ 0 ] { Level statements }
[50%]: MONSTER: random, random

EXIT
EXIT

Immediately finishes the level script.

BREAK
BREAK

The BREAK keyword will make the script skip the rest of the statement block. Breaks can be used within LOOPs, FOR-loops, SWITCHes,
ROOM and SUBROOM contents, CONTAINER contents, MONSTER inventories, and REGION contents.
Example:

FOR $x = 5 TO 60 {
 OBJECT:'$',coord($x,10)
 IF [ $x &gt; 30 ] { BREAK }
}

Variables and Types
variable
Variable names start with a dollar sign, and can contain any alphanumeric characters. Variables must be defined before they can be used.
Some variable definitions must have the variable type: terrain, monster, object and selection.

$foo = 123
$foo = "any string"
$foo = mathematical expression
$bar = $foo
$foo = terrain:'T'
$foo = terrain:('.', lit)
$foo = monster:'d'
$foo = monster:"little dog"
$foo = monster:('d', "little dog")
$foo = monster:random
$foo = object:'/'
$foo = object:"elven cloak"
$foo = object:('?', "identify")
$foo = (40, 12)
$foo = (5,5, 40,12)
$foo = selection:selection

array variable
$foo = { 1, 2, 3, 4, 5 }
$foo = { "string a", "bcdef", "and something" }
$foo = { (1,2), (40,12) }
$foo = { (5,5,40,12), (1,1,20,18), (40,10,50,12) }
$foo = terrain: { 'T', 'L', ('.', unlit) }
$foo = monster: { 'n', "newt", ('d', "little dog") }
$foo = object: { '/', "elven cloak", ('?', "identify") }

To access one element of an array variable, use eg. $foo[0] to access variable $foo's first element.
Array length can be accessed with the .length method:

$foo = { 1, 2, 4 }
MESSAGE: "length is " . string($foo.length)

coord or variable
This parameter can be either a pair of coordinates, or a variable of the type coord. For example: 

GRAVE: (10,5)
$foo = (4,10)
$bar = { (4,10), (3,12), (50,2) }
GRAVE: $foo
GRAVE: $bar[1]

GRAVE: rndcoord(selection)

A random pair of coordinates selected from within the selection
The x and y coordinates can be accessed (but not set) separately:

$foo = (4, 10)
IF [ $foo.x == 4 ] {
  MESSAGE: " y = " . string($foo.y)
}

strings
$foo = "This is a string"
MESSAGE: $foo . " and another"

Strings are any characters surrounded by double quotes. Strings can be concatenated with full stop. If you wish to concatenate an integer value, it must be first converted to string with the string() function.

region or variable
This parameter can be either a region, or a variable of the region type. For example:

NON_DIGGABLE:(5,5, 40,12)
$foo = (5,5, 40,12)
NON_DIGGABLE:$foo

map character or variable
This parameter can be either a map character, a map character and lightstate combination, or a variable of terrain type:

TERRAIN:(5,5), 'L'
TERRAIN:(6,6), ('.', unlit)
$lava = terrain:'L'
TERRAIN:(7,7), $lava
$floor = terrain:('.', lit)
TERRAIN:(8,8), $floor

mathematical expression
A mathematical expression can consist of plain integer values, D-notations, variables of integer type, and the operands '+', '-', '*', '/', and '%'. For example: 1 + 2, or 3d6 * (2 + 3).
Negative integer values should be enclosed inside parenthesis: (-1) * (-3)

selection
A selection is a collection of points, represented by map coordinates. The selection keyword is only needed when defining a variable of selection type.
Selections can be added together with the '&amp;' operator, for example rect(5,5, 50,18) &amp; rect(10,2, 40,13):

$foo = selection:rect(5,5, 50,18) &amp; rect(10,2, 40,13)

coordinate
$foo = selection:coord or variable

The selection contains a single point on the map.
Example:

$foo = selection:(55,12)
$bar = (4,10)
$baz = selection:$bar

rectangle
$foo = selection:rect region or variable

The selection includes the border of the rectangle.
Example:

$foo = selection: rect(5,3, 72,18)

filled rectangle
$foo = selection:fillrect region or variable

The selection contains a rectangular area.
Example:

$foo = selection: fillrect(5,3, 72,18)

line
$foo = selection:line coord or variable-coord or variable

The selection contains a straight line between the points.
Example:

$foo = selection: line(1,1)-(76,21)

random line
$foo = selection:randline coord or variable-coord or variable,mathematical expression

The selection contains a meandering line between the points. The integer value is the "roughness" of the line.
Example:

$foo = selection: randline(1,1)-(76,21), 4

grow
$foo = selection:grow (selection)
$foo = selection:grow (list of directions, selection)

Grow a selection by adding the surrounding map points to it. The second form can take a list of directions, and the growth will pick points from those directions to grow into.
Example:

$foo = selection:grow(line(1,1)-(76,21))
$bar = selection:grow(north|south, rect(5,3, 72,18))

filter
$foo = selection:filter (50%, selection)
$foo = selection:filter (selection, selection)
$foo = selection:filter (map character or variable, selection)

Remove points from the selection. The first form picks (at random) 50% of the points in the selection, the second chooses points that are common to both selections, third one leaves only places that match the map character.
Example:

$foo = selection: filter(20%, fillrect(5,3, 72,18))
$foo = selection: filter('L', fillrect(1,1, 76,21))

floodfill
$foo = selection:floodfill coord or variable

"Floodfill" from the point, adding all connected points with the same terrain type to the selection.

circle
$foo = selection:circle (coord or variable, mathematical expression)
$foo = selection:circle (coord or variable, mathematical expression, filled)
$foo = selection:circle (coord or variable, mathematical expression, unfilled)

Circle shape. Parameters are center point, radius, and optional filled or unfilled.
Creates an unfilled circle by default.
For example:

$foo = selection: circle((5,10), 3) &amp;
                  circle((15,10), 3, unfilled) &amp;
                  circle((25,10), 3, filled)
TERRAIN:$foo, 'L'

ellipse
$foo = selection:ellipse (coord or variable, mathematical expression, mathematical expression)
$foo = selection:ellipse (coord or variable, mathematical expression, mathematical expression, filled)
$foo = selection:ellipse (coord or variable, mathematical expression, mathematical expression, unfilled)

Ellipse shape. Parameters are center point, horizontal and vertical radius, and optional filled or unfilled.
Creates an unfilled ellipse by default.
For example:

$foo = selection: ellipse((35,10), 3,5) &amp;
                  ellipse((45,10), 3,5, unfilled) &amp;
                  ellipse((55,10), 3,5, filled)
TERRAIN:$foo, 'L'

gradient
$foo = selection: gradient(grad_type, (min_dist - max_dist [, limited]), coord [, coord2 ])

Selects random points with distance from coord between min_dist and max_dist, with higher probability closer to max_dist.
No points closer than min_dist will be included. All points at max_dist will be included.
Using the optional "limited" will make the selection stop at max_dist.
Leaving the "limited" out, or using "unlimited", will select all points outside the max_dist radius.
grad_type can be one of "radial" or "square", and affects the distance calculation from the center.
If the optional second pair of coordinates is given, the "center" of the area is a line segment between the two pairs of coordinates.
For example:

$r = selection: gradient(radial, (1 - 9, limited), (11,10))
TERRAIN:$r,'L'

complement
$foo = selection: complement(selection)

Returns a bitwise not, or complement, of the selection.

rndcoord
To select a random pair of coordinates from a selection, use rndcoord(selection):

$bar = rndcoord(rect(5,5, 50,18) &amp; rect(10,2, 40,13))

Predefined functions and constants
These are internal functions from the game's code that are available during level creation:

name

return value

time.discordian_holiday

integer, 0 or 1

time.pirateday

integer, 0 or 1

time.aprilfoolsday

integer, 0 or 1

time.piday

integer, 0 or 1

time.towelday

integer, 0 or 1

time.midnight

integer, 0 or 1

time.night

integer, 0 or 1

time.friday_13th

integer, 0 or 1

time.phase_of_the_moon

integer, 0..7, where 0=new, 4=full

time.yyyymmdd

integer

Current date in the YYYYMMDD format, eg. 20120418

level.depth

integer

Returns the level depth from surface.

level.difficulty

integer

level.obj_at(obj, coord)

integer, 0 or 1

Return 1 if the specified object is present at the coordinates.

level.mon_at(monster, coord)

integer, 0 or 1

Return 1 if there's a monster of certain class, or a certain type of monster, or any monster at the coordinates. level.mon_at(monster:'h', (5,5)) matches any monster of class h, level.mon_at(monster:('h', "hobbit"), (5,5)) matches only a hobbit, level.mon_at(monster:random, (5,5)) matches any monster.

hero.name

string

hero.role

string, eg. "Priest"

hero.race

string, eg. "human"

hero.carrying(obj)

integer, 0 or 1

Return 1 if player has object in main inventory.

string(int)

string

Convert an integer to string. Alias: str()

int(str)

integer

Convert a string to integer. Alias: integer()

coord(int, int)

coordinates

Convert two integer values into a pair of map coordinates.

region(int, int, int, int)

region

Convert four integer values into a region

rnd(int)

integer

Returns a random integer number between 0 and (int-1). This is equal to the rn2-function in the sourcecode.

room.width

integer

Returns the width of the current (SUB)ROOM, minus the outer walls. If used outside a ROOM context, returns 0.

room.height

integer

Returns the height of the current (SUB)ROOM, minus the outer walls. If used outside a ROOM context, returns 0.

room.x

integer

Returns the x coordinate of the top-left corner of the current (SUB)ROOM. If used outside a ROOM context, returns 0.

room.y

integer

Returns the y coordinate of the top-left corner of the current (SUB)ROOM. If used outside a ROOM context, returns 0.

For example:

IF [ level.obj_at(obj:"pick-axe", coord(2 + 3, 5)) ] {
 MESSAGE: "Today is " . string(time.yyyymmdd)
}

Map characters

character

dungeon feature

' '

solid wall

'#'

corridor

'.'

room floor (Unlit, unless lit with REGION-command)

'-'

horizontal wall

'|'

vertical wall

'+'

door (State is defined with DOOR -command)

'A'

air

'B'

crosswall / boundary symbol hack (See REGION)

'C'

cloud

'S'

secret door

'H'

secret corridor

'{'

fountain

'\'

throne

'K'

sink

'}'

moat

'P'

pool of water

'L'

lava pool

'I'

ice

'W'

water

'T'

tree

't'

dead tree

'F'

iron bars

'M'

muddy swamp

'Y'

crystal ice wall

'U'

ice wall

'x'

"transparent" map character

Trap names
"anti magic", "arrow", "bear", "board", "dart", "falling rock", "fire", "hole", "land mine", "level teleport", "magic portal", "magic", "pit", "polymorph", "rolling boulder", "rust", "sleep gas", "spiked pit", "statue", "teleport", "trap door", "web", "cold"

Room types
"ordinary", "throne", "swamp", "vault", "beehive", "morgue", "barracks", "zoo", "delphi", "temple", "lemurepit", "anthole", "cocknest", "garden", "leprehall", "shop", "armor shop", "scroll shop", "potion shop", "weapon shop", "food shop", "ring shop", "wand shop", "tool shop", "book shop", "tin shop", "music shop", "candle shop", "pet shop", "black market"