diff options
author | Darshan Shaligram <dshaligram@users.sourceforge.net> | 2010-01-05 01:31:26 +0530 |
---|---|---|
committer | Darshan Shaligram <dshaligram@users.sourceforge.net> | 2010-01-05 01:34:27 +0530 |
commit | ed85466e0202b396bb8d5469d2babd2a24664afc (patch) | |
tree | dc8803ffada803a7910d1cea36d96361c916f59d | |
parent | e88370a40d2cad80bf114500d42291f11dcff5fb (diff) | |
download | crawl-ref-ed85466e0202b396bb8d5469d2babd2a24664afc.tar.gz crawl-ref-ed85466e0202b396bb8d5469d2babd2a24664afc.zip |
Fix Shoal:$ generation bugs: stairs could be surrounded by deep water, hut entrances could be blocked by rock.
shoal-hut.lua test generates 1k Shoal:$ levels and verifies that the levels pass sanity tests.
-rw-r--r-- | crawl-ref/source/cluautil.cc | 8 | ||||
-rw-r--r-- | crawl-ref/source/cluautil.h | 8 | ||||
-rw-r--r-- | crawl-ref/source/ctest.cc | 8 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/dungeon.lua | 33 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/iter.lua | 17 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/test.lua | 23 | ||||
-rw-r--r-- | crawl-ref/source/dgn-shoals.cc | 49 | ||||
-rw-r--r-- | crawl-ref/source/dlua.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/l_dgn.cc | 124 | ||||
-rw-r--r-- | crawl-ref/source/l_libs.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/main.cc | 1 | ||||
-rw-r--r-- | crawl-ref/source/test/shoal-hut.lua | 98 |
14 files changed, 350 insertions, 43 deletions
diff --git a/crawl-ref/source/cluautil.cc b/crawl-ref/source/cluautil.cc index a9cb1cec7b..d774b3318a 100644 --- a/crawl-ref/source/cluautil.cc +++ b/crawl-ref/source/cluautil.cc @@ -46,12 +46,6 @@ void clua_push_map(lua_State *ls, map_def *map) *mapref = map; } -void clua_push_coord(lua_State *ls, const coord_def &c) -{ - lua_pushnumber(ls, c.x); - lua_pushnumber(ls, c.y); -} - void clua_push_dgn_event(lua_State *ls, const dgn_event *devent) { const dgn_event **de = @@ -110,6 +104,8 @@ int clua_stringtable(lua_State *ls, const std::vector<std::string> &s) return clua_gentable(ls, s, clua_pushcxxstring); } +// Pushes a coord_def as a dgn.point Lua object. Note that this is quite +// different from dlua_pushcoord. int clua_pushpoint(lua_State *ls, const coord_def &pos) { lua_pushnumber(ls, pos.x); diff --git a/crawl-ref/source/cluautil.h b/crawl-ref/source/cluautil.h index 8b3a91937b..60f8f73e14 100644 --- a/crawl-ref/source/cluautil.h +++ b/crawl-ref/source/cluautil.h @@ -104,10 +104,14 @@ inline void dlua_push_userdata(lua_State *ls, T udata, const char *meta) } template <class T> -static void dlua_push_object_type(lua_State *ls, const char *meta, const T &data) +static int dlua_push_object_type(lua_State *ls, const char *meta, const T &data) { T **ptr = clua_new_userdata<T*>(ls, meta); - *ptr = new T(data); + if (ptr) + *ptr = new T(data); + else + lua_pushnil(ls); + return (1); } /* diff --git a/crawl-ref/source/ctest.cc b/crawl-ref/source/ctest.cc index f8a3f74001..cfff5edecb 100644 --- a/crawl-ref/source/ctest.cc +++ b/crawl-ref/source/ctest.cc @@ -75,6 +75,7 @@ namespace crawl_tests { lua_stack_cleaner clean(dlua); luaL_openlib(dlua, "crawl", crawl_test_lib, 0); + dlua.execfile("clua/test.lua", true, true); } bool is_test_selected(const std::string &testname) @@ -119,6 +120,13 @@ namespace crawl_tests init_test_bindings(); + if (crawl_state.tests_selected.empty() + || (crawl_state.tests_selected[0].find("makeitem") != + std::string::npos)) + { + makeitem_tests(); + } + // Get a list of Lua files in test. Order of execution of // tests should be irrelevant. const std::vector<std::string> tests( diff --git a/crawl-ref/source/dat/clua/dungeon.lua b/crawl-ref/source/dat/clua/dungeon.lua index 0a11bdd330..4359733855 100644 --- a/crawl-ref/source/dat/clua/dungeon.lua +++ b/crawl-ref/source/dat/clua/dungeon.lua @@ -182,6 +182,16 @@ function dgn.fnum_map(map) return fnmap end +-- Given a list of feature names, returns a dictionary mapping feature +-- numbers to true. +function dgn.feature_number_set(feature_names) + local dict = { } + for _, name in ipairs(feature_names) do + dict[dgn.fnum(name)] = true + end + return dict +end + -- Replaces all features matching function dgn.replace_feat(rmap) local cmap = dgn.fnum_map(rmap) @@ -197,6 +207,27 @@ function dgn.replace_feat(rmap) end end +function dgn.feature_set_fn(...) + local chosen_features = dgn.feature_number_set({ ... }) + return function (fnum) + return chosen_features[fnum] + end +end + +-- Finds all points in the map satisfying the supplied predicate. +function dgn.find_points(predicate) + local points = { } + for x = 0, dgn.GXM - 1 do + for y = 0, dgn.GYM - 1 do + local p = dgn.point(x, y) + if predicate(p) then + table.insert(points, p) + end + end + end + return points +end + -- Returns a function that returns true if the point specified is -- travel-passable and is not one of the features specified. function dgn.passable_excluding(...) @@ -395,7 +426,7 @@ dgn.good_scrolls = [[ w:10 scroll of acquirement / scroll of acquirement q:2 w:4 / scroll of acquirement q:3 w:1/ w:5 scroll of vorpalise weapon / - w:5 scroll of immolation / + w:5 scroll of immolation / w:5 scroll of vulnerability ]] diff --git a/crawl-ref/source/dat/clua/iter.lua b/crawl-ref/source/dat/clua/iter.lua index d9496bdb3c..e4d1409781 100644 --- a/crawl-ref/source/dat/clua/iter.lua +++ b/crawl-ref/source/dat/clua/iter.lua @@ -136,6 +136,11 @@ function iter.rect_iterator(top_corner, bottom_corner, filter, rvi) return iter.rectangle_iterator:new(top_corner, bottom_corner, filter, rvi) end +function iter.rect_size_iterator(top_corner, size, filter, rvi) + return iter.rect_iterator(top_corner, top_corner + size - dgn.point(1, 1), + filter, rvi) +end + function iter.mons_rect_iterator (top_corner, bottom_corner, filter) return iter.rect_iterator(top_corner, bottom_corner, iter.monster_filter(filter), true) end @@ -212,7 +217,7 @@ function iter.adjacent_iterator (ic, filter, center, rvi) local function check_adj (point) local _x, _y = point:xy() - local npoint = nil + local npoint = point if filter ~= nil then if rvi then @@ -246,8 +251,12 @@ function iter.mons_adjacent_iterator (ic, filter, center) return iter.adjacent_iterator(ic, iter.monster_filter(filter), center, true) end +function iter.adjacent_iterator_to(center, include_center, filter) + return iter.adjacent_iterator(include_center, filter, center, true) +end + ------------------------------------------------------------------------------- --- circle_iterator +-- Circle_iterator ------------------------------------------------------------------------------- function iter.circle_iterator (radius, ic, filter, center, rvi) @@ -449,7 +458,7 @@ end function iter.point_iterator:check_filter(point) if self.filter ~= nil then if self.filter(point) then - if self.rvi then + if self.rvi then return self.filter(point) else return point @@ -513,7 +522,7 @@ end function iter.invent_iterator:check_filter(item) if self.filter ~= nil then if self.filter(item) then - if self.rvi then + if self.rvi then return self.filter(item) else return item diff --git a/crawl-ref/source/dat/clua/test.lua b/crawl-ref/source/dat/clua/test.lua new file mode 100644 index 0000000000..404b2e1d1f --- /dev/null +++ b/crawl-ref/source/dat/clua/test.lua @@ -0,0 +1,23 @@ +-- Support code used primarily for tests. This is loaded only when running +-- tests, not during normal Crawl execution. + +util.namespace('test') + +test.FAILMAP = 'level-fail.map' + +function test.map_assert(condition, message) + if not condition then + debug.dump_map(test.FAILMAP) + assert(false, message .. " (map dumped to " .. test.FAILMAP .. ")") + end + return condition +end + +function test.regenerate_level(place) + if place then + debug.goto_place(place) + end + debug.flush_map_memory() + dgn.reset_level() + debug.generate_level() +end
\ No newline at end of file diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc index 428a6cf90e..3a263cccf3 100644 --- a/crawl-ref/source/dgn-shoals.cc +++ b/crawl-ref/source/dgn-shoals.cc @@ -398,15 +398,36 @@ static void _shoals_furniture(int margin) unwind_var<dungeon_feature_set> vault_exc(dgn_Vault_Excavatable_Feats); dgn_Vault_Excavatable_Feats.insert(DNGN_STONE_WALL); - const coord_def c = _pick_shoals_island(); - // Put all the stairs on one island. - grd(c) = DNGN_STONE_STAIRS_UP_I; - grd(c + coord_def(1, 0)) = DNGN_STONE_STAIRS_UP_II; - grd(c - coord_def(1, 0)) = DNGN_STONE_STAIRS_UP_III; - dgn_excavate(c, dgn_random_direction()); - - const coord_def p = _pick_shoals_island_distant_from(c); - const map_def *vault = random_map_for_tag("shoal_rune"); + int stair_tries = 50; + bool did_place_stairs = false; + coord_def stair_place; + while (stair_tries-- > 0) + { + stair_place = _pick_shoals_island(); + if (grd(stair_place) == DNGN_FLOOR) + { + // Put all the stairs on one island. + grd(stair_place) = DNGN_STONE_STAIRS_UP_I; + grd(stair_place + coord_def(1, 0)) = DNGN_STONE_STAIRS_UP_II; + grd(stair_place - coord_def(1, 0)) = DNGN_STONE_STAIRS_UP_III; + did_place_stairs = true; + break; + } + else + { + _shoals_islands.push_back(stair_place); + } + } + + if (!did_place_stairs) + { + dgn_veto_level(); + return; + } + + const coord_def p = _pick_shoals_island_distant_from(stair_place); + const char *SHOAL_RUNE_HUT = "shoal_rune"; + const map_def *vault = random_map_for_tag(SHOAL_RUNE_HUT); { // Place the rune dgn_map_parameters mp("rune"); @@ -425,7 +446,15 @@ static void _shoals_furniture(int margin) vault = random_map_for_tag("shoal_rune"); while (!vault && --tries > 0); if (vault) - dgn_place_map(vault, false, true, _pick_shoals_island(), 0); + dgn_place_map(vault, false, false, _pick_shoals_island(), 0); + } + + // Fixup pass to connect vaults. + for (int i = 0, size = Level_Vaults.size(); i < size; ++i) + { + vault_placement &vp(Level_Vaults[i]); + if (vp.map.has_tag(SHOAL_RUNE_HUT)) + dgn_dig_vault_loose(vp); } } else diff --git a/crawl-ref/source/dlua.cc b/crawl-ref/source/dlua.cc index 218819a4d5..5583fb3c1c 100644 --- a/crawl-ref/source/dlua.cc +++ b/crawl-ref/source/dlua.cc @@ -273,16 +273,8 @@ void init_dungeon_lua() dluaopen_mapgrd(dlua); dluaopen_monsters(dlua); dluaopen_you(dlua); + dluaopen_dgn(dlua); - luaL_openlib(dlua, "dgn", dgn_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_build_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_event_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_grid_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_item_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_level_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_mons_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_subvault_dlib, 0); - luaL_openlib(dlua, "dgn", dgn_tile_dlib, 0); luaL_openlib(dlua, "feat", feat_dlib, 0); luaL_openlib(dlua, "spells", spells_dlib, 0); luaL_openlib(dlua, "debug", debug_dlib, 0); diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index d432d479ae..71dffc3610 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -978,6 +978,11 @@ static void _dgn_init_vault_excavatable_feats() dgn_Vault_Excavatable_Feats.insert(DNGN_ROCK_WALL); } +void dgn_veto_level() +{ + dgn_level_vetoed = true; +} + void dgn_reset_level() { dgn_level_vetoed = false; @@ -4204,6 +4209,11 @@ bool dgn_place_map(const map_def *mdef, return (did_map); } +void dgn_dig_vault_loose(vault_placement &vp) +{ + _dig_vault_loose(vp, vp.exits); +} + // Places a vault somewhere in an already built level if possible. // Returns true if the vault was successfully placed. static bool _build_secondary_vault(int level_number, const map_def *vault, diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index 9eb1cf0eb2..0bdbac5b50 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -176,6 +176,7 @@ void read_level_connectivity(reader &th); void write_level_connectivity(writer &th); bool builder(int level_number, int level_type); +void dgn_veto_level(); void dgn_flush_map_memory(); @@ -276,6 +277,7 @@ void dgn_replace_area(int sx, int sy, int ex, int ey, unsigned mmask = 0, bool needs_update = false); void dgn_excavate(coord_def dig_at, coord_def dig_dir); +void dgn_dig_vault_loose(vault_placement &vp); coord_def dgn_random_direction(); bool dgn_ensure_vault_placed(bool vault_success, diff --git a/crawl-ref/source/l_dgn.cc b/crawl-ref/source/l_dgn.cc index e0cb80bf33..918c66a452 100644 --- a/crawl-ref/source/l_dgn.cc +++ b/crawl-ref/source/l_dgn.cc @@ -24,6 +24,8 @@ #endif #include "view.h" +const char *VAULT_PLACEMENT_METATABLE = "crawl.vault-placement"; + /////////////////////////////////////////////////////////////////////////// // Lua dungeon bindings (in the dgn table). @@ -653,7 +655,7 @@ static int dgn_has_exit_from(lua_State *ls) return dgn_map_pathfind(ls, 3, &map_flood_finder::has_exit_from); } -static void dlua_push_coord(lua_State *ls, const coord_def &c) +static void dlua_push_coordinates(lua_State *ls, const coord_def &c) { lua_pushnumber(ls, c.x); lua_pushnumber(ls, c.y); @@ -665,7 +667,7 @@ static int dgn_gly_point(lua_State *ls) coord_def c = map->find_first_glyph(*luaL_checkstring(ls, 2)); if (c.x != -1 && c.y != -1) { - dlua_push_coord(ls, c); + dlua_push_coordinates(ls, c); return (2); } return (0); @@ -677,7 +679,7 @@ static int dgn_gly_points(lua_State *ls) std::vector<coord_def> cs = map->find_glyph(*luaL_checkstring(ls, 2)); for (int i = 0, size = cs.size(); i < size; ++i) - dlua_push_coord(ls, cs[i]); + dlua_push_coordinates(ls, cs[i]); return (cs.size() * 2); } @@ -1129,7 +1131,7 @@ static int dgn_random_walk(lua_State *ls) dist_left -= (dir % 2 == 0) ? 1.0 : SQRT_2; } - dlua_push_coord(ls, pos); + dlua_push_coordinates(ls, pos); return (2); } @@ -1377,8 +1379,8 @@ static bool _lua_map_place_valid(const map_def &map, // Push map, pos.x, pos.y, size.x, size.y clua_push_map(ls, const_cast<map_def*>(&map)); - clua_push_coord(ls, c); - clua_push_coord(ls, size); + dlua_push_coordinates(ls, c); + dlua_push_coordinates(ls, size); const int err = lua_pcall(ls, 5, 1, 0); @@ -1527,6 +1529,16 @@ LUAFN(_dgn_map_parameters) return clua_stringtable(ls, map_parameters); } +int dgn_push_vault_placement(lua_State *ls, const vault_placement &vp) +{ + return dlua_push_object_type(ls, VAULT_PLACEMENT_METATABLE, vp); +} + +LUAFN(_dgn_maps_used_here) +{ + return clua_gentable(ls, Level_Vaults, dgn_push_vault_placement); +} + LUAFN(_dgn_find_marker_position_by_prop) { const char *prop = luaL_checkstring(ls, 1); @@ -1534,7 +1546,7 @@ LUAFN(_dgn_find_marker_position_by_prop) lua_gettop(ls) >= 2 ? luaL_checkstring(ls, 2) : ""); const coord_def place = find_marker_position_by_prop(prop, value); if (map_bounds(place)) - clua_push_coord(ls, place); + dlua_push_coordinates(ls, place); else { lua_pushnil(ls); @@ -1602,8 +1614,8 @@ LUAFN(dgn_get_special_room_info) } lua_pushnumber(ls, lua_special_room_level); - dlua_push_coord(ls, lua_special_room_spec.tl); - dlua_push_coord(ls, lua_special_room_spec.br); + dlua_push_coordinates(ls, lua_special_room_spec.tl); + dlua_push_coordinates(ls, lua_special_room_spec.br); return (5); } @@ -1792,6 +1804,8 @@ const struct luaL_reg dgn_dlib[] = { "map_parameters", _dgn_map_parameters }, +{ "maps_used_here", _dgn_maps_used_here }, + { "find_marker_position_by_prop", _dgn_find_marker_position_by_prop }, { "find_marker_positions_by_prop", _dgn_find_marker_positions_by_prop }, { "find_markers_by_prop", _dgn_find_markers_by_prop }, @@ -1805,3 +1819,95 @@ const struct luaL_reg dgn_dlib[] = { NULL, NULL } }; + +#define VP(name) \ + vault_placement &name = \ + **clua_get_userdata<vault_placement*>( \ + ls, VAULT_PLACEMENT_METATABLE) + +LUAFN(_vp_pos) +{ + VP(vp); + clua_pushpoint(ls, vp.pos); + return 1; +} + +LUAFN(_vp_size) +{ + VP(vp); + clua_pushpoint(ls, vp.size); + return 1; +} + +LUAFN(_vp_orient) +{ + VP(vp); + PLUARET(number, vp.orient) +} + +LUAFN(_vp_map) +{ + VP(vp); + clua_push_map(ls, &vp.map); + return 1; +} + +LUAFN(_vp_exits) +{ + VP(vp); + return clua_gentable(ls, vp.exits, clua_pushpoint); +} + +LUAFN(_vp_level_number) +{ + VP(vp); + PLUARET(number, vp.level_number) +} + +LUAFN(_vp_num_runes) +{ + VP(vp); + PLUARET(number, vp.num_runes) +} + +LUAFN(_vp_rune_subst) +{ + VP(vp); + PLUARET(number, vp.rune_subst) +} + +static const luaL_reg dgn_vaultplacement_ops[] = +{ + { "pos", _vp_pos }, + { "size", _vp_size }, + { "orient", _vp_orient }, + { "map", _vp_map }, + { "exits", _vp_exits }, + { "level_number", _vp_level_number }, + { "num_runes", _vp_num_runes }, + { "rune_subst", _vp_rune_subst }, + { NULL, NULL } +}; + +static void _dgn_register_metatables(lua_State *ls) +{ + clua_register_metatable(ls, + VAULT_PLACEMENT_METATABLE, + dgn_vaultplacement_ops, + lua_object_gc<vault_placement*>); +} + +void dluaopen_dgn(lua_State *ls) +{ + _dgn_register_metatables(ls); + + luaL_openlib(ls, "dgn", dgn_dlib, 0); + luaL_openlib(ls, "dgn", dgn_build_dlib, 0); + luaL_openlib(ls, "dgn", dgn_event_dlib, 0); + luaL_openlib(ls, "dgn", dgn_grid_dlib, 0); + luaL_openlib(ls, "dgn", dgn_item_dlib, 0); + luaL_openlib(ls, "dgn", dgn_level_dlib, 0); + luaL_openlib(ls, "dgn", dgn_mons_dlib, 0); + luaL_openlib(ls, "dgn", dgn_subvault_dlib, 0); + luaL_openlib(ls, "dgn", dgn_tile_dlib, 0); +} diff --git a/crawl-ref/source/l_libs.h b/crawl-ref/source/l_libs.h index d09434be0c..d6008ed2c7 100644 --- a/crawl-ref/source/l_libs.h +++ b/crawl-ref/source/l_libs.h @@ -68,7 +68,7 @@ void dluaopen_file(lua_State *ls); void dluaopen_mapgrd(lua_State *ls); void dluaopen_monsters(lua_State *ls); void dluaopen_you(lua_State *ls); - +void dluaopen_dgn(lua_State *ls); /* * Some shared helper functions. diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc index 7de3206765..2854529db9 100644 --- a/crawl-ref/source/main.cc +++ b/crawl-ref/source/main.cc @@ -3792,7 +3792,6 @@ static bool _initialise(void) tiles.initialise_items(); #endif Options.show_more_prompt = false; - makeitem_tests(); crawl_tests::run_tests(true); // Superfluous, just to make it clear that this is the end of // the line. diff --git a/crawl-ref/source/test/shoal-hut.lua b/crawl-ref/source/test/shoal-hut.lua new file mode 100644 index 0000000000..392a57e42d --- /dev/null +++ b/crawl-ref/source/test/shoal-hut.lua @@ -0,0 +1,98 @@ +-- Generates lots of Shoal:$ maps and tests that a) all huts are +-- connected to the exterior b) the stairs are not completely surrounded by +-- deep water. + +local iterations = 1000 + +local isdoor = dgn.feature_set_fn("closed_door", "open_door", "secret_door") +local floor = dgn.fnum("floor") + +local function find_vault_doors(vault) + local doors = { } + local size = vault:size() + if size.x == 0 and size.y == 0 then + return doors + end + for p in iter.rect_size_iterator(vault:pos(), size) do + local thing = dgn.grid(p.x, p.y) + if isdoor(thing) then + table.insert(doors, p) + end + end + return doors +end + +local function shoal_hut_doors() + local maps = dgn.maps_used_here() + test.map_assert(#maps > 0, "No maps used on Shoal:$?") + local doors = { } + for _, vault in ipairs(maps) do + -- Sweep the vault looking for (secret) doors. + local vault_doors = find_vault_doors(vault) + if #vault_doors > 0 then + table.insert(doors, vault_doors) + end + end + test.map_assert(#doors > 0, "No hut doors found on Shoal:$") + return doors +end + +-- The hut door is blocked if there is no adjacent square that is not solid +-- or in a vault. +local function hut_door_blocked(door) + for p in iter.adjacent_iterator_to(door) do + if not feat.is_solid(dgn.grid(p.x, p.y)) then + return false + end + end + return true +end + +local function verify_stair_connected(p) + local function good_square(c) + return dgn.grid(c.x, c.y) == floor + end + local function traversable_square(c) + local dfeat = dgn.grid(c.x, c.y) + return dfeat == floor or feat.is_stone_stair(dfeat) + end + test.map_assert(dgn.find_adjacent_point(p, good_square, traversable_square), + "Stairs not connected at " .. p) +end + +local function verify_stair_connectivity() + local function is_stair(p) + return feat.is_stone_stair(dgn.grid(p.x, p.y)) + end + + local stair_pos = dgn.find_points(is_stair) + test.map_assert(#stair_pos > 0, "No stairs in map?") + + for _, stair in ipairs(stair_pos) do + verify_stair_connected(stair) + end +end + +local function verify_hut_connectivity() + for _, vault_doors in ipairs(shoal_hut_doors()) do + if util.forall(vault_doors, hut_door_blocked) then + for _, door in ipairs(vault_doors) do + dgn.grid(door.x, door.y, "floor_special") + end + test.map_assert(false, "Shoal hut doors blocked") + end + end +end + +local function test_shoal_huts(nlevels) + debug.goto_place("Shoal:$") + for i = 1, nlevels do + crawl.mesclr() + crawl.mpr("Shoal test " .. i .. " of " .. nlevels) + test.regenerate_level() + verify_stair_connectivity() + verify_hut_connectivity() + end +end + +test_shoal_huts(iterations)
\ No newline at end of file |