summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-24 20:43:26 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-24 20:43:26 +0000
commit376669c4079cfc19380a15b7791f744d06fe0ed1 (patch)
tree51a7bba01b01c48dd5b6a6461a04303e2dab30a2 /crawl-ref/source
parentb369e7edc13b4f3528ffcaa93dfc427281e70758 (diff)
downloadcrawl-ref-376669c4079cfc19380a15b7791f744d06fe0ed1.tar.gz
crawl-ref-376669c4079cfc19380a15b7791f744d06fe0ed1.zip
Add pillars to ziggurat, more utility functions for Lua to handle maps.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7591 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/clua.cc17
-rw-r--r--crawl-ref/source/dat/clua/dungeon.lua18
-rw-r--r--crawl-ref/source/dat/clua/point.lua57
-rw-r--r--crawl-ref/source/dat/clua/util.lua18
-rw-r--r--crawl-ref/source/dat/clua/ziggurat.lua87
-rw-r--r--crawl-ref/source/dat/ziggurat.des10
-rw-r--r--crawl-ref/source/dungeon.cc21
-rw-r--r--crawl-ref/source/dungeon.h19
-rw-r--r--crawl-ref/source/luadgn.cc105
9 files changed, 301 insertions, 51 deletions
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index fac00a74dd..ae30763ab3 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -69,6 +69,7 @@ static int _clua_panic(lua_State *);
static void _clua_throttle_hook(lua_State *, lua_Debug *);
static void *_clua_allocator(void *ud, void *ptr, size_t osize, size_t nsize);
static int _clua_guarded_pcall(lua_State *);
+static int _clua_require(lua_State *);
static int _clua_dofile(lua_State *);
static int _clua_loadfile(lua_State *);
@@ -637,6 +638,8 @@ void CLua::init_lua()
lua_register(_state, "loadfile", _clua_loadfile);
lua_register(_state, "dofile", _clua_dofile);
+ lua_register(_state, "require", _clua_require);
+
execfile("clua/util.lua", true, true);
if (managed_vm)
@@ -2929,6 +2932,20 @@ static int _clua_loadfile(lua_State *ls)
return (1);
}
+static int _clua_require(lua_State *ls)
+{
+ const char *file = luaL_checkstring(ls, 1);
+ if (!file)
+ return (0);
+
+ CLua &vm(CLua::get_vm(ls));
+ if (vm.execfile(file, false, false) != 0)
+ luaL_error(ls, vm.error.c_str());
+
+ lua_pushboolean(ls, true);
+ return (1);
+}
+
static int _clua_dofile(lua_State *ls)
{
const char *file = luaL_checkstring(ls, 1);
diff --git a/crawl-ref/source/dat/clua/dungeon.lua b/crawl-ref/source/dat/clua/dungeon.lua
index 2736e1f372..4c8d5ddc86 100644
--- a/crawl-ref/source/dat/clua/dungeon.lua
+++ b/crawl-ref/source/dat/clua/dungeon.lua
@@ -3,6 +3,8 @@
-- Dungeoneering functions.
------------------------------------------------------------------------------
+require("clua/point.lua")
+
dgn.GXM, dgn.GYM = dgn.max_bounds()
dgn.f_map = { }
@@ -247,13 +249,27 @@ end
function dgn.colour_map(fselect, colour)
for x = 0, dgn.GXM - 1 do
for y = 0, dgn.GYM - 1 do
- if fselect(x, y) then
+ if fselect(dgn.point(x, y)) then
dgn.colour_at(x, y, colour)
end
end
end
end
+-- Returns true if fpred returns true for all squares in the rectangle
+-- whose top-left corner is tl and bottom right corner is br (br.x >=
+-- tl.x and br.y >= tl.y).
+function dgn.rectangle_forall(tl, br, fpred)
+ for x = tl.x, br.x do
+ for y = tl.y, br.y do
+ if not fpred(dgn.point(x, y)) then
+ return false
+ end
+ end
+ end
+ return true
+end
+
----------------------------------------------------------------------
-- Convenience functions for vaults.
diff --git a/crawl-ref/source/dat/clua/point.lua b/crawl-ref/source/dat/clua/point.lua
new file mode 100644
index 0000000000..e57115e033
--- /dev/null
+++ b/crawl-ref/source/dat/clua/point.lua
@@ -0,0 +1,57 @@
+--------------------------------------------------------------------------
+-- point.lua
+--------------------------------------------------------------------------
+
+local point_metatable = { }
+
+function dgn.point(x, y)
+ local pt = { x = x, y = y }
+ setmetatable(pt, point_metatable)
+ return pt
+end
+
+point_metatable.__add = function (a, b)
+ if type(b) == "number" then
+ return dgn.point(a.x + b, a.y + b)
+ else
+ return dgn.point(a.x + b.x, a.y + b.y)
+ end
+ end
+
+point_metatable.__sub = function (a, b)
+ if type(b) == "number" then
+ return dgn.point(a.x - b, a.y - b)
+ else
+ return dgn.point(a.x - b.x, a.y - b.y)
+ end
+ end
+
+point_metatable.__div = function (a, b)
+ if type(b) ~= "number" then
+ error("Can only divide by numbers.")
+ end
+ return dgn.point(math.floor(a.x / b),
+ math.floor(a.y / b))
+ end
+
+point_metatable.__mul = function (a, b)
+ if type(b) ~= "number" then
+ error("Can only multiply by numbers.")
+ end
+ return dgn.point(a.x * b, a.y * b)
+ end
+
+point_metatable.__unm = function (a)
+ return dgn.point(-a.x, -a.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
+ else
+ return pre .. pstr(post)
+ end
+ end
diff --git a/crawl-ref/source/dat/clua/util.lua b/crawl-ref/source/dat/clua/util.lua
index 0c327fd194..950449f94e 100644
--- a/crawl-ref/source/dat/clua/util.lua
+++ b/crawl-ref/source/dat/clua/util.lua
@@ -62,6 +62,24 @@ function util.map(fn, ...)
return res
end
+function util.forall(list, pred)
+ for _, value in ipairs(list) do
+ if not pred(value) then
+ return false
+ end
+ end
+ return true
+end
+
+function util.exists(list, pred)
+ for _, value in ipairs(list) do
+ if pred(value) then
+ return true
+ end
+ end
+ return false
+end
+
function util.random_from(list)
return list[ crawl.random2(#list) + 1 ]
end \ No newline at end of file
diff --git a/crawl-ref/source/dat/clua/ziggurat.lua b/crawl-ref/source/dat/clua/ziggurat.lua
index dbeb8eb001..182f0f6d5e 100644
--- a/crawl-ref/source/dat/clua/ziggurat.lua
+++ b/crawl-ref/source/dat/clua/ziggurat.lua
@@ -309,29 +309,65 @@ end
local function ziggurat_place_pillars(c)
local range = crawl.random_range
+ local floor = dgn.fnum("floor")
- local function pillar_spot()
- local floor = dgn.fnum("floor")
- for i = 1, 100 do
- local place = { x = c.x + range(-30, 30), y = c.y + range(-30, 30) }
- if (dgn.grid(place.x, place.y) == floor) then
- return place
- end
+ local map, vplace = dgn.resolve_map(dgn.map_by_tag("ziggurat_pillar"))
+
+ if not map then
+ return
+ end
+
+ local name = dgn.name(map)
+
+ local size = dgn.point(dgn.mapsize(map))
+
+ -- Does the pillar want to be centered?
+ local centered = string.find(dgn.tags(map), " centered ")
+
+ local function good_place(p)
+ local function good_square(where)
+ return dgn.grid(where.x, where.y) == floor
end
- return nil
+ return dgn.rectangle_forall(p, p + size - 1, good_square)
end
- local function place_pillar(p)
- local map = dgn.map_by_tag("ziggurat_pillar")
- if map then
- dgn.place_map(map, false, true, p.x, p.y)
+ local function place_pillar()
+ if centered then
+ if good_place(c) then
+ return dgn.place_map(map, false, true, c.x, c.y)
+ end
+ else
+ for i = 1, 100 do
+ local offset = range(-15, -size.x)
+ local offsets = {
+ dgn.point(offset, offset) - size + 1,
+ dgn.point(offset - size.x + 1, -offset),
+ dgn.point(-offset, -offset),
+ dgn.point(-offset, offset - size.y + 1)
+ }
+
+ offsets = util.map(function (o)
+ return o + c
+ end, offsets)
+
+ if util.forall(offsets, good_place) then
+ local function replace(at, hflip, vflip)
+ dgn.reuse_map(vplace, at.x, at.y, hflip, vflip)
+ end
+
+ replace(offsets[1], false, false)
+ replace(offsets[2], false, true)
+ replace(offsets[3], true, false)
+ replace(offsets[4], false, true)
+ return true
+ end
+ end
end
end
- for i = 1, crawl.random_range(1,3) do
- local p = pillar_spot()
- if p then
- place_pillar(p)
+ for i = 1, 5 do
+ if place_pillar() then
+ break
end
end
end
@@ -347,11 +383,10 @@ local function ziggurat_rectangle_builder(e)
dgn.fill_area(unpack( util.catlist(flip_rectangle(x1, y1, x2, y2),
{ "floor" }) ) )
- local cx = math.floor((x1 + x2) / 2)
- local cy = math.floor((y1 + y2) / 2)
+ local c = dgn.point(x1 + x2, y1 + y2) / 2
- local entry = { x = x1, y = cy }
- local exit = { x = x2, y = cy }
+ local entry = { x = x1, y = c.y }
+ local exit = { x = x2, y = c.y }
if zig_depth() % 2 == 0 then
entry, exit = exit, entry
@@ -362,16 +397,18 @@ 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 { x = cx, y = cy }
+ ziggurat_place_pillars(c)
ziggurat_create_loot(exit)
ziggurat_create_monsters(exit)
- dgn.colour_map(function (x, y)
- return dgn.grid(x, y) == dgn.fnum("stone_wall")
- end,
- zig().colour)
+ 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")
+ end
+
+ dgn.colour_map(needs_colour, zig().colour)
crawl.mpr("Ziggurat depth is now " .. zig_depth(), "diagnostic")
end
diff --git a/crawl-ref/source/dat/ziggurat.des b/crawl-ref/source/dat/ziggurat.des
index 886f7514f1..e2f30776d3 100644
--- a/crawl-ref/source/dat/ziggurat.des
+++ b/crawl-ref/source/dat/ziggurat.des
@@ -17,6 +17,10 @@ ENDMAP
#######################################################################
# Pillars for ziggurats.
+# Ziggurat pillars are handled specially in ziggurat.lua. In particular:
+# - ziggurat pillars do not need allow_dup. The pillar map is never
+# registered as used.
+# - ziggurat pillars cannot use map markers.
#######################################################################
NAME: ziggurat_pillar_a
TAGS: ziggurat_pillar
@@ -29,18 +33,20 @@ NAME: ziggurat_pillar_b
TAGS: ziggurat_pillar
SUBST: c : cxv
MAP
-cc
+c
cc
ENDMAP
NAME: ziggurat_pillar_c
-TAGS: ziggurat_pillar
+TAGS: ziggurat_pillar centered
MAP
lll
lGl
lll
ENDMAP
+#######################################################################
+
NAME: ziggurat1
: ziggurat_level(_G)
MAP
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 4217c8bcd0..8cde1a11b4 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -236,6 +236,7 @@ static bool _fixup_interlevel_connectivity();
// A mask of vaults and vault-specific flags.
map_mask dgn_Map_Mask;
std::vector<vault_placement> Level_Vaults;
+std::vector<vault_placement> Temp_Vaults;
std::set<std::string> Level_Unique_Maps;
std::set<std::string> Level_Unique_Tags;
std::string dgn_Build_Method;
@@ -298,10 +299,6 @@ bool builder(int level_number, int level_type)
mapgen_report_map_build_start();
#endif
- dgn_level_vetoed = false;
- Level_Unique_Maps.clear();
- Level_Unique_Tags.clear();
-
_reset_level();
// If we're getting low on available retries, disable random vaults
@@ -356,6 +353,7 @@ void level_welcome_messages()
void level_clear_vault_memory()
{
Level_Vaults.clear();
+ Temp_Vaults.clear();
dgn_Map_Mask.init(0);
}
@@ -467,7 +465,7 @@ static void _dgn_register_vault(const map_def &map)
if (!map.has_tag("allow_dup"))
you.uniq_map_names.insert(map.name);
- if (map.has_tag("uniq"))
+ if (map.has_tag("luniq"))
Level_Unique_Maps.insert(map.name);
std::vector<std::string> tags = split_string(" ", map.tags);
@@ -755,9 +753,10 @@ static void _mask_vault(const vault_placement &place, unsigned mask)
}
}
-static void _register_place(const vault_placement &place)
+void dgn_register_place(const vault_placement &place, bool register_vault)
{
- _dgn_register_vault(place.map);
+ if (register_vault)
+ _dgn_register_vault(place.map);
if (!place.map.has_tag("layout"))
_mask_vault(place, MMT_VAULT | MMT_NO_DOOR);
@@ -869,6 +868,10 @@ static bool _valid_dungeon_level(int level_number, int level_type)
static void _reset_level()
{
+ dgn_level_vetoed = false;
+ Level_Unique_Maps.clear();
+ Level_Unique_Tags.clear();
+
dgn_Build_Method.clear();
dgn_Layout_Type.clear();
level_clear_vault_memory();
@@ -3963,7 +3966,7 @@ static bool _build_minivaults(int level_number, const map_def *vault,
mapgen_report_map_use(place.map);
#endif
- _register_place(place);
+ dgn_register_place(place, true);
place.apply_grid();
@@ -4488,7 +4491,7 @@ static bool _build_vaults(int level_number, const map_def *vault,
return (false);
place.apply_grid();
- _register_place(place);
+ dgn_register_place(place, true);
std::vector<coord_def> &target_connections = place.exits;
if (target_connections.empty() && gluggy != MAP_ENCOMPASS)
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index 3d01688f29..e0b2c9b31b 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -50,13 +50,6 @@ const int MAKE_GOOD_ITEM = 351;
typedef FixedArray<unsigned short, GXM, GYM> map_mask;
-extern map_mask dgn_Map_Mask;
-extern bool Generating_Level;
-extern std::string dgn_Layout_Type;
-
-extern std::set<std::string> Level_Unique_Maps;
-extern std::set<std::string> Level_Unique_Tags;
-
// Map mask constants.
enum map_mask_type
@@ -168,6 +161,16 @@ public:
void draw_at(const coord_def &c);
};
+extern map_mask dgn_Map_Mask;
+extern bool Generating_Level;
+extern std::string dgn_Layout_Type;
+
+extern std::set<std::string> Level_Unique_Maps;
+extern std::set<std::string> Level_Unique_Tags;
+
+extern std::vector<vault_placement> Level_Vaults;
+extern std::vector<vault_placement> Temp_Vaults;
+
//////////////////////////////////////////////////////////////////////////
template <typename fgrd, typename bound_check>
class flood_find : public travel_pathfind
@@ -375,6 +378,8 @@ void dgn_set_lt_callback(std::string level_type_name,
// vaults used in the current level).
bool dgn_square_is_passable(const coord_def &c);
+void dgn_register_place(const vault_placement &place, bool register_vault);
+
struct spec_room
{
bool created;
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 483164951d..152368bb6a 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -28,6 +28,7 @@
#include "misc.h"
#include "mon-util.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "tags.h"
#include "terrain.h"
@@ -900,6 +901,14 @@ static int dgn_kmask(lua_State *ls)
return (0);
}
+static int dgn_map_size(lua_State *ls)
+{
+ MAP(ls, 1, map);
+ lua_pushnumber(ls, map->map.width());
+ lua_pushnumber(ls, map->map.height());
+ return (2);
+}
+
static int dgn_name(lua_State *ls)
{
MAP(ls, 1, map);
@@ -1128,7 +1137,8 @@ static int dgn_change_floor_colour(lua_State *ls)
{
const int colour = _lua_colour(ls, 1, BLACK);
env.floor_colour = (unsigned char) colour;
- viewwindow(true, false);
+ if (crawl_state.need_save)
+ viewwindow(true, false);
return (0);
}
@@ -1136,7 +1146,8 @@ static int dgn_change_rock_colour(lua_State *ls)
{
const int colour = _lua_colour(ls, 1, BLACK);
env.rock_colour = (unsigned char) colour;
- viewwindow(true, false);
+ if (crawl_state.need_save)
+ viewwindow(true, false);
return (0);
}
@@ -2230,7 +2241,7 @@ static inline bool _lua_boolean(lua_State *ls, int ndx, bool defval)
static int _lua_push_map(lua_State *ls, const map_def *map)
{
if (map)
- lua_pushlightuserdata(ls, const_cast<map_def*>(map));
+ clua_push_map(ls, const_cast<map_def*>(map));
else
lua_pushnil(ls);
return (1);
@@ -2263,9 +2274,7 @@ LUAFN(dgn_map_by_place)
LUAFN(_dgn_place_map)
{
- if (!lua_isuserdata(ls, 1))
- luaL_argerror(ls, 1, "Expected map");
- const map_def *map = static_cast<map_def *>(lua_touserdata(ls, 1));
+ MAP(ls, 1, map);
const bool clobber = _lua_boolean(ls, 2, false);
const bool no_exits = _lua_boolean(ls, 3, false);
coord_def where(-1, -1);
@@ -2274,10 +2283,88 @@ LUAFN(_dgn_place_map)
COORDS(c, 4, 5);
where = c;
}
- lua_pushboolean(ls, dgn_place_map(map, clobber, no_exits, where));
+ if (dgn_place_map(map, clobber, no_exits, where) && !Level_Vaults.empty())
+ lua_pushlightuserdata(ls, &Level_Vaults[Level_Vaults.size() - 1]);
+ else
+ lua_pushnil(ls);
return (1);
}
+LUAFN(_dgn_in_vault)
+{
+ GETCOORD(c, 1, 2, map_bounds);
+ const int mask = lua_isnone(ls, 3) ? MMT_VAULT : lua_tointeger(ls, 3);
+ lua_pushboolean(ls, dgn_Map_Mask(c) & mask);
+ return (1);
+}
+
+LUAFN(_dgn_resolve_map)
+{
+ if (lua_isnil(ls, 1))
+ {
+ lua_pushnil(ls);
+ return (1);
+ }
+
+ MAP(ls, 1, map);
+ const bool check_collisions = _lua_boolean(ls, 2, true);
+
+ // Save the vault_placement into Temp_Vaults because the map_def
+ // will need to be alive through to the end of dungeon gen.
+ Temp_Vaults.push_back(vault_placement());
+
+ vault_placement &place(Temp_Vaults[Temp_Vaults.size() - 1]);
+
+ if (vault_main(place, map, check_collisions) != MAP_NONE)
+ {
+ clua_push_map(ls, &place.map);
+ lua_pushlightuserdata(ls, &place);
+ }
+ else
+ {
+ lua_pushnil(ls);
+ lua_pushnil(ls);
+ }
+ return (2);
+}
+
+LUAFN(_dgn_reuse_map)
+{
+ if (!lua_isuserdata(ls, 1))
+ luaL_argerror(ls, 1, "Expected vault_placement");
+
+ vault_placement &vp(
+ *static_cast<vault_placement*>(lua_touserdata(ls, 1)));
+
+ COORDS(place, 2, 3);
+
+ const bool flip_horiz = _lua_boolean(ls, 4, false);
+ const bool flip_vert = _lua_boolean(ls, 5, false);
+
+ // 1 for clockwise, -1 for anticlockwise, 0 for no rotation.
+ const int rotate_dir = lua_isnone(ls, 6) ? 0 : luaL_checkint(ls, 6);
+
+ const bool register_place = _lua_boolean(ls, 7, true);
+ const bool register_vault = register_place && _lua_boolean(ls, 8, false);
+
+ if (flip_horiz)
+ vp.map.hmirror();
+ if (flip_vert)
+ vp.map.vmirror();
+ if (rotate_dir)
+ vp.map.rotate(rotate_dir == 1);
+
+ vp.size = vp.map.map.size();
+
+ // draw_at changes vault_placement.
+ vp.draw_at(place);
+
+ if (register_place)
+ dgn_register_place(vp, register_vault);
+
+ return (0);
+}
+
static int dgn_debug_dump_map(lua_State *ls)
{
const int pos = lua_isuserdata(ls, 1) ? 2 : 1;
@@ -2318,6 +2405,7 @@ static const struct luaL_reg dgn_lib[] =
{ "kitem", dgn_kitem },
{ "kmons", dgn_kmons },
{ "kmask", dgn_kmask },
+ { "mapsize", dgn_map_size },
{ "grid", dgn_grid },
{ "max_bounds", dgn_max_bounds },
@@ -2395,6 +2483,9 @@ static const struct luaL_reg dgn_lib[] =
{ "map_in_depth", dgn_map_in_depth },
{ "map_by_place", dgn_map_by_place },
{ "place_map", _dgn_place_map },
+ { "reuse_map", _dgn_reuse_map },
+ { "resolve_map", _dgn_resolve_map },
+ { "in_vault", _dgn_in_vault },
{ "debug_dump_map", dgn_debug_dump_map },