summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-26 18:34:19 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-26 18:34:19 +0000
commit21cfdbc39885c510cf562bbd86f5f29cf8e38b3d (patch)
treeb91489672cc2bb9b425425f53f07d498d07cd2e5 /crawl-ref
parent851436e3e120efac69cb0cdb443a4cc3f30976d4 (diff)
downloadcrawl-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.lua56
-rw-r--r--crawl-ref/source/dat/clua/point.lua11
-rw-r--r--crawl-ref/source/dat/clua/util.lua11
-rw-r--r--crawl-ref/source/dat/clua/ziggurat.lua176
-rw-r--r--crawl-ref/source/dat/ziggurat.des5
-rw-r--r--crawl-ref/source/luadgn.cc40
-rw-r--r--crawl-ref/source/mapmark.cc14
-rw-r--r--crawl-ref/source/mapmark.h2
-rw-r--r--crawl-ref/source/stuff.cc2
-rw-r--r--crawl-ref/source/tags.cc9
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)