diff --git a/game/engines/default/engine/Entity.lua b/game/engines/default/engine/Entity.lua
index ed9bb3c97f2a5fff32846db89198ee231c763402..dad642e16ff379ef1d53988cc627054477143b0b 100644
--- a/game/engines/default/engine/Entity.lua
+++ b/game/engines/default/engine/Entity.lua
@@ -324,6 +324,8 @@ function _M:makeMapObject(tiles, idx)
 		end
 	end
 
+	self._mo, self.z, last_mo = self:alterMakeMapObject(tiles, self._mo, self.z, last_mo)
+
 	-- Setup shader
 	if tiles.use_images and core.shader.active() and self.shader then
 		local shad = Shader.new(self.shader, self.shader_args)
@@ -333,8 +335,6 @@ function _M:makeMapObject(tiles, idx)
 		end
 	end
 
-	self._mo, self.z, last_mo = self:alterMakeMapObject(tiles, self._mo, self.z, last_mo)
-
 	return self._mo, self.z, last_mo
 end
 
diff --git a/game/engines/default/engine/Target.lua b/game/engines/default/engine/Target.lua
index 2b3627bb2a52d1bd97b73fac1a3bd97b9445e941..9009969f83c679650ee3164c18d12de94cd60598 100644
--- a/game/engines/default/engine/Target.lua
+++ b/game/engines/default/engine/Target.lua
@@ -19,6 +19,7 @@
 
 require "engine.class"
 local Map = require "engine.Map"
+local Shader = require "engine.Shader"
 
 --- handles targetting
 module(..., package.seeall, class.make)
@@ -32,34 +33,62 @@ function _M:init(map, source_actor)
 
 	self.cursor = engine.Tiles:loadImage("target_cursor.png"):glTexture()
 	self.arrow = engine.Tiles:loadImage("target_arrow.png"):glTexture()
+	self.targetshader = engine.Tiles:loadImage("ui/targetshader.png"):glTexture()
 
+	self:createTextures()
+
+	self.source_actor = source_actor
+
+	-- Setup the tracking target table
+	-- Notice its values are set to weak references, this has no effects on the number for x and y
+	-- but it means if the entity field is set to an entity, when it disappears this link wont prevent
+	-- the garbage collection
+	self.target = {x=self.source_actor.x, y=self.source_actor.y, entity=nil}
+--	setmetatable(self.target, {__mode='v'})
+end
+
+function _M:createTextures()
 	--Use power of two (pot) width and height, rounded up
-	local pot_width = math.pow(2, math.ceil(math.log(map.tile_w-0.1) / math.log(2.0)))
-	local pot_height = math.pow(2, math.ceil(math.log(map.tile_h-0.1) / math.log(2.0)))
+	local pot_width = math.pow(2, math.ceil(math.log(self.tile_w-0.1) / math.log(2.0)))
+	local pot_height = math.pow(2, math.ceil(math.log(self.tile_h-0.1) / math.log(2.0)))
 	self.sr = core.display.newSurface(pot_width, pot_height)
-	self.sr:erase(255, 0, 0, 90)
+	self.sr:erase(255, 0, 0, self.fbo and 150 or 90)
 	self.sr = self.sr:glTexture()
 	self.sb = core.display.newSurface(pot_width, pot_height)
-	self.sb:erase(0, 0, 255, 90)
+	self.sb:erase(0, 0, 255, self.fbo and 150 or 90)
 	self.sb = self.sb:glTexture()
 	self.sg = core.display.newSurface(pot_width, pot_height)
-	self.sg:erase(0, 255, 0, 90)
+	self.sg:erase(0, 255, 0, self.fbo and 150 or 90)
 	self.sg = self.sg:glTexture()
 	self.sy = core.display.newSurface(pot_width, pot_height)
-	self.sy:erase(255, 255, 0, 90)
+	self.sy:erase(255, 255, 0, self.fbo and 150 or 90)
 	self.sy = self.sy:glTexture()
 	self.syg = core.display.newSurface(pot_width, pot_height)
-	self.syg:erase(153, 204, 50, 90)
+	self.syg:erase(153, 204, 50, self.fbo and 150 or 90)
 	self.syg = self.syg:glTexture()
+end
 
-	self.source_actor = source_actor
+function _M:enableFBORenderer(texture, shader)
+	if not shader then 
+		self.fbo = nil
+		return
+		self:createTextures()
+	end
+	self.fbo = core.display.newFBO(Map.viewport.width, Map.viewport.height)
+	if not self.fbo then
+		self:createTextures()
+		return
+	end
 
-	-- Setup the tracking target table
-	-- Notice its values are set to weak references, this has no effects on the number for x and y
-	-- but it means if the entity field is set to an entity, when it disappears this link wont prevent
-	-- the garbage collection
-	self.target = {x=self.source_actor.x, y=self.source_actor.y, entity=nil}
---	setmetatable(self.target, {__mode='v'})
+	self.fbo_shader = Shader.new(shader)
+	if not self.fbo_shader.shad then
+		self.fbo = nil
+		self:createTextures()
+		return
+	end
+
+	self.targetshader = engine.Tiles:loadImage(texture):glTexture()
+	self:createTextures()
 end
 
 function _M:displayArrow(sx, sy, tx, ty, full)
@@ -77,7 +106,41 @@ function _M:displayArrow(sx, sy, tx, ty, full)
 	core.display.glMatrix(false)
 end
 
-function _M:display(dispx, dispy)
+function _M:display(dispx, dispy, prevfbo)
+	local ox, oy = self.display_x, self.display_y
+	local sx, sy = game.level.map._map:getScroll()
+	sx = sx + game.level.map.display_x
+	sy = sy + game.level.map.display_y
+	self.display_x, self.display_y = dispx or sx or self.display_x, dispy or sy or self.display_y
+	
+	if self.active then
+		if not self.fbo then
+			self:realDisplay(self.display_x, self.display_y)
+		else
+			self.fbo:use(true, 0, 0, 0, 0)
+			self:realDisplay(0, 0)
+			self.fbo:use(false, prevfbo)
+			self.targetshader:bind(1, false)
+			self.fbo_shader.shad:paramNumber2("tileSize", self.tile_w, self.tile_h)
+			self.fbo_shader.shad:paramNumber2("scrollOffset", 0, 0)
+			self.fbo:toScreen(self.display_x, self.display_y, Map.viewport.width, Map.viewport.height, self.fbo_shader.shad, 1, 1, 1, 1, true)
+		end
+
+		if not self.target_type.immediate_keys or firstx then
+			self.cursor:toScreen(self.display_x + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (self.target.y - game.level.map.my + util.hexOffset(self.target.x)) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom)
+		end
+
+		if self.target_type.immediate_keys then
+			for dir, spot in pairs(util.adjacentCoords(self.target_type.start_x, self.target_type.start_y)) do
+				self:displayArrow(self.target_type.start_x, self.target_type.start_y, spot[1], spot[2], firstx == spot[1] and firsty == spot[2])
+			end
+		end
+	end
+
+	self.display_x, self.display_y = ox, oy
+end
+
+function _M:realDisplay(dispx, dispy)
 	-- Make sure we have a source
 	if not self.target_type.source_actor then
 		self.target_type.source_actor = self.source_actor
@@ -92,13 +155,8 @@ function _M:display(dispx, dispy)
 	self.target_type.start_x = self.target_type.start_x or self.target_type.x or self.target_type.source_actor and self.target_type.source_actor.x or self.x
 	self.target_type.start_y = self.target_type.start_y or self.target_type.y or self.target_type.source_actor and self.target_type.source_actor.y or self.y
 
-	local ox, oy = self.display_x, self.display_y
-	local sx, sy = game.level.map._map:getScroll()
-	sx = sx + game.level.map.display_x
-	sy = sy + game.level.map.display_y
-	self.display_x, self.display_y = dispx or sx or self.display_x, dispy or sy or self.display_y
 
---	self.cursor:toScreen(self.display_x + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (self.target.y - game.level.map.my) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom)
+--	self.cursor:toScreen(dispx + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, dispy + (self.target.y - game.level.map.my) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom)
 
 	-- Do not display if not requested
 	if not self.active then return end
@@ -107,16 +165,16 @@ function _M:display(dispx, dispy)
 	if util.isHex() then
 		display_highlight = function(texture, tx, ty)
 			texture:toScreenHighlightHex(
-				self.display_x + (tx - game.level.map.mx) * self.tile_w * Map.zoom,
-				self.display_y + (ty - game.level.map.my + util.hexOffset(tx)) * self.tile_h * Map.zoom,
+				dispx + (tx - game.level.map.mx) * self.tile_w * Map.zoom,
+				dispy + (ty - game.level.map.my + util.hexOffset(tx)) * self.tile_h * Map.zoom,
 				self.tile_w * Map.zoom,
 				self.tile_h * Map.zoom)
 			end
 	else
 		display_highlight = function(texture, tx, ty)
 			texture:toScreen(
-				self.display_x + (tx - game.level.map.mx) * self.tile_w * Map.zoom,
-				self.display_y + (ty - game.level.map.my) * self.tile_h * Map.zoom,
+				dispx + (tx - game.level.map.mx) * self.tile_w * Map.zoom,
+				dispy + (ty - game.level.map.my) * self.tile_h * Map.zoom,
 				self.tile_w * Map.zoom,
 				self.tile_h * Map.zoom)
 			end
@@ -205,9 +263,6 @@ function _M:display(dispx, dispy)
 		end
 
 	end
-	if not self.target_type.immediate_keys or firstx then
-		self.cursor:toScreen(self.display_x + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (self.target.y - game.level.map.my + util.hexOffset(self.target.x)) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom)
-	end
 
 	if self.target_type.ball and self.target_type.ball > 0 then
 		core.fov.calc_circle(
@@ -275,14 +330,6 @@ function _M:display(dispx, dispy)
 			end,
 		nil)
 	end
-
-	if self.target_type.immediate_keys then
-		for dir, spot in pairs(util.adjacentCoords(self.target_type.start_x, self.target_type.start_y)) do
-			self:displayArrow(self.target_type.start_x, self.target_type.start_y, spot[1], spot[2], firstx == spot[1] and firsty == spot[2])
-		end
-	end
-
-	self.display_x, self.display_y = ox, oy
 end
 
 -- @return t The target table used by ActorProject, Projectile, GameTargeting, etc.
diff --git a/game/engines/default/modules/boot/class/Game.lua b/game/engines/default/modules/boot/class/Game.lua
index e7ff4dbe6c0c814ebd93464790be393ff4aa474b..f3ff768e2b77231a6f11c8cb8c2f0d826716c9ef 100644
--- a/game/engines/default/modules/boot/class/Game.lua
+++ b/game/engines/default/modules/boot/class/Game.lua
@@ -142,6 +142,22 @@ Now go and have some fun!]]
 	-- Setup FPS
 	core.game.setFPS(config.settings.display_fps)
 	self:triggerHook{"Boot:runEnd"}
+
+	if not config.settings.upgrades or not config.settings.upgrades.v1_0_5 then
+		if not config.settings.background_saves or config.settings.tome.save_zone_levels then
+			Dialog:simpleLongPopup("Upgrade to 1.0.5", [[The way the engine manages saving has been reworked for v1.0.5.
+
+The background saves should no longer lag horribly and as such it is highly recommended that you use the option. The upgrade turned it on for you.
+
+For the same reason the save per level option should not be used unless you have severe memory problems. The upgrade turned it off for you.
+]], 400)
+		end
+		self:saveSettings("upgrades", "upgrades.v1_0_5 = true\n")
+		self:saveSettings("background_saves", "background_saves = true\n")
+		self:saveSettings("tome.save_zone_levels", "tome.save_zone_levels = false\n")
+		config.settings.background_saves = true
+		config.settings.tome.save_zone_levels = false
+	end
 end
 
 function _M:newGame()
diff --git a/game/engines/default/modules/boot/dialogs/MainMenu.lua b/game/engines/default/modules/boot/dialogs/MainMenu.lua
index 5989e632efd299be33f442a29b77c461ca4ffd2b..a0eca7391141b8eb99ee6cb9e5de02e9792b78c8 100644
--- a/game/engines/default/modules/boot/dialogs/MainMenu.lua
+++ b/game/engines/default/modules/boot/dialogs/MainMenu.lua
@@ -91,8 +91,8 @@ function _M:uiLogin(uis)
 
 	local str = Textzone.new{auto_width=true, auto_height=true, text="#GOLD#Online Profile"}
 	local bt = Button.new{text="Login", width=50, fct=function() self:login() end}
-	self.c_login = Textbox.new{title="Username: ", text="", chars=20, max_len=20, fct=function(text) self:login() end}
-	self.c_pass = Textbox.new{title="Password: ", size_title=self.c_login.title, text="", chars=20, max_len=20, hide=true, fct=function(text) self:login() end}
+	self.c_login = Textbox.new{title="Username: ", text="", chars=16, max_len=20, fct=function(text) self:login() end}
+	self.c_pass = Textbox.new{title="Password: ", size_title=self.c_login.title, text="", chars=16, max_len=20, hide=true, fct=function(text) self:login() end}
 
 	uis[#uis+1] = {left=10, bottom=bt.h + self.c_login.h + self.c_pass.h + str.h, ui=Separator.new{dir="vertical", size=self.iw - 20}}
 	uis[#uis+1] = {hcenter=0, bottom=bt.h + self.c_login.h + self.c_pass.h, ui=str}
@@ -113,7 +113,7 @@ end
 function _M:uiStats(uis)
 	self.logged_url = "http://te4.org/users/"..profile.auth.page
 	local str1 = Textzone.new{auto_width=true, auto_height=true, text="#GOLD#Online Profile#WHITE#"}
-	local str2 = Textzone.new{auto_width=true, auto_height=true, text="View online: #LIGHT_BLUE##{underline}#"..self.logged_url.."#LAST##{normal}#", fct=function() util.browserOpenUrl(self.logged_url) end}
+	local str2 = Textzone.new{auto_width=true, auto_height=true, text="#LIGHT_BLUE##{underline}#"..self.logged_url.."#LAST##{normal}#", fct=function() util.browserOpenUrl(self.logged_url) end}
 
 	local logoff = Textzone.new{text="#LIGHT_BLUE##{underline}#Logout", auto_height=true, width=50, fct=function() self:logout() end}
 
diff --git a/game/engines/default/modules/boot/load.lua b/game/engines/default/modules/boot/load.lua
index ca06ae1fc7424a44a2a21474c3847f0880475823..dac7ae741ace82395e8b9c8ea3f97897868b2433 100644
--- a/game/engines/default/modules/boot/load.lua
+++ b/game/engines/default/modules/boot/load.lua
@@ -29,6 +29,15 @@ local ActorTemporaryEffects = require "engine.interface.ActorTemporaryEffects"
 local Birther = require "engine.Birther"
 local UIBase = require "engine.ui.Base"
 
+UIBase.font = core.display.newFont("/data/font/DroidSans.ttf", 16)
+UIBase.font_bold = core.display.newFont("/data/font/DroidSans.ttf", 16)
+UIBase.font_mono = core.display.newFont("/data/font/DroidSansMono.ttf", 16)
+UIBase.font_bold:setStyle("bold")
+UIBase.font_h = UIBase.font:lineSkip()
+UIBase.font_bold_h = UIBase.font_bold:lineSkip()
+UIBase.font_mono_w = UIBase.font_mono:size(" ")
+UIBase.font_mono_h = UIBase.font_mono:lineSkip()+2
+
 local n = core.noise.new(2)
 _2DNoise = n:makeTexture2D(64, 64)
 
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index b51e98358095e0da5b958946feb085a9636e41bd..6af40442edec35bce7f17b303b7bfff588fcf99e 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -1277,7 +1277,8 @@ function _M:getRankStatAdjust()
 	elseif self.rank == 3.2 then return 0.5
 	elseif self.rank == 3.5 then return 1
 	elseif self.rank == 4 then return 1
-	elseif self.rank >= 5 then return 1
+	elseif self.rank == 5 then return 1
+	elseif self.rank >= 10 then return 2.5
 	else return 0
 	end
 end
@@ -1289,7 +1290,8 @@ function _M:getRankLevelAdjust()
 	elseif self.rank == 3.2 then return 1
 	elseif self.rank == 3.5 then return 2
 	elseif self.rank == 4 then return 3
-	elseif self.rank >= 5 then return 4
+	elseif self.rank == 5 then return 4
+	elseif self.rank >= 10 then return 8
 	else return 0
 	end
 end
@@ -1301,7 +1303,8 @@ function _M:getRankVimAdjust()
 	elseif self.rank == 3.2 then return 1.2
 	elseif self.rank == 3.5 then return 2.2
 	elseif self.rank == 4 then return 2.6
-	elseif self.rank >= 5 then return 2.8
+	elseif self.rank == 5 then return 2.8
+	elseif self.rank >= 10 then return 6
 	else return 0
 	end
 end
@@ -1314,7 +1317,8 @@ function _M:getRankLifeAdjust(value)
 	elseif self.rank == 3.2 then return value * (level_adjust + 0.15)
 	elseif self.rank == 3.5 then return value * (level_adjust + 1)
 	elseif self.rank == 4 then return value * (level_adjust + 2)
-	elseif self.rank >= 5 then return value * (level_adjust + 3)
+	elseif self.rank == 5 then return value * (level_adjust + 3)
+	elseif self.rank >= 10 then return value * (level_adjust + 6)
 	else return 0
 	end
 end
@@ -1326,7 +1330,8 @@ function _M:getRankResistAdjust()
 	elseif self.rank == 3.2 then return 0.8, 1.5
 	elseif self.rank == 3.5 then return 0.9, 1.5
 	elseif self.rank == 4 then return 0.9, 1.5
-	elseif self.rank >= 5 then return 0.9, 1.5
+	elseif self.rank == 5 then return 0.9, 1.5
+	elseif self.rank >= 10 then return 2.5, 3.5
 	else return 0
 	end
 end
@@ -1338,7 +1343,8 @@ function _M:getRankSaveAdjust()
 	elseif self.rank == 3.2 then return 1.3, 1.8
 	elseif self.rank == 3.5 then return 1.5, 2
 	elseif self.rank == 4 then return 1.7, 2.1
-	elseif self.rank >= 5 then return 1.9, 2.3
+	elseif self.rank == 5 then return 1.9, 2.3
+	elseif self.rank >= 10 then return 2.8, 3.5
 	else return 0
 	end
 end
@@ -1351,7 +1357,8 @@ function _M:TextRank()
 	elseif self.rank == 3.2 then rank, color = "rare", "#SALMON#"
 	elseif self.rank == 3.5 then rank, color = "unique", "#SANDY_BROWN#"
 	elseif self.rank == 4 then rank, color = "boss", "#ORANGE#"
-	elseif self.rank >= 5 then rank, color = "elite boss", "#GOLD#"
+	elseif self.rank == 5 then rank, color = "elite boss", "#GOLD#"
+	elseif self.rank >= 10 then rank, color = "god", "#FF4000#"
 	end
 	return rank, color
 end
@@ -3349,34 +3356,34 @@ function _M:learnPool(t)
 
 --	if tt.mana_regen and self.mana_regen == 0 then self.mana_regen = 0.5 end
 
-	if t.type[1]:find("^spell/") and (t.mana or t.sustain_mana) then
+	if t.mana or t.sustain_mana then
 		self:checkPool(t.id, self.T_MANA_POOL)
 	end
-	if t.type[1]:find("^wild%-gift/") and (t.equilibrium or t.sustain_equilibrium) then
+	if t.equilibrium or t.sustain_equilibrium then
 		self:checkPool(t.id, self.T_EQUILIBRIUM_POOL)
 	end
-	if (t.type[1]:find("^technique/") or t.type[1]:find("^cunning/")) and (t.stamina or t.sustain_stamina) then
+	if t.stamina or t.sustain_stamina then
 		self:checkPool(t.id, self.T_STAMINA_POOL)
 	end
-	if t.type[1]:find("^corruption/") and (t.vim or t.sustain_vim) then
+	if t.vim or t.sustain_vim then
 		self:checkPool(t.id, self.T_VIM_POOL)
 	end
-	if t.type[1]:find("^celestial/") and (t.positive or t.sustain_positive) then
+	if t.positive or t.sustain_positive then
 		self:checkPool(t.id, self.T_POSITIVE_POOL)
 	end
-	if t.type[1]:find("^celestial/") and (t.negative or t.sustain_negative) then
+	if t.negative or t.sustain_negative then
 		self:checkPool(t.id, self.T_NEGATIVE_POOL)
 	end
-	if t.type[1]:find("^cursed/") and t.hate then
+	if t.hate then
 		self:checkPool(t.id, self.T_HATE_POOL)
 	end
-	if t.type[1]:find("^chronomancy/") then
+	if t.paradox or t.sustain_paradox then
 		self:checkPool(t.id, self.T_PARADOX_POOL)
 	end
-	if t.type[1]:find("^psionic/") and not (t.type[1]:find("^psionic/feedback") or t.type[1]:find("^psionic/discharge")) then
+	if t.psi or t.sustain_psi then
 		self:checkPool(t.id, self.T_PSI_POOL)
 	end
-	if t.type[1]:find("^psionic/feedback") or t.type[1]:find("^psionic/discharge") then
+	if t.type[1]:find("^psionic/feedback") or t.type[1]:find("^psionic/discharge") or t.feedback or t.sustain_feedback then
 		self:checkPool(t.id, self.T_FEEDBACK_POOL)
 	end
 	-- If we learn an archery talent, also learn to shoot
@@ -4440,10 +4447,11 @@ function _M:removeEffectsFilter(t, nb, silent, force)
 		local e = self.tempeffect_def[eff_id]
 		if type(t) == "function" then 
 			if t(e) then effs[#effs+1] = eff_id end
-		elseif (not t.type or t.type == e.type) and (not t.status or e.status == t.status) then
+		elseif (not t.type or t.type == e.type) and (not t.status or e.status == t.status) and (not t.ignore_crosstier or not e.subtype["cross tier"]) then
 			effs[#effs+1] = eff_id
 		end
 	end
+	table.print(effs)
 
 	while #effs > 0 and nb > 0 do
 		local eff = rng.tableRemove(effs)
diff --git a/game/modules/tome/class/FortressPC.lua b/game/modules/tome/class/FortressPC.lua
index 493179ca2fb6b462969b203f2247d58de7205f32..f5c41a39751a493cf230fed325cd2f17f3b87fca 100644
--- a/game/modules/tome/class/FortressPC.lua
+++ b/game/modules/tome/class/FortressPC.lua
@@ -63,6 +63,9 @@ function _M:init(t, no_default)
 	self:learnTalent(self.T_SHERTUL_FORTRESS_ORBIT, true)
 
 	self:addParticles(Particles.new("shertul_fortress_orbiters", 1, {}))
+	if core.shader.active(4) then
+		self:addParticles(Particles.new("shader_shield", 1, {size_factor=1.8, img="shield5"}, {type="shield", ellipsoidalFactor=1.5, shieldIntensity=0.18, color={0xbe/255, 0x3e/255, 0xf9/255}}))
+	end
 	if core.shader.allow("distort") then self:addParticles(Particles.new("shertul_fortress_engine", 1, {})) end
 end
 
@@ -81,14 +84,7 @@ function _M:defineDisplayCallback()
 
 	local ps = self:getParticlesList()
 
-	local f_self = nil
-	local f_danger = nil
-	local f_powerful = nil
-	local f_friend = nil
-	local f_enemy = nil
-	local f_neutral = nil
-
-	self._mo:displayCallback(function(x, y, w, h, zoom, on_map)
+	local fct = function(x, y, w, h, zoom, on_map)
 		local e
 		for i = 1, #ps do
 			e = ps[i]
@@ -99,7 +95,13 @@ function _M:defineDisplayCallback()
 		end
 
 		return true
-	end)
+	end
+
+	if self._mo == self._last_mo or not self._last_mo then
+		self._mo:displayCallback(fct)
+	else
+		self._last_mo:displayCallback(fct)
+	end
 end
 
 function _M:move(x, y, force)
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 4be7c91631a73d364f5bbd0d2d73562568be4239..d465ae39792df171068b37bd7f6462f27a80e897 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -134,6 +134,7 @@ function _M:runReal()
 	if not self.player then self:newGame() end
 
 	engine.interface.GameTargeting.init(self)
+	if self.target then self.target:enableFBORenderer("ui/targetshader.png", "target_fbo") end
 
 	self.uiset.hotkeys_display.actor = self.player
 	self.uiset.npcs_display.actor = self.player
@@ -515,6 +516,8 @@ function _M:createFBOs()
 	if self.fbo and self.fbo2 then core.particles.defineFramebuffer(self.fbo)
 	else core.particles.defineFramebuffer(nil) end
 
+	if self.target then self.target:enableFBORenderer("ui/targetshader.png", "target_fbo") end
+
 --	self.mm_fbo = core.display.newFBO(200, 200)
 --	if self.mm_fbo then self.mm_fbo_shader = Shader.new("mm_fbo") if not self.mm_fbo_shader.shad then self.mm_fbo = nil self.mm_fbo_shader = nil end end
 end
@@ -1145,8 +1148,9 @@ function _M:tick()
 	end
 
 	if savefile_pipe.saving then self.player.changed = true end
+	if self.on_tick_end and #self.on_tick_end > 0 then return false end -- Force a new tick
+	if self.creating_player then return true end
 	if self.paused and not savefile_pipe.saving then return true end
---	if self.on_tick_end and #self.on_tick_end > 0 then return true end
 end
 
 -- Game Log management functions:
@@ -1358,13 +1362,13 @@ function _M:displayMap(nb_keyframes)
 
 			_2DNoise:bind(1, false)
 			self.fbo2:toScreen(map.display_x, map.display_y, map.viewport.width, map.viewport.height, self.fbo_shader.shad)
-			if self.target then self.target:display() end
+			if self.target then self.target:display(nil, nil, self.full_fbo) end
 
 		-- Basic display; no FBOs
 		else
 			if self.level.data.background then self.level.data.background(self.level, map.display_x, map.display_y, nb_keyframes) end
 			map:display(nil, nil, nb_keyframes, config.settings.tome.smooth_fov)
-			if self.target then self.target:display() end
+			if self.target then self.target:display(nil, nil, self.full_fbo) end
 			if self.level.data.foreground then self.level.data.foreground(self.level, map.display_x, map.display_y, nb_keyframes) end
 			if self.level.data.weather_particle then self.state:displayWeather(self.level, self.level.data.weather_particle, nb_keyframes) end
 			if self.level.data.weather_shader then self.state:displayWeatherShader(self.level, self.level.data.weather_shader, map.display_x, map.display_y, nb_keyframes) end
diff --git a/game/modules/tome/class/interface/PlayerDumpJSON.lua b/game/modules/tome/class/interface/PlayerDumpJSON.lua
index 9a76dd58326f7d8a1a7a049265dc930a35a1a646..76934797684da58388d33577a46f5eff18c3dab1 100644
--- a/game/modules/tome/class/interface/PlayerDumpJSON.lua
+++ b/game/modules/tome/class/interface/PlayerDumpJSON.lua
@@ -48,7 +48,7 @@ function _M:dumpToJSON(js, bypass, nosub)
 
 	local addons = {}
 	for name, add in pairs(game.__mod_info.addons) do
-		addons[#addons+1] = ("%s %d.%d.%d"):format(add.long_name, add.version[1], add.version[2], add.version[3])
+		addons[add.short_name] = ("%s %d.%d.%d"):format(add.long_name, add.version[1], add.version[2], add.version[3])
 	end
 
 	js:newSection("character", {
@@ -421,7 +421,7 @@ function _M:dumpToJSON(js, bypass, nosub)
 		addons[#addons+1] = add.short_name
 	end
 	if #addons > 0 then
-		tags.addons = table.concat(addons, ',')
+		tags.addon = addons
 	end
 
 	if self.has_custom_tile then
diff --git a/game/modules/tome/data/chats/last-hope-lost-merchant.lua b/game/modules/tome/data/chats/last-hope-lost-merchant.lua
index 6f00cb916318037e10768737eedec0f09b220035..96ad3fc77fdc5b21ba1fde36ee8b36c28780f09b 100644
--- a/game/modules/tome/data/chats/last-hope-lost-merchant.lua
+++ b/game/modules/tome/data/chats/last-hope-lost-merchant.lua
@@ -68,110 +68,129 @@ newChat{ id="unique1",
 }
 
 local maker_list = function()
-	local bases = {
-		"elven-silk robe",
-		"drakeskin leather armour",
-		"voratun mail armour",
-		"voratun plate armour",
-		"elven-silk cloak",
-		"drakeskin leather gloves",
-		"voratun gauntlets",
-		"elven-silk wizard hat",
-		"drakeskin leather cap",
-		"voratun helm",
-		"pair of drakeskin leather boots",
-		"pair of voratun boots",
-		"drakeskin leather belt",
-		"voratun ring",
-		"voratun amulet",
-		"dwarven lantern",
-		"voratun battleaxe",
-		"voratun greatmaul",
-		"voratun greatsword",
-		"voratun waraxe",
-		"voratun mace",
-		"voratun longsword",
-		"voratun dagger",
-		"dragonbone longbow",
-		"drakeskin leather sling",
-		"voratun shield",
-		"dragonbone staff",
-		"living mindstar",
+	local mainbases = {
+		armours = {
+			"elven-silk robe",
+			"drakeskin leather armour",
+			"voratun mail armour",
+			"voratun plate armour",
+			"elven-silk cloak",
+			"drakeskin leather gloves",
+			"voratun gauntlets",
+			"elven-silk wizard hat",
+			"drakeskin leather cap",
+			"voratun helm",
+			"pair of drakeskin leather boots",
+			"pair of voratun boots",
+			"drakeskin leather belt",
+			"voratun shield",
+		},
+		weapons = {
+			"voratun battleaxe",
+			"voratun greatmaul",
+			"voratun greatsword",
+			"voratun waraxe",
+			"voratun mace",
+			"voratun longsword",
+			"voratun dagger",
+			"living mindstar",
+			"quiver of dragonbone arrows",
+			"dragonbone longbow",
+			"drakeskin leather sling",
+			"dragonbone staff",
+			"pouch of voratun shots",
+		},
+		misc = {
+			"voratun ring",
+			"voratun amulet",
+			"dwarven lantern",
+			"voratun pickaxe",
+			{"dragonbone wand", "dragonbone wand"},
+			{"dragonbone totem", "dragonbone totem"},
+			{"voratun torque", "voratun torque"},
+		},
 	}
 	local l = {{"I've changed my mind.", jump = "welcome"}}
-	for i, name in ipairs(bases) do
-		
-		local not_ps, force_themes
-		if player:attr("forbid_arcane") then -- no magic gear for antimatic characters
-			not_ps = {arcane=true}
-			force_themes = {'antimagic'}
-		else -- no antimagic gear for characters with arcane-powered classes
-			if player:attr("has_arcane_knowledge") then not_ps = {antimagic=true} end
-		end
-		
---game.log("Force_themes = %s, not_ps = %s", tostring(force_themes), tostring(not_ps and (not_ps.antimagic and "antimagic" or not_ps.arcane and "arcane")))
+	for kind, bases in pairs(mainbases) do
+		l[#l+1] = {kind:capitalize(), action=function(npc, player)
+			local l = {{"I've changed my mind.", jump = "welcome"}}
+			newChat{ id="makereal",
+				text = [[Which kind of item would you like ?]],
+				answers = l,
+			}
 
---	not_ps = table.merge(not_ps or {}, {
---		'physical', 'mental', 'spell', 'defense', 'misc', 'fire', 'technique', 'psionic',
---		'lightning', 'acid', 'mind', 'arcane', 'blight', 'nature',
---		'temporal', 'light', 'dark', 'antimagic'
---	})
-		local o, ok
-		repeat
-			o = game.zone:makeEntity(game.level, "object", {name=name, ignore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}}, nil, true)
-			if o then ok = true end
-			if o and o.power_source and player:attr("forbid_arcane") and o.power_source.arcane then ok = false end
-		until ok
-		if o then
-			l[#l+1] = {o:getName{force_id=true, do_color=true, no_count=true}, action=function(npc, player)
-				local art, ok
-				local nb = 0
+			for i, name in ipairs(bases) do
+				local dname = nil
+				if type(name) == "table" then name, dname = name[1], name[2] end
+				local not_ps, force_themes
+				if player:attr("forbid_arcane") then -- no magic gear for antimatic characters
+					not_ps = {arcane=true}
+					force_themes = {'antimagic'}
+				else -- no antimagic gear for characters with arcane-powered classes
+					if player:attr("has_arcane_knowledge") then not_ps = {antimagic=true} end
+				end
+				
+				local o, ok
 				repeat
-					art = game.state:generateRandart{base=o, lev=70, egos=4, force_themes=force_themes, forbid_power_source=not_ps}
-					if art then ok = true end
-					if art and art.power_source and player:attr("forbid_arcane") and art.power_source.arcane then ok = false end
-					nb = nb + 1
-					if nb == 40 then break end
+					o = game.zone:makeEntity(game.level, "object", {name=name, ignore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}}, nil, true)
+					if o then ok = true end
+					if o and o.power_source and player:attr("forbid_arcane") and o.power_source.arcane then ok = false end
 				until ok
-				if art and nb < 40 then
-					art:identify(true)
-					player:addObject(player.INVEN_INVEN, art)
-					player:incMoney(-4000)
-					-- clear chrono worlds and their various effects
-					if game._chronoworlds then
-						game.log("#CRIMSON#Your timetravel has no effect on pre-determined outcomes such as this.")
-						game._chronoworlds = nil
-					end
-					game:saveGame()
+				if o then
+					if not dname then dname = o:getName{force_id=true, do_color=true, no_count=true}
+					else dname = "#B4B4B4#"..o:getDisplayString()..dname.."#LAST#" end
+					l[#l+1] = {dname, action=function(npc, player)
+						local art, ok
+						local nb = 0
+						repeat
+							art = game.state:generateRandart{base=o, lev=70, egos=4, force_themes=force_themes, forbid_power_source=not_ps}
+							if art then ok = true end
+							if art and art.power_source and player:attr("forbid_arcane") and art.power_source.arcane then ok = false end
+							nb = nb + 1
+							if nb == 40 then break end
+						until ok
+						if art and nb < 40 then
+							art:identify(true)
+							player:addObject(player.INVEN_INVEN, art)
+							player:incMoney(-4000)
+							-- clear chrono worlds and their various effects
+							if game._chronoworlds then
+								game.log("#CRIMSON#Your timetravel has no effect on pre-determined outcomes such as this.")
+								game._chronoworlds = nil
+							end
+							game:saveGame()
 
-					newChat{ id="naming",
-						text = "Do you want to name your item?\n"..tostring(art:getTextualDesc()),
-						answers = {
-							{"Yes, please.", action=function(npc, player)
-								local d = require("engine.dialogs.GetText").new("Name your item", "Name", 2, 40, function(txt)
-									art.name = txt:removeColorCodes():gsub("#", " ")
-									game.log("#LIGHT_BLUE#The merchant carefully hands you: %s", art:getName{do_color=true})
-								end, function() game.log("#LIGHT_BLUE#The merchant carefully hands you: %s", art:getName{do_color=true}) end)
-								game:registerDialog(d)
-							end},
-							{"No thanks.", action=function() game.log("#LIGHT_BLUE#The merchant carefully hands you: %s", art:getName{do_color=true}) end},
-						},
-					}
-					return "naming"
-				else
-					newChat{ id="oups",
-						text = "Oh I am sorry, it seems we could not make the item your require.",
-						answers = {
-							{"Oh, let's try something else then.", jump="make"},
-							{"Oh well, maybe later then."},
-						},
-					}
-					return "oups"
+							newChat{ id="naming",
+								text = "Do you want to name your item?\n"..tostring(art:getTextualDesc()),
+								answers = {
+									{"Yes, please.", action=function(npc, player)
+										local d = require("engine.dialogs.GetText").new("Name your item", "Name", 2, 40, function(txt)
+											art.name = txt:removeColorCodes():gsub("#", " ")
+											game.log("#LIGHT_BLUE#The merchant carefully hands you: %s", art:getName{do_color=true})
+										end, function() game.log("#LIGHT_BLUE#The merchant carefully hands you: %s", art:getName{do_color=true}) end)
+										game:registerDialog(d)
+									end},
+									{"No thanks.", action=function() game.log("#LIGHT_BLUE#The merchant carefully hands you: %s", art:getName{do_color=true}) end},
+								},
+							}
+							return "naming"
+						else
+							newChat{ id="oups",
+								text = "Oh I am sorry, it seems we could not make the item your require.",
+								answers = {
+									{"Oh, let's try something else then.", jump="make"},
+									{"Oh well, maybe later then."},
+								},
+							}
+							return "oups"
+						end
+					end}
 				end
-			end}
-		end
-	end
+			end
 
+			return "makereal"
+		end}
+	end
 	return l
 end
 
diff --git a/game/modules/tome/data/chats/shertul-fortress-gladium-orb.lua b/game/modules/tome/data/chats/shertul-fortress-gladium-orb.lua
new file mode 100644
index 0000000000000000000000000000000000000000..07f685a35a7bc3af880a26c6f9f279d00cfde9c6
--- /dev/null
+++ b/game/modules/tome/data/chats/shertul-fortress-gladium-orb.lua
@@ -0,0 +1,28 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newChat{ id="welcome",
+	text = [[*#LIGHT_GREEN#This orb is used to control the gladium arena.#WHITE#*]],
+	answers = {
+		{"[Go back to the Fortress]", action=function() game:changeLevel(1, "shertul-fortress") end},
+		{"[Leave the orb alone]"},
+	}
+}
+
+return "welcome"
diff --git a/game/modules/tome/data/general/objects/digger.lua b/game/modules/tome/data/general/objects/digger.lua
index ddc4adb49d5da82ad4d7f0b962f27b7988a5863f..df4735dc2ddd48ea560915244726720646a4d836 100644
--- a/game/modules/tome/data/general/objects/digger.lua
+++ b/game/modules/tome/data/general/objects/digger.lua
@@ -35,6 +35,7 @@ newEntity{
 	},
 
 	egos = "/data/general/objects/egos/digger.lua", egos_chance = resolvers.mbonus(10, 5),
+	randart_able = "/data/general/objects/random-artifacts/generic.lua",
 }
 
 newEntity{ base = "BASE_DIGGER",
diff --git a/game/modules/tome/data/general/objects/egos/staves.lua b/game/modules/tome/data/general/objects/egos/staves.lua
index 1cba138bba8911e5ca9bbd9538225840e13a964b..228b889b73078d9f6fbfbd2c3dfdd58f1d3408ff 100644
--- a/game/modules/tome/data/general/objects/egos/staves.lua
+++ b/game/modules/tome/data/general/objects/egos/staves.lua
@@ -348,7 +348,9 @@ newEntity{
 		function(self, who)
 			local tg = {type="ball", range=0, radius=self.material_level + 1, selffire=false}
 			local weapon = who:hasStaffWeapon()
+			if not weapon then return end
 			local combat = weapon.combat
+			if not combat then return end
 
 			local DamageType = require "engine.DamageType"
 			local damtype = combat.damtype
diff --git a/game/modules/tome/data/gfx/shaders/mm_fbo.frag b/game/modules/tome/data/gfx/shaders/mm_fbo.frag
deleted file mode 100644
index 79c44c55d51a9e1860fc78cdc7437fba9054ee90..0000000000000000000000000000000000000000
--- a/game/modules/tome/data/gfx/shaders/mm_fbo.frag
+++ /dev/null
@@ -1,172 +0,0 @@
-//#version 150
-uniform sampler2D Texture0;
-//varying vec2 texCoord;
-
-#define HueLevCount 6
-#define SatLevCount 7
-#define ValLevCount 4
-float[HueLevCount] HueLevels = float[] (0.0,80.0,160.0,240.0,320.0,360.0);
-float[SatLevCount] SatLevels = float[] (0.0,0.15,0.3,0.45,0.6,0.8,1.0);
-float[ValLevCount] ValLevels = float[] (0.0,0.3,0.6,1.0);
-
-vec3 RGBtoHSV( float r, float g, float b) {
-	float minv, maxv, delta;
-	vec3 res;
-
-	minv = min(min(r, g), b);
-	maxv = max(max(r, g), b);
-	res.z = maxv;            // v
-
-	delta = maxv - minv;
-
-	if( maxv != 0.0 )
-		res.y = delta / maxv;      // s
-	else {
-		// r = g = b = 0      // s = 0, v is undefined
-		res.y = 0.0;
-		res.x = -1.0;
-		return res;
-	}
-
-	if( r == maxv )
-		res.x = ( g - b ) / delta;      // between yellow & magenta
-	else if( g == maxv )
-		res.x = 2.0 + ( b - r ) / delta;   // between cyan & yellow
-	else
-		res.x = 4.0 + ( r - g ) / delta;   // between magenta & cyan
-
-	res.x = res.x * 60.0;            // degrees
-	if( res.x < 0.0 )
-		res.x = res.x + 360.0;
-
-	return res;
-}
-
-vec3 HSVtoRGB(float h, float s, float v ) {
-	int i;
-	float f, p, q, t;
-	vec3 res;
-
-	if( s == 0.0 ) {
-		// achromatic (grey)
-		res.x = v;
-		res.y = v;
-		res.z = v;
-		return res;
-	}
-
-	h /= 60.0;         // sector 0 to 5
-	i = int(floor( h ));
-	f = h - float(i);         // factorial part of h
-	p = v * ( 1.0 - s );
-	q = v * ( 1.0 - s * f );
-	t = v * ( 1.0 - s * ( 1.0 - f ) );
-
-	switch( i ) {
-	case 0:
-		res.x = v;
-		res.y = t;
-		res.z = p;
-		break;
-	case 1:
-		res.x = q;
-		res.y = v;
-		res.z = p;
-		break;
-	case 2:
-		res.x = p;
-		res.y = v;
-		res.z = t;
-		break;
-	case 3:
-		res.x = p;
-		res.y = q;
-		res.z = v;
-		break;
-	case 4:
-		res.x = t;
-		res.y = p;
-		res.z = v;
-		break;
-	default:      // case 5:
-		res.x = v;
-		res.y = p;
-		res.z = q;
-		break;
-	}
-
-	return res;
-}
-
-float nearestLevel(float col, int mode) {
-	int levCount;
-	if (mode==0) levCount = HueLevCount;
-	if (mode==1) levCount = SatLevCount;
-	if (mode==2) levCount = ValLevCount;
-
-	for (int i =0; i<levCount-1; i++ ) {
-		if (mode==0) {
-			if (col >= HueLevels[i] && col <= HueLevels[i+1]) {
-				return HueLevels[i+1];
-			}
-		}
-		if (mode==1) {
-			if (col >= SatLevels[i] && col <= SatLevels[i+1]) {
-				return SatLevels[i+1];
-			}
-		}
-		if (mode==2) {
-			if (col >= ValLevels[i] && col <= ValLevels[i+1]) {
-				return ValLevels[i+1];
-			}
-		}
-	}
-}
-
-// averaged pixel intensity from 3 color channels
-float avg_intensity(vec4 pix) {
-	return (pix.r + pix.g + pix.b)/3.;
-}
-
-vec4 get_pixel(vec2 coords, float dx, float dy) {
-	return texture2D(Texture0,coords + vec2(dx, dy));
-}
-
-// returns pixel color
-float IsEdge(in vec2 coords){
-	float dxtex = 1.0 /float(textureSize(Texture0,0)) ;
-	float dytex = 1.0 /float(textureSize(Texture0,0));
-	float pix[9];
-	int k = -1;
-	float delta;
-
-	// read neighboring pixel intensities
-	for (int i=-1; i<2; i++) {
-		for(int j=-1; j<2; j++) {
-			k++;
-			pix[k] = avg_intensity(get_pixel(coords,float(i)*dxtex,
-				float(j)*dytex));
-		}
-	}
-
-	// average color differences around neighboring pixels
-	delta = (abs(pix[1]-pix[7])+
-		abs(pix[5]-pix[3]) +
-		abs(pix[0]-pix[8])+
-		abs(pix[2]-pix[6])
-		)/4.;
-
-	return clamp(5.5*delta,0.0,1.0);
-}
-
-void main(void)
-{
-	vec4 colorOrg = texture2D( Texture0, gl_TexCoord[0].st );
-	vec3 vHSV =  RGBtoHSV(colorOrg.r,colorOrg.g,colorOrg.b);
-	vHSV.x = nearestLevel(vHSV.x, 0);
-	vHSV.y = nearestLevel(vHSV.y, 1);
-	vHSV.z = nearestLevel(vHSV.z, 2);
-	float edg = IsEdge(gl_TexCoord[0].st);
-	vec3 vRGB = (edg >= 0.3)? vec3(0.0,0.0,0.0):HSVtoRGB(vHSV.x,vHSV.y,vHSV.z);
-	gl_FragColor = vec4(vRGB.x,vRGB.y,vRGB.z,1.0);
-}
diff --git a/game/modules/tome/data/gfx/shaders/moving_transparency.lua b/game/modules/tome/data/gfx/shaders/moving_transparency.lua
index df58ab1f5d0620725bf0d0450e956f17b3321505..0cac4f29e70702a1e60825ea2dc8c4495899145d 100644
--- a/game/modules/tome/data/gfx/shaders/moving_transparency.lua
+++ b/game/modules/tome/data/gfx/shaders/moving_transparency.lua
@@ -21,8 +21,8 @@ return {
 	frag = "moving_transparency",
 	vert = nil,
 	args = {
-		a_min = 0.4,
-		a_max = 1.5,
+		a_min = a_min or 0.4,
+		a_max = a_max or 1.5,
 		base = base or 0.3,
 		time_factor = time_factor or 3000,
 		p2 = p2 or {1,1},
diff --git a/game/modules/tome/data/gfx/shaders/runicshield.frag b/game/modules/tome/data/gfx/shaders/runicshield.frag
index fbea99d92651575369cf3a6893dc4736339ab300..43711a0a56660eaea00d9cf1e82aa409d31fd98e 100644
--- a/game/modules/tome/data/gfx/shaders/runicshield.frag
+++ b/game/modules/tome/data/gfx/shaders/runicshield.frag
@@ -1,5 +1,6 @@
 uniform sampler2D tex;
 uniform float tick;
+uniform float tick_start;
 uniform float aadjust;
 uniform vec4 bubbleColor;
 uniform vec4 auraColor;
@@ -121,7 +122,7 @@ vec2 snoise2(vec3 pos)
 float GetFireDelta(float currTime, vec2 pos, float freqMult, float stretchMult, float scrollSpeed, float evolutionSpeed)
 {
 	//firewall
-	float delta = 0;
+	float delta = 0.0;
 //	pos.y += (1.0 - pos.y) * 0.5;
 	//pos.y += 0.5;
 	pos.y /= stretchMult;
@@ -230,7 +231,7 @@ void main(void)
 
 		vec2 sphericalProjectedCoord = vec2(0.5, 0.5) + radius * (alpha / (3.141592 / 2.0)) / radiusLen;
 
-		shieldColorSample = texture2D(tex, (sphericalProjectedCoord * 0.3 + vec2(scrollingSpeed * tick / time_factor, 0.0)));
+		shieldColorSample = texture2D(tex, (sphericalProjectedCoord * 0.3 + vec2(scrollingSpeed * (tick - tick_start) / time_factor, 0.0)));
 		shieldColorSample.a = 1.0 - exp(-shieldColorSample.a * shieldIntensity / cos(alpha));
 		//impact adjusts resulting transperency
 		shieldColorSample.a *= aadjust;
@@ -241,7 +242,7 @@ void main(void)
 	vec4 auraColorSample = vec4(0.0, 0.0, 0.0, 0.0);
 	if(length(radius) > innerRadius && length(radius) < outerRadius)
 	{
-		auraColorSample = GetFireRingColor(tick / time_factor, radius, 5.0, 50.0, 1.0, 2.0, innerRadius, outerRadius, 0.1, 0.25) * auraColor;
+		auraColorSample = GetFireRingColor((tick - tick_start) / time_factor, radius, 5.0, 50.0, 1.0, 2.0, innerRadius, outerRadius, 0.1, 0.25) * auraColor;
 	}
 
 	float ratio = (radiusLen - innerRadius) / (shieldRadius - innerRadius);
diff --git a/game/modules/tome/data/gfx/shaders/runicshield.lua b/game/modules/tome/data/gfx/shaders/runicshield.lua
index 57ccebea66a9eaf14c0d9dab9a3e092b6f728b4a..94d2f76b76557c7ea66296983ede3e2ee682a40f 100644
--- a/game/modules/tome/data/gfx/shaders/runicshield.lua
+++ b/game/modules/tome/data/gfx/shaders/runicshield.lua
@@ -40,5 +40,8 @@ return {
 		scrollingSpeed = scrollingSpeed or 1.0,
 		auraWidth = auraWidth or 0.1,
 	},
+	resetargs = {
+		tick_start = function() return core.game.getFrameTime() end,
+	},
 	clone = false,
 }
diff --git a/game/modules/tome/data/gfx/shaders/shield.frag b/game/modules/tome/data/gfx/shaders/shield.frag
index a1323570b78704d6bc8d69310cedde1f30025373..e45fb9dcae62161f2299473a06b92e372e0c4ede 100644
--- a/game/modules/tome/data/gfx/shaders/shield.frag
+++ b/game/modules/tome/data/gfx/shaders/shield.frag
@@ -1,5 +1,6 @@
 uniform sampler2D tex;
 uniform float tick;
+uniform float tick_start;
 uniform float aadjust;
 uniform vec3 color;
 uniform float time_factor;
@@ -68,8 +69,8 @@ void main(void)
 	vec2 sphericalProjectedCoord = vec2(0.5, 0.5) + radius * (alpha / (3.141592 / 2.0)) / radiusLen;
 	
 	//two scrolling textures
-	vec4 c1 = texture2D(tex, (sphericalProjectedCoord + vec2(horizontalScrollingSpeed * tick / time_factor, 0.0)));
-	vec4 c2 = texture2D(tex, (sphericalProjectedCoord + vec2(0.0, verticalScrollingSpeed * tick / time_factor)));
+	vec4 c1 = texture2D(tex, (sphericalProjectedCoord + vec2(horizontalScrollingSpeed * (tick - tick_start) / time_factor, 0.0)));
+	vec4 c2 = texture2D(tex, (sphericalProjectedCoord + vec2(0.0, verticalScrollingSpeed * (tick - tick_start) / time_factor)));
 	vec4 c = c1 * c2;
 
 	//exponential thin layer absorbtion under angle alpha
diff --git a/game/modules/tome/data/gfx/shaders/shield.lua b/game/modules/tome/data/gfx/shaders/shield.lua
index 79f29fecbd63b7feefe18a4279885b56d361c1b0..27686f6af0ee4f829ebde846792dc768a5be31e6 100644
--- a/game/modules/tome/data/gfx/shaders/shield.lua
+++ b/game/modules/tome/data/gfx/shaders/shield.lua
@@ -40,5 +40,8 @@ return {
 		horizontalScrollingSpeed = horizontalScrollingSpeed or 1.0,
 		verticalScrollingSpeed = verticalScrollingSpeed or 0.3,
 	},
+	resetargs = {
+		tick_start = function() return core.game.getFrameTime() end,
+	},
 	clone = false,
 }
diff --git a/game/modules/tome/data/gfx/shaders/target_fbo.frag b/game/modules/tome/data/gfx/shaders/target_fbo.frag
new file mode 100644
index 0000000000000000000000000000000000000000..5045fd33dfaeaae0c652eabd4d95ee25e8c01b44
--- /dev/null
+++ b/game/modules/tome/data/gfx/shaders/target_fbo.frag
@@ -0,0 +1,141 @@
+//#version 150
+uniform sampler2D fboTex;
+uniform sampler2D targetSkin;
+uniform vec2 mapCoord;
+uniform vec2 tileSize;
+uniform vec2 scrollOffset;
+
+void main(void)
+{
+	vec2 offset = vec2(1.0, 1.0) / mapCoord * tileSize * 0.5;
+	
+	/*vec4 colorm0 = texture2D( fboTex, gl_TexCoord[0].xy + vec2(-offset.x, 0.0));
+	vec4 colorp0 = texture2D( fboTex, gl_TexCoord[0].xy + vec2( offset.x, 0.0));
+
+	vec4 color0m = texture2D( fboTex, gl_TexCoord[0].xy + vec2(0.0, -offset.y));
+	vec4 color0p = texture2D( fboTex, gl_TexCoord[0].xy + vec2(0.0,  offset.y));*/
+	
+	vec4 colormm = texture2D( fboTex, gl_TexCoord[0].xy + vec2(-offset.x,-offset.y));
+	vec4 colormp = texture2D( fboTex, gl_TexCoord[0].xy + vec2(-offset.x, offset.y));
+	vec4 colorpm = texture2D( fboTex, gl_TexCoord[0].xy + vec2( offset.x,-offset.y));	
+	vec4 colorpp = texture2D( fboTex, gl_TexCoord[0].xy + vec2( offset.x, offset.y));	
+
+	vec4 color00 = texture2D( fboTex, gl_TexCoord[0].xy);
+	
+	vec4 resultColor = color00;
+		
+	bool loc1 = false;
+	bool loc2 = false;
+	bool loc3 = false;
+	bool loc4 = false;
+	bool loc5 = false;
+	bool loc6 = false;
+	bool loc7 = false;
+	bool loc8 = false;
+	bool loc9 = false;
+	
+	if(colormm.a > 0.1)
+		loc1 = true;
+	if(colormp.a > 0.1)
+		loc7 = true;
+	if(colorpm.a > 0.1)
+		loc3 = true;
+	if(colorpp.a > 0.1)
+		loc9 = true;
+	if(color00.a > 0.1)
+		loc5 = true;
+		
+	if(gl_TexCoord[0].x + offset.x > 1.0)
+	{
+		loc9 = 0; 
+		loc3 = 0;
+	}
+
+	if(gl_TexCoord[0].x - offset.x < 0.0)
+	{
+		loc1 = 0; 
+		loc7 = 0;
+	}
+
+	if(gl_TexCoord[0].y + offset.y > 1.0)
+	{
+		loc7 = 0; 
+		loc9 = 0;
+	}
+
+	if(gl_TexCoord[0].y - offset.y < 0.0)
+	{
+		loc1 = 0; 
+		loc3 = 0;
+	}
+			
+
+	vec2 fboCoord = gl_TexCoord[0].xy;
+	fboCoord.y = 1.0 - fboCoord.y;
+	vec2 texCoord = (fboCoord * mapCoord + scrollOffset) / tileSize + vec2(0.5, 0.5);
+	texCoord.x = mod(texCoord.x, 1.0);
+	texCoord.y = mod(texCoord.y, 1.0);
+
+	vec4 borderColor = vec4(0.0, 0.0, 0.0, 0.0);
+	
+	if(loc1 && loc7 && loc3 && !loc9) //1 internal
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 3.0));
+		
+	if(loc9 && !loc7 && !loc3 && !loc1) //1 external
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 1.0));
+			
+	if(loc7 && !loc3 && loc9 && !loc1) //2
+		borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 1.0));
+
+	if(loc3 && loc1 && loc9 && !loc7) //3 internal
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 3.0));
+		
+	if(loc7 && !loc1 && !loc9 && !loc3) //3 external
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 1.0));
+		
+	if(loc1 && !loc9 && loc7 && !loc3) //8
+		borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 3.0, 1.0 / 4.0 * 0.0));
+			
+	if(loc9 && loc7 && loc3 && !loc1)
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 2.0));
+
+	if(loc1 && !loc7 && !loc3 && !loc9) //9 external
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 0.0));
+
+	if(loc1 && !loc9  && loc3 && !loc7)
+		borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 0.0));
+
+	if(loc7 && loc1 && loc9 && !loc3) //7 internal
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 2.0));
+		
+	if(loc3 && !loc1 && !loc9 && !loc7) //7 external
+		borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 0.0));
+
+	if(loc3 && !loc7 && loc9 && !loc1) //4
+		borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 3.0, 1.0 / 4.0 * 1.0));
+
+	if(loc3 && loc7 && !loc9 && !loc1) //3-7 diag
+		borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 2.0));
+
+	if(!loc3 && !loc7 && loc9 && loc1) //1-9 diag
+		borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 3.0, 1.0 / 4.0 * 2.0));
+
+	if(loc3 && loc7 && loc9 && loc1) //internal quad
+		borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 3.0));
+		
+	if(!loc5 && borderColor.a > 0.0)
+	{
+		vec4 avgColor = 
+			(colormm * colormm.a + colormp * colormp.a + colorpm * colorpm.a + colorpp * colorpp.a)
+			/ (colormm.a + colormp.a + colorpm.a + colorpp.a + 1e-5);
+		resultColor += avgColor;
+		resultColor.rgb += borderColor.rgb * borderColor.a;
+		resultColor.a = borderColor.a;
+	}else
+	{
+		borderColor.rgb *= borderColor.a;
+		resultColor += borderColor;
+	}
+
+	gl_FragColor = resultColor;
+}
diff --git a/game/modules/tome/data/gfx/shaders/target_fbo.lua b/game/modules/tome/data/gfx/shaders/target_fbo.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8e0ba1def4205224fd586ce3cc7d59de8014ac05
--- /dev/null
+++ b/game/modules/tome/data/gfx/shaders/target_fbo.lua
@@ -0,0 +1,30 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+return {
+	frag = "target_fbo",
+	vert = nil,
+	args = {
+		fboTex = { texture = 0 },
+		targetSkin = { texture = 1 },
+		scrollOffset = {0, 0},
+	},
+	clone = false,
+	permanent = true,
+}
diff --git a/game/modules/tome/data/gfx/ui/targetshader.png b/game/modules/tome/data/gfx/ui/targetshader.png
new file mode 100644
index 0000000000000000000000000000000000000000..99db06ac533b4c45731ad11bb84d02a8b70b7749
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/targetshader.png differ
diff --git a/game/modules/tome/data/maps/zones/gladium.lua b/game/modules/tome/data/maps/zones/gladium.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1ce2f16ff2d9daba53a2f8bf8f5d2947863dc957
--- /dev/null
+++ b/game/modules/tome/data/maps/zones/gladium.lua
@@ -0,0 +1,43 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+defineTile("#", "HARDWALL")
+defineTile("1", "HARDWALL")
+defineTile(".", "FLOOR")
+defineTile("&", "HARDGLASSWALL")
+defineTile("*", "GLADIUM_ORB")
+
+startx = 13
+starty = 6
+
+-- ASCII map section
+return [[
+###############
+#...1.....1...#
+#....1...1....#
+#1............#
+#...........&&#
+#...........&.#
+#...1.......&.#
+#...........&*#
+#...........&&#
+#1............#
+#....1...1....#
+#...1.....1...#
+###############]]
diff --git a/game/modules/tome/data/quests/staff-absorption.lua b/game/modules/tome/data/quests/staff-absorption.lua
index f79454b9e34d92dd4540d412038cea0e894a8154..1ac2f63cb9e4d11d4bfa6513d1a2517f8eb07cb7 100644
--- a/game/modules/tome/data/quests/staff-absorption.lua
+++ b/game/modules/tome/data/quests/staff-absorption.lua
@@ -30,7 +30,7 @@ desc = function(self, who)
 		desc[#desc+1] = "They asked about the staff and stole it from you."
 		desc[#desc+1] = "#LIGHT_GREEN#Go at once to Last Hope to report those events!"
 	elseif self:isCompleted("ambush-finished") and self:isCompleted("survived-ukruk") then
-		desc[#desc+1] = "On your way out of Last Hope you were ambushed by a band of orcs."
+		desc[#desc+1] = "On your way out of the Dreadfell you were ambushed by a band of orcs."
 		desc[#desc+1] = "They asked about the staff and stole it from you."
 		desc[#desc+1] = "You told them nothing and vanquished them."
 		desc[#desc+1] = "#LIGHT_GREEN#Go at once to Last Hope to report those events!"
diff --git a/game/modules/tome/data/talents/celestial/guardian.lua b/game/modules/tome/data/talents/celestial/guardian.lua
index 7706e2f95816f42db028834d4071bb1fd54668c8..a3a285798ccd0395931b18c4179965f7d70430fd 100644
--- a/game/modules/tome/data/talents/celestial/guardian.lua
+++ b/game/modules/tome/data/talents/celestial/guardian.lua
@@ -158,7 +158,7 @@ newTalent{
 		game:playSoundNear(self, "talents/heal")
 		local ret = {}
 		if core.shader.active(4) then
-			ret.particle = self:addParticles(Particles.new("shader_ring_rotating", 1, {toback=true, rotation=0, radius=2, img="flamesgeneric"}, {type="sunaura", time_factor=6000}))
+			ret.particle = self:addParticles(Particles.new("shader_ring_rotating", 1, {toback=true, a=0.6, rotation=0, radius=2, img="flamesgeneric"}, {type="sunaura", time_factor=6000}))
 		else
 			ret.particle = self:addParticles(Particles.new("golden_shield", 1))
 		end
diff --git a/game/modules/tome/data/talents/celestial/light.lua b/game/modules/tome/data/talents/celestial/light.lua
index 9b40d85dc16f2a86180297b1ad917b8a595e2b3a..8136e4b7e8e2a35b6628866cfafd834d44406508 100644
--- a/game/modules/tome/data/talents/celestial/light.lua
+++ b/game/modules/tome/data/talents/celestial/light.lua
@@ -100,7 +100,7 @@ newTalent{
 	tactical = { DEFEND = 2 },
 	getAbsorb = function(self, t) return self:combatTalentSpellDamage(t, 30, 470) end,
 	action = function(self, t)
-		self:setEffect(self.EFF_DAMAGE_SHIELD, 10, {power=t.getAbsorb(self, t)})
+		self:setEffect(self.EFF_DAMAGE_SHIELD, 10, {color={0xe1/255, 0xcb/255, 0x3f/255}, power=t.getAbsorb(self, t)})
 		game:playSoundNear(self, "talents/heal")
 		return true
 	end,
diff --git a/game/modules/tome/data/talents/corruptions/plague.lua b/game/modules/tome/data/talents/corruptions/plague.lua
index 393747d588e598c6f5eb3d69310b0fb07b8bc6a4..e8a176104d4290a709c545725540fb87261953cf 100644
--- a/game/modules/tome/data/talents/corruptions/plague.lua
+++ b/game/modules/tome/data/talents/corruptions/plague.lua
@@ -234,6 +234,7 @@ newTalent{
 	spreadFactor = function(self, t) return self:combatTalentLimit(t, 0.05, 0.35, 0.17) end, -- Based on previous formula: 256 damage gave 100% chance (1500 hps assumed)
 	
 	do_spread = function(self, t, carrier, dam)
+		if not dam or type(dam) ~= "number" then return end
 		if not rng.percent(100*dam/(t.spreadFactor(self, t)*carrier.max_life)) then return end
 		game.logSeen(self, "The diseases of %s spread!", self.name)
 		-- List all diseases
diff --git a/game/modules/tome/data/talents/cunning/stealth.lua b/game/modules/tome/data/talents/cunning/stealth.lua
index 18efd70a7dc0046a1cf89c8b21defe07b1fede4e..dcb6d13f69ff7a03588f19e5f98726a87541cf08 100644
--- a/game/modules/tome/data/talents/cunning/stealth.lua
+++ b/game/modules/tome/data/talents/cunning/stealth.lua
@@ -27,7 +27,7 @@ local function stealthDetection(self, radius)
 	for i, act in ipairs(self.fov.actors_dist) do
 		dist = core.fov.distance(self.x, self.y, act.x, act.y)
 		if dist > radius then break end
-		if act ~= self and act:reactionToward(self) < 0 and not act:attr("blind") then
+		if act ~= self and act:reactionToward(self) < 0 and not act:attr("blind") and (not act.fov or not act.fov.actors or act.fov.actors[self]) then
 			detect = detect + act:combatSeeStealth() * (1.1 - dist/10) -- detection strength reduced 10% per tile
 			if dist < closest then closest = dist end
 		end
@@ -45,7 +45,7 @@ newTalent{
 	allow_autocast = true,
 	no_energy = true,
 	tactical = { BUFF = 3 },
-	getStealthPower = function(self, t) return self:combatScale(math.max(1,self:getCun(10, true) * self:getTalentLevel(t)), 5, 1, 54, 50) end, --TL 5, cun 100 = 54
+	getStealthPower = function(self, t) return 10 + self:combatScale(math.max(1,self:getCun(10, true) * self:getTalentLevel(t)), 5, 1, 54, 50) end, --TL 5, cun 100 = 54
 	getRadius = function(self, t) return math.ceil(self:combatTalentLimit(t, 0, 8.9, 4.6)) end, -- Limit to range >= 1
 	on_pre_use = function(self, t, silent)
 		if self:isTalentActive(t.id) then return true end
diff --git a/game/modules/tome/data/talents/misc/inscriptions.lua b/game/modules/tome/data/talents/misc/inscriptions.lua
index 5217b2f9e3b16613bdb5fb6bb5faff359c0759ee..b761ad7e4d7b81baff3462cea946764cc1d72197 100644
--- a/game/modules/tome/data/talents/misc/inscriptions.lua
+++ b/game/modules/tome/data/talents/misc/inscriptions.lua
@@ -291,7 +291,7 @@ newInscription{
 		local x, y = self:getTarget(tg)
 		if not x or not y then return nil end
 		self:projectile(tg, x, y, DamageType.INSIDIOUS_POISON, {dam=data.power + data.inc_stat, dur=7, heal_factor=data.heal_factor}, {type="slime"})
-		self:removeEffectsFilter({status="detrimental", type="magical"}, 1)
+		self:removeEffectsFilter({status="detrimental", type="magical", ignore_crosstier=true}, 1)
 		game:playSoundNear(self, "talents/slime")
 		return true
 	end,
@@ -613,7 +613,7 @@ newInscription{
 		self:project(tg, x, y, DamageType.FIREBURN, {dur=5, initial=0, dam=data.power + data.inc_stat})
 		local _ _, x, y = self:canProject(tg, x, y)
 		game.level.map:particleEmitter(self.x, self.y, tg.radius, "flamebeam", {tx=x-self.x, ty=y-self.y})
-		self:removeEffectsFilter({status="detrimental", type="physical"}, 1)
+		self:removeEffectsFilter({status="detrimental", type="physical", ignore_crosstier=true}, 1)
 		game:playSoundNear(self, "talents/fire")
 		attack_rune(self, t.id)
 		return true
@@ -659,7 +659,7 @@ newInscription{
 		local x, y = self:getTarget(tg)
 		if not x or not y then return nil end
 		self:project(tg, x, y, DamageType.ICE, data.power + data.inc_stat, {type="freeze"})
-		self:removeEffectsFilter({status="detrimental", type="mental"}, 1)
+		self:removeEffectsFilter({status="detrimental", type="mental", ignore_crosstier=true}, 1)
 		game:playSoundNear(self, "talents/ice")
 		attack_rune(self, t.id)
 		return true
diff --git a/game/modules/tome/data/talents/psionic/focus.lua b/game/modules/tome/data/talents/psionic/focus.lua
index e5916d75c4d4203043c4989d858a644a612e8bfe..c1f79ae348d53255f06da2b111c1099ac58eb471 100644
--- a/game/modules/tome/data/talents/psionic/focus.lua
+++ b/game/modules/tome/data/talents/psionic/focus.lua
@@ -33,7 +33,11 @@ newTalent{
 		local gem_level = getGemLevel(self)
 		return math.max(c - gem_level, 0)
 	end,
-	psi = 10,
+	psi = function(self, t)
+		local eff = self:hasEffect(self.EFF_MINDLASH)
+		local power = eff and eff.power or 1
+		return 10 * power
+	end,
 	tactical = { ATTACK = function(self, t, target)
 		local val = { PHYSICAL = 2}
 		local gem_level = getGemLevel(self)
@@ -94,6 +98,7 @@ newTalent{
 			end
 
 		end
+		self:setEffect(self.EFF_MINDLASH, 4, {})
 		return true
 	end,
 	info = function(self, t)
diff --git a/game/modules/tome/data/talents/psionic/voracity.lua b/game/modules/tome/data/talents/psionic/voracity.lua
index 515a711a5f4618cc2ddcaaa5f1f66e39cb90374e..6f70c0aaed62e5df0859fdd4671cd71b514b267a 100644
--- a/game/modules/tome/data/talents/psionic/voracity.lua
+++ b/game/modules/tome/data/talents/psionic/voracity.lua
@@ -31,7 +31,7 @@ newTalent{
 	range = 0,
 	radius = function(self, t)
 		local r = 2
-		local gem_level = getGemLevel(self)
+		local gem_level = getGemLevel(self) or 1
 		local mult = 1 + 0.01*gem_level*self:callTalent(self.T_REACH, "rangebonus")
 		return math.ceil(r*mult)
 	end,
@@ -79,7 +79,7 @@ newTalent{
 	range = 0,
 	radius = function(self, t)
 		local r = 1
-		local gem_level = getGemLevel(self)
+		local gem_level = getGemLevel(self) or 1
 		local mult = 1 + 0.01*gem_level*self:callTalent(self.T_REACH, "rangebonus")
 		return math.ceil(r*mult)
 	end,
@@ -126,7 +126,7 @@ newTalent{
 	range = 0,
 	radius = function(self, t)
 		local r = 2
-		local gem_level = getGemLevel(self)
+		local gem_level = getGemLevel(self) or 1
 		local mult = 1 + 0.01*gem_level*self:callTalent(self.T_REACH, "rangebonus")
 		return math.ceil(r*mult)
 	end,
diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua
index b6d7fb0ffc6b9ea37a65bfde0f5ea7d4e0cf0810..75195c986daedc852e32aed40383b45a76e68623 100644
--- a/game/modules/tome/data/timed_effects/magical.lua
+++ b/game/modules/tome/data/timed_effects/magical.lua
@@ -510,7 +510,13 @@ newEffect{
 		self.damage_shield_absorb = self.damage_shield_absorb + eff.power * aegis / 100
 		if core.shader.active(4) then
 			self:removeParticles(eff.particle)
-			eff.particle = self:addParticles(Particles.new("shader_shield", 1, {size_factor=1.3, img="runicshield"}, {type="runicshield", shieldIntensity=0.14, ellipsoidalFactor=1.2, time_factor=5000, bubbleColor={0.4, 0.7, 1.0, 1.0}, auraColor={0x21/255, 0x9f/255, 0xff/255, 1}}))
+			local bc = {0.4, 0.7, 1.0, 1.0}
+			local ac = {0x21/255, 0x9f/255, 0xff/255, 1}
+			if eff.color then
+				bc = table.clone(eff.color) bc[4] = 1
+				ac = table.clone(eff.color) ac[4] = 1
+			end
+			eff.particle = self:addParticles(Particles.new("shader_shield", 1, {size_factor=1.3, img="runicshield"}, {type="runicshield", shieldIntensity=0.14, ellipsoidalFactor=1.2, time_factor=5000, bubbleColor=bc, auraColor=ac}))
 		end		
 	end,
 	damage_feedback = function(self, eff, src, value)
@@ -530,7 +536,7 @@ newEffect{
 		self.damage_shield_absorb = eff.power
 		self.damage_shield_absorb_max = eff.power
 		if core.shader.active(4) then
-			eff.particle = self:addParticles(Particles.new("shader_shield", 1, nil, {type="shield", shieldIntensity=0.2, color={0.4, 0.7, 1.0}}))
+			eff.particle = self:addParticles(Particles.new("shader_shield", 1, nil, {type="shield", shieldIntensity=0.2, color=eff.color or {0.4, 0.7, 1.0}}))
 		else
 			eff.particle = self:addParticles(Particles.new("damage_shield", 1))
 		end
@@ -969,12 +975,24 @@ newEffect{
 		eff.tmpid = self:addTemporaryValue("can_pass", {pass_wall=20})
 		eff.defid = self:addTemporaryValue("combat_def", eff.def)
 		eff.armid = self:addTemporaryValue("combat_armor", eff.armor)
+		if not self.shader then
+			eff.set_shader = true
+			self.shader = "moving_transparency"
+			self.shader_args = { a_min=0.3, a_max=0.8, time_factor = 3000 }
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 	end,
 	deactivate = function(self, eff)
+		if eff.set_shader then
+			self.shader = nil
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 		self:removeTemporaryValue("can_pass", eff.tmpid)
 		self:removeTemporaryValue("combat_def", eff.defid)
 		self:removeTemporaryValue("combat_armor", eff.armid)
-		if not self:canMove(self.x, self.y) then
+		if not self:canMove(self.x, self.y, true) then
 			self:teleportRandom(self.x, self.y, 50)
 		end
 	end,
@@ -1022,7 +1040,6 @@ newEffect{
 		end
 	end,
 	activate = function(self, eff)
-		eff.tmpid = self:addTemporaryValue("life_regen", eff.power)
 		eff.tmpid = self:addTemporaryValue("life_regen", eff.power)
 		if core.shader.active(4) then
 			eff.particle1 = self:addParticles(Particles.new("shader_shield", 1, {toback=true,  size_factor=1.5, y=-0.3, img="healcelestial"}, {type="healing", time_factor=4000, noup=2.0, beamColor1={0xd8/255, 0xff/255, 0x21/255, 1}, beamColor2={0xf7/255, 0xff/255, 0x9e/255, 1}, circleColor={0,0,0,0}, beamsCount=5}))
diff --git a/game/modules/tome/data/timed_effects/mental.lua b/game/modules/tome/data/timed_effects/mental.lua
index c0f2f9c874302155cafe50998a088209a1dcae71..2eb45045ef3d6b06657051899de6c5de871b23b7 100644
--- a/game/modules/tome/data/timed_effects/mental.lua
+++ b/game/modules/tome/data/timed_effects/mental.lua
@@ -2931,3 +2931,20 @@ newEffect{
 		self:effectTemporaryValue(eff, "random_talent_cooldown_on_use_turns", eff.turns)
 	end,
 }
+
+newEffect{
+	name = "MINDLASH", image = "talents/mindlash.png",
+	desc = "Mindlash",
+	long_desc = function(self, eff) return ("Repeated mindlash usage is very taxing increasing the psi cost each time (currently %d%%)"):format(eff.power * 100) end,
+	type = "mental",
+	subtype = { mind=true },
+	status = "detrimental",
+	parameters = {  },
+	on_merge = function(self, old_eff, new_eff)
+		new_eff.power = old_eff.power + 1
+		return new_eff
+	end,
+	activate = function(self, eff)
+		eff.power = 2
+	end,
+}
diff --git a/game/modules/tome/data/zones/crypt-kryl-feijan/zone.lua b/game/modules/tome/data/zones/crypt-kryl-feijan/zone.lua
index 30131fe0c13bf03de42eedfa212569ca1449d920..b1c43c3df0fd070d19cc8ec6afd429e13e2c930d 100644
--- a/game/modules/tome/data/zones/crypt-kryl-feijan/zone.lua
+++ b/game/modules/tome/data/zones/crypt-kryl-feijan/zone.lua
@@ -87,8 +87,10 @@ return {
 						local x, y = e.x, e.y
 						e:die()
 						local m = game.zone:makeEntityByName(game.level, "actor", "KRYL_FEIJAN")
-						game.zone:addEntity(game.level, m, "actor", x, y)
-						game.level.map:particleEmitter(x, y, 1, "blood")
+						if m then
+							game.zone:addEntity(game.level, m, "actor", x, y)
+							game.level.map:particleEmitter(x, y, 1, "blood")
+						end
 						game.player:setQuestStatus("kryl-feijan-escape", engine.Quest.FAILED)
 
 						local spot = game.level:pickSpot{type="locked-door", subtype="locked-door"}
diff --git a/game/modules/tome/data/zones/gladium/grids.lua b/game/modules/tome/data/zones/gladium/grids.lua
new file mode 100644
index 0000000000000000000000000000000000000000..783e2734c1d26c1e3a43d917e4a65d5b25fad005
--- /dev/null
+++ b/game/modules/tome/data/zones/gladium/grids.lua
@@ -0,0 +1,59 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+load("/data/general/grids/basic.lua")
+
+newEntity{
+	define_as = "GLADIUM_ORB",
+	name = "Gladium Control Orb", image = "terrain/marble_floor.png", add_displays = {class.new{z=18, image="terrain/pedestal_orb_02.png", display_h=2, display_y=-1}},
+	display = '*', color=colors.PURPLE,
+	notice = true,
+	always_remember = true,
+	block_move = function(self, x, y, e, act, couldpass)
+		if e and e.player and act then
+			local chat = require("engine.Chat").new("shertul-fortress-gladium-orb", self, e, {player=e})
+			chat:invoke()
+		end
+		return true
+	end,
+}
+
+-----------------------------------------
+-- Glass Walls
+-----------------------------------------
+newEntity{
+	define_as = "HARDGLASSWALL",
+	type = "wall", subtype = "floor",
+	name = "glass wall", image = "terrain/hardglasswall.png",
+	display = '#', color=colors.AQUAMARINE, back_color=colors.GREY,
+	z = 3,
+	nice_tiler = { method="wall3d", inner="HARDGLASSWALLF", north="HARDGLASSWALL_NORTH", south="HARDGLASSWALL_SOUTH", north_south="HARDGLASSWALL_NORTH_SOUTH", small_pillar="HARDGLASSWALL_SMALL_PILLAR", pillar_2="HARDGLASSWALL_PILLAR_2", pillar_8="HARDGLASSWALL_PILLAR_8", pillar_4="HARDGLASSWALL_PILLAR_4" },
+	always_remember = true,
+	does_block_move = true,
+	air_level = -20,
+}
+newEntity{ base = "HARDGLASSWALL", define_as = "HARDGLASSWALLF", image = "terrain/marble_floor.png",add_mos={{image = "terrain/glass/wall_glass_middle_01_64.png"}}}
+newEntity{ base = "HARDGLASSWALL", define_as = "HARDGLASSWALL_NORTH", image = "terrain/marble_floor.png",add_mos={{image = "terrain/glass/wall_glass_middle_01_64.png"}}, z = 3, add_displays = {class.new{image="terrain/glass/wall_glass_top_01_64.png", z=18, display_y=-1}}}
+newEntity{ base = "HARDGLASSWALL", define_as = "HARDGLASSWALL_NORTH_SOUTH", image = "terrain/marble_floor.png",add_mos={{image = "terrain/glass/wall_glass_01_64.png"}}, z = 3, add_displays = {class.new{image="terrain/glass/wall_glass_top_01_64.png", z=18, display_y=-1}}}
+newEntity{ base = "HARDGLASSWALL", define_as = "HARDGLASSWALL_SOUTH", image = "terrain/marble_floor.png",add_mos={{image = "terrain/glass/wall_glass_01_64.png"}}, z = 3}
+newEntity{ base = "HARDGLASSWALL_NORTH_SOUTH", define_as = "HARDGLASSWALL_PILLAR_6"}
+newEntity{ base = "HARDGLASSWALL_NORTH_SOUTH", define_as = "HARDGLASSWALL_PILLAR_4"}
+newEntity{ base = "HARDGLASSWALL_NORTH_SOUTH", define_as = "HARDGLASSWALL_SMALL_PILLAR"}
+newEntity{ base = "HARDGLASSWALL_NORTH", define_as = "HARDGLASSWALL_PILLAR_8"}
+newEntity{ base = "HARDGLASSWALL_SOUTH", define_as = "HARDGLASSWALL_PILLAR_2"}
diff --git a/game/modules/tome/data/zones/gladium/npcs.lua b/game/modules/tome/data/zones/gladium/npcs.lua
new file mode 100644
index 0000000000000000000000000000000000000000..31d77de9646b897494e8d88952dd6f6cf883cb4b
--- /dev/null
+++ b/game/modules/tome/data/zones/gladium/npcs.lua
@@ -0,0 +1,21 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+load("/data/zones/town-angolwen/npcs.lua", rarity(0))
+load("/data/zones/golem-graveyard/npcs.lua", rarity(0))
diff --git a/game/modules/tome/data/gfx/shaders/mm_fbo.lua b/game/modules/tome/data/zones/gladium/objects.lua
similarity index 91%
rename from game/modules/tome/data/gfx/shaders/mm_fbo.lua
rename to game/modules/tome/data/zones/gladium/objects.lua
index 6aac51e1be541ccfb4b1986dff09a6b8695e09ab..df9c8f344637837d7d089ced1d3ca3c694eb844b 100644
--- a/game/modules/tome/data/gfx/shaders/mm_fbo.lua
+++ b/game/modules/tome/data/zones/gladium/objects.lua
@@ -17,10 +17,4 @@
 -- Nicolas Casalini "DarkGod"
 -- darkgod@te4.org
 
-return {
-	frag = "mm_fbo",
-	vert = nil,
-	args = {
-	},
-	clone = false,
-}
+load("/data/general/objects/objects-maj-eyal.lua")
diff --git a/game/modules/tome/data/zones/gladium/traps.lua b/game/modules/tome/data/zones/gladium/traps.lua
new file mode 100644
index 0000000000000000000000000000000000000000..02f32361a395c0d5716087b09a38d3fe13e0b8e7
--- /dev/null
+++ b/game/modules/tome/data/zones/gladium/traps.lua
@@ -0,0 +1,21 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+load("/data/general/traps/elemental.lua")
+load("/data/general/traps/alarm.lua")
diff --git a/game/modules/tome/data/zones/gladium/zone.lua b/game/modules/tome/data/zones/gladium/zone.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1e6cbb37ace339670efa7ccea1180577f214d6fb
--- /dev/null
+++ b/game/modules/tome/data/zones/gladium/zone.lua
@@ -0,0 +1,36 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+return {
+	name = "Fortress Gladium",
+	level_range = {1, 1},
+	level_scheme = "player",
+	max_level = 1,
+	actor_adjust_level = function(zone, level, e) return zone.base_level end,
+	width = 15, height = 15,
+	all_remembered = true,
+	all_lited = true,
+	no_level_connectivity = true,
+	generator =  {
+		map = {
+			class = "engine.generator.map.Static",
+			map = "zones/gladium",
+		},
+	},
+}
diff --git a/game/modules/tome/data/zones/shertul-fortress-caldizar/npcs.lua b/game/modules/tome/data/zones/shertul-fortress-caldizar/npcs.lua
index b0a39b4029f20107d230d5e0619bada4cc2a9958..7e05b176a904d4d0956f31d153196498fccbd892 100644
--- a/game/modules/tome/data/zones/shertul-fortress-caldizar/npcs.lua
+++ b/game/modules/tome/data/zones/shertul-fortress-caldizar/npcs.lua
@@ -24,7 +24,7 @@ newEntity{ base = "BASE_NPC_SHERTUL", define_as = "CALDIZAR",
 	name = "Caldizar", color=colors.LIGHT_RED, unique="Caldizar Unknown Fortress",
 	resolvers.nice_tile{image="invis.png", add_mos = {{image="npc/horror_sher_tul_caldizar.png", display_h=2, display_y=-1}}},
 	desc ="A creature stands before you, with long tentacle-like appendages and a squat bump in place of a head. An intense aura of power radiates from this being unlike anything you've ever felt before. It can only be a Sher'Tul. A living Sher'Tul!",
-	level_range = {100, nil}, exp_worth = 5,
+	level_range = {1000, nil}, exp_worth = 5,
 	life_rating = 40,
 	rank = 5,
 	size_category = 4,
diff --git a/game/modules/tome/data/zones/void/npcs.lua b/game/modules/tome/data/zones/void/npcs.lua
index 9f4219a325352b4ae337bc84a54ded3f67ab9a2f..e55c9c193b30d1ba609f74e8389cd68367298bc7 100644
--- a/game/modules/tome/data/zones/void/npcs.lua
+++ b/game/modules/tome/data/zones/void/npcs.lua
@@ -23,16 +23,16 @@
 local Talents = require("engine.interface.ActorTalents")
 
 newEntity{ define_as = "GOD_GERLYK",
-	type = "god", subtype = "god", unique = true,
+	type = "god", subtype = "eyal", unique = true,
 	name = "Gerlyk, the Creator",
 	display = "P", color=colors.VIOLET,
-	desc = [[During the Age of Haze nearly all gods were destroyed by the Sher'tuls Godslayers. yet a few escaped.
+	desc = [[During the Age of Haze nearly all gods were destroyed by the Sher'tuls Godslayers. Yet a few escaped.
 Gerlyk, the creator of the human race, prefered to flee into the void between the stars than to face death. He has been trapped ever since.
 The sorcerers tried to bring him back and nearly succeeded.
 Now you have come to finish what the Sher'tul began. Become a Godslayer yourself.]],
 	level_range = {100, nil}, exp_worth = 3,
-	max_life = 900, life_rating = 80, fixed_rating = true,
-	life_regen = 25,
+	max_life = 900, life_rating = 100, fixed_rating = true,
+	life_regen = 70,
 	max_stamina = 10000,
 	max_mana = 10000,
 	max_positive = 10000,
@@ -40,7 +40,7 @@ Now you have come to finish what the Sher'tul began. Become a Godslayer yourself
 	max_vim = 10000,
 	stats = { str=100, dex=100, con=100, mag=100, wil=100, cun=100 },
 	inc_stats = { str=80, dex=80, con=80, mag=80, wil=80, cun=80 },
-	rank = 5,
+	rank = 10,
 	size_category = 5,
 	infravision = 10,
 
diff --git a/game/modules/tome/dialogs/GameOptions.lua b/game/modules/tome/dialogs/GameOptions.lua
index 817d598c2e500ddbadc35a85d2092b182106fb42..3cd966d50b5e64e379b3b24dd5b280862bfd22be 100644
--- a/game/modules/tome/dialogs/GameOptions.lua
+++ b/game/modules/tome/dialogs/GameOptions.lua
@@ -393,7 +393,7 @@ function _M:generateListMisc()
 	local list = {}
 	local i = 0
 
-	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text=string.toTString"Saves in the background, allowing you to continue playing. If disabled you will have to wait until the saving is done, but it will be faster.#WHITE#"}
+	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text=string.toTString"Saves in the background, allowing you to continue playing.\n#LIGHT_RED#Disabling it is not recommended.#WHITE#"}
 	list[#list+1] = { zone=zone, name=string.toTString"#GOLD##{bold}#Save in the background#WHITE##{normal}#", status=function(item)
 		return tostring(config.settings.background_saves and "enabled" or "disabled")
 	end, fct=function(item)
@@ -402,7 +402,7 @@ function _M:generateListMisc()
 		self.c_list:drawItem(item)
 	end,}
 
-	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text=string.toTString"Forces the game to save each level instead of each zone.\nThis makes it save more often but the game will use less memory when deep in a dungeon.\n\n#LIGHT_RED#Changing this option will not affect already visited zones.\n*THIS DOES NOT MAKE A FULL SAVE EACH LEVEL*.#WHITE#"}
+	local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text=string.toTString"Forces the game to save each level instead of each zone.\nThis makes it save more often but the game will use less memory when deep in a dungeon.\n\n#LIGHT_RED#Changing this option will not affect already visited zones.\n*THIS DOES NOT MAKE A FULL SAVE EACH LEVEL*.\n#LIGHT_RED#Disabling it is not recommended#WHITE#"}
 	list[#list+1] = { zone=zone, name=string.toTString"#GOLD##{bold}#Zone save per level#WHITE##{normal}#", status=function(item)
 		return tostring(config.settings.tome.save_zone_levels and "enabled" or "disabled")
 	end, fct=function(item)
diff --git a/ideas/DLCs.ods b/ideas/DLCs.ods
index b7d5a72dce5dcdf39a692f94deae7628a7ae25b8..df5950d7ac7c864b0fadda65b2f0434ac0216ffc 100644
Binary files a/ideas/DLCs.ods and b/ideas/DLCs.ods differ
diff --git a/src/core_lua.c b/src/core_lua.c
index 988e86de5ceee9f5fdc5697bae14496cbd575d87..44b6798ec82ec84a377fcb711c6d0b39f9a40b65 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -2301,6 +2301,15 @@ static int gl_fbo_use(lua_State *L)
 {
 	lua_fbo *fbo = (lua_fbo*)auxiliar_checkclass(L, "gl{fbo}", 1);
 	bool active = lua_toboolean(L, 2);
+	float r = 0, g = 0, b = 0, a = 1;
+
+	if (lua_isnumber(L, 3))
+	{
+		r = luaL_checknumber(L, 3);
+		g = luaL_checknumber(L, 4);
+		b = luaL_checknumber(L, 5);
+		a = luaL_checknumber(L, 6);
+	}
 
 	if (active)
 	{
@@ -2319,7 +2328,7 @@ static int gl_fbo_use(lua_State *L)
 		// Reset The View
 		glLoadIdentity();
 
-		tglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+		tglClearColor(r, g, b, a);
 		glClear(GL_COLOR_BUFFER_BIT);
 	}
 	else
@@ -2351,6 +2360,7 @@ static int gl_fbo_toscreen(lua_State *L)
 	int y = luaL_checknumber(L, 3);
 	int w = luaL_checknumber(L, 4);
 	int h = luaL_checknumber(L, 5);
+	bool allowblend = lua_toboolean(L, 11);
 	float r = 1, g = 1, b = 1, a = 1;
 	if (lua_isnumber(L, 7))
 	{
@@ -2382,7 +2392,7 @@ static int gl_fbo_toscreen(lua_State *L)
 		useShader(s, fbo->w, fbo->h, w, h, r, g, b, a);
 	}
 
-	glDisable(GL_BLEND);
+	if (!allowblend) glDisable(GL_BLEND);
 	tglBindTexture(GL_TEXTURE_2D, fbo->texture);
 
 
@@ -2404,7 +2414,7 @@ static int gl_fbo_toscreen(lua_State *L)
 	glDrawArrays(GL_QUADS, 0, 4);
 
 	if (lua_isuserdata(L, 6)) glUseProgramObjectARB(0);
-	glEnable(GL_BLEND);
+	if (!allowblend) glEnable(GL_BLEND);
 	return 0;
 }