diff --git a/game/engine/Savefile.lua b/game/engine/Savefile.lua
index a6adb5b4e4d2f9036b09ccbe4e8ad60b144accee..ad1a0e174315c78862b8d44673ee9faee818bf07 100644
--- a/game/engine/Savefile.lua
+++ b/game/engine/Savefile.lua
@@ -99,6 +99,20 @@ function _M:saveGame(game)
 	game:unregisterDialog(popup)
 end
 
+--- Save a zone
+function _M:saveZone(zone)
+	fs.mkdir(self.save_dir)
+
+	local popup = Dialog:simplePopup("Saving zone", "Please wait while saving the zone...")
+	core.display.forceRedraw()
+
+	local zip = fs.zipOpen(self.save_dir..("zone-%s.teaz"):format(zone.short_name))
+	self:saveObject(zone, zip)
+	zip:close()
+
+	game:unregisterDialog(popup)
+end
+
 --- Save a level
 function _M:saveLevel(level)
 	fs.mkdir(self.save_dir)
@@ -172,6 +186,30 @@ function _M:loadGame()
 	return loadedGame
 end
 
+--- Loads a zone
+function _M:loadZone(zone)
+	local path = fs.getRealPath(self.save_dir..("zone-%s.teaz"):format(zone))
+	if not path or path == "" then return false end
+
+	fs.mount(path, self.load_dir)
+
+	local popup = Dialog:simplePopup("Loading zone", "Please wait while loading the zone...")
+	core.display.forceRedraw()
+
+	local loadedZone = self:loadReal("main")
+
+	-- Delay loaded must run
+	for i, o in ipairs(self.delayLoad) do
+--		print("loader executed for class", o, o.__CLASSNAME)
+		o:loaded()
+	end
+
+	game:unregisterDialog(popup)
+
+	fs.umount(path)
+	return loadedZone
+end
+
 --- Loads a level
 function _M:loadLevel(zone, level)
 	local path = fs.getRealPath(self.save_dir..("level-%s-%d.teal"):format(zone, level))
diff --git a/game/engine/Zone.lua b/game/engine/Zone.lua
index b5d8a9bbfccdef5bd6835aeaa0f166854fd30948..f9de14c15f1fc105d099392101e41b92f76f0493 100644
--- a/game/engine/Zone.lua
+++ b/game/engine/Zone.lua
@@ -25,24 +25,37 @@ end
 -- @param short_name the short name of the zone to load, if should correspond to a directory in your module data/zones/short_name/ with a zone.lua, npcs.lua, grids.lua and objects.lua files inside
 function _M:init(short_name)
 	self.short_name = short_name
-	self:load()
-	self.level_range = self.level_range or {1,1}
-	if type(self.level_range) == "number" then self.level_range = {self.level_range, self.level_range} end
-	self.level_scheme = self.level_scheme or "fixed"
-	assert(self.max_level, "no zone max level")
-	self.levels = self.levels or {}
-	self.npc_list = self.npc_class:loadList("/data/zones/"..self.short_name.."/npcs.lua")
-	self.grid_list = self.grid_class:loadList("/data/zones/"..self.short_name.."/grids.lua")
-	self.object_list = self.object_class:loadList("/data/zones/"..self.short_name.."/objects.lua")
-	self.trap_list = self.trap_class:loadList("/data/zones/"..self.short_name.."/traps.lua")
-
-	-- Determine a zone base level
-	self.base_level = self.level_range[1]
-	if self.level_scheme == "player" then
-		local plev = game:getPlayer().level
-		self.base_level = util.bound(plev, self.level_range[1], self.level_range[2])
+	if not self:load() then
+		self.level_range = self.level_range or {1,1}
+		if type(self.level_range) == "number" then self.level_range = {self.level_range, self.level_range} end
+		self.level_scheme = self.level_scheme or "fixed"
+		assert(self.max_level, "no zone max level")
+		self.levels = self.levels or {}
+		self.npc_list = self.npc_class:loadList("/data/zones/"..self.short_name.."/npcs.lua")
+		self.grid_list = self.grid_class:loadList("/data/zones/"..self.short_name.."/grids.lua")
+		self.object_list = self.object_class:loadList("/data/zones/"..self.short_name.."/objects.lua")
+		self.trap_list = self.trap_class:loadList("/data/zones/"..self.short_name.."/traps.lua")
+
+		-- Determine a zone base level
+		self.base_level = self.level_range[1]
+		if self.level_scheme == "player" then
+			local plev = game:getPlayer().level
+			self.base_level = util.bound(plev, self.level_range[1], self.level_range[2])
+		end
+		print("Initiated zone", self.name, "with base_level", self.base_level)
+	else
+		print("Loaded zone", self.name, "with base_level", self.base_level)
+	end
+end
+
+--- Leaves a zone
+-- Saves the zone to a .teaz file if requested with persistant="zone" flag
+function _M:leave()
+	if type(self.persistant) == "string" and self.persistant == "zone" then
+		local save = Savefile.new(game.save_name)
+		save:saveZone(self)
+		save:close()
 	end
-	print("Initiated zone", self.name, "with base_level", self.base_level)
 end
 
 --- Parses the npc/objects list and compute rarities for random generation
@@ -246,9 +259,16 @@ function _M:addEntity(level, e, typ, x, y)
 end
 
 function _M:load()
-	local f, err = loadfile("/data/zones/"..self.short_name.."/zone.lua")
-	if err then error(err) end
-	local data = f()
+	-- Try to load from a savefile
+	local save = Savefile.new(game.save_name)
+	local data = save:loadZone(self.short_name)
+	save:close()
+
+	if not data then
+		local f, err = loadfile("/data/zones/"..self.short_name.."/zone.lua")
+		if err then error(err) end
+		data = f()
+	end
 	for k, e in pairs(data) do self[k] = e end
 end
 
@@ -273,7 +293,11 @@ function _M:leaveLevel(no_close, lev, old_lev)
 	if not no_close and game.level and game.level.map then
 		game:leaveLevel(game.level, lev, old_lev)
 
-		if type(game.level.data.persistant) == "string" and game.level.data.persistant == "memory" then
+		if type(game.level.data.persistant) == "string" and game.level.data.persistant == "zone" then
+			print("[LEVEL] persisting to zone memory", game.level.id)
+			self.memory_levels = self.memory_levels or {}
+			self.memory_levels[game.level.level] = game.level
+		elseif type(game.level.data.persistant) == "string" and game.level.data.persistant == "memory" then
 			print("[LEVEL] persisting to memory", game.level.id)
 			game.memory_levels = game.memory_levels or {}
 			game.memory_levels[game.level.id] = game.level
@@ -300,7 +324,18 @@ function _M:getLevel(game, lev, old_lev, no_close)
 
 	local level
 	-- Load persistant level?
-	if type(level_data.persistant) == "string" and level_data.persistant == "memory" then
+	if type(level_data.persistant) == "string" and level_data.persistant == "zone" then
+		self.memory_levels = self.memory_levels or {}
+		level = self.memory_levels[lev]
+
+		if level then
+			-- Setup the level in the game
+			game:setLevel(level)
+			-- Recreate the map because it could have been saved with a different tileset or whatever
+			-- This is not needed in case of a direct to file persistance becuase the map IS recreated each time anyway
+			level.map:recreate()
+		end
+	elseif type(level_data.persistant) == "string" and level_data.persistant == "memory" then
 		game.memory_levels = game.memory_levels or {}
 		level = game.memory_levels[self.short_name.."-"..lev]
 
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 80944b636ac778416d5f0f6d3b7d9cc26716c151..c51778d22fcdc67884109ed8895d05fd89992114 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -195,6 +195,7 @@ function _M:changeLevel(lev, zone)
 	if zone then
 		if self.zone then
 			self.zone:leaveLevel(false, lev, old_lev)
+			self.zone:leave()
 		end
 		self.zone = Zone.new(zone)
 	end
diff --git a/game/modules/tome/data/zones/illusory-castle/zone.lua b/game/modules/tome/data/zones/illusory-castle/zone.lua
index 4f1e51161d469d82a5bf2d54c8f4241ea10df1df..9c7cd7011bcaa3142537198538156c7926ed4dd9 100644
--- a/game/modules/tome/data/zones/illusory-castle/zone.lua
+++ b/game/modules/tome/data/zones/illusory-castle/zone.lua
@@ -7,7 +7,7 @@ return {
 	width = 50, height = 50,
 	all_remembered = true,
 	all_lited = true,
---	persistant = true,
+--	persistant = "zone",
 	generator =  {
 		map = {
 --			class = "engine.generator.map.Rooms",
diff --git a/game/modules/tome/data/zones/maze/zone.lua b/game/modules/tome/data/zones/maze/zone.lua
index a2dd3b01ae97d08ec3aedd402f07d6f7fdbad0ce..96ab6478b4c9163bba59d233d0df680c00cac5cf 100644
--- a/game/modules/tome/data/zones/maze/zone.lua
+++ b/game/modules/tome/data/zones/maze/zone.lua
@@ -7,7 +7,7 @@ return {
 	width = 40, height = 40,
 --	all_remembered = true,
 --	all_lited = true,
-	persistant = true,
+	persistant = "zone",
 	generator =  {
 		map = {
 			class = "engine.generator.map.Maze",
diff --git a/game/modules/tome/data/zones/old-forest/zone.lua b/game/modules/tome/data/zones/old-forest/zone.lua
index f5649345d6e361ad8ab025d784bb8cbee3e80531..05663c6d6f5ec9bba9899a16afb97a12376881b3 100644
--- a/game/modules/tome/data/zones/old-forest/zone.lua
+++ b/game/modules/tome/data/zones/old-forest/zone.lua
@@ -7,7 +7,7 @@ return {
 	width = 50, height = 50,
 --	all_remembered = true,
 	all_lited = true,
-	persistant = true,
+	persistant = "zone",
 	generator =  {
 		map = {
 			class = "engine.generator.map.Roomer",
diff --git a/game/modules/tome/data/zones/sandworm-lair/zone.lua b/game/modules/tome/data/zones/sandworm-lair/zone.lua
index 7d653b216d3525ed1edac217e1125ae1a62af340..2dbd19335f6ad409e34338d56e4a79ba20eefcab 100644
--- a/game/modules/tome/data/zones/sandworm-lair/zone.lua
+++ b/game/modules/tome/data/zones/sandworm-lair/zone.lua
@@ -7,7 +7,7 @@ return {
 	width = 50, height = 50,
 --	all_remembered = true,
 --	all_lited = true,
-	persistant = true,
+	persistant = "zone",
 	generator =  {
 		map = {
 			class = "engine.generator.map.Roomer",
diff --git a/game/modules/tome/data/zones/tol-falas/zone.lua b/game/modules/tome/data/zones/tol-falas/zone.lua
index ac60d8e621feab923f3d0129cdb2758af019360e..4c89a140e2777df35c63ef9c1fc1e19f0267a1b6 100644
--- a/game/modules/tome/data/zones/tol-falas/zone.lua
+++ b/game/modules/tome/data/zones/tol-falas/zone.lua
@@ -7,7 +7,7 @@ return {
 	width = 50, height = 50,
 --	all_remembered = true,
 --	all_lited = true,
-	persistant = true,
+	persistant = "zone",
 	generator =  {
 		map = {
 			class = "engine.generator.map.Roomer",
diff --git a/game/modules/tome/data/zones/tower-amon-sul/zone.lua b/game/modules/tome/data/zones/tower-amon-sul/zone.lua
index b608735ed45b8b4f97e0fa33a2fb72cff3b83bb8..2507490c3e0e1befd2607b6adf7bf4ad7a81d6a0 100644
--- a/game/modules/tome/data/zones/tower-amon-sul/zone.lua
+++ b/game/modules/tome/data/zones/tower-amon-sul/zone.lua
@@ -7,7 +7,7 @@ return {
 	width = 50, height = 50,
 --	all_remembered = true,
 --	all_lited = true,
-	persistant = true,
+	persistant = "zone",
 --	ambiant_music = "10_23.ogg",
 	generator =  {
 		map = {
diff --git a/game/modules/tome/data/zones/trollshaws/zone.lua b/game/modules/tome/data/zones/trollshaws/zone.lua
index c0fa8ac05bd87d608d0f59afff4287f8180d3778..ccceb72085025ba2967ddfeec831abe04bf5abc4 100644
--- a/game/modules/tome/data/zones/trollshaws/zone.lua
+++ b/game/modules/tome/data/zones/trollshaws/zone.lua
@@ -7,7 +7,7 @@ return {
 	width = 50, height = 50,
 --	all_remembered = true,
 	all_lited = true,
-	persistant = true,
+	persistant = "zone",
 	generator =  {
 		map = {
 			class = "engine.generator.map.Roomer",