diff options
author | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-11-26 18:34:19 +0000 |
---|---|---|
committer | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-11-26 18:34:19 +0000 |
commit | 21cfdbc39885c510cf562bbd86f5f29cf8e38b3d (patch) | |
tree | b91489672cc2bb9b425425f53f07d498d07cd2e5 /crawl-ref | |
parent | 851436e3e120efac69cb0cdb443a4cc3f30976d4 (diff) | |
download | crawl-ref-21cfdbc39885c510cf562bbd86f5f29cf8e38b3d.tar.gz crawl-ref-21cfdbc39885c510cf562bbd86f5f29cf8e38b3d.zip |
Attempt to place ziggurat loot vault inside the ziggurat. If the vault doesn't fit, we fall back to generating the loot in the open.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7639 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/source/dat/clua/dungeon.lua | 56 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/point.lua | 11 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/util.lua | 11 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/ziggurat.lua | 176 | ||||
-rw-r--r-- | crawl-ref/source/dat/ziggurat.des | 5 | ||||
-rw-r--r-- | crawl-ref/source/luadgn.cc | 40 | ||||
-rw-r--r-- | crawl-ref/source/mapmark.cc | 14 | ||||
-rw-r--r-- | crawl-ref/source/mapmark.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/stuff.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/tags.cc | 9 |
10 files changed, 239 insertions, 87 deletions
diff --git a/crawl-ref/source/dat/clua/dungeon.lua b/crawl-ref/source/dat/clua/dungeon.lua index f1997af8e6..ef602034a3 100644 --- a/crawl-ref/source/dat/clua/dungeon.lua +++ b/crawl-ref/source/dat/clua/dungeon.lua @@ -29,6 +29,15 @@ function dgn.fnum(name) return fnum end +-- Given a feature name or number, returns a feature number. +function dgn.find_feature_number(name_num) + if type(name_num) == "number" then + return name_num + else + return dgn.fnum(name_num) + end +end + -- Wraps a map_def into a Lua environment (a table) such that -- functions run in the environment (with setfenv) can directly -- address the map with function calls such as name(), tags(), etc. @@ -170,6 +179,20 @@ function dgn.replace_feat(rmap) end 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(...) + local forbidden_features = + util.set(util.map(dgn.find_feature_number, { ... })) + return function (p) + local x, y = p.x, p.y + return dgn.is_passable(x, y) and + not forbidden_features[dgn.grid(x, y)] + end +end + +-- Returns all adjacent points of c which are in_bounds (i.e. excluding the +-- outermost layer of wall) and for which faccept returns true. function dgn.adjacent_points(c, faccept) local plist = { } @@ -179,7 +202,7 @@ function dgn.adjacent_points(c, faccept) } for _, cp in ipairs(compass) do - local p = { x = c.x + cp[1], y = c.y + cp[2] } + local p = dgn.point(c.x + cp[1], c.y + cp[2]) if dgn.in_bounds(p.x, p.y) and faccept(p) then table.insert(plist, p) end @@ -187,19 +210,25 @@ function dgn.adjacent_points(c, faccept) return plist end +-- Returns the closest point p starting from c (including c) for which +-- fcondition(p) is true, without passing through squares for which +-- fpassable(p) is false. If no suitable square is found, returns nil. +-- +-- All points are instances of dgn.point, i.e. a Lua table with x and y keys. +-- +-- fpassable may be omitted, in which case it defaults to dgn.is_passable. function dgn.find_adjacent_point(c, fcondition, fpassable) - local mapped_points = { } + -- Just in case c isn't a real dgn.point - canonicalise. + c = dgn.point(c.x, c.y) - local function pstr(p) - return p.x .. "," .. p.y - end + local mapped_points = { } local function seen(p) - return mapped_points[pstr(p)] + return mapped_points[p:str()] end local function record(p, val) - mapped_points[pstr(p)] = val or 1 + mapped_points[p:str()] = val or 1 end if not fpassable then @@ -246,6 +275,8 @@ function dgn.find_adjacent_point(c, fcondition, fpassable) return nil end +-- Scans the entire map, colouring squares for which fselect(p) +-- returns true with colour. function dgn.colour_map(fselect, colour) for x = 0, dgn.GXM - 1 do for y = 0, dgn.GYM - 1 do @@ -270,6 +301,17 @@ function dgn.rectangle_forall(tl, br, fpred) return true end +-- Sets the grid feature at (x,y) to grid. Optionally, if a marker value +-- is provided, creates a suitable marker at (x,y). +-- +-- marker may be +-- 1) a function, in which case a Lua marker is created that +-- will call the function to create a marker table. +-- 2) a table, in which case a Lua marker is created that uses the table +-- directly as a marker table. +-- 3) anything else, which is assumed to be a feature name or number, and +-- is used to create a feature marker. +-- function dgn.gridmark(x, y, grid, marker) dgn.grid(x, y, grid) if marker then diff --git a/crawl-ref/source/dat/clua/point.lua b/crawl-ref/source/dat/clua/point.lua index a6a8077997..594ab6b984 100644 --- a/crawl-ref/source/dat/clua/point.lua +++ b/crawl-ref/source/dat/clua/point.lua @@ -65,13 +65,14 @@ point_metatable.__unm = function (a) return dgn.point(-a.x, -a.y) end +point_metatable.str = function (p) + return "(" .. p.x .. "," .. p.y .. ")" + end + point_metatable.__concat = function (pre, post) - local function pstr(p) - return "(" .. p.x .. "," .. p.y .. ")" - end if getmetatable(pre) == point_metatable then - return pstr(pre) .. post + return pre:str() .. post else - return pre .. pstr(post) + return pre .. post:str() end end diff --git a/crawl-ref/source/dat/clua/util.lua b/crawl-ref/source/dat/clua/util.lua index cdfa77fbe5..c001be55bc 100644 --- a/crawl-ref/source/dat/clua/util.lua +++ b/crawl-ref/source/dat/clua/util.lua @@ -18,6 +18,15 @@ function util.identity(x) return x end +-- Creates a set (a map of keys to true) from the list supplied. +function util.set(list) + local set = { } + for _, value in ipairs(list) do + set[value] = true + end + return set +end + function util.catlist(...) local res = { } local tables = { ... } @@ -40,7 +49,7 @@ function util.cathash(...) return tables[1] else for _, tab in ipairs(tables) do - for key, val in ipairs(tab) do + for key, val in pairs(tab) do res[key] = val end end diff --git a/crawl-ref/source/dat/clua/ziggurat.lua b/crawl-ref/source/dat/clua/ziggurat.lua index da27272ad9..057b9677c9 100644 --- a/crawl-ref/source/dat/clua/ziggurat.lua +++ b/crawl-ref/source/dat/clua/ziggurat.lua @@ -170,6 +170,21 @@ local function rectangle_dimensions() return x1, y1, x2, y2 end +local function set_floor_colour(colour) + if not zig().level.floor_colour then + zig().level.floor_colour = colour + dgn.change_floor_colour(colour, false) + end +end + +local function set_random_floor_colour() + set_floor_colour( random_floor_colour() ) +end + +local function with_props(spec, props) + return util.cathash({ spec = spec }, props) +end + local function depth_if(spec, fn) return { spec = spec, cond = fn } end @@ -186,34 +201,24 @@ local function depth_lt(lev, spec) end) end -local function set_floor_colour(colour) - if not zig().level.floor_colour then - zig().level.floor_colour = colour - dgn.change_floor_colour(colour, false) - end -end - -local function set_random_floor_colour() - set_floor_colour( random_floor_colour() ) -end - local function monster_creator_fn(arg) local atyp = type(arg) if atyp == "string" then local _, _, branch = string.find(arg, "^place:(%w+):") - return function (x, y, nth) - if branch then - set_floor_colour(dgn.br_floorcol(branch)) - end + local function mspec(x, y, nth) + if branch then + set_floor_colour(dgn.br_floorcol(branch)) + end - return dgn.create_monster(x, y, arg) - end + return dgn.create_monster(x, y, arg) + end + return { fn = mspec } elseif atyp == "table" then - if arg.cond() then - return monster_creator_fn(arg.spec) + if not arg.cond or arg.cond() then + return util.cathash(monster_creator_fn(arg.spec), arg) end - else - return arg + elseif atyp == "function" then + return { fn = arg } end end @@ -223,7 +228,7 @@ local mons_populations = { "deep elf annihilator / deep elf sorcerer / deep elf demonologist", "place:Orc:4 w:120 / orc warlord / orc knight / stone giant", "place:Vault:8", - "place:Slime:6", + with_props("place:Slime:6", { jelly_protect = true }), "place:Snake:5", "place:Lair:10", "place:Tomb:3", @@ -239,6 +244,9 @@ local function mons_random_gen(x, y, nth) local mgen = nil while not mgen do mgen = monster_creator_fn(util.random_from(mons_populations)) + if mgen then + mgen = mgen.fn + end end return mgen(x, y, nth) end @@ -268,34 +276,39 @@ function ziggurat_monster_creators() util.catlist(mons_populations, mons_generators)) end -local function ziggurat_vet_monster(fn) - return function (x, y, nth, hdmax) - for i = 1, 100 do - local mons = fn(x, y, nth) - if mons then - -- Discard zero-exp monsters, and monsters that explode - -- the HD limit. - if mons.experience == 0 or mons.hd > hdmax * 1.3 then - mons.dismiss() - else - if mons.muse == "eats_items" then - zig().level.jelly_protect = true - end - -- Monster is ok! - return mons - end - end - end - -- Give up. - return nil - end +local function ziggurat_vet_monster(fmap) + local fn = fmap.fn + fmap.fn = function (x, y, nth, hdmax) + for i = 1, 100 do + local mons = fn(x, y, nth) + if mons then + -- Discard zero-exp monsters, and monsters that explode + -- the HD limit. + if mons.experience == 0 or mons.hd > hdmax * 1.3 then + mons.dismiss() + else + if mons.muse == "eats_items" then + zig().level.jelly_protect = true + end + -- Monster is ok! + return mons + end + end + end + -- Give up. + return nil + end + return fmap end local function choose_monster_set() return ziggurat_vet_monster(util.random_from(ziggurat_monster_creators())) end -local function ziggurat_create_monsters(p) +-- Function to find travel-safe squares, excluding closed doors. +local dgn_passable = dgn.passable_excluding("closed_door") + +local function ziggurat_create_monsters(p, mfn) local depth = zig_depth() local hd_pool = depth * (depth + 8) @@ -303,18 +316,17 @@ local function ziggurat_create_monsters(p) return not dgn.mons_at(point.x, point.y) end - local mfn = choose_monster_set() local nth = 1 - -- No monsters while hd_pool > 0 do - local place = dgn.find_adjacent_point(p, mons_place_p) + local place = dgn.find_adjacent_point(p, mons_place_p, dgn_passable) local mons = mfn(place.x, place.y, nth, hd_pool) if mons then nth = nth + 1 hd_pool = hd_pool - mons.hd else + -- Can't find any suitable monster for the HD we have left. break end end @@ -342,15 +354,10 @@ local function ziggurat_create_loot_at(c) return is_free_space end - local door = dgn.fnum("closed_door") - - local function passable(p) - return dgn.is_passable(p.x, p.y) and dgn.grid(p.x, p.y) ~= door - end - local function free_space_do(fn) for i = 0, 20 do - local p = dgn.find_adjacent_point(c, free_space_threshold(i), passable) + local p = + dgn.find_adjacent_point(c, free_space_threshold(i), dgn_passable) if p then fn(p) break @@ -380,6 +387,14 @@ local function ziggurat_create_loot_at(c) end end +-- Suitable for use in loot vaults. +function ziggurat_loot_spot(e, key) + e.lua_marker(key, portal_desc { ziggurat_loot = "X" }) + e.kfeat(key .. " = .") + e.marker("@ = feat: permarock_wall") + e.kfeat("@ = +") +end + local function ziggurat_create_loot_vault(entry, exit) local inc = (exit - entry):sgn() @@ -390,13 +405,7 @@ local function ziggurat_create_loot_vault(entry, exit) return p end - -- Place a door. - local doorplace = find_door_spot(exit, inc) - - -- Closed door with the permarock wall feature marker. - dgn.gridmark(doorplace.x, doorplace.y, "closed_door", "permarock_wall") - - local connect_point = doorplace + inc + local connect_point = exit - inc * 3 local map = dgn.map_by_tag("ziggurat_loot_chamber", false) @@ -411,16 +420,32 @@ local function ziggurat_create_loot_vault(entry, exit) end local function place_loot_chamber() - return dgn.place_map(map, false, true) + local res = dgn.place_map(map, false, true) + if res then + zig().level.loot_chamber = true + end + return res end local function bad_loot_bounds(map, px, py, xs, ys) local vc = dgn.point(px + math.floor(xs / 2), py + math.floor(ys / 2)) - local linc = (vc - exit):sgn() + + + local function safe_area() + local p = dgn.point(px, py) + local sz = dgn.point(xs, ys) + local floor = dgn.fnum("floor") + return dgn.rectangle_forall(p, p + sz - 1, + function (c) + return dgn.grid(c.x, c.y) == floor + end) + end + + local linc = (exit - vc):sgn() -- The map's positions should be at the same increment to the exit -- as the exit is to the entrance, else reject the place. - return not (inc == linc) + return not (inc == linc) or not safe_area() end local function connect_loot_chamber() @@ -432,7 +457,14 @@ local function ziggurat_create_loot_vault(entry, exit) if not res then loot_fallback() else - ziggurat_create_loot_at(connect_point) + -- Find the square to drop the loot. + local lootx, looty = dgn.find_marker_prop("ziggurat_loot") + + if lootx and looty then + ziggurat_create_loot_at(dgn.point(lootx, looty)) + else + loot_fallback() + end end end @@ -538,12 +570,22 @@ local function ziggurat_rectangle_builder(e) zigstair(exit.x, exit.y + 1, "exit_portal_vault", cleanup_ziggurat()) zigstair(exit.x, exit.y - 1, "exit_portal_vault", cleanup_ziggurat()) - ziggurat_place_pillars(c) + local monster_generation = choose_monster_set() - ziggurat_create_monsters(exit) + -- If we're going to spawn jellies, do our loot protection thing. + if monster_generation.jelly_protect then + zig().level.jelly_protect = true + end ziggurat_create_loot(entry, exit) + if not zig().level.loot_chamber then + -- Place pillars if we did not create a loot chamber. + ziggurat_place_pillars(c) + end + + ziggurat_create_monsters(exit, monster_generation.fn) + local function needs_colour(p) return not dgn.in_vault(p.x, p.y) and dgn.grid(p.x, p.y) == dgn.fnum("stone_wall") diff --git a/crawl-ref/source/dat/ziggurat.des b/crawl-ref/source/dat/ziggurat.des index 59dad4731b..ce01d09f3c 100644 --- a/crawl-ref/source/dat/ziggurat.des +++ b/crawl-ref/source/dat/ziggurat.des @@ -5,7 +5,7 @@ # Most ziggurat code is in ziggurat.lua. # XXX: Ziggurat code is incomplete. -: dofile("clua/ziggurat.lua") +: require("clua/ziggurat.lua") NAME: enter_the_ziggurat # FIXME: Ziggurat is still incomplete - enabled for testing porpoises. @@ -58,10 +58,11 @@ ENDMAP NAME: ziggurat_loot_1 TAGS: ziggurat_loot_chamber allow_dup no_rotate ORIENT: float +: ziggurat_loot_spot(_G, "X") MAP cccccccccccc c..........c -@..........c +@.........Xc c..........c cccccccccccc ENDMAP diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc index d75ea8f2fd..896b882be1 100644 --- a/crawl-ref/source/luadgn.cc +++ b/crawl-ref/source/luadgn.cc @@ -2464,6 +2464,22 @@ LUAFN(_dgn_in_vault) return (1); } +LUAFN(_dgn_find_marker_prop) +{ + const char *prop = luaL_checkstring(ls, 1); + const std::string value( + lua_gettop(ls) >= 2 ? luaL_checkstring(ls, 2) : ""); + const coord_def place = find_marker_prop(prop, value); + if (map_bounds(place)) + clua_push_coord(ls, place); + else + { + lua_pushnil(ls); + lua_pushnil(ls); + } + return (2); +} + extern spec_room lua_special_room_spec; extern int lua_special_room_level; @@ -2678,6 +2694,8 @@ static const struct luaL_reg dgn_lib[] = { "resolve_map", _dgn_resolve_map }, { "in_vault", _dgn_in_vault }, + { "find_marker_prop", _dgn_find_marker_prop }, + { "get_special_room_info", dgn_get_special_room_info }, { "debug_dump_map", dgn_debug_dump_map }, @@ -2703,6 +2721,8 @@ static int file_marshall(lua_State *ls) writer &th(*static_cast<writer*>( lua_touserdata(ls, 1) )); if (lua_isnumber(ls, 2)) marshallLong(th, luaL_checklong(ls, 2)); + else if (lua_isboolean(ls, 2)) + marshallByte(th, lua_toboolean(ls, 2)); else if (lua_isstring(ls, 2)) marshallString(th, lua_tostring(ls, 2)); else if (lua_isfunction(ls, 2)) @@ -2713,6 +2733,15 @@ static int file_marshall(lua_State *ls) return (0); } +static int file_unmarshall_boolean(lua_State *ls) +{ + if (lua_gettop(ls) != 1) + luaL_error(ls, "Need reader as one argument"); + reader &th(*static_cast<reader*>( lua_touserdata(ls, 1) )); + lua_pushboolean(ls, unmarshallByte(th)); + return (1); +} + static int file_unmarshall_number(lua_State *ls) { if (lua_gettop(ls) != 1) @@ -2749,7 +2778,8 @@ enum lua_persist_type LPT_NUMBER, LPT_STRING, LPT_FUNCTION, - LPT_NIL + LPT_NIL, + LPT_BOOLEAN }; static int file_marshall_meta(lua_State *ls) @@ -2762,6 +2792,8 @@ static int file_marshall_meta(lua_State *ls) lua_persist_type ptype = LPT_NONE; if (lua_isnumber(ls, 2)) ptype = LPT_NUMBER; + else if (lua_isboolean(ls, 2)) + ptype = LPT_BOOLEAN; else if (lua_isstring(ls, 2)) ptype = LPT_STRING; else if (lua_isfunction(ls, 2)) @@ -2769,7 +2801,9 @@ static int file_marshall_meta(lua_State *ls) else if (lua_isnil(ls, 2)) ptype = LPT_NIL; else - luaL_error(ls, "Can marshall only numbers, strings and functions."); + luaL_error(ls, + make_stringf("Cannot marshall %s", + lua_typename(ls, lua_type(ls, 2))).c_str()); marshallByte(th, ptype); if (ptype != LPT_NIL) file_marshall(ls); @@ -2783,6 +2817,8 @@ static int file_unmarshall_meta(lua_State *ls) static_cast<lua_persist_type>(unmarshallByte(th)); switch (ptype) { + case LPT_BOOLEAN: + return file_unmarshall_boolean(ls); case LPT_NUMBER: return file_unmarshall_number(ls); case LPT_STRING: diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc index 1d92b09c14..7399515473 100644 --- a/crawl-ref/source/mapmark.cc +++ b/crawl-ref/source/mapmark.cc @@ -819,3 +819,17 @@ bool feature_marker_at(const coord_def &pos, dungeon_feature_type feat) } return (false); } + +const coord_def find_marker_prop(const std::string &prop, + const std::string &expected) +{ + for (rectangle_iterator i(0, 0); i; ++i) + { + const std::string value = + env.markers.property_at(*i, MAT_ANY, prop); + if (!value.empty() && (expected.empty() || value == expected)) + return (*i); + } + const coord_def nowhere(-1, -1); + return (nowhere); +} diff --git a/crawl-ref/source/mapmark.h b/crawl-ref/source/mapmark.h index a0d9a8edaa..67b2c23f75 100644 --- a/crawl-ref/source/mapmark.h +++ b/crawl-ref/source/mapmark.h @@ -26,6 +26,8 @@ class writer; bool marker_vetoes_operation(const char *op); bool feature_marker_at(const coord_def &pos, dungeon_feature_type feat); +const coord_def find_marker_prop(const std::string &prop, + const std::string &expected = ""); class map_marker { diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index 42a3ede04c..dca0e8ab4d 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -141,7 +141,7 @@ rectangle_iterator::rectangle_iterator( int x_border_dist, int y_border_dist ) y_border_dist = x_border_dist; topleft.set( x_border_dist, y_border_dist ); - bottomright.set( GXM - x_border_dist, GYM - y_border_dist ); + bottomright.set( GXM - x_border_dist - 1, GYM - y_border_dist - 1 ); current = topleft; } diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 2ac7e883f3..8c8af99ade 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -1039,7 +1039,8 @@ static void tag_construct_you(writer &th) // minorVersion 7 starts here marshallByte(th, you.friendly_pickup); - dlua.callfn("dgn_save_data", "u", &th); + if (!dlua.callfn("dgn_save_data", "u", &th)) + mprf(MSGCH_ERROR, "Failed to save Lua data: %s", dlua.error.c_str()); } static void tag_construct_you_items(writer &th) @@ -1445,7 +1446,11 @@ static void tag_read_you(reader &th, char minorVersion) you.friendly_pickup = unmarshallByte(th); if (minorVersion >= TAG_MINOR_LUADGN) - dlua.callfn("dgn_load_data", "u", &th); + { + if (!dlua.callfn("dgn_load_data", "u", &th)) + mprf(MSGCH_ERROR, "Failed to load Lua persist table: %s", + dlua.error.c_str()); + } } static void tag_read_you_items(reader &th, char minorVersion) |