LEV_COMP(6)
LEV_COMP(6) π
okay bestie, sit DOWN, we're reading the lev_comp page from the Games Manual together. it's long, it's giving arcane-grammar-energy, and we're gonna eat it up anyway π
β¨ NAME β¨
lev_comp β NetHack special levels compiler π§
πΈ SYNOPSIS πΈ
lev_comp [ -w ] [ files ]
If you give it no arguments at all, bestie, it just reads from standard input. no cap. π
π¦ DESCRIPTION π¦
lev_comp is a special level compiler for NetHack version 3.2 and higher. you hand it description files as arguments, and it hands you back level files that NetHack can load at runtime. iconic behaviour fr fr β¨
the whole point of this tool is to give NetHack administrators and implementors a convenient way to add special levels to the game, or modify existing ones, without having to recompile the entire world. the way that saves so much time?? obsessed π
-wβ makeslev_compdo extra checks on the level and show extra warnings. but heads up, those warnings are sometimes superfluous, which is exactly why they're not normally displayed. lowkey makes sense tbh.
π GRAMMAR π
okay so THIS is the main character section. it's a whole grammar spec and it's giving formal language theory and i respect it deeply. no notes. every line stays exactly as written, because grammar does not care about our vibes π
here's the top of the tree, the vibes from which all other vibes flow:
file : /* nothing */
| levels
;
levels : level
| level levels
;
level : maze_level
| room_level
;
two flavours of level, bestie: maze or room. choose your fighter π
maze_level : maze_def flags lev_init messages regions
;
room_level : level_def flags lev_init messages rreg_init rooms corridors_def
;
level_def : LEVEL_ID ':' string
;
lev_init : /* nothing */
| LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled
;
walled : BOOLEAN
| RANDOM_TYPE
;
flags : /* nothing */
| FLAGS_ID ':' flag_list
;
flag_list : FLAG_TYPE ',' flag_list
| FLAG_TYPE
;
messages : /* nothing */
| message messages
;
message : MESSAGE_ID ':' STRING
;
rreg_init : /* nothing */
| rreg_init init_rreg
;
init_rreg : RANDOM_OBJECTS_ID ':' object_list
| RANDOM_MONSTERS_ID ':' monster_list
;
see how /* nothing */ and /* empty */ keep showing up? that's the grammar saying "this part is optional bestie, skip it if you want". the range?? unmatched π
π rooms & corridors π
rooms : /* Nothing - dummy room for use with INIT_MAP */
| roomlist
;
roomlist : aroom
| aroom roomlist
;
corridors_def : random_corridors
| corridors
;
random_corridors: RAND_CORRIDOR_ID
;
corridors : /* nothing */
| corridors corridor
;
corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec
| CORRIDOR_ID ':' corr_spec ',' INTEGER
;
corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')'
;
note that one comment up there: /* Nothing - dummy room for use with INIT_MAP */ β that's a real note from the original and we're keeping it verbatim, spacing and all π«Ά
π the anatomy of a room π
aroom : room_def room_details
| subroom_def room_details
;
subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill
;
room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill
;
roomfill : /* nothing */
| ',' BOOLEAN
;
room_pos : '(' INTEGER ',' INTEGER ')'
| RANDOM_TYPE
;
subroom_pos : '(' INTEGER ',' INTEGER ')'
| RANDOM_TYPE
;
room_align : '(' h_justif ',' v_justif ')'
| RANDOM_TYPE
;
room_size : '(' INTEGER ',' INTEGER ')'
| RANDOM_TYPE
;
room_details : /* nothing */
| room_details room_detail
;
room_detail : room_name
| room_chance
| room_door
| monster_detail
| object_detail
| trap_detail
| altar_detail
| fountain_detail
| sink_detail
| pool_detail
| gold_detail
| engraving_detail
| stair_detail
;
room_name : NAME_ID ':' string
;
room_chance : CHANCE_ID ':' INTEGER
;
room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
;
secret : BOOLEAN
| RANDOM_TYPE
;
door_wall : DIRECTION
| RANDOM_TYPE
;
door_pos : INTEGER
| RANDOM_TYPE
;
maze_def : MAZE_ID ':' string ',' filling
;
filling : CHAR
| RANDOM_TYPE
;
that room_detail list is literally a menu of everything you can stuff in a room and honestly? it ate. every single entry stays. don't skip a one, bestie π
π regions, maps & init π
regions : aregion
| aregion regions
;
aregion : map_definition reg_init map_details
;
map_definition : NOMAP_ID
| map_geometry MAP_ID
;
map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif
;
h_justif : LEFT_OR_RIGHT
| CENTER
;
v_justif : TOP_OR_BOT
| CENTER
;
reg_init : /* nothing */
| reg_init init_reg
;
init_reg : RANDOM_OBJECTS_ID ':' object_list
| RANDOM_PLACES_ID ':' place_list
| RANDOM_MONSTERS_ID ':' monster_list
;
object_list : object
| object ',' object_list
;
monster_list : monster
| monster ',' monster_list
;
place_list : place
| place ',' place_list
;
map_details : /* nothing */
| map_details map_detail
;
map_detail : monster_detail
| object_detail
| door_detail
| trap_detail
| drawbridge_detail
| region_detail
| stair_region
| portal_region
| teleprt_region
| branch_region
| altar_detail
| fountain_detail
| mazewalk_detail
| wallify_detail
| ladder_detail
| stair_detail
| gold_detail
| engraving_detail
| diggable_detail
| passwall_detail
;
look at all those map_detail options!! twenty of them, and we're listing all twenty, because that's the whole assignment here π§
π monsters & objects in detail π
monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate
monster_infos
;
monster_infos : /* nothing */
| monster_infos monster_info
;
monster_info : ',' string
| ',' MON_ATTITUDE
| ',' MON_ALERTNESS
| ',' alignment
| ',' MON_APPEARANCE string
;
object_detail : OBJECT_ID object_desc
| COBJECT_ID object_desc
;
object_desc : chance ':' object_c ',' o_name ',' object_where object_infos
;
object_where : coordinate
| CONTAINED
;
object_infos : /* nothing */
| ',' curse_state ',' monster_id ',' enchantment optional_name
| ',' curse_state ',' enchantment optional_name
| ',' monster_id ',' enchantment optional_name
;
curse_state : RANDOM_TYPE
| CURSE_TYPE
;
monster_id : STRING
;
enchantment : RANDOM_TYPE
| INTEGER
;
optional_name : /* nothing */
| ',' NONE
| ',' STRING
;
careful withmonster_detail: that first production wraps onto a second line, and the continuation line is indented with seventeen spaces to line up underMONSTER_ID. keep it exactly like that. the grammar is picky and so are we π
β doors, traps, bridges & movement β
door_detail : DOOR_ID ':' door_state ',' coordinate
;
trap_detail : TRAP_ID chance ':' trap_name ',' coordinate
;
drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state
;
mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION
;
wallify_detail : WALLIFY_ID
;
ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN
;
stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN
;
stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN
;
portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' string
;
teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail
;
branch_region : BRANCH_ID ':' lev_region ',' lev_region
;
teleprt_detail : /* empty */
| ',' UP_OR_DOWN
;
lev_region : region
| LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
;
fountain_detail : FOUNTAIN_ID ':' coordinate
;
sink_detail : SINK_ID ':' coordinate
;
pool_detail : POOL_ID ':' coordinate
;
diggable_detail : NON_DIGGABLE_ID ':' region
;
passwall_detail : NON_PASSWALL_ID ':' region
;
region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled
;
altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type
;
gold_detail : GOLD_ID ':' amount ',' coordinate
;
engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string
;
monster_c : monster
| RANDOM_TYPE
| m_register
;
object_c : object
| RANDOM_TYPE
| o_register
;
m_name : string
| RANDOM_TYPE
;
o_name : string
| RANDOM_TYPE
;
trap_name : string
| RANDOM_TYPE
;
room_type : string
| RANDOM_TYPE
;
prefilled : /* empty */
| ',' FILLING
| ',' FILLING ',' BOOLEAN
;
okay notice fountain_detail, sink_detail, pool_detail, diggable_detail and passwall_detail all have their colon sitting flush against the nonterminal name β like sink_detail : SINK_ID β while everything else has the padding. that's not a typo on my part, that's literally how it's written, and we are not "fixing" it π«Ά
and that's the whole grammar, all the way down to prefilled. slay.
coordinate : coord
| p_register
| RANDOM_TYPE
;
door_state : DOOR_STATE
| RANDOM_TYPE
;
light_state : LIGHT_STATE
| RANDOM_TYPE
;
alignment : ALIGNMENT
| a_register
| RANDOM_TYPE
;
altar_type : ALTAR_TYPE
| RANDOM_TYPE
;
p_register : P_REGISTER '[' INTEGER ']'
;
o_register : O_REGISTER '[' INTEGER ']'
;
m_register : M_REGISTER '[' INTEGER ']'
;
a_register : A_REGISTER '[' INTEGER ']'
;
place : coord
;
monster : CHAR
;
object : CHAR
;
string : STRING
;
amount : INTEGER
| RANDOM_TYPE
;
chance : /* empty */
| PERCENT
;
engraving_type : ENGRAVING_TYPE
| RANDOM_TYPE
;
coord : '(' INTEGER ',' INTEGER ')'
;
region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
;
NOTE: Lines beginning with # are considered comments. π¬
okay so the contents of a "MAP" description of a maze is literally a rectangle that shows the exact level map that should be used for the given part of a maze. every character in the map corresponds to a location on the screen. different location types are denoted using different ASCII characters. here's the full menu of what's recognized. to see how these are used, peep the EXAMPLE below. also the maximum size of a map is normally 76 columns by 21 rows. periodt. π
'-'β horizontal wall'|'β vertical wall'+'β a doorway (state is specified in aDOORdeclaration)'A'β open air'B'β boundary room location (for bounding unwalled irregular regions)'C'β cloudy air'I'β ice'S'β a secret door'H'β a secret corridor'{'β a fountain'\'β a throne'K'β a sink'}'β a part of a moat or other deep water'P'β a pool'L'β lava'W'β water (yes, different from a pool)'T'β a tree'F'β iron bars'#'β a corridor'.'β a normal room location (unlit unless lit in aREGIONdeclaration)' 'β stone
β¨ EXAMPLE β¨
here's a whole description file, a very simple one, and it's giving main character energy π
MAZE : "fortress", random
GEOMETRY : center , center
MAP
}}}}}}}}}
}}}|-|}}}
}}|-.-|}}
}|-...-|}
}|.....|}
}|-...-|}
}}|-.-|}}
}}}|-|}}}
}}}}}}}}}
ENDMAP
MONSTER: '@', "Wizard of Yendor", (4,4)
OBJECT: '"', "Amulet of Yendor", (4,4)
# a hell hound flanking the Wiz on a random side
RANDOM_PLACES: (4,3), (4,5), (3,4), (5,4)
MONSTER: 'd', "hell hound", place[0]
# a chest on another random side
OBJECT: '(', "chest", place[1]
# a sack on a random side, with a diamond and maybe a ruby in it
CONTAINER: '(', "sack", place[2]
OBJECT: '*', "diamond", contained
OBJECT[50%]: '*', "ruby", contained
# a random dragon somewhere
MONSTER: 'D', random, random
# 3 out of 4 chance for a random trap in the EAST end
TRAP[75%]: random, (6,4)
# an electric eel below the SOUTH end
MONSTER: ';', "electric eel", (4,8)
# make the walls non-diggable
NON_DIGGABLE: (0,0,8,8)
TELEPORT_REGION: levregion(0,0,79,20), (0,0,8,8)
this example will produce a file named "fortress" that can be integrated into one of the numerous mazes of the game. iconic. π°
note especially the final, TELEPORT_REGION specification. this says that level teleports or other non-stairway arrivals on this level can land anywhere on the level except the area of the map. this shows the use of the levregion prefix allowed in certain region specifications. normally, regions apply only to the most recent MAP specification, but when prefixed with levregion, one can refer to any area of the level, regardless of the placement of the current MAP in the level. big brain energy, no cap. π§ β¨
π AUTHOR π
Jean-Christophe Collet, David Cohrs.
π SEE ALSO π
π BUGS π
Probably infinite. Most importantly, still needs additional bounds checking. π like, it's giving "probably infinite" and still needs additional bounds checking. stay safe out there, bestie. π
π COPYRIGHT π
This file is Copyright (C) Kenneth Lorber and was last modified 2018/04/25 (version NetHack-3.6.0:1.7). NetHack may be freely redistributed. See license for details.
so basically, this file is Copyright (C) Kenneth Lorber and was last modified 2018/04/25 (version NetHack-3.6.0:1.7). NetHack may be freely redistributed. see license for details, bestie. π
catch u later! this was LEV_COMP(6) from the NETHACK squad, dated 25 May 2015 πβ¨π¦
π¦ where this page comes from
- alpine 3.24: nethack-doc 3.6.7-r2 Β· NGPL
- debian bookworm: nethack-common 3.6.6-3+b2 Β· NGPL
- debian trixie: nethack-common 3.6.7-1+b2 Β· NGPL
- epel 10: nethack 3.6.7-5.el10_0 Β· NGPL
- epel 9: nethack 3.6.7-1.el9 Β· NGPL
- fedora 43: nethack 3.6.7-8.fc43 Β· NGPL
- fedora 44: nethack 3.6.7-9.fc44 Β· NGPL
- ubuntu jammy: nethack-common 3.6.6-2build1 Β· NGPL
- ubuntu noble: nethack-common 3.6.7-1build3 Β· NGPL
- ubuntu questing: nethack-common 3.6.7-2
- ubuntu resolute: nethack-common 3.6.7-2build1 Β· NGPL
- ubuntu stonking: nethack-common 3.6.7-4 Β· NGPL
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms