diff options
Diffstat (limited to 'crawl-ref/source')
-rw-r--r-- | crawl-ref/source/clua.cc | 30 | ||||
-rw-r--r-- | crawl-ref/source/clua.h | 6 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/dungeon.lua | 38 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/lm_1way.lua | 6 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/loadmaps.lua | 2 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/ziggurat.lua | 120 | ||||
-rw-r--r-- | crawl-ref/source/dat/ziggurat.des | 70 | ||||
-rw-r--r-- | crawl-ref/source/debug.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.cc | 81 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 11 | ||||
-rw-r--r-- | crawl-ref/source/luadgn.cc | 218 | ||||
-rw-r--r-- | crawl-ref/source/mapdef.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/mapmark.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 23 | ||||
-rw-r--r-- | crawl-ref/source/tags.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/tags.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/view.cc | 7 |
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 |