summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/docs/level-design.txt193
-rw-r--r--crawl-ref/source/dat/vaults.des41
-rw-r--r--crawl-ref/source/dungeon.cc48
-rw-r--r--crawl-ref/source/mapdef.cc4
-rw-r--r--crawl-ref/source/mapdef.h6
5 files changed, 200 insertions, 92 deletions
diff --git a/crawl-ref/docs/level-design.txt b/crawl-ref/docs/level-design.txt
index 5bb33ad73e..c3723ab71e 100644
--- a/crawl-ref/docs/level-design.txt
+++ b/crawl-ref/docs/level-design.txt
@@ -19,16 +19,18 @@ are in use:
splev.des: * branch endings (like Elf:7, Vaults:8)
* premade level maps (like the Ecumenical Temples and Geryon)
* Pan lairs of named demons
- * branch entries (these can ornament the stairs for a branch)
vaults.des: * random vaults (Crawl sometimes chooses a special level
when making up a new level; these are often challenging
and sometimes contain loot)
- * entry vaults (each game - except turorials - uses one of
- these premade maps for the vicinity of the entrance)
* minivaults
* Pan minivaults
+ entry.des * entry vaults (each game - but not tutorial games - uses one of
+ these premade maps for the vicinity of the entrance)
+
+ ebranch.des * branch entries (these can ornament the stairs for a branch)
+
tricky.des: * a few entry vaults which are harder in some regard
(use of special items, or being puzzles)
@@ -79,6 +81,10 @@ 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 solely by the absence
+of an ORIENT: declaration. Any map without a specified ORIENT: is a
+minivault.
+
B. Sample Map
---------------
@@ -103,7 +109,7 @@ FLAGS: no_rotate
SHUFFLE: de
SUBST: 1=12.
MONS: butterfly, plant
-ITEM: stone, w:10 any_good book / w:90 nothing
+ITEM: stone, w:10 any book / w:90 nothing
# actual map below:
MAP
xx1@2xx
@@ -119,11 +125,11 @@ ENDMAP
"CHANCE: 5" makes it appear less often (default is 10).
"TAGS: temple_entry" turns the 'O' on the map into stairs to the Temple.
"FLAGS: no_rotate" forbids rotation (but mirroring is still allowed).
-"SHUFFLE: dw" may replace all 'd' with 'w' in the map.
+"SHUFFLE: de" may replace all 'd' with 'e' in the map.
"SUBST: 1=12." may replace each '1' with either '1' or '2' or '.'.
"MONS: butterfly, plant" turns all '1' into butterflies, and '2' into plants.
"ITEM: stone" turns all 'd' into stones
-"ITEM: w:10 any book / w:100 nothing" turns all 'e' into a book
+"ITEM: w:10 any book / w:90 nothing" turns all 'e' into a book
(with 10% chance) or creates no object (with 90% chance).
The symbols on the map:
@@ -156,25 +162,25 @@ Terrain
= - secret door (DNGN_SECRET_DOOR)
W - shallow water
- w - deep water - can be turned into shallow water; prevent this with the
- no_pool_fixup TAG. Also, this may receive water creatures! For entry
+ 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.
l - lava - again, use the no_monster_gen TAG for entry vaults!
Features
--------
- @ - entry point - must be on outside and, except in ORIENT:float layouts,
- must always be on a particular side or sides - see templates. 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.
- }{ - stairs 82/86 - You must be able to reach these from each other. The
+ @ - 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.
- )( - stairs 83/87
- ][ - stairs 84/88
+ )( - Stone stairs, set 2.
+ ][ - Stone stairs, set 3.
- >< - extra rock stairs - you can leave level by these but will rarely be
+ >< - extra rock stairs - you can leave the level by these but will rarely be
placed on them from another level
I - orcish idol (does nothing)
@@ -196,15 +202,15 @@ Features
U - Magic fountain
V - Permanently dry fountain
-# Note: Due to the level maker having seen incremental improvements over the
-# years, there are some inconsistencies. For examples, dangerous statues
-# (orange, silver ice) are now genuine monsters. In particular, the 'G' and 'S'
-# glyphs could be dispensed with (but many older vaults use them, of course) -
-# especially as there's no glyph for ice statues.
-#
-# Also, the most of the other feature glyphs can be replaced with KFEAT:
-# lines. The same goes for some item glyphs ('O', 'P', 'R', 'Z') which could
-# be replaced by KITEM: lines.
+Note: Due to the level maker having seen incremental improvements over
+the years, there are some inconsistencies. For examples, dangerous
+statues (orange, silver ice) are now genuine monsters. In particular,
+the 'H' and 'S' glyphs could be dispensed with (but many older vaults
+use them, of course) - especially as there's no glyph for ice statues.
+
+Also, 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 by KITEM: lines.
Items
-----
@@ -237,7 +243,7 @@ NAME: a_string
ORIENT: (float |encompass | north | northwest | ... | southeast)
Some kind of ORIENT: line is mandatory, unless you want the vault to
- be a minivault, which is usually not what you want. Valid values are:
+ be a minivault. Valid values are:
* "float": The dungeon builder puts your vault wherever it wants to.
* "some_direction": The vault lies along that side of the map:
xxxxxxxxxx xxxxxxxxxxxxx
@@ -255,10 +261,51 @@ ORIENT: (float |encompass | north | northwest | ... | southeast)
* "encompass": the vault completely occupies the entire level.
Padding is needed on all 4 sides.
+ ORIENT: float vaults need no padding and 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 and minivaults, this gives the range where the vault
- may be placed in the main dungeon. E.g.
- DEPTH: 7-20
+ may be placed in the dungeon. Branch entry vaults can also be
+ constrained by depth. E.g.
+
+ DEPTH: 7-20
+ 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:7-9
+
+ (Anywhere between levels 7-9 of the Lair, inclusive.)
+
+ You can apply multiple constraints (with multiple DEPTH: lines, if
+ necessary, or on one 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: (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
@@ -281,6 +328,10 @@ PLACE: Used to specify certain special levels. Existing special levels are:
TAGS: generate_awake, no_item_gen, no_monster_gen, no_pool_fixup, orc_entry
Tags go an a TAGS: line and are space-separated. Valid tags are:
+ * "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.
* "generate_awake": Monsters placed (using MONS, KMONS) in this
@@ -292,14 +343,14 @@ TAGS: generate_awake, no_item_gen, no_monster_gen, no_pool_fixup, orc_entry
a player-hostile geography, MUST-HAVE for those with water/lava.
* "no_pool_fixup": prevents water squares next to land from being
randomly converted from deep water (the default) to shallow.
- * "branch_entry" eg. "orc_entry", "lair_entry" etc. Currently used:
- temple_entry, orc_entry, vault_entry, lair_entry, hive_entry.
+ * "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. Branch entries should go to splev.des.
- As long as a branch has very few entries, a dummy one is a must.
+ Use "O" to place the stairs. Branch entries should go to
+ ebranch.des. 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.
* "mnoleg" or the name of some other pandemonium lord. This makes
- the map eligible for said pan lord's lair (and it can't appear
- anywhere else).
+ the map eligible for said pan lord's lair.
FLAGS: no_rotate, no_hmirror, no_vmirror
Flags go on a FLAGS: line and are space-separated. Valid flags are:
@@ -425,30 +476,44 @@ KFEAT: Z = C / needle trap / antique armour shop / altar of Zin
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:). Fr example,
- KFEAT: Z = W
- KMONS: Z = rat
+ 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
+
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.
- For items like gold or fountains, you have to use the description
- of items instead of their shortcuts. For example,
- KITEM: none / gold
+ For items like gold, you have to use the description of items
+ instead of their shortcuts. For example,
+ KITEM: ? = nothing / gold
works but the following does not:
- KITEM: none / $
+ KITEM: ? = nothing / $
+
+ KITEM: allows you to place multiple items on the same square:
+ KITEM: ? = bread ration, potion of water, potion of porridge
E. Hints for level makers
----------------------------
* Technical stuff:
+
If your map is not a minivault or a floating vault, make sure the
side(s) forming the border have a rock wall padding at least 6 deep. For
instance, if your map is ORIENT: north, you must have a 6 deep border of
@@ -464,16 +529,38 @@ E. Hints for level makers
rooms with no exit (use at least > or < to make it possible for players
to get away).
- The entry point '@' must be present (except full-screen vaults where it
- must not). For ORIENT: float maps, all @ will be connected to floors in
- the rest of the map. Make sure that no part of your entry level can be
- cut off! If no @ is present, the level builder will put one on a random
- floor space '.' at the circumference. (Sometimes this may be used for
- good effect. When you give no @'s with this feature in mind, please make
- a comment stating this - else somebody may just add @'s later on :)
+ Minivaults should generally be completely surrounded by one-space of
+ floor for accessibility. Minivaults are not handled like regular
+ vaults in terms of entry-points: the entry-point glyph @ is ignored
+ for minivaults. In general, at least one square of a minivault will
+ be reachable from the rest of the level, but there is no way to
+ predict which one. If your minivault is intended to be accessible,
+ surround it with floor.
+
+ The entry point '@' must be present for all vaults (except
+ full-screen vaults and minivaults where it must not, and floating
+ vaults 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 put
+ one or more on a random floor space '.' at the circumference. Note
+ that it is not possible to predict which floor 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. :)
- Note that non-rectangular maps will be padded with rock walls for the
- smallest rectangle containing them. Unfortunately.
+ Non-rectangular maps will be padded (to the right) with rock walls
+ (or with floor spaces for minivaults) for the smallest rectangle
+ containing them. Unfortunately.
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.
@@ -522,7 +609,9 @@ E. Hints for level makers
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 CHANCE: again, if the map has alternatives (like Snake:5, or
- Coc:7).
+ 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.
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.
diff --git a/crawl-ref/source/dat/vaults.des b/crawl-ref/source/dat/vaults.des
index c53d0bb780..56699ad926 100644
--- a/crawl-ref/source/dat/vaults.des
+++ b/crawl-ref/source/dat/vaults.des
@@ -1282,7 +1282,7 @@ ENDMAP
# attribute makes the map a normal vault, and mayhem can result.
# Default depth for minivaults.
-default-depth: 8-27, !Orc, !Lair
+default-depth: 8-27, !Orc, !Lair, !Swamp, !Shoal
##############################################################################
# Minivault balancer
@@ -1299,7 +1299,7 @@ ENDMAP
# Greed's colour
NAME: david_greed
-DEPTH: 10-26, !Orc, !Lair
+DEPTH: 10-26, !Orc, !Lair, !Swamp, !Shoal
ITEM: nothing / any good_item
MONS: silver statue / orange crystal statue / ice statue
SHUFFLE: d|
@@ -1324,7 +1324,7 @@ ENDMAP
# Defended altar
NAME: david_defended_altar
-DEPTH: 7-20
+DEPTH: 7-20, !Lair, !Swamp, !Shoal
ITEM: nothing
SHUFFLE: 1I/2T
MONS: orc priest, deep elf priest / w:30 nothing
@@ -1487,7 +1487,7 @@ ENDMAP
###################################
# Evil zoo
NAME: minivault_9
-DEPTH: 15-27
+DEPTH: 15-27, !Orc, !Lair, !Swamp, !Shoal
MAP
............
.==========.
@@ -1948,7 +1948,7 @@ ENDMAP
# Dispersion (David)
#
NAME: dispersion
-DEPTH: 13-26
+DEPTH: 13-26, !Orc, !Lair, !Swamp, !Shoal
SUBST: Y = 89
KITEM: 8 = % / * / w:1 |
KITEM: 9 = % / * / w:1 |
@@ -1977,15 +1977,17 @@ NAME: fake_naga_vault
# Intentionally moved this deeper because explore will gladly run into the
# room, and being hit by multiple mimics is un-fun.
-DEPTH: 15-26
+DEPTH: 15-26, !Orc, !Lair, !Swamp, !Shoal
MONS: mimic, guardian naga
MAP
-xxxxxxxxx
-x1111111x
-x1111111x
-x1111111x
-x11.2.11x
-xxxx+xxxx
+...........
+.xxxxxxxxx.
+.x1111111x.
+.x1111111x.
+.x1111111x.
+.x11.2.11x.
+.xxxx+xxxx.
+...........
ENDMAP
##############################################################################
@@ -1997,10 +1999,12 @@ TAGS: no_monster_gen
ITEM: potion of water w:20 / bread ration / meat ration / arrow / bolt / spear / any potion w:5
SUBST: ? = +=
MAP
-x?xx
-xddx
-xddx
-xxxx
+......
+.x?xx.
+.xddx.
+.xddx.
+.xxxx.
+......
ENDMAP
##############################################################################
@@ -2223,7 +2227,6 @@ x
ENDMAP
###################################
-# minvault intended for Orc Mines
# pond with fungi
NAME: mines1_lemuel
MONS: fungus, wandering mushroom
@@ -2246,7 +2249,6 @@ MAP
ENDMAP
###################################
-# minvault intended for Orc Mines
# hidden treasure chamber
NAME: mines2_lemuel
SUBST: ? = x.
@@ -2261,7 +2263,6 @@ MAP
ENDMAP
###################################
-# minvault intended for Orc Mines
# treasure chamber with oklob pant
NAME: mines3_lemuel
SUBST: ? = +=.
@@ -2285,7 +2286,6 @@ MAP
ENDMAP
###################################
-# minvault intended for Orc Mines
# mage tower -- either orc with assistants, or ogre with guards
NAME: mines4_lemuel
SUBST: ? = +=
@@ -2309,7 +2309,6 @@ MAP
ENDMAP
###################################
-# minvault intended for Orc Mines
# warg stables, with goblin stableboy
NAME: mines5_lemuel
SUBST: ?: wx
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index c2b3c8aebd..b590650b36 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -3183,7 +3183,8 @@ static void dngn_place_item_explicit(int index, int x, int y,
dngn_place_item_explicit(spec, x, y, level);
}
-static void dngn_place_monster(
+static bool dngn_place_monster(
+ const vault_placement &place,
const mons_spec &monster_type_thing,
int monster_level,
int vx, int vy)
@@ -3191,6 +3192,10 @@ static void dngn_place_monster(
if (monster_type_thing.mid != -1)
{
const int mid = monster_type_thing.mid;
+ const bool generate_awake =
+ monster_type_thing.generate_awake
+ || place.map.has_tag("generate_awake");
+
int not_used;
const int mlev = monster_type_thing.mlevel;
@@ -3207,18 +3212,35 @@ static void dngn_place_monster(
if (mid != RANDOM_MONSTER && mid < NUM_MONSTERS)
{
if (mons_is_unique(mid) && you.unique_creatures[mid])
- return;
+ return (false);
const int habitat = monster_habitat(mid);
if (habitat != DNGN_FLOOR)
grd[vx][vy] = habitat;
}
-
- place_monster( not_used, mid, monster_level,
- monster_type_thing.generate_awake?
- BEH_WANDER : BEH_SLEEP,
- MHITNOT, true, vx, vy, false );
+
+ return (place_monster( not_used, mid, monster_level,
+ generate_awake? BEH_WANDER : BEH_SLEEP,
+ MHITNOT, true, vx, vy, false ));
}
+ return (false);
+}
+
+static bool dngn_place_one_monster(
+ const vault_placement &place,
+ mons_list &mons,
+ int monster_level,
+ int vx, int vy)
+{
+ for (int i = 0, size = mons.size(); i < size; ++i)
+ {
+ if (dngn_place_monster(place, mons.get_monster(i),
+ monster_level, vx, vy))
+ {
+ return (true);
+ }
+ }
+ return (false);
}
static monster_type random_evil_statue()
@@ -3277,10 +3299,8 @@ static int vault_grid( vault_placement &place,
else
grd[vx][vy] = DNGN_FLOOR;
- mons_spec mons = mapsp->get_mons();
- if (place.map.has_tag("generate_awake"))
- mons.generate_awake = true;
- dngn_place_monster(mons, level_number, vx, vy);
+ mons_list &mons = mapsp->get_monsters();
+ dngn_place_one_monster(place, mons, level_number, vx, vy);
item_list &items = mapsp->get_items();
dngn_place_multiple_items(items, vx, vy, level_number);
@@ -3487,11 +3507,7 @@ static int vault_grid( vault_placement &place,
if (vgrid != '8' && vgrid != '9' && vgrid != '0')
monster_type_thing = place.map.mons.get_monster(vgrid - '1');
- if (place.map.has_tag("generate_awake"))
- monster_type_thing.generate_awake = true;
-
- dngn_place_monster(monster_type_thing, monster_level,
- vx, vy);
+ dngn_place_monster(place, monster_type_thing, monster_level, vx, vy);
}
// again, this seems odd, given that this is just one of many
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index 2420d3ba9e..67a4257f47 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -1531,9 +1531,9 @@ feature_spec keyed_mapspec::get_feat()
return feat.get_feat(key_glyph);
}
-mons_spec keyed_mapspec::get_mons()
+mons_list &keyed_mapspec::get_monsters()
{
- return (mons.size()? mons.get_monster(0) : mons_spec(-1));
+ return (mons);
}
item_list &keyed_mapspec::get_items()
diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h
index 3d5866af96..1f6cc05fa4 100644
--- a/crawl-ref/source/mapdef.h
+++ b/crawl-ref/source/mapdef.h
@@ -56,6 +56,10 @@ public:
std::string str_depth_range() const;
operator raw_range () const;
+ operator std::string () const
+ {
+ return describe();
+ }
};
typedef std::pair<int,int> glyph_weighted_replacement_t;
@@ -331,7 +335,7 @@ public:
std::string set_item(const std::string &s, bool fix);
feature_spec get_feat();
- mons_spec get_mons();
+ mons_list &get_monsters();
item_list &get_items();
private: