git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@956 c06c8d41-db1a-0410-9941-cceddc491573
JQFQX7IWSJ4TYWVUVXAFMCPSAN67PRMNECDQI5WMON2JFMQVVUEQC
4NEULAWXO2BTDHJLIVHBJQDYK5626KU3W35VUJXYESIIF3USLVWQC
2NCKGJDDPPGP2NXYYPEPVRJIIWEP6M7HE6WYMQN3UNNN3C2JIRFQC
RIRJ746W5ESARX4HUEA4JRVAKXXF3WYVXUCFFONPJMMKWHQAGI2AC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
WKTZHLOJ65WSK6FR5MF7RWGSMZ22T2D6LHB66FV3IPGXIBLYHHNAC
34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC
A3CO4KBFTFU3ZSHWRY2OPPX3MMTFV7OUCZGL7Q4Y2FU7JO4AP7MAC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
SVUM62ARSXH6RUBFRWS6KAQC7PTNTMGSV2GPZJQQJ4GNEML2HBVQC
UPU5QYUWCXSX233JNGE37QEN5TG5HDRGLNSCEKHH3GPU4AEXW3KAC
5E7K2S4F4QDZC5UH3JVMYQ5SFJIKIATZII4EJL7IOT66ZBJ5GUPQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
C52GDIYN6W4WNYL2QV7L7OKFBVLPFSBQAEBCX44PAXCZ5H7JXCJQC
UFLQ2LXPSQHE3XF57FPHQZIQPJUCFHB3Y5DMNZMRHOCV4LYKJGGQC
I5N4EIR6SCLLRGKRBUKW5FKUVYK62EA5DOWIAS5XFIHZQKMCXWBAC
6CHNAAPWNROCQNX6EWPLXZOWX5HHKL5ZOHO24XRMNQTQF3CWB3VQC
class subst_spec
{
public:
subst_spec(int torepl, bool fix, const glyph_replacements_t &repls);
int key() const
{
return (foo);
}
int value();
private:
int foo; // The thing to replace.
bool fix; // If true, the first replacement fixes the value.
int frozen_value;
glyph_replacements_t repl;
};
}
std::string map_lines::clean_shuffle(std::string s)
{
return replace_all_of(s, " \t", "");
}
std::string map_lines::check_block_shuffle(const std::string &s)
{
const std::vector<std::string> segs = split_string("/", s);
const unsigned seglen = segs[0].length();
for (int i = 1, size = segs.size(); i < size; ++i)
{
if (seglen != segs[i].length())
return ("block shuffle segment length mismatch");
}
return ("");
}
std::string map_lines::check_shuffle(std::string &s)
{
if (s.find(',') != std::string::npos)
return ("use / for block shuffle, or multiple SHUFFLE: lines");
s = clean_shuffle(s);
if (s.find('/') != std::string::npos)
return check_block_shuffle(s);
return ("");
}
std::string map_lines::parse_glyph_replacements(std::string s,
glyph_replacements_t &gly)
{
s = replace_all_of(s, "\t", " ");
std::vector<std::string> segs = split_string(" ", s);
for (int i = 0, size = segs.size(); i < size; ++i)
{
const std::string &is = segs[i];
if (is.length() > 2 && is[1] == ':')
{
const int glych = is[0];
int weight = atoi( is.substr(2).c_str() );
if (weight < 1)
weight = 10;
gly.push_back( glyph_weighted_replacement_t(glych, weight) );
}
else
{
for (int c = 0, cs = is.length(); c < cs; ++c)
gly.push_back( glyph_weighted_replacement_t(is[c], 10) );
}
}
return ("");
}
std::string map_lines::add_subst(const std::string &sub)
{
std::string s = trimmed_string(sub);
if (s.empty())
return ("");
std::string::size_type
norm = s.find("="),
fixe = s.find(":");
const std::string::size_type sep = norm < fixe? norm : fixe;
if (sep == std::string::npos)
return ("malformed SUBST declaration - must use = or :");
const bool fixed = (sep == fixe);
std::string what_to_subst = trimmed_string(sub.substr(0, sep));
std::string substitute = trimmed_string(sub.substr(sep + 1));
if (what_to_subst.length() != 1)
return make_stringf("selector '%s' must be exactly one character",
what_to_subst.c_str());
glyph_replacements_t repl;
std::string err = parse_glyph_replacements(substitute, repl);
if (!err.empty())
return (err);
substitutions.push_back(
subst_spec( what_to_subst[0], fixed, repl ) );
return ("");
}
std::string map_lines::add_shuffle(const std::string &raws)
{
std::string s = raws;
const std::string err = check_shuffle(s);
if (err.empty())
shuffles.push_back(s);
return (err);
if (fillins.empty() || fillins.find('?') != std::string::npos)
return;
for (int i = 0, size = lines.size(); i < size; ++i)
resolve(lines[i], fillins);
for (int i = 0, size = substitutions.size(); i < size; ++i)
{
for (int y = 0, ysize = lines.size(); y < ysize; ++y)
subst(lines[y], substitutions[i]);
}
}
std::string map_def::clean_shuffle(std::string s)
{
return replace_all_of(s, " \t", "");
}
std::string map_def::check_block_shuffle(const std::string &s)
{
const std::vector<std::string> segs = split_string("/", s);
const unsigned seglen = segs[0].length();
for (int i = 1, size = segs.size(); i < size; ++i)
{
if (seglen != segs[i].length())
return ("block shuffle segment length mismatch");
}
return ("");
std::string map_def::check_shuffle(std::string &s)
{
if (s.find(',') != std::string::npos)
return ("use / for block shuffle, or multiple SHUFFLE: lines");
s = clean_shuffle(s);
if (s.find('/') != std::string::npos)
return check_block_shuffle(s);
return ("");
}
std::string map_def::add_shuffle(const std::string &raws)
{
std::string s = raws;
const std::string err = check_shuffle(s);
if (err.empty())
shuffles.push_back(s);
return (err);
}
/////////////////////////////////////////////////////////////////////////
// subst_spec
subst_spec::subst_spec(int torepl, bool dofix, const glyph_replacements_t &g)
: foo(torepl), fix(dofix), frozen_value(0), repl(g)
{
}
int subst_spec::value()
{
if (frozen_value)
return (frozen_value);
int cumulative = 0;
int chosen = 0;
for (int i = 0, size = repl.size(); i < size; ++i)
{
if (random2(cumulative += repl[i].second) < repl[i].second)
chosen = repl[i].first;
}
if (fix)
frozen_value = chosen;
return (chosen);
}
# Several SHUFFLE lines are possible.
# Several SHUFFLE: lines can be used, and the shuffles will be applied in
# order.
#
# SUBST:
# The SUBST: directive allows you to specify a placeholder symbol that is
# replaced with a random glyph from a set. For instance:
# SUBST: ? = TUV
# will replace occurrences of ? with one of TUV.
# SUBST: ? = T U V
# does the same thing - whitespace is not significant.
# 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 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 symbol can be any non-space, printable character apart from
# : and =. The replacement symbols can be any non-space printable character,
# including : and = ("SUBST: ? = +=:123def" is valid).
# 1-7 - monster array monster. See section below on MONS: arrays for more inf
# 1-7 - monster array monster. See section below on MONS: arrays for more
# information
#
# A vault always has its body between MAP and ENDMAP commands. Furthermore,
# several other additional commands are possible (some of them mandatory).
# ORIENT: LINES:
# Some kind of orient: line is mandatory, unless you want the vault to be a
# minivault, which is usually not what you want. Valid orient: lines are:
# float: The dungeon builder will put your vault wherever it wants to.
# some_direction: The vault will lie along the mentioned side of the map:
# NAME
# Each vault/level/map must have a unique name. Underscores and digits are ok.
#
# ORIENT: (north | northwest | ... | float | encompass)
# 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:
# "float": The dungeon builder will put your vault wherever it wants to.
# "some_direction": The vault will lie along the mentioned side of the map:
# 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. Positions can contain multiple possibilities, one of which
# the builder will choose randomly. Separate such multiple possibilities usin
# a slash. Note that "nothing" (without the quotes) is a valid possibility.
# 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.
# 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.
# Modifiers: "good_item" makes the builder try to make the item a good one.
# "any" by itself lets it plop down any object -- and you can combine "any"
# with "good_item." "any" plus an item class gives a random item of that clas
# (e.g. "any book").
# Modifiers:
# "good_item" makes the builder try to make the item a good one.
# "any" by itself gives random choice; you can combine "any" with "good_item."
# "any book", "any misc" etc. gives a random item of that class.
# entry: this tag MUST be there for a vault to be pickable as an entry vault.
# no_monster_gen: this tag prevents 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
# or lava.
# no_pool_fixup: prevents water squares next to land from being randomly conv
# from deep water (the default) to shallow.
# "entry": this tag MUST be there for a vault to be pickable as an entry vault.
# "no_monster_gen": this tag prevents 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
# or 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. If chosen, these maps
# will contain the stairs for that branch. Use "O" to place
# the stairs. Branch entries should go to splev.des.
# 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.
# "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.
# note that a lot of the vaults are in there mainly to add some
# SHUFFLE:
# This allows you to randomly permute glyphs on the map. There are two ways:
# SHUFFLE: 123w (i.e. list of glyphs, NOT comma-separated)
# could, for example, swap all occurences of "1" with "2",
# as well as swapping all "3" with "w" (or any other of the 23
# 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 the shuffles will be applied in
# order.
#
# SUBST:
# The SUBST: directive allows you to specify a placeholder symbol that is
# replaced with a random glyph from a set. For instance:
# SUBST: ? = TUV
# will replace occurrences of ? with one of TUV.
# SUBST: ? = T U V
# does the same thing - whitespace is not significant.
# 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 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 symbol can be any non-space, printable character apart from
# : and =. The replacement symbols can be any non-space printable character,
# including : and = ("SUBST: ? = +=:123def" is valid).
#
# SUBST: lines can safely replace symbols with themselves:
#
# SUBST: w = wW
#
# Multiple SUBST: lines can be used, and will be applied in order.
# Substitutions are performed after any declared shuffles.
#
# Note that a lot of the vaults are in there mainly to add some
# that form 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 rock wall (or
# any other kind of wall) along the northern, eastern, and western edges of the
# map. If you're doing a fullscreen map (encompass), you must pad all around
# the map with 6 layers of wall. For ORIENT: encompass maps, you don't need to
# explicitly include the padding provided you make the map small enough that
# the padding can be provided automatically.
# 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 rock wall
# (or any other kind of wall) along the northern, eastern, and western edges
# of the map. If you're doing a fullscreen map (encompass), you must pad all
# around the map with 6 layers of wall. For ORIENT: encompass maps, you
# don't need to explicitly include the padding provided you make the map
# small enough that the padding can be provided automatically.
# 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.
# 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.
# You can use the templates below to build vaults. The entry point
# '@' must be present (except full-screen vaults where it must not
# and orient:float maps, where it is optional - the builder will
# randomly convert '.' spaces on edges to entry points if needed) and
# be on an edge of the vault.
# You can use the templates below to build vaults. The entry point '@' must
# be present (except full-screen vaults where it must not and orient:float
# maps, where it is optional - the builder will randomly convert '.' spaces
# on edges to entry points if needed) and be on an edge of the vault.
# 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, whereas vaults
# can be forced to appear using a PLACE: attribute.
# 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, whereas
# vaults can be forced to appear using a PLACE: attribute.
" levdes.vim:
"
" Basic Vim syntax highlighting for Dungeon Crawl Stone Soup level design
" (.des) files.
"
" This syntax highlighting script is distributed under the terms of the
" Crawl Public License. See licence.txt for details.
" Vim syntax file
" Language: Dungeon Crawl level design (.des) files.
" Maintainer: Darshan Shaligram <scintilla@gmail.com>
" Last Change: 2007 Feb 20
" Remark: Basic Vim syntax highlighting for Dungeon Crawl Stone Soup
" level design (.des) files.
syn keyword desDeclarator NAME: ORIENT: DEPTH: PLACE: MONS: FLAGS: SYMBOL: default-depth: TAGS: CHANCE: ITEM: SHUFFLE:
syn keyword desOrientation encompass north south east west northeast northwest southeast southwest float
syn region desSubst start=/^SUBST:\s*/ end=/$/ contains=desSubstDec,desSubstArg,desSubstSep,@desMapElements keepend
syn region desShuffle start=/^SHUFFLE:\s*/ end=/$/ contains=desShuffleDec,desMapFrag keepend
syn keyword desSubstDec SUBST: contained
syn keyword desShuffleDec SHUFFLE: contained
syn keyword desDeclarator NAME: ORIENT: DEPTH: PLACE: MONS: FLAGS: default-depth: TAGS: CHANCE: ITEM:
syn keyword desOrientation encompass north south east west northeast northwest southeast southwest float no_hmirror no_vmirror no_rotate entry pan no_pool_fixup no_monster_gen generate_awake