summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/clua.cc30
-rw-r--r--crawl-ref/source/clua.h6
-rw-r--r--crawl-ref/source/dat/clua/dungeon.lua38
-rw-r--r--crawl-ref/source/dat/clua/lm_1way.lua6
-rw-r--r--crawl-ref/source/dat/clua/loadmaps.lua2
-rw-r--r--crawl-ref/source/dat/clua/ziggurat.lua120
-rw-r--r--crawl-ref/source/dat/ziggurat.des70
-rw-r--r--crawl-ref/source/debug.cc2
-rw-r--r--crawl-ref/source/dungeon.cc81
-rw-r--r--crawl-ref/source/externs.h11
-rw-r--r--crawl-ref/source/luadgn.cc218
-rw-r--r--crawl-ref/source/mapdef.cc4
-rw-r--r--crawl-ref/source/mapmark.cc2
-rw-r--r--crawl-ref/source/misc.cc23
-rw-r--r--crawl-ref/source/tags.cc10
-rw-r--r--crawl-ref/source/tags.h3
-rw-r--r--crawl-ref/source/view.cc7
17 files changed, 458 insertions, 175 deletions
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index 7fb7a310a7..c0c6e6845f 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -2946,3 +2946,33 @@ void lua_datum::cleanup()
lua_settable(lua, LUA_REGISTRYINDEX);
}
}
+
+#define LUA_CHECK_TYPE(check) \
+ lua_stack_cleaner clean(lua); \
+ push(); \
+ return check(lua, -1)
+
+bool lua_datum::is_table() const
+{
+ LUA_CHECK_TYPE(lua_istable);
+}
+
+bool lua_datum::is_function() const
+{
+ LUA_CHECK_TYPE(lua_isfunction);
+}
+
+bool lua_datum::is_number() const
+{
+ LUA_CHECK_TYPE(lua_isnumber);
+}
+
+bool lua_datum::is_string() const
+{
+ LUA_CHECK_TYPE(lua_isstring);
+}
+
+bool lua_datum::is_udata() const
+{
+ LUA_CHECK_TYPE(lua_isuserdata);
+}
diff --git a/crawl-ref/source/clua.h b/crawl-ref/source/clua.h
index e6ae4ecde7..a2de0f4f2c 100644
--- a/crawl-ref/source/clua.h
+++ b/crawl-ref/source/clua.h
@@ -79,6 +79,12 @@ public:
// Push the datum onto the Lua stack.
void push() const;
+ bool is_table() const;
+ bool is_function() const;
+ bool is_number() const;
+ bool is_string() const;
+ bool is_udata() const;
+
private:
bool need_cleanup;
CLua &lua;
diff --git a/crawl-ref/source/dat/clua/dungeon.lua b/crawl-ref/source/dat/clua/dungeon.lua
index 7f7f0cd688..66148a3708 100644
--- a/crawl-ref/source/dat/clua/dungeon.lua
+++ b/crawl-ref/source/dat/clua/dungeon.lua
@@ -4,6 +4,19 @@
------------------------------------------------------------------------------
dgn.GXM, dgn.GYM = dgn.max_bounds()
+dgn.f_rockwall = dgn.feature_number("rock_wall")
+dgn.f_floor = dgn.feature_number("floor")
+
+-- Table that will be saved in <foo>.sav.
+dgn.persist = { }
+
+function dgn_save_data(th)
+ lmark.marshall_table(th, dgn.persist)
+end
+
+function dgn_load_data(th)
+ dgn.persist = lmark.unmarshall_table(th) or { }
+end
-- Wraps a map_def into a Lua environment (a table) such that
-- functions run in the environment (with setfenv) can directly
@@ -144,4 +157,29 @@ function dgn.replace_feat(rmap)
end
end
end
+end
+
+----------------------------------------------------------------------
+-- Convenience functions for vaults.
+
+-- Returns a marker table that sets the destination tag for that square,
+-- usually used to set a destination tag for a portal or a stair in a
+-- portal vault.
+function portal_stair_dst(dst)
+ return one_way_stair { dst = dst }
+end
+
+-- Common initialisation for portal vaults.
+function portal_vault(e, tag)
+ if tag then
+ e.tags(tag)
+ end
+ e.orient("encompass")
+end
+
+-- Set all stone downstairs in this vault to go to the tag 'next'.
+function portal_next(e, next)
+ for _, feat in ipairs({ "]", ")", "}" }) do
+ e.lua_marker(feat, portal_stair_dst(next))
+ end
end \ No newline at end of file
diff --git a/crawl-ref/source/dat/clua/lm_1way.lua b/crawl-ref/source/dat/clua/lm_1way.lua
index f2c65da612..f390d0dd84 100644
--- a/crawl-ref/source/dat/clua/lm_1way.lua
+++ b/crawl-ref/source/dat/clua/lm_1way.lua
@@ -20,6 +20,12 @@ end
function OneWayStair:event(marker, ev)
if ev:type() == dgn.dgn_event_type('player_climb') then
local x, y = ev:pos()
+
+ -- If there's an onclimb function, call it before we do our thing.
+ if self.props.onclimb then
+ self.props.onclimb(self, marker, ev)
+ end
+
dgn.terrain_changed(x, y, self.props.floor or 'floor', false, false)
dgn.remove_listener(marker, ev:pos())
dgn.remove_marker(marker)
diff --git a/crawl-ref/source/dat/clua/loadmaps.lua b/crawl-ref/source/dat/clua/loadmaps.lua
index 2f6b617635..cd39b2397d 100644
--- a/crawl-ref/source/dat/clua/loadmaps.lua
+++ b/crawl-ref/source/dat/clua/loadmaps.lua
@@ -13,7 +13,7 @@ local des_files = {
"altar.des", "bazaar.des", "entry.des", "elf.des", "float.des",
"hells.des", "hive.des", "lab.des", "lair.des", "large.des", "layout.des",
"mini.des", "orc.des", "pan.des", "sewer.des", "temple.des", "vaults.des",
- "crypt.des", "zot.des"
+ "crypt.des", "ziggurat.des", "zot.des"
}
for _, file in ipairs(des_files) do
diff --git a/crawl-ref/source/dat/clua/ziggurat.lua b/crawl-ref/source/dat/clua/ziggurat.lua
new file mode 100644
index 0000000000..1b8439a0cf
--- /dev/null
+++ b/crawl-ref/source/dat/clua/ziggurat.lua
@@ -0,0 +1,120 @@
+------------------------------------------------------------------------------
+-- ziggurat.lua:
+--
+-- Code for ziggurats.
+--
+-- Important notes:
+-- ----------------
+-- Functions that are attached to Lua markers' onclimb properties
+-- cannot be closures, because Lua markers must be saved and closure
+-- upvalues cannot (yet) be saved.
+------------------------------------------------------------------------------
+
+function zig()
+ if not dgn.persist.ziggurat then
+ dgn.persist.ziggurat = { }
+ end
+ return dgn.persist.ziggurat
+end
+
+-- Returns a function that changes the depth in the ziggurat to the depth
+-- specified.
+local function zig_depth_increment()
+ return function (...)
+ zig().depth = zig().depth + 1
+ end
+end
+
+function ziggurat_initializer()
+ local z = zig()
+ z.depth = 1
+ z.builder = ziggurat_choose_builder()
+end
+
+-- Returns the current depth in the ziggurat.
+local function zig_depth()
+ return zig().depth or 0
+end
+
+-- Common setup for ziggurat entry vaults.
+function ziggurat_portal(e)
+ local function stair()
+ return one_way_stair {
+ desc = "gateway to a ziggurat",
+ dst = "ziggurat",
+ floor = "stone_arch",
+ onclimb = ziggurat_initializer
+ }
+ end
+
+ e.lua_marker("O", stair)
+ e.kfeat("O = enter_portal_vault")
+end
+
+-- Common setup for ziggurat levels.
+function ziggurat_level(e)
+ e.tags("ziggurat")
+ e.tags("allow_dup")
+ e.orient("encompass")
+ ziggurat_build_level(e)
+end
+
+-----------------------------------------------------------------------------
+-- Ziggurat level builders.
+
+function ziggurat_build_level(e)
+ local builder = zig().builder
+ if builder then
+ return ziggurat_builder_map[builder](e)
+ end
+end
+
+local function zigstair(x, y, stair, marker)
+ dgn.grid(x, y, stair)
+ if marker then
+ local t = type(marker)
+ if t == "function" or t == "table" then
+ dgn.register_lua_marker(x, y, marker)
+ else
+ dgn.register_feature_marker(x, y, marker)
+ end
+ end
+end
+
+-- Creates a Lua marker table that increments ziggurat depth.
+local function zig_go_deeper()
+ return one_way_stair {
+ onclimb = zig_depth_increment()
+ }
+end
+
+local function ziggurat_rectangle_builder(e)
+ local grid = dgn.grid
+
+ -- FIXME: Cool code goes here.
+ local x1, y1 = 20, 20
+ local x2, y2 = dgn.GXM - 20, dgn.GYM - 20
+ dgn.fill_area(x1, y1, x2, y2, "floor")
+
+ local my = math.floor((y1 + y2) / 2)
+ zigstair(x1, my, "stone_arch", "stone_stairs_up_i")
+ zigstair(x2, my, "stone_stairs_down_i", zig_go_deeper)
+ grid(x2, my + 1, "exit_portal_vault")
+
+ crawl.mpr("Ziggurat depth is now " .. zig_depth())
+end
+
+----------------------------------------------------------------------
+
+ziggurat_builder_map = {
+ rectangle = ziggurat_rectangle_builder
+}
+
+local ziggurat_builders = { }
+for key, val in pairs(ziggurat_builder_map) do
+ table.insert(ziggurat_builders, key)
+end
+
+function ziggurat_choose_builder()
+ return ziggurat_builders[crawl.random_range(1, #ziggurat_builders)]
+end \ No newline at end of file
diff --git a/crawl-ref/source/dat/ziggurat.des b/crawl-ref/source/dat/ziggurat.des
new file mode 100644
index 0000000000..73ce42e5ff
--- /dev/null
+++ b/crawl-ref/source/dat/ziggurat.des
@@ -0,0 +1,70 @@
+###############################################################################
+# ziggurat.des - Ziggurat entry vaults and ziggurat layouts.
+###############################################################################
+
+# Most ziggurat code is in ziggurat.lua.
+# XXX: Ziggurat code is incomplete.
+
+: dofile("clua/ziggurat.lua")
+
+NAME: enter_the_ziggurat
+# Disabled; ziggurat is still incomplete.
+WEIGHT: 0
+: ziggurat_portal(_G)
+MAP
+O
+ENDMAP
+
+
+NAME: ziggurat1
+: ziggurat_level(_G)
+MAP
+ENDMAP
+
+#############################################################################
+# Multilevel portal vault structure:
+# This is how a multilevel portal vault should be laid out. All stairs are
+# one-way; the player cannot return to a level once left.
+
+NAME: multilevel_portal_vault_entry
+# Demo vault, disabled.
+WEIGHT: 0
+MARKER: O = lua:one_way_stair { \
+ dst="multilevel portal vault", \
+ desc="An entrance to a multilevel portal vault" \
+ }
+KFEAT: O = enter_portal_vault
+MAP
+O
+ENDMAP
+
+NAME: portal_level_1
+TAGS: multilevel_portal_vault
+: portal_vault(_G, "multilevel_portal_vault")
+# portal_next() links all downstairs to the vault with the specified tag.
+: portal_next(_G, "multilevel_portal_vault_b")
+MAP
+xxxxxx
+xA..]x
+xxxxxx
+ENDMAP
+
+NAME: portal_level_2
+: portal_vault(_G, "multilevel_portal_vault_b")
+: portal_next(_G, "multilevel_portal_vault_c")
+MAP
+xxxxxx
+xAWW]x
+xxxxxx
+ENDMAP
+
+NAME: portal_level_3
+: portal_vault(_G, "multilevel_portal_vault_c")
+KFEAT: < = exit_portal_vault
+MAP
+xxxxxxx
+xlllllx
+xA...<x
+xlllllx
+xxxxxxx
+ENDMAP
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 7e70a2be39..b17e02d521 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -4728,7 +4728,7 @@ static bool mg_build_dungeon()
you.where_are_you = lid.branch;
you.level_type = lid.level_type;
if (you.level_type == LEVEL_PORTAL_VAULT)
- you.level_type_name = "bazaar";
+ you.level_type_tag = you.level_type_name = "bazaar";
if (!mg_do_build_level(1))
return (false);
}
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 8263cb69a2..1a31f4fb67 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -2256,11 +2256,11 @@ static builder_rc_type _builder_by_type(int level_number, char level_type)
static void _portal_vault_level(int level_number)
{
- // level_type_name may contain spaces for human readability, but the
+ // level_type_tag may contain spaces for human readability, but the
// corresponding vault tag name cannot use spaces, so force spaces to
// _ when searching for the tag.
const std::string trimmed_name =
- replace_all(trimmed_string(you.level_type_name), " ", "_");
+ replace_all(trimmed_string(you.level_type_tag), " ", "_");
ASSERT(!trimmed_name.empty());
@@ -2290,7 +2290,7 @@ static void _portal_vault_level(int level_number)
lowercase(name);
name = replace_all(name, " ", "_");
- vault = find_map_by_name(you.level_type_name + "_" + name);
+ vault = find_map_by_name(you.level_type_tag + "_" + name);
if (vault == -1)
mprf(MSGCH_DIAGNOSTICS, "No such %s, try again.",
@@ -2324,7 +2324,7 @@ static void _portal_vault_level(int level_number)
// TODO: Let portal vault map have arbitrary properties which can
// be passed onto the callback.
callback_map::const_iterator
- i = level_type_post_callbacks.find(you.level_type_name);
+ i = level_type_post_callbacks.find(you.level_type_tag);
if (i != level_type_post_callbacks.end())
dlua.callfn(i->second.c_str(), 0, 0);
@@ -4549,32 +4549,35 @@ static bool _build_vaults(int level_number, int force_vault, int rune_subst,
int num_runes = 0;
dgn_region this_vault(place.pos, place.size);
- // NOTE: assumes *no* previous item (I think) or monster (definitely)
- // placement.
- for ( rectangle_iterator ri(place.pos, place.pos + place.size - 1);
- ri; ++ri )
+ if (!place.size.zero())
{
- if (vgrid[ri->y][ri->x] == ' ')
- continue;
+ // NOTE: assumes *no* previous item (I think) or monster (definitely)
+ // placement.
+ for ( rectangle_iterator ri(place.pos, place.pos + place.size - 1);
+ ri; ++ri )
+ {
+ if (vgrid[ri->y][ri->x] == ' ')
+ continue;
- const dungeon_feature_type oldgrid = grd(*ri);
- altar_count = _vault_grid( place, level_number, *ri, altar_count,
- acq_item_class,
- vgrid[ri->y][ri->x],
- target_connections,
- num_runes,
- rune_subst );
- if (!generating_level)
- {
- // Have to link items each square at a time, or
- // dungeon_terrain_changed could blow up.
- link_items();
- const dungeon_feature_type newgrid = grd(*ri);
- grd(*ri) = oldgrid;
- dungeon_terrain_changed(*ri, newgrid, true, true);
- env.markers.remove_markers_at(*ri, MAT_ANY);
+ const dungeon_feature_type oldgrid = grd(*ri);
+ altar_count = _vault_grid( place, level_number, *ri, altar_count,
+ acq_item_class,
+ vgrid[ri->y][ri->x],
+ target_connections,
+ num_runes,
+ rune_subst );
+ if (!generating_level)
+ {
+ // Have to link items each square at a time, or
+ // dungeon_terrain_changed could blow up.
+ link_items();
+ const dungeon_feature_type newgrid = grd(*ri);
+ grd(*ri) = oldgrid;
+ dungeon_terrain_changed(*ri, newgrid, true, true);
+ env.markers.remove_markers_at(*ri, MAT_ANY);
+ }
+ env.map(*ri).property |= FPROP_VAULT;
}
- env.map(*ri).property |= FPROP_VAULT;
}
place.map.map.apply_overlays(place.pos);
@@ -5815,7 +5818,7 @@ void place_spec_shop( int level_number,
env.shop[i].greed = 15 + random2avg(19, 2) + random2(level_number);
// Allow bargains in bazaars, prices randomly between 60% and 95%.
- if (you.level_type == LEVEL_PORTAL_VAULT && you.level_type_name == "bazaar")
+ if (you.level_type == LEVEL_PORTAL_VAULT && you.level_type_tag == "bazaar")
{
// Need to calculate with factor as greed (unsigned char)
// is capped at 255.
@@ -5858,7 +5861,7 @@ void place_spec_shop( int level_number,
// Make bazaar items more valuable (up to double value).
if (you.level_type == LEVEL_PORTAL_VAULT
- && you.level_type_name == "bazaar")
+ && you.level_type_tag == "bazaar")
{
int help = random2(item_level) + 1;
item_level += help;
@@ -7964,17 +7967,31 @@ coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
}
}
+ // Last attempt: look for marker.
+ const coord_def pos(_dgn_find_feature_marker(stair_to_find));
+ if (in_bounds(pos))
+ return (pos);
+
+ // Still hosed? If we're in a portal vault, convert to a search for
+ // any stone arch.
+ if (you.level_type == LEVEL_PORTAL_VAULT
+ && stair_to_find != DNGN_STONE_ARCH)
+ {
+ return dgn_find_nearby_stair(DNGN_STONE_ARCH, base_pos, find_closest);
+ }
+
+ // FAIL
ASSERT( found );
return result;
}
-void dgn_set_lt_callback(std::string level_type_name,
+void dgn_set_lt_callback(std::string level_type_tag,
std::string callback_name)
{
- ASSERT(!level_type_name.empty());
+ ASSERT(!level_type_tag.empty());
ASSERT(!callback_name.empty());
- level_type_post_callbacks[level_type_name] = callback_name;
+ level_type_post_callbacks[level_type_tag] = callback_name;
}
////////////////////////////////////////////////////////////////////
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 21bedd446f..6419609046 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -215,6 +215,11 @@ struct coord_def
{
return (!x && !y);
}
+
+ bool zero() const
+ {
+ return origin();
+ }
};
class actor
@@ -731,8 +736,14 @@ public:
KillMaster* kills;
level_area_type level_type;
+
+ // Human-readable name for portal vault. Will be set to level_type_tag
+ // if not explicitly set by the entry portal.
std::string level_type_name;
+ // .des file tag for portal vault
+ std::string level_type_tag;
+
entry_cause_type entry_cause;
god_type entry_cause_god;
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 4df7078a69..11d4ccfac1 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -315,6 +315,40 @@ std::string dlua_chunk::get_chunk_prefix(const std::string &sorig) const
#define MAPMARKER(ls, n, var) \
map_marker *var = *(map_marker **) luaL_checkudata(ls, n, MAPMARK_METATABLE)
+static dungeon_feature_type _get_lua_feature(lua_State *ls, int idx)
+{
+ dungeon_feature_type feat = (dungeon_feature_type)0;
+ if (lua_isnumber(ls, idx))
+ feat = (dungeon_feature_type)luaL_checkint(ls, idx);
+ else if (lua_isstring(ls, idx))
+ feat = dungeon_feature_by_name(luaL_checkstring(ls, idx));
+ else
+ luaL_argerror(ls, idx, "Feature must be a string or a feature index.");
+
+ return feat;
+}
+
+static dungeon_feature_type _check_lua_feature(lua_State *ls, int idx)
+{
+ const dungeon_feature_type f = _get_lua_feature(ls, idx);
+ if (!f)
+ luaL_argerror(ls, idx, "Invalid dungeon feature");
+ return (f);
+}
+
+#define COORDS(c, p1, p2) \
+ coord_def c; \
+ c.x = luaL_checkint(ls, p1); \
+ c.y = luaL_checkint(ls, p2); \
+ if (!in_bounds(c)) \
+ luaL_error( \
+ ls, \
+ make_stringf("Point (%d,%d) is out of map bounds", \
+ c.x, c.y).c_str());
+
+#define FEAT(f, pos) \
+ dungeon_feature_type f = _check_lua_feature(ls, pos)
+
void dgn_reset_default_depth()
{
lc_default_depths.clear();
@@ -786,8 +820,11 @@ static int dgn_item(lua_State *ls)
static int dgn_lua_marker(lua_State *ls)
{
MAP(ls, 1, map);
- if (lua_gettop(ls) != 3 || !lua_isstring(ls, 2) || !lua_isfunction(ls, 3))
- luaL_error(ls, "Expected marker key and marker function.");
+ if (lua_gettop(ls) != 3 || !lua_isstring(ls, 2)
+ || (!lua_isfunction(ls, 3) && !lua_istable(ls, 3)))
+ {
+ luaL_error(ls, "Expected marker key and marker function/table.");
+ }
CLua &lvm(CLua::get_vm(ls));
std::string key = lua_tostring(ls, 2);
@@ -871,16 +908,12 @@ static int dgn_welcome(lua_State *ls)
static int dgn_grid(lua_State *ls)
{
- const int x = luaL_checkint(ls, 1), y = luaL_checkint(ls, 2);
- if (!map_bounds(x, y))
- luaL_error(ls,
- make_stringf("(%d,%d) is out of bounds (%d-%d,%d-%d)",
- x, y,
- X_BOUND_1, X_BOUND_2,
- Y_BOUND_1, Y_BOUND_2).c_str());
- if (lua_isnumber(ls, 3))
- grd[x][y] = static_cast<dungeon_feature_type>(luaL_checkint(ls, 3));
- PLUARET(number, grd[x][y]);
+ COORDS(c, 1, 2);
+
+ const dungeon_feature_type feat = _get_lua_feature(ls, 3);
+ if (feat)
+ grd(c) = feat;
+ PLUARET(number, grd(c));
}
static int dgn_max_bounds(lua_State *ls)
@@ -1715,19 +1748,6 @@ static int dgn_apply_area_cloud(lua_State *ls)
return (0);
}
-static dungeon_feature_type _get_lua_feature(lua_State *ls, int idx)
-{
- dungeon_feature_type feat = (dungeon_feature_type)0;
- if (lua_isnumber(ls, idx))
- feat = (dungeon_feature_type)luaL_checkint(ls, idx);
- else if (lua_isstring(ls, idx))
- feat = dungeon_feature_by_name(luaL_checkstring(ls, idx));
- else
- luaL_argerror(ls, idx, "Feature must be a string or a feature index.");
-
- return feat;
-}
-
static void _clamp_to_bounds(int &x, int &y, bool edge_ok = false)
{
const int edge_offset = edge_ok ? 0 : 1;
@@ -1741,12 +1761,7 @@ static int dgn_fill_area(lua_State *ls)
int y1 = luaL_checkint(ls, 2);
int x2 = luaL_checkint(ls, 3);
int y2 = luaL_checkint(ls, 4);
- dungeon_feature_type feat = _get_lua_feature(ls, 5);
- if (!feat)
- {
- luaL_argerror(ls, 5, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type feat = _check_lua_feature(ls, 5);
_clamp_to_bounds(x1, y1);
_clamp_to_bounds(x2, y2);
@@ -1768,18 +1783,8 @@ static int dgn_replace_area(lua_State *ls)
int y1 = luaL_checkint(ls, 2);
int x2 = luaL_checkint(ls, 3);
int y2 = luaL_checkint(ls, 4);
- dungeon_feature_type search = _get_lua_feature(ls, 5);
- if (!search)
- {
- luaL_argerror(ls, 5, "Invalid feature.");
- return 0;
- }
- dungeon_feature_type replace = _get_lua_feature(ls, 6);
- if (!replace)
- {
- luaL_argerror(ls, 6, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type search = _check_lua_feature(ls, 5);
+ dungeon_feature_type replace = _check_lua_feature(ls, 6);
// gracefully handle out of bound areas by truncating them.
_clamp_to_bounds(x1, y1);
@@ -1804,12 +1809,7 @@ static int dgn_octa_room(lua_State *ls)
int x2 = luaL_checkint(ls, 3);
int y2 = luaL_checkint(ls, 4);
int oblique = luaL_checkint(ls, 5);
- dungeon_feature_type fill = _get_lua_feature(ls, 6);
- if (!fill)
- {
- luaL_argerror(ls, 6, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type fill = _check_lua_feature(ls, 6);
spec_room sr;
sr.tl.x = x1;
@@ -1830,12 +1830,7 @@ static int dgn_make_pillars(lua_State *ls)
int scale_x = luaL_checkint(ls, 4);
int big_radius = luaL_checkint(ls, 5);
int pillar_radius = luaL_checkint(ls, 6);
- dungeon_feature_type fill = _get_lua_feature(ls, 8);
- if (!fill)
- {
- luaL_argerror(ls, 8, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type fill = _check_lua_feature(ls, 8);
// [enne] The underscore is for DJGPP's brain damage.
const float _PI = 3.14159265f;
@@ -1862,12 +1857,7 @@ static int dgn_make_square(lua_State *ls)
int center_x = luaL_checkint(ls, 1);
int center_y = luaL_checkint(ls, 2);
int radius = std::abs(luaL_checkint(ls, 3));
- dungeon_feature_type fill = _get_lua_feature(ls, 4);
- if (!fill)
- {
- luaL_argerror(ls, 4, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type fill = _check_lua_feature(ls, 4);
for (int x = -radius; x <= radius; x++)
for (int y = -radius; y <= radius; y++)
@@ -1881,12 +1871,7 @@ static int dgn_make_rounded_square(lua_State *ls)
int center_x = luaL_checkint(ls, 1);
int center_y = luaL_checkint(ls, 2);
int radius = std::abs(luaL_checkint(ls, 3));
- dungeon_feature_type fill = _get_lua_feature(ls, 4);
- if (!fill)
- {
- luaL_argerror(ls, 4, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type fill = _check_lua_feature(ls, 4);
for (int x = -radius; x <= radius; x++)
for (int y = -radius; y <= radius; y++)
@@ -1901,12 +1886,7 @@ static int dgn_make_circle(lua_State *ls)
int center_x = luaL_checkint(ls, 1);
int center_y = luaL_checkint(ls, 2);
int radius = std::abs(luaL_checkint(ls, 3));
- dungeon_feature_type fill = _get_lua_feature(ls, 4);
- if (!fill)
- {
- luaL_argerror(ls, 4, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type fill = _check_lua_feature(ls, 4);
for (int x = -radius; x <= radius; x++)
for (int y = -radius; y <= radius; y++)
@@ -1931,20 +1911,8 @@ static int dgn_replace_first(lua_State *ls)
int y = luaL_checkint(ls, 2);
int dx = luaL_checkint(ls, 3);
int dy = luaL_checkint(ls, 4);
- dungeon_feature_type search = _get_lua_feature(ls, 5);
- if (!search)
- {
- luaL_argerror(ls, 5, "Invalid feature.");
- lua_pushboolean(ls, false);
- return 1;
- }
- dungeon_feature_type replace = _get_lua_feature(ls, 6);
- if (!replace)
- {
- luaL_argerror(ls, 6, "Invalid feature.");
- lua_pushboolean(ls, false);
- return 1;
- }
+ dungeon_feature_type search = _check_lua_feature(ls, 5);
+ dungeon_feature_type replace = _check_lua_feature(ls, 6);
_clamp_to_bounds(x, y);
bool found = false;
@@ -1967,18 +1935,8 @@ static int dgn_replace_first(lua_State *ls)
static int dgn_replace_random(lua_State *ls)
{
- dungeon_feature_type search = _get_lua_feature(ls, 1);
- if (!search)
- {
- luaL_argerror(ls, 1, "Invalid feature.");
- return 0;
- }
- dungeon_feature_type replace = _get_lua_feature(ls, 2);
- if (!replace)
- {
- luaL_argerror(ls, 2, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type search = _check_lua_feature(ls, 1);
+ dungeon_feature_type replace = _check_lua_feature(ls, 2);
int x, y;
do
@@ -2007,12 +1965,7 @@ static int dgn_smear_feature(lua_State *ls)
{
int iterations = luaL_checkint(ls, 1);
bool boxy = lua_toboolean(ls, 2);
- dungeon_feature_type feat = _get_lua_feature(ls, 3);
- if (!feat)
- {
- luaL_argerror(ls, 3, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type feat = _check_lua_feature(ls, 3);
int x1 = luaL_checkint(ls, 4);
int y1 = luaL_checkint(ls, 5);
@@ -2033,13 +1986,7 @@ static int dgn_count_feature_in_box(lua_State *ls)
int y1 = luaL_checkint(ls, 2);
int x2 = luaL_checkint(ls, 3);
int y2 = luaL_checkint(ls, 4);
- dungeon_feature_type feat = _get_lua_feature(ls, 5);
- if (!feat)
- {
- luaL_argerror(ls, 5, "Invalid feature.");
- lua_pushnil(ls);
- return 1;
- }
+ dungeon_feature_type feat = _check_lua_feature(ls, 5);
lua_pushnumber(ls, count_feature_in_box(x1, y1, x2, y2, feat));
return 1;
@@ -2051,13 +1998,7 @@ static int dgn_count_antifeature_in_box(lua_State *ls)
int y1 = luaL_checkint(ls, 2);
int x2 = luaL_checkint(ls, 3);
int y2 = luaL_checkint(ls, 4);
- dungeon_feature_type feat = _get_lua_feature(ls, 5);
- if (!feat)
- {
- luaL_argerror(ls, 5, "Invalid feature.");
- lua_pushnil(ls);
- return 1;
- }
+ dungeon_feature_type feat = _check_lua_feature(ls, 5);
lua_pushnumber(ls, count_antifeature_in_box(x1, y1, x2, y2, feat));
return 1;
@@ -2067,13 +2008,7 @@ static int dgn_count_neighbours(lua_State *ls)
{
int x = luaL_checkint(ls, 1);
int y = luaL_checkint(ls, 2);
- dungeon_feature_type feat = _get_lua_feature(ls, 3);
- if (!feat)
- {
- luaL_argerror(ls, 3, "Invalid feature.");
- lua_pushnil(ls);
- return 1;
- }
+ dungeon_feature_type feat = _check_lua_feature(ls, 3);
lua_pushnumber(ls, count_neighbours(x, y, feat));
return 1;
@@ -2105,18 +2040,34 @@ static int dgn_fill_disconnected_zones(lua_State *ls)
int to_x = luaL_checkint(ls, 3);
int to_y = luaL_checkint(ls, 4);
- dungeon_feature_type feat = _get_lua_feature(ls, 5);
- if (!feat)
- {
- luaL_argerror(ls, 5, "Invalid feature.");
- return 0;
- }
+ dungeon_feature_type feat = _check_lua_feature(ls, 5);
process_disconnected_zones(from_x, from_y, to_x, to_y, true, feat);
return 0;
}
+static int dgn_register_feature_marker(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+ FEAT(feat, 3);
+ env.markers.add( new map_feature_marker(c, feat) );
+ return (0);
+}
+
+static int dgn_register_lua_marker(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+ if (!lua_istable(ls, 3) && !lua_isfunction(ls, 3))
+ return luaL_argerror(ls, 3, "Expected marker table or function");
+
+ lua_datum table(CLua::get_vm(ls), 3, false);
+ map_marker *marker = new map_lua_marker(table);
+ marker->pos = c;
+ env.markers.add(marker);
+ return (0);
+}
+
static int dgn_debug_dump_map(lua_State *ls)
{
const int pos = lua_isuserdata(ls, 1) ? 2 : 1;
@@ -2211,6 +2162,9 @@ static const struct luaL_reg dgn_lib[] =
{ "join_the_dots", dgn_join_the_dots },
{ "fill_disconnected_zones", dgn_fill_disconnected_zones },
+ { "register_feature_marker", dgn_register_feature_marker },
+ { "register_lua_marker", dgn_register_lua_marker },
+
{ "debug_dump_map", dgn_debug_dump_map },
{ NULL, NULL }
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index fb0b1b6a3a..1203d6d483 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -2837,8 +2837,10 @@ std::string shuffle_spec::describe() const
std::string map_marker_spec::apply_transform(map_lines &map)
{
std::vector<coord_def> positions = map.find_glyph(key);
+
+ // Markers with no key are not an error.
if (positions.empty())
- return make_stringf("cant find key '%c' for marker", key);
+ return ("");
for (int i = 0, size = positions.size(); i < size; ++i)
{
diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc
index ecbed091e3..269b973cbf 100644
--- a/crawl-ref/source/mapmark.cc
+++ b/crawl-ref/source/mapmark.cc
@@ -170,7 +170,7 @@ map_lua_marker::map_lua_marker(const lua_datum &fn)
{
lua_stack_cleaner clean(dlua);
fn.push();
- if (!dlua.callfn("dgn_run_map", 1, 1))
+ if (fn.is_function() && !dlua.callfn("dgn_run_map", 1, 1))
mprf(MSGCH_ERROR, "lua_marker exec error: %s", dlua.error.c_str());
else
check_register_table();
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index dcf1abb4aa..2498be75ce 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1356,10 +1356,27 @@ static void leaving_level_now()
const std::string newtype =
env.markers.property_at(you.pos(), MAT_ANY, "dst");
+ std::string newname =
+ env.markers.property_at(you.pos(), MAT_ANY, "dstname");
+
dungeon_events.fire_position_event(DET_PLAYER_CLIMBS, you.pos());
dungeon_events.fire_event(DET_LEAVING_LEVEL);
- you.level_type_name = newtype;
+ // Don't clobber level_type_name for stairs in portal vaults.
+ if (you.level_type_name.empty() || !newname.empty()
+ || you.level_type != LEVEL_PORTAL_VAULT)
+ {
+ you.level_type_name = newname;
+ }
+
+ if (you.level_type_tag.empty() || !newtype.empty()
+ || you.level_type != LEVEL_PORTAL_VAULT)
+ {
+ you.level_type_tag = newtype;
+ }
+
+ if (!you.level_type_tag.empty() && you.level_type_name.empty())
+ you.level_type_name = you.level_type_tag;
}
static void set_entry_cause(entry_cause_type default_cause,
@@ -1866,7 +1883,9 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
if (you.level_type != LEVEL_DUNGEON
&& (you.level_type != LEVEL_PANDEMONIUM
- || stair_find != DNGN_TRANSIT_PANDEMONIUM))
+ || stair_find != DNGN_TRANSIT_PANDEMONIUM)
+ && (you.level_type != LEVEL_PORTAL_VAULT
+ || !grid_is_stone_stair(stair_find)))
{
you.level_type = LEVEL_DUNGEON;
}
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 1414019b59..a03e3f1d98 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -852,6 +852,7 @@ static void tag_construct_you(writer &th)
marshallLong(th, you.sage_bonus_degree);
marshallByte(th, you.level_type);
marshallString(th, you.level_type_name);
+ marshallString(th, you.level_type_tag);
marshallByte(th, you.entry_cause);
marshallByte(th, you.entry_cause_god);
marshallByte(th, you.synch_time);
@@ -1012,6 +1013,8 @@ static void tag_construct_you(writer &th)
// minorVersion 7 starts here
marshallByte(th, you.friendly_pickup);
+
+ dlua.callfn("dgn_save_data", "u", &th);
}
static void tag_construct_you_items(writer &th)
@@ -1244,6 +1247,10 @@ static void tag_read_you(reader &th, char minorVersion)
you.sage_bonus_degree = unmarshallLong(th);
you.level_type = static_cast<level_area_type>( unmarshallByte(th) );
you.level_type_name = unmarshallString(th);
+
+ if (minorVersion >= TAG_MINOR_LUADGN)
+ you.level_type_tag = unmarshallString(th);
+
you.entry_cause = static_cast<entry_cause_type>( unmarshallByte(th) );
you.entry_cause_god = static_cast<god_type>( unmarshallByte(th) );
you.synch_time = unmarshallByte(th);
@@ -1408,6 +1415,9 @@ static void tag_read_you(reader &th, char minorVersion)
if (minorVersion >= TAG_MINOR_FPICKUP)
you.friendly_pickup = unmarshallByte(th);
+
+ if (minorVersion >= TAG_MINOR_LUADGN)
+ dlua.callfn("dgn_load_data", "u", &th);
}
static void tag_read_you_items(reader &th, char minorVersion)
diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h
index 3c87a55d17..0f9df30f9c 100644
--- a/crawl-ref/source/tags.h
+++ b/crawl-ref/source/tags.h
@@ -56,7 +56,8 @@ enum tag_minor_version
TAG_MINOR_MPATROL = 8, // Added monster patrol points.
TAG_MINOR_PATHFIND = 9, // Added monster pathfinding.
TAG_MINOR_TRTARGET = 10, // Added travel target.
- TAG_MINOR_VERSION = 10 // Current version
+ TAG_MINOR_LUADGN = 11, // Allow dungeon Lua to persist data.
+ TAG_MINOR_VERSION // Current version
};
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index ce36cd6568..9aa4a9c514 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -3069,10 +3069,9 @@ static std::string _level_description_string()
if (you.level_type == LEVEL_PORTAL_VAULT)
{
- if (you.level_type_name == "bazaar")
- return "- a Bazaar";
-
- return "- a Portal Chamber";
+ if (!you.level_type_name.empty())
+ return "- " + article_a(upcase_first(you.level_type_name));
+ return "- a Portal Chamber";
}
// level_type == LEVEL_DUNGEON