summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJude Brown <bookofjude@users.sourceforge.net>2009-11-19 10:59:18 +1000
committerJude Brown <bookofjude@users.sourceforge.net>2009-11-19 10:59:18 +1000
commitf95ed5801c4bd054caee02425025eef4babeedae (patch)
tree855a0c0544fa8f064e44493dfeaa022ea9d3a9e7
parentd608f8e4951b1f61f1f267315763124920abb900 (diff)
downloadcrawl-ref-f95ed5801c4bd054caee02425025eef4babeedae.tar.gz
crawl-ref-f95ed5801c4bd054caee02425025eef4babeedae.zip
dat/clua/iter.lua: iterators for Lua.
Currently only includes: rectangle_iterator: iterates points between two corners. los_iterator: iterates over currently visible points in LOS. adjacent_iterator: iterates over adjacent points to the center. Most iterators accept a "filter" parameter that is a function which should either return true if the point is acceptable for the iteration, or false if it is not. los_iterator is currently restricted to player LOS rather than actor or monster LOS, but could be expanded at a later date. All of the iterators seem to work as intended: hopefully I haven't made too many mistakes with them.
-rw-r--r--crawl-ref/source/clua.cc1
-rw-r--r--crawl-ref/source/dat/clua/iter.lua176
2 files changed, 177 insertions, 0 deletions
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index 4f25a2d362..d750fc9f09 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -636,6 +636,7 @@ void CLua::init_lua()
lua_register(_state, "require", _clua_require);
execfile("clua/util.lua", true, true);
+ execfile("clua/iter.lua", true, true);
execfile("clua/init.lua", true, true);
if (managed_vm)
diff --git a/crawl-ref/source/dat/clua/iter.lua b/crawl-ref/source/dat/clua/iter.lua
new file mode 100644
index 0000000000..9972a1208c
--- /dev/null
+++ b/crawl-ref/source/dat/clua/iter.lua
@@ -0,0 +1,176 @@
+------------------------------------------------------------------------------
+-- iter.lua:
+-- Iterationeering functions.
+------------------------------------------------------------------------------
+--
+-- Example usage of adjacent_iterator:
+--
+-- function iter.rats()
+-- local i
+-- for i in iter.adjacent_iterator() do
+-- dgn.create_monster(i.x, i.y, "rat")
+-- end
+-- end
+--
+-- The above function will surround the player with rats.
+--
+------------------------------------------------------------------------------
+-- dgn.point iterators.
+-- All functions expect dgn.point parameters, and return dgn.points.
+------------------------------------------------------------------------------
+iter = {}
+
+------------------------------------------------------------------------------
+-- rectangle_iterator
+------------------------------------------------------------------------------
+iter.rectangle_iterator = {}
+
+function iter.rectangle_iterator:_new ()
+ local m = {}
+ setmetatable(m, self)
+ self.__index = self
+ return m
+end
+
+function iter.rectangle_iterator:new (corner1, corner2, filter)
+ if corner1 == nil or corner2 == nil then
+ error("need two corners to a rectangle")
+ end
+
+ if corner2.x < corner1.x then
+ error("corner2's x less than corner1's; did you swap them?")
+ elseif corner2.y < corner1.y then
+ error("corner2's y less than corner1's; did you swap them?")
+ end
+
+ local mt = iter.rectangle_iterator:_new()
+ mt.min_x = corner1.x
+ mt.min_y = corner1.y
+ mt.max_x = corner2.x
+ mt.max_y = corner2.y
+ mt.cur_x = corner1.x - 1
+ mt.cur_y = corner1.y
+ mt.filter = filter or nil
+
+ return mt:iter()
+end
+
+function iter.rectangle_iterator:next()
+ local point = nil
+ repeat
+ if self.cur_x >= self.max_x then
+ self.cur_y = self.cur_y + 1
+ self.cur_x = self.min_x
+ if self.cur_y > self.max_y then
+ point = -1
+ else
+ point = dgn.point(self.cur_x, self.cur_y)
+ if not self:check_filter(point) then
+ point = -2
+ end
+ end
+ else
+ self.cur_x = self.cur_x + 1
+ point = dgn.point(self.cur_x, self.cur_y)
+ if not self:check_filter(point) then
+ point = -2
+ end
+ end
+ if point == -1 then
+ return nil
+ elseif point == -2 then
+ point = nil
+ end
+ until point
+
+ return point
+end
+
+function iter.rectangle_iterator:check_filter(point)
+ if self.filter ~= nil then
+ if self.filter(point) then
+ return true
+ else
+ return false
+ end
+ else
+ return true
+ end
+end
+
+function iter.rectangle_iterator:iter ()
+ return function() return self:next() end, nil, nil
+end
+
+function iter.rect_iterator(top_corner, bottom_corner, filter)
+ return iter.rectangle_iterator:new(top_corner, bottom_corner, filter)
+end
+
+-------------------------------------------------------------------------------
+-- los_iterator
+-------------------------------------------------------------------------------
+
+function iter.los_iterator (include_center, filter, center)
+ local y_x, y_y
+ if center == nil then
+ y_x, y_y = you.pos()
+ else
+ y_x, y_y = center:xy()
+ end
+ local top_corner = dgn.point(y_x - 8, y_y - 8)
+ local bottom_corner = dgn.point(y_x + 8, y_y + 8)
+ local function check_los (point)
+ local _x, _y = point:xy()
+
+ if filter ~= nil then
+ if not filter(point) then
+ return false
+ end
+ end
+
+ if include_center == true and y_x == _x and y_y == y then
+ return true
+ else
+ return false
+ end
+
+ if you.see_cell(_x, _y) then
+ return true
+ else
+ return false
+ end
+
+ end
+ return iter.rect_iterator(top_corner, bottom_corner, check_los)
+end
+
+-------------------------------------------------------------------------------
+-- adjacent_iterator
+-------------------------------------------------------------------------------
+
+function iter.adjacent_iterator (include_center, filter, center)
+ local y_x, y_y
+ if center == nil then
+ y_x, y_y = you.pos()
+ else
+ y_x, y_y = center:xy()
+ end
+ local top_corner = dgn.point(y_x - 1, y_y - 1)
+ local bottom_corner = dgn.point(y_x + 1, y_y + 1)
+ local function check_adj (point)
+ local _x, _y = point:xy()
+
+ if filter ~= nil then
+ if not filter(point) then
+ return false
+ end
+ end
+
+ if include_center ~= true and y_x == _x and y_y == y then
+ return false
+ end
+
+ return true
+ end
+ return iter.rect_iterator(top_corner, bottom_corner, check_adj)
+end