summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-05-09 19:52:59 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-05-09 19:52:59 +0000
commitd69688f0d70ebd684181678a77ca10f800258cfe (patch)
tree19b8b9fdd4c8194ea65d0729cdf44adf31ee7e60
parentb31a9edb3090aa8dac6dc1fc70c5e241c3019642 (diff)
downloadcrawl-ref-d69688f0d70ebd684181678a77ca10f800258cfe.tar.gz
crawl-ref-d69688f0d70ebd684181678a77ca10f800258cfe.zip
Added Lemuel's mines minivaults.
Extended map DEPTH: attribute to support branch specifiers and negated depth specifiers. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1442 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/branch.cc10
-rw-r--r--crawl-ref/source/branch.h2
-rw-r--r--crawl-ref/source/dat/vaults.des151
-rw-r--r--crawl-ref/source/dungeon.cc48
-rw-r--r--crawl-ref/source/hiscores.cc12
-rw-r--r--crawl-ref/source/makefile.unix2
-rw-r--r--crawl-ref/source/mapdef.cc116
-rw-r--r--crawl-ref/source/mapdef.h37
-rw-r--r--crawl-ref/source/maps.cc14
-rw-r--r--crawl-ref/source/maps.h2
-rw-r--r--crawl-ref/source/misc.cc4
-rw-r--r--crawl-ref/source/misc.h8
-rw-r--r--crawl-ref/source/util/levcomp.cc5
-rw-r--r--crawl-ref/source/util/levcomp.h2
-rw-r--r--crawl-ref/source/util/levcomp.lpp4
-rw-r--r--crawl-ref/source/util/levcomp.ypp91
16 files changed, 410 insertions, 98 deletions
diff --git a/crawl-ref/source/branch.cc b/crawl-ref/source/branch.cc
index 298431f866..3f81d87d32 100644
--- a/crawl-ref/source/branch.cc
+++ b/crawl-ref/source/branch.cc
@@ -12,6 +12,16 @@ Branch& your_branch()
return branches[static_cast<int>(you.where_are_you)];
}
+branch_type str_to_branch(const std::string &branch, branch_type err)
+{
+ for (int i = 0; i < NUM_BRANCHES; ++i)
+ {
+ if (branches[i].abbrevname && branches[i].abbrevname == branch)
+ return (static_cast<branch_type>(i));
+ }
+ return (err);
+}
+
Branch branches[] = {
{ BRANCH_MAIN_DUNGEON, BRANCH_MAIN_DUNGEON, 27, -1,
diff --git a/crawl-ref/source/branch.h b/crawl-ref/source/branch.h
index d1e3ca7c7c..009bb89bca 100644
--- a/crawl-ref/source/branch.h
+++ b/crawl-ref/source/branch.h
@@ -39,5 +39,7 @@ struct Branch
extern Branch branches[];
Branch& your_branch();
+branch_type str_to_branch(const std::string &branch,
+ branch_type err = NUM_BRANCHES);
#endif
diff --git a/crawl-ref/source/dat/vaults.des b/crawl-ref/source/dat/vaults.des
index 506770c6db..c53d0bb780 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
+default-depth: 8-27, !Orc, !Lair
##############################################################################
# Minivault balancer
@@ -1299,23 +1299,25 @@ ENDMAP
# Greed's colour
NAME: david_greed
-DEPTH: 10-26
+DEPTH: 10-26, !Orc, !Lair
ITEM: nothing / any good_item
MONS: silver statue / orange crystal statue / ice statue
SHUFFLE: d|
MAP
-xxxxxxxxx
-xbbbbbbbx
-xb1...1bx
-xb.....bx
-xb.....bx
-xbb.|.bbx
-xxb.d.bxx
-xxb...bxx
-xxb...bxx
-xxb.*.bxx
-xxb...bxx
-xxx@I@xxx
+...........
+.xxxxxxxxx.
+.xbbbbbbbx.
+.xb1...1bx.
+.xb.....bx.
+.xb.....bx.
+.xbb.|.bbx.
+.xxb.d.bxx.
+.xxb...bxx.
+.xxb...bxx.
+.xxb.*.bxx.
+.xxb...bxx.
+.xxx@I@xxx.
+...........
ENDMAP
##############################################################################
@@ -2202,3 +2204,124 @@ MAP
.xxxxxxxx=x.
............
ENDMAP
+
+############################################################################
+# Minivaults specific to particular branches
+############################################################################
+# Orcish mines minivaults:
+
+default-depth: Orc:*
+
+##################################
+# Dummy Orc minivault balancer.
+#
+NAME: mines_dummy
+TAGS: dummy
+CHANCE: 100
+MAP
+x
+ENDMAP
+
+###################################
+# minvault intended for Orc Mines
+# pond with fungi
+NAME: mines1_lemuel
+MONS: fungus, wandering mushroom
+SUBST: 1 = . 1 2:4
+SUBST: ? : w..
+SUBST: ! : ww.
+MAP
+..1...?.....
+....1???1...
+..1...??ww1.
+....1wwwwww.
+.11wwwwwwww.
+..www!!wwww.
+..ww!!www1..
+..1ww!ww11..
+1..1w!!w1...
+....!!1.....
+.1...1!.1...
+...........1
+ENDMAP
+
+###################################
+# minvault intended for Orc Mines
+# hidden treasure chamber
+NAME: mines2_lemuel
+SUBST: ? = x.
+MAP
+..........
+..?x=x?...
+.?xx-xx?..
+?xx$$$xx?.
+?xx$$$xx?.
+.?xxxxx?..
+...???....
+ENDMAP
+
+###################################
+# minvault intended for Orc Mines
+# treasure chamber with oklob pant
+NAME: mines3_lemuel
+SUBST: ? = +=.
+SUBST: ! = x.
+SUBST: $ = $:30 *
+MONS: oklob plant
+MAP
+.....!.!......
+....!x?x!.....
+....!x.xx!....
+...!xx..xx!...
+...!xxx..xx!..
+....!xxx.1x!..
+....!xxxx.x!..
+...!xxxxx.xx!.
+..!xx$$x..xxx.
+.!!xx$$?.xxxx.
+.!xxx$$xxxx!..
+..!xxxxxxx!...
+..............
+ENDMAP
+
+###################################
+# minvault intended for Orc Mines
+# mage tower -- either orc with assistants, or ogre with guards
+NAME: mines4_lemuel
+SUBST: ? = +=
+SUBST: d = $d
+SUBST: I = IG
+SHUFFLE: 112/334
+MONS: orc sorcerer,orc/orc wizard,ogre-mage,ogre/nothing
+ITEM: any book
+MAP
+...............
+...xxxx?xxxx...
+..xx2.....2xx..
+.xx.2xxxxx2.xx.
+.x..xxd1dxx..x.
+.x.Ix$$G$$xI.x.
+.x..xx222xx..x.
+.xx.2xx?xx2.xx.
+..xx..2.2..xx..
+...xxxxxxxxx...
+...............
+ENDMAP
+
+###################################
+# minvault intended for Orc Mines
+# warg stables, with goblin stableboy
+NAME: mines5_lemuel
+SUBST: ?: wx
+MONS: warg/wolf,goblin
+MAP
+...........
+.x???????x.
+.xwwwwwwwx.
+.xwwwwwwwx.
+.x1.1.1.1x.
+.x.1.1.1.x.
+.x1.2...1x.
+.xxxx+xxxx.
+...........
+ENDMAP
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 46fb3b6c79..c2b3c8aebd 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -177,6 +177,7 @@ static dgn_region_list no_monster_zones;
static dgn_region_list no_item_zones;
static dgn_region_list no_pool_fixup_zones;
static dgn_region_list no_door_fixup_zones;
+static int minivault_chance = 3;
static std::vector<vault_placement> level_vaults;
@@ -341,6 +342,7 @@ static void reset_level()
no_item_zones.clear();
no_pool_fixup_zones.clear();
no_door_fixup_zones.clear();
+ minivault_chance = 3;
// blank level with DNGN_ROCK_WALL
make_box(0, 0, GXM - 1, GYM - 1, DNGN_ROCK_WALL, DNGN_ROCK_WALL);
@@ -1177,8 +1179,18 @@ static void place_special_minivaults(int level_number, int level_type)
if (level_type != LEVEL_DUNGEON)
return;
- int chance = level_number == 0? 50 : 100;
std::set<int> used;
+ if (minivault_chance && one_chance_in(minivault_chance))
+ {
+ const int vault = random_map_for_depth(level_id::current(), true);
+ if (vault != -1)
+ {
+ build_minivaults(level_number, vault);
+ used.insert(vault);
+ }
+ }
+
+ int chance = level_number == 0? 50 : 100;
while (chance && random2(100) < chance)
{
const int vault = random_map_for_dlevel(level_number, true);
@@ -1216,7 +1228,7 @@ static builder_rc_type builder_normal(int level_number, char level_type,
if (vault == -1
&& player_in_branch( BRANCH_MAIN_DUNGEON )
&& one_chance_in(9))
- vault = random_map_for_depth(level_number);
+ vault = random_map_for_depth(level_id::current());
if (vault != -1)
{
@@ -1257,14 +1269,7 @@ static builder_rc_type builder_normal(int level_number, char level_type,
if (level_number > 2 && level_number < 23 && one_chance_in(3))
{
plan_main(level_number, 0);
-
- if (one_chance_in(3))
- {
- int mvault = random_map_for_depth(level_number, true);
- if (mvault != -1)
- build_minivaults(level_number, mvault);
- }
-
+ minivault_chance = 3;
return BUILD_SKIP;
}
@@ -1276,17 +1281,7 @@ static builder_rc_type builder_normal(int level_number, char level_type,
{
// sometimes roguey_levels generate a special room
roguey_level(level_number, sr);
-
- if (player_in_branch( BRANCH_MAIN_DUNGEON )
- && one_chance_in(4))
- {
- int mvault = random_map_for_depth(level_number, true);
- if (mvault != -1)
- {
- build_minivaults(level_number, mvault);
- return BUILD_SKIP;
- }
- }
+ minivault_chance = 4;
}
else
{
@@ -1413,17 +1408,6 @@ static void builder_extras( int level_number, int level_type )
if (level_number >= 11 && level_number <= 23 && one_chance_in(15))
place_specific_stair(DNGN_ENTER_LABYRINTH);
- if (player_in_branch( BRANCH_MAIN_DUNGEON )
- && one_chance_in(3))
- {
- int mvault = random_map_for_depth(level_number, true);
- if (mvault != -1)
- {
- build_minivaults(level_number, mvault);
- return;
- }
- }
-
if (level_number > 6 && one_chance_in(10))
{
many_pools( level_number < 11 || coinflip() ?
diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc
index 50e697b100..30f1928da9 100644
--- a/crawl-ref/source/hiscores.cc
+++ b/crawl-ref/source/hiscores.cc
@@ -631,16 +631,6 @@ static const char *short_branch_name(int branch)
return ("");
}
-static branch_type str_to_branch(const std::string &branch)
-{
- for (int i = 0; i < NUM_BRANCHES; ++i)
- {
- if (branches[i].abbrevname && branches[i].abbrevname == branch)
- return (static_cast<branch_type>(i));
- }
- return (BRANCH_MAIN_DUNGEON);
-}
-
static const char *level_type_names[] =
{
"D", "Lab", "Abyss", "Pan"
@@ -691,7 +681,7 @@ void scorefile_entry::init_with_fields()
death_type = str_to_kill_method(fields->str_field("ktyp"));
death_source_name = fields->str_field("killer");
auxkilldata = fields->str_field("kaux");
- branch = str_to_branch(fields->str_field("br"));
+ branch = str_to_branch(fields->str_field("br"), BRANCH_MAIN_DUNGEON);
dlvl = fields->int_field("lvl");
level_type = str_to_level_area_type(fields->str_field("ltyp"));
diff --git a/crawl-ref/source/makefile.unix b/crawl-ref/source/makefile.unix
index b0e2c1c27a..f67953792c 100644
--- a/crawl-ref/source/makefile.unix
+++ b/crawl-ref/source/makefile.unix
@@ -161,7 +161,7 @@ prebuildyacc: $(UTIL)levcomp.tab.cc $(UTIL)levcomp.tab.h $(UTIL)levcomp.lex.cc
$(UTIL)levcomp.tab.cc: $(UTIL)levcomp.ypp
cd $(UTIL) && $(YACC) -d -b levcomp levcomp.ypp \
- && mv $(YTABC) levcomp.tab.cc
+ && mv $(YTABC) levcomp.tab.cc || false
$(UTIL)levcomp.lex.cc: $(UTIL)levcomp.lpp
cd $(UTIL) && $(LEX) -olevcomp.lex.cc levcomp.lpp
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index 3cf3ad9b41..2420d3ba9e 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -3,6 +3,7 @@
#include <cctype>
#include "AppHdr.h"
+#include "branch.h"
#include "describe.h"
#include "direct.h"
#include "invent.h"
@@ -122,17 +123,75 @@ static std::string split_key_item(const std::string &s,
// level_range
//
-level_range::level_range(int s, int d)
- : shallowest(), deepest()
+level_range::level_range(branch_type br, int s, int d)
+ : branch(br), shallowest(), deepest(), deny(false)
{
set(s, d);
}
+level_range::level_range(const raw_range &r)
+ : branch(r.branch), shallowest(r.shallowest), deepest(r.deepest),
+ deny(r.deny)
+{
+}
+
+std::string level_range::str_depth_range() const
+{
+ if (shallowest == -1)
+ return (":??");
+
+ if (shallowest == 1 && deepest >= branches[branch].depth)
+ return ("");
+
+ if (shallowest == deepest)
+ return make_stringf(":%d", shallowest);
+
+ return make_stringf(":%d-%d", shallowest, deepest);
+}
+
+std::string level_range::describe() const
+{
+ return make_stringf("%s%s%s",
+ deny? "!" : "",
+ branch == NUM_BRANCHES? "Any" :
+ branches[branch].abbrevname,
+ str_depth_range().c_str());
+}
+
+level_range::operator raw_range () const
+{
+ raw_range r;
+ r.branch = branch;
+ r.shallowest = shallowest;
+ r.deepest = deepest;
+ r.deny = deny;
+ return (r);
+}
+
+void level_range::set(const std::string &br, int s, int d)
+ throw (std::string)
+{
+ if (br == "any" || br == "Any")
+ branch = NUM_BRANCHES;
+ else
+ {
+ if ((branch = str_to_branch(br)) == NUM_BRANCHES)
+ throw make_stringf("Unknown branch: '%s'", br.c_str());
+ }
+
+ shallowest = s;
+ deepest = d;
+
+ if (deepest < shallowest)
+ throw make_stringf("Level-range %s:%d-%d is malformed",
+ br.c_str(), s, d);
+}
+
void level_range::set(int s, int d)
{
shallowest = s;
deepest = d;
- if (deepest == -1)
+ if (deepest == -1 || deepest < shallowest)
deepest = shallowest;
}
@@ -141,7 +200,16 @@ void level_range::reset()
deepest = shallowest = -1;
}
-bool level_range::contains(int x) const
+bool level_range::matches(const level_id &lid) const
+{
+ if (branch == NUM_BRANCHES)
+ return (matches(absdungeon_depth(lid.branch, lid.depth)));
+ else
+ return (branch == lid.branch
+ && lid.depth >= shallowest && lid.depth <= deepest);
+}
+
+bool level_range::matches(int x) const
{
// [ds] The level ranges used by the game are zero-based, adjust for that.
++x;
@@ -559,7 +627,7 @@ void map_def::init()
place.clear();
items.clear();
keyspecs.clear();
- depth.reset();
+ depths.clear();
orient = MAP_NONE;
// Base chance; this is not a percentage.
@@ -573,6 +641,38 @@ void map_def::init()
mons.clear();
}
+bool map_def::is_usable_in(const level_id &lid) const
+{
+ bool any_matched = false;
+ for (int i = 0, size = depths.size(); i < size; ++i)
+ {
+ const level_range &lr = depths[i];
+ if (lr.matches(lid))
+ {
+ if (lr.deny)
+ return (false);
+ any_matched = true;
+ }
+ }
+ return (any_matched);
+}
+
+void map_def::add_depth(const level_range &range)
+{
+ depths.push_back(range);
+}
+
+void map_def::add_depths(depth_ranges::const_iterator s,
+ depth_ranges::const_iterator e)
+{
+ depths.insert(depths.end(), s, e);
+}
+
+bool map_def::has_depth() const
+{
+ return (!depths.empty());
+}
+
bool map_def::is_minivault() const
{
return (orient == MAP_NONE);
@@ -796,6 +896,12 @@ bool map_def::has_tag(const std::string &tagwanted) const
&& tags.find(" " + tagwanted + " ") != std::string::npos;
}
+bool map_def::has_tag_prefix(const std::string &prefix) const
+{
+ return !tags.empty() && !prefix.empty()
+ && tags.find(" " + prefix) != std::string::npos;
+}
+
keyed_mapspec *map_def::mapspec_for_key(int key)
{
keyed_specs::iterator i = keyspecs.find(key);
diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h
index ffb5cef40e..3d5866af96 100644
--- a/crawl-ref/source/mapdef.h
+++ b/crawl-ref/source/mapdef.h
@@ -24,20 +24,38 @@ enum map_flags
MAPF_ROTATE = 0x40 // may be rotated
};
-class level_range
+struct raw_range
+{
+ branch_type branch;
+ int shallowest, deepest;
+ bool deny;
+};
+
+struct level_range
{
public:
+ branch_type branch;
int shallowest, deepest;
+ bool deny;
public:
- level_range(int s = -1, int d = -1);
+ level_range(const raw_range &range);
+ level_range(branch_type br = BRANCH_MAIN_DUNGEON, int s = -1, int d = -1);
void set(int s, int d = -1);
+ void set(const std::string &branch, int s, int d) throw (std::string);
+
void reset();
- bool contains(int depth) const;
+ bool matches(const level_id &) const;
+ bool matches(int depth) const;
bool valid() const;
int span() const;
+
+ std::string describe() const;
+ std::string str_depth_range() const;
+
+ operator raw_range () const;
};
typedef std::pair<int,int> glyph_weighted_replacement_t;
@@ -328,6 +346,8 @@ private:
typedef std::map<int, keyed_mapspec> keyed_specs;
+typedef std::vector<level_range> depth_ranges;
+
// Not providing a constructor to make life easy for C-style initialisation.
class map_def
{
@@ -335,7 +355,8 @@ public:
std::string name;
std::string tags;
std::string place;
- level_range depth;
+
+ depth_ranges depths;
map_section_type orient;
int chance;
long flags;
@@ -355,7 +376,14 @@ public:
void resolve();
void fixup();
+ bool is_usable_in(const level_id &lid) const;
+
keyed_mapspec *mapspec_for_key(int key);
+
+ bool has_depth() const;
+ void add_depth(const level_range &depth);
+ void add_depths(depth_ranges::const_iterator s,
+ depth_ranges::const_iterator e);
std::string add_key_item(const std::string &s);
std::string add_key_mons(const std::string &s);
@@ -369,6 +397,7 @@ public:
bool is_minivault() const;
bool has_tag(const std::string &tag) const;
+ bool has_tag_prefix(const std::string &tag) const;
private:
std::string add_key_field(
diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc
index 98ecb5c25f..bc9c9acf27 100644
--- a/crawl-ref/source/maps.cc
+++ b/crawl-ref/source/maps.cc
@@ -283,19 +283,19 @@ int random_map_for_place(const std::string &place, bool want_minivault)
return (mapindex);
}
-int random_map_for_depth(int depth, bool want_minivault)
+int random_map_for_depth(const level_id &place, bool want_minivault)
{
int mapindex = -1;
int rollsize = 0;
for (unsigned i = 0, size = vdefs.size(); i < size; ++i)
- if (vdefs[i].depth.contains(depth)
+ if (vdefs[i].is_minivault() == want_minivault
+ && vdefs[i].is_usable_in(place)
// Tagged levels cannot be selected by depth. This is
// the only thing preventing Pandemonium demon vaults from
// showing up in the main dungeon.
&& !vdefs[i].has_tag("entry")
- && !vdefs[i].has_tag("pan")
- && vdefs[i].is_minivault() == want_minivault)
+ && !vdefs[i].has_tag("pan"))
{
rollsize += vdefs[i].chance;
@@ -305,7 +305,7 @@ int random_map_for_depth(int depth, bool want_minivault)
if (mapindex != -1 && vdefs[mapindex].has_tag("dummy"))
mapindex = -1;
-
+
return (mapindex);
}
@@ -319,8 +319,8 @@ int random_map_for_tag(const std::string &tag,
for (unsigned i = 0, size = vdefs.size(); i < size; ++i)
{
if (vdefs[i].has_tag(tag) && vdefs[i].is_minivault() == want_minivault
- && (!check_depth || !vdefs[i].depth.valid()
- || vdefs[i].depth.contains(you.your_level)))
+ && (!check_depth || !vdefs[i].has_depth()
+ || vdefs[i].is_usable_in(level_id::current())))
{
rollsize += vdefs[i].chance;
diff --git a/crawl-ref/source/maps.h b/crawl-ref/source/maps.h
index 82738abd5c..6b3ab76089 100644
--- a/crawl-ref/source/maps.h
+++ b/crawl-ref/source/maps.h
@@ -41,7 +41,7 @@ int vault_main(map_type vgrid,
const map_def *map_by_index(int index);
int random_map_for_place(const std::string &place, bool mini = false);
-int random_map_for_depth(int depth, bool want_minivault = false);
+int random_map_for_depth(const level_id &lid, bool want_minivault = false);
int random_map_for_tag(const std::string &tag, bool want_minivault,
bool check_depth = false);
void add_parsed_map(const map_def &md);
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index a7a7887402..d8baa06295 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -2042,7 +2042,7 @@ std::string prep_branch_level_name()
return prep_branch_level_name( get_packed_place() );
}
-int absdungeon_depth(unsigned char branch, int subdepth)
+int absdungeon_depth(branch_type branch, int subdepth)
{
if (branch >= BRANCH_VESTIBULE_OF_HELL && branch <= BRANCH_THE_PIT)
return subdepth + 27;
@@ -2058,7 +2058,7 @@ int absdungeon_depth(unsigned char branch, int subdepth)
return subdepth;
}
-int subdungeon_depth(unsigned char branch, int depth)
+int subdungeon_depth(branch_type branch, int depth)
{
return depth - absdungeon_depth(branch, 0);
}
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index 59d1e5a2b8..6c82049174 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -182,14 +182,14 @@ std::string prep_branch_level_name();
// Get displayable depth in the current branch, given the absolute
// depth.
-int subdungeon_depth(unsigned char branch, int depth);
+int subdungeon_depth(branch_type branch, int depth);
+
+// Get absolute depth given the displayable depth in the branch.
+int absdungeon_depth(branch_type branch, int subdepth);
// Get displayable depth in the current branch.
int player_branch_depth();
-// Get absolute depth given the displayable depth in the branch.
-int absdungeon_depth(unsigned char branch, int subdepth);
-
bool single_level_branch(branch_type branch);
//////////////////////////////////////////////////////////////////////
diff --git a/crawl-ref/source/util/levcomp.cc b/crawl-ref/source/util/levcomp.cc
index 5e0bb4cb64..af92a23bb6 100644
--- a/crawl-ref/source/util/levcomp.cc
+++ b/crawl-ref/source/util/levcomp.cc
@@ -1,10 +1,11 @@
#include "AppHdr.h"
#include "levcomp.h"
+#include <vector>
std::string lc_desfile;
map_def lc_map;
level_range lc_range;
-level_range lc_default_depth;
+depth_ranges lc_default_depths;
extern int yylineno;
@@ -12,7 +13,7 @@ void reset_map_parser()
{
lc_map.init();
lc_range.reset();
- lc_default_depth.reset();
+ lc_default_depths.clear();
yylineno = 1;
}
diff --git a/crawl-ref/source/util/levcomp.h b/crawl-ref/source/util/levcomp.h
index 99f0495f90..c3bf3a73ea 100644
--- a/crawl-ref/source/util/levcomp.h
+++ b/crawl-ref/source/util/levcomp.h
@@ -6,7 +6,7 @@
extern map_def lc_map;
extern level_range lc_range;
-extern level_range lc_default_depth;
+extern depth_ranges lc_default_depths;
extern std::string lc_desfile;
void reset_map_parser();
diff --git a/crawl-ref/source/util/levcomp.lpp b/crawl-ref/source/util/levcomp.lpp
index 64d790017c..157d53b5bc 100644
--- a/crawl-ref/source/util/levcomp.lpp
+++ b/crawl-ref/source/util/levcomp.lpp
@@ -188,6 +188,10 @@ float return FLOAT;
\" return QUOTE;
+: return COLON;
+\* return STAR;
+! return NOT;
+
[a-zA-Z_][a-zA-Z_0-9]+ {
settext();
return IDENTIFIER;
diff --git a/crawl-ref/source/util/levcomp.ypp b/crawl-ref/source/util/levcomp.ypp
index f917ad37e6..d62800845e 100644
--- a/crawl-ref/source/util/levcomp.ypp
+++ b/crawl-ref/source/util/levcomp.ypp
@@ -3,6 +3,7 @@
#include "AppHdr.h"
#include "libutil.h"
#include "levcomp.h"
+#include "mapdef.h"
#include "stuff.h"
#include <map>
@@ -34,12 +35,26 @@ void yyerror(const char *e)
end(1);
}
+level_range set_range(const char *s, int start, int end)
+{
+ try
+ {
+ lc_range.set(s, start, end);
+ }
+ catch (const std::string &err)
+ {
+ yyerror(err.c_str());
+ }
+ return (lc_range);
+}
+
%}
%union
{
int i;
const char *text;
+ raw_range range;
}
%token <i> BRANCHDEF BRANCH DESC DEFAULT
@@ -58,10 +73,11 @@ void yyerror(const char *e)
%token <i> NO_HMIRROR NO_VMIRROR NO_ROTATE
%token <i> PANDEMONIC
-%token <i> DASH COMMA QUOTE OPAREN CPAREN
+%token <i> DASH COMMA QUOTE OPAREN CPAREN COLON STAR NOT
%token <i> INTEGER
%type <i> orient_name flagname
+%type <range> lev_range ext_range
%token <text> STRING MAP_LINE MONSTER_NAME ITEM_INFO
%token <text> IDENTIFIER
@@ -72,20 +88,19 @@ file : definitions { }
;
definitions : /* empty */ {}
- | definition definitions {}
+ | definitions definition {}
;
definition : def {}
| level {}
;
-def : defdepth
+def : defdepth {}
;
-defdepth : DEFAULT_DEPTH depth_range
- {
- lc_default_depth = lc_range;
- }
+defdepth : DEFAULT_DEPTH
+ { lc_default_depths.clear(); }
+ default_depth_ranges
;
level : name metalines map_def metalines
@@ -123,6 +138,10 @@ level : name metalines map_def metalines
if (lc_map.map.height() == 0)
yyerror("Must define map.");
+ if (!lc_map.has_depth() && !lc_default_depths.empty())
+ lc_map.add_depths(lc_default_depths.begin(),
+ lc_default_depths.end());
+
add_parsed_map( lc_map );
}
;
@@ -130,7 +149,6 @@ level : name metalines map_def metalines
name : NAME STRING
{
lc_map.init();
- lc_map.depth = lc_default_depth;
lc_map.name = $2;
map_load_info_t::const_iterator i =
@@ -203,7 +221,7 @@ shuffle : SHUFFLE shuffle_specifiers {}
;
shuffle_specifiers : shuffle_spec
- | shuffle_spec COMMA shuffle_specifiers
+ | shuffle_specifiers COMMA shuffle_spec
;
shuffle_spec : ITEM_INFO
@@ -300,20 +318,65 @@ place : PLACE STRING
;
depth : DEPTH {}
- | DEPTH depth_range
+ | DEPTH extended_depth_ranges {}
+ ;
+
+default_depth_ranges :
+ ext_range
+ {
+ lc_default_depths.push_back($1);
+ }
+
+ | default_depth_ranges COMMA ext_range
+ {
+ lc_default_depths.push_back($3);
+ }
+ ;
+
+extended_depth_ranges :
+ ext_range
{
- lc_map.depth = lc_range;
+ lc_map.add_depth($1);
+ }
+
+ | extended_depth_ranges COMMA ext_range
+ {
+ lc_map.add_depth($3);
}
;
-depth_range : INTEGER DASH INTEGER
+ext_range : lev_range { $$ = $1; }
+ | NOT lev_range { $$ = $2; $$.deny = true; }
+ ;
+
+lev_range : IDENTIFIER
+ {
+ $$ = set_range($1, 1, 100);
+ }
+
+ | IDENTIFIER COLON STAR
+ {
+ $$ = set_range($1, 1, 100);
+ }
+
+ | IDENTIFIER COLON INTEGER DASH INTEGER
+ {
+ $$ = set_range($1, $3, $5);
+ }
+
+ | IDENTIFIER COLON INTEGER
+ {
+ $$ = set_range($1, $3, $3);
+ }
+
+ | INTEGER DASH INTEGER
{
- lc_range.set($1, $3);
+ $$ = set_range("Any", $1, $3);
}
| INTEGER
{
- lc_range.set($1);
+ $$ = set_range("Any", $1, $1);
}
;