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/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index b73cd6ee7711679fff51b497bdb8075be2267f00..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
@@ -1359,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/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/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/mm_fbo.lua b/game/modules/tome/data/gfx/shaders/target_fbo.lua
similarity index 87%
rename from game/modules/tome/data/gfx/shaders/mm_fbo.lua
rename to game/modules/tome/data/gfx/shaders/target_fbo.lua
index 6aac51e1be541ccfb4b1986dff09a6b8695e09ab..8e0ba1def4205224fd586ce3cc7d59de8014ac05 100644
--- a/game/modules/tome/data/gfx/shaders/mm_fbo.lua
+++ b/game/modules/tome/data/gfx/shaders/target_fbo.lua
@@ -18,9 +18,13 @@
 -- darkgod@te4.org
 
 return {
-	frag = "mm_fbo",
+	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