diff --git a/game/engine/Entity.lua b/game/engine/Entity.lua
index 2fb1cd9f6fd51fa3ac0e856b7480a553515933d6..845b878a054a408665924e0093a808c4645fa09d 100644
--- a/game/engine/Entity.lua
+++ b/game/engine/Entity.lua
@@ -18,16 +18,18 @@ function _M:init(t)
 	self.uid = next_uid
 	__uids[self.uid] = self
 
-	self.image = t.image or nil
-	self.display = t.display or '.'
-	self.color_r = t.color_r or 0
-	self.color_g = t.color_g or 0
-	self.color_b = t.color_b or 0
-	self.color_br = t.color_br or -1
-	self.color_bg = t.color_bg or -1
-	self.color_bb = t.color_bb or -1
-	self.block_sight = t.block_sight
-	self.block_move = t.block_move
+	for k, e in pairs(t) do self[k] = e end
+
+	self.image = self.image or nil
+	self.display = self.display or '.'
+	self.color_r = self.color_r or 0
+	self.color_g = self.color_g or 0
+	self.color_b = self.color_b or 0
+	self.color_br = self.color_br or -1
+	self.color_bg = self.color_bg or -1
+	self.color_bb = self.color_bb or -1
+	self.block_sight = self.block_sight or false
+	self.block_move = self.block_move or false
 
 	next_uid = next_uid + 1
 end
diff --git a/game/engine/generator/map/DungeonBuilder.lua b/game/engine/generator/map/DungeonBuilder.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1a93fd51ec18b687c34c10444d3e4664731b0e16
--- /dev/null
+++ b/game/engine/generator/map/DungeonBuilder.lua
@@ -0,0 +1,24 @@
+require "engine.class"
+local Map = require "engine.Map"
+require "engine.Generator"
+module(..., package.seeall, class.inherit(engine.Generator))
+
+function _M:init(map, grid_list, data)
+	engine.Generator.init(self, map)
+	self.floor = grid_list[data.floor]
+	self.wall = grid_list[data.wall]
+	self.up = grid_list[data.up]
+	self.down = grid_list[data.down]
+end
+
+function _M:generate()
+	for i = 0, self.map.w - 1 do for j = 0, self.map.h - 1 do
+		self.map(i, j, Map.TERRAIN, self.wall)
+	end end
+
+
+
+	-- Always starts at 1, 1
+	self.map(1, 1, Map.TERRAIN, self.up)
+	return 1, 1
+end
diff --git a/game/engine/generator/map/Rooms.lua b/game/engine/generator/map/Rooms.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ebc91f694054c595c73adef3e42a17f86ca53c7f
--- /dev/null
+++ b/game/engine/generator/map/Rooms.lua
@@ -0,0 +1,53 @@
+require "engine.class"
+local Map = require "engine.Map"
+require "engine.Generator"
+
+--- Generator that makes a map
+module(..., package.seeall, class.inherit(engine.Generator))
+
+function _M:init(map, grid_list, data)
+	engine.Generator.init(self, map)
+	self.floor = grid_list[data.floor]
+	self.wall = grid_list[data.wall]
+	self.door = grid_list[data.door]
+	self.up = grid_list[data.up]
+	self.down = grid_list[data.down]
+end
+
+function _M:doRooms(room, no, tab)
+	if room.w * room.h >= 60 and room.w >= 5 and room.h >= 5 and not room.no_touch and no > 0 then
+		local sy, sx = rng.range(3, room.h - 2), rng.range(3, room.w - 2)
+		local axis = rng.percent(50)
+		if room.w < (room.h * 3) then axis = true else axis = false end
+		if axis then
+			for z = 0, room.w - 1 do
+				self.map(room.x + z, room.y + sy, Map.TERRAIN, self.wall)
+			end
+			self:doRooms({ y=room.y, x=room.x, h=sy, w=room.w}, no-1,"  "..tab)
+			self:doRooms({ y=room.y + sy + 1, x=room.x, h=room.h - sy - 1, w=room.w}, no-1,"  "..tab)
+		else
+			for z = 0, room.h - 1 do
+				self.map(room.x + sx, room.y + z, Map.TERRAIN, self.wall)
+			end
+			self:doRooms({ y=room.y, x=room.x,      h=room.h, w=sx}, no-1,"  "..tab)
+			self:doRooms({ y=room.y, x=room.x + sx + 1, h=room.h, w=room.w - sx - 1}, no-1,"  "..tab)
+		end
+		self.map(room.x + sx, room.y + sy, Map.TERRAIN, self.door)
+	end
+end
+
+function _M:generate()
+	for i = 0, self.map.w - 1 do for j = 0, self.map.h - 1 do
+		if j == 0 or j == self.map.h - 1 or i == 0 or i == self.map.w - 1 then
+			self.map(i, j, Map.TERRAIN, self.wall)
+		else
+			self.map(i, j, Map.TERRAIN, self.floor)
+		end
+	end end
+
+	self:doRooms({ x=1, y=1, h=self.map.h - 2, w=self.map.w - 2 }, 10, "#")
+
+	-- Always starts at 1, 1
+	self.map(1, 1, Map.TERRAIN, self.up)
+	return 1, 1
+end
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index c162cb39fd1a43b70cfa9e71af9396370898352d..64a9c64d57737e6e7261cef7d319b0050c31600e 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -4,7 +4,6 @@ require "engine.Actor"
 module(..., package.seeall, class.inherit(engine.Actor))
 
 function _M:init(t)
-	t.block_move = _M.bumped
 	self.level = 1
 	self.life = 100
 	self.mana = 100
@@ -27,7 +26,7 @@ function _M:move(x, y, force)
 	return moved
 end
 
-function _M:bumped(x, y, e)
+function _M:block_move(x, y, e)
 	-- Dont bump yourself!
 	if e and e ~= self then
 		game.log("%s attacks %s.", tostring(e.name), tostring(self.name))
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 305ac9f675ffdc8e1780a39511aa8c31c745b6c1..259eacc8e786602162c0e739c41ec1a82781426d 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -20,7 +20,7 @@ end
 function _M:run()
 	self:setupCommands()
 
-	Zone:setup{npc_class="mod.class.NPC", grid_class="engine.Grid", object_class="engine.Entity"}
+	Zone:setup{npc_class="mod.class.NPC", grid_class="mod.class.Grid", object_class="engine.Entity"}
 	Map:setViewPort(self.w, math.floor(self.h * 0.80), 16, 16)
 
 	self.zone = Zone.new("ancient_ruins")
diff --git a/game/modules/tome/class/Grid.lua b/game/modules/tome/class/Grid.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8c9a2029e091b230bdefaf45df4dc66ee9394811
--- /dev/null
+++ b/game/modules/tome/class/Grid.lua
@@ -0,0 +1,17 @@
+require "engine.class"
+require "engine.Grid"
+
+module(..., package.seeall, class.inherit(engine.Grid))
+
+function _M:init(t)
+	engine.Grid.init(self, t)
+end
+
+function _M:block_move(x, y, e)
+	-- Open doors
+	if self.door_opened then
+		game.level.map(x, y, engine.Map.TERRAIN, game.zone.grid_list.DOOR_OPEN)
+		return true
+	end
+	return false
+end
diff --git a/game/modules/tome/data/zones/ancient_ruins/grids.lua b/game/modules/tome/data/zones/ancient_ruins/grids.lua
index ab41eafcec39dcf178b80bfc78563da374c186b9..4defc1458b0a6a6f44fd89ec8e70d9445a0e22c3 100644
--- a/game/modules/tome/data/zones/ancient_ruins/grids.lua
+++ b/game/modules/tome/data/zones/ancient_ruins/grids.lua
@@ -22,5 +22,20 @@ return {
 	block_move = true,
 	block_sight = true,
 },
+{
+	define_as = "DOOR",
+	name = "door",
+	display = '+', color_r=238, color_g=154, color_b=77,
+	block_sight = true,
+	door_opened = "DOOR_OPEN",
+},
+{
+	define_as = "DOOR_OPEN",
+	name = "open door",
+	display = "'", color_r=238, color_g=154, color_b=77,
+	block_move = false,
+	block_sight = false,
+	door_closed = "DOOR",
+},
 
 }
diff --git a/game/modules/tome/data/zones/ancient_ruins/zone.lua b/game/modules/tome/data/zones/ancient_ruins/zone.lua
index b1d3a8201ac41057d9c5d173a086f43c2eaeb283..7b0e31eefde204e95e532041c56a93adcf534a91 100644
--- a/game/modules/tome/data/zones/ancient_ruins/zone.lua
+++ b/game/modules/tome/data/zones/ancient_ruins/zone.lua
@@ -1,20 +1,21 @@
 return {
 	name = "ancient ruins",
 	max_level = 5,
-	width = 26, height = 5,
+	width = 50, height = 30,
 	all_remembered = true,
 	all_lited = true,
 	generator =  {
 		map = {
-			class= "engine.generator.map.Empty",
+			class= "engine.generator.map.Rooms",
 			floor = "FLOOR",
 			wall = "WALL",
 			up = "UP",
 			down = "DOWN",
+			door = "DOOR",
 		},
 		actor = {
 			class = "engine.generator.actor.Random",
-			nb_npc = {6, 6},
+			nb_npc = {10, 20},
 		},
 	}
 }
diff --git a/src/core_lua.c b/src/core_lua.c
index 20a9e667c4345b6b0d3d8144de93d93d9c24c889..864ac034194c0daa31ef41041eaf89d44946450b 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -422,7 +422,15 @@ static int rng_range(lua_State *L)
 static int rng_call(lua_State *L)
 {
 	int x = luaL_checknumber(L, 1);
-	lua_pushnumber(L, rand_div(x));
+	if (lua_isnumber(L, 2))
+	{
+		int y = luaL_checknumber(L, 2);
+		lua_pushnumber(L, x + rand_div(1 + y - x));
+	}
+	else
+	{
+		lua_pushnumber(L, rand_div(x));
+	}
 	return 1;
 }
 
@@ -443,6 +451,13 @@ static int rng_chance(lua_State *L)
 	return 1;
 }
 
+static int rng_percent(lua_State *L)
+{
+	int x = luaL_checknumber(L, 1);
+	lua_pushboolean(L, rand_div(100) < x);
+	return 1;
+}
+
 static const struct luaL_reg rnglib[] =
 {
 	{"__call", rng_call},
@@ -450,6 +465,7 @@ static const struct luaL_reg rnglib[] =
 	{"dice", rng_dice},
 	{"seed", rng_seed},
 	{"chance", rng_chance},
+	{"percent", rng_percent},
 	{NULL, NULL},
 };