diff --git a/game/engine/Map.lua b/game/engine/Map.lua
index f28e3713418c99a668ab0291f0bbc56bf6856d78..c8207b806a02ab9343a506e67e1b2ec11c34fb1e 100644
--- a/game/engine/Map.lua
+++ b/game/engine/Map.lua
@@ -89,9 +89,6 @@ end
 --- Serialization
 function _M:save()
 	return class.save(self, {
-		_fov_esp = true,
-		_fov_lite = true,
-		_fov = true,
 		_map = true,
 		surface = true,
 		particle = true,
@@ -139,9 +136,6 @@ function _M:loaded()
 	setmetatable(self.remembers, {__call = mapremember})
 
 	self.surface = core.display.newSurface(self.viewport.width, self.viewport.height)
-	self._fov = core.fov.new(_M.opaque, _M.apply, self)
-	self._fov_lite = core.fov.new(_M.opaque, _M.applyLite, self)
-	self._fov_esp = core.fov.new(_M.opaqueESP, _M.applyESP, self)
 	self.changed = true
 	self.finished = true
 
@@ -170,51 +164,14 @@ end
 -- to the map. Cyclic references! BAD BAD BAD !<br/>
 -- The closing should be handled automatically by the Zone class so no bother for authors
 function _M:close()
-	self._fov = false
-	self._fov_lite = false
-	self._fov_esp = false
-end
-
---- Runs the FOV algorithm on the map
--- @param x source point of the ligth
--- @param y source point of the ligth
--- @param d radius of the light
-function _M:fov(x, y, d)
-	-- Reset seen grids
-	if self.clean_fov then
-		self.clean_fov = false
-		for i = 0, self.w * self.h - 1 do self.seens[i] = nil end
-		self._map:cleanSeen();
-	end
-	self._fov(x, y, d)
-end
-
---- Runs the FOV algorithm on the map, ligthing grids to allow rememberance
--- @param x source point of the ligth
--- @param y source point of the ligth
--- @param d radius of the light
-function _M:fovLite(x, y, d)
-	-- Reset seen grids
-	if self.clean_fov then
-		self.clean_fov = false
-		for i = 0, self.w * self.h - 1 do self.seens[i] = nil end
-		self._map:cleanSeen();
-	end
-	self._fov_lite(x, y, d)
-end
-
---- Runs the FOV algorithm on the map, finding ESP(Extra Sensorial Power) targets
--- @param x source point of the ligth
--- @param y source point of the ligth
--- @param d radius of the light
-function _M:fovESP(x, y, d)
-	-- Reset seen grids
-	if self.clean_fov then
-		self.clean_fov = false
-		for i = 0, self.w * self.h - 1 do self.seens[i] = nil end
-		self._map:cleanSeen();
-	end
-	self._fov_esp(x, y, d)
+end
+
+--- Cleans the FOV infos (seens table)
+function _M:cleanFOV()
+	if not self.clean_fov then return end
+	self.clean_fov = false
+	for i = 0, self.w * self.h - 1 do self.seens[i] = nil end
+	self._map:cleanSeen()
 end
 
 function _M:updateMap(x, y)
diff --git a/game/engine/Tooltip.lua b/game/engine/Tooltip.lua
index 82ac0dbc42f97914c615b56708094f813f8dd3e8..5fefca31886a07afb9e2e4861ca94a82d350f6d4 100644
--- a/game/engine/Tooltip.lua
+++ b/game/engine/Tooltip.lua
@@ -1,5 +1,7 @@
 require "engine.class"
+local Map = require "engine.Map"
 
+--- Displays a tooltip
 module(..., package.seeall, class.make)
 
 tiles = engine.Tiles.new(16, 16)
@@ -13,6 +15,7 @@ function _M:init(fontname, fontsize, color, bgcolor)
 	self.changed = true
 end
 
+--- Set the tooltip text
 function _M:set(str, ...)
 	self.text = str:format(...):splitLines(300, self.font)
 	self.w, self.h = 0, 0
@@ -54,3 +57,28 @@ function _M:display()
 	end
 	return self.surface
 end
+
+--- Displays the tooltip at the given map coordinates
+-- @param tmx the map coordinate to get tooltip from
+-- @param tmy the map coordinate to get tooltip from
+-- @param mx the screen coordinate to display at, if nil it will be computed from tmx
+-- @param my the screen coordinate to display at, if nil it will be computed from tmy
+function _M:displayAtMap(tmx, tmy, mx, my)
+	if not mx then
+		mx, my = game.level.map:getTileToScreen(tmx, tmy)
+	end
+
+	local tt = game.level.map:checkEntity(tmx, tmy, Map.ACTOR, "tooltip") or
+			game.level.map:checkEntity(tmx, tmy, Map.OBJECT, "tooltip") or
+			game.level.map:checkEntity(tmx, tmy, Map.TRAP, "tooltip") or
+			game.level.map:checkEntity(tmx, tmy, Map.TERRAIN, "tooltip")
+	if tt and game.level.map.seens(tmx, tmy) then
+		self:set("%s", tt)
+		local t = self:display()
+		mx = mx - self.w
+		my = my - self.h
+		if mx < 0 then mx = 0 end
+		if my < 0 then my = 0 end
+		if t then t:toScreen(mx, my) end
+	end
+end
diff --git a/game/engine/interface/ActorFOV.lua b/game/engine/interface/ActorFOV.lua
index 9547c40cd0c208ad6bdaad780a2aec8b4ff05ca8..307c080826b653495b99855898417b32bb026caf 100644
--- a/game/engine/interface/ActorFOV.lua
+++ b/game/engine/interface/ActorFOV.lua
@@ -19,42 +19,58 @@ end
 --- Computes actor's FOV
 -- @param radius the FOV radius, defaults to 20
 -- @param block the property to look for FOV blocking, defaults to "block_sight"
+-- @param apply an apply function that will be called on each seen grids, defaults to nil
 -- @param force set to true to force a regeneration even if we did not move
-function _M:computeFOV(radius, block, force)
+-- @param no_store do not store FOV informations
+function _M:computeFOV(radius, block, apply, force, no_store)
 	-- If we did not move, do not update
 	if not force and self.fov_last_x == self.x and self.fov_last_y == self.y and self.fov_computed then return end
 	radius = radius or 20
 	block = block or "block_sight"
 
-	local fov = {actors={}, actors_dist={}}
-	setmetatable(fov.actors, {__mode='k'})
-	setmetatable(fov.actors_dist, {__mode='v'})
+	-- Simple FOV compute no storage
+	if no_store and apply then
+		local map = game.level.map
+		core.fov.calc_circle(self.x, self.y, radius, function(_, x, y)
+			if map:checkAllEntities(x, y, block, self) then return true end
+		end, function(_, x, y, dx, dy)
+			apply(x, y, dx, dy)
+		end, self)
 
-	local map = game.level.map
-	core.fov.calc_circle(self.x, self.y, radius, function(_, x, y)
-		if map:checkAllEntities(x, y, block, self) then return true end
-	end, function(_, x, y, dx, dy)
-		-- Note actors
-		local a = map(x, y, Map.ACTOR)
-		if a and a ~= self and not a.dead then
-			local t = {x=x,y=y, dx=dx, dy=dy, sqdist=dx*dx+dy*dy}
-			fov.actors[a] = t
-			fov.actors_dist[#fov.actors_dist+1] = a
-			a:updateFOV(self, t.sqdist)
-		end
-	end, self)
+	-- FOV + storage
+	elseif not no_store then
+		local fov = {actors={}, actors_dist={}}
+		setmetatable(fov.actors, {__mode='k'})
+		setmetatable(fov.actors_dist, {__mode='v'})
 
-	-- Sort actors by distance (squared but we do not care)
-	table.sort(fov.actors_dist, function(a, b) return fov.actors[a].sqdist < fov.actors[b].sqdist end)
-	for i = 1, #fov.actors_dist do fov.actors_dist[i].i = i end
---	print("Computed FOV for", self.uid, self.name, ":: seen ", #fov.actors_dist, "actors closeby")
+		local map = game.level.map
+		core.fov.calc_circle(self.x, self.y, radius, function(_, x, y)
+			if map:checkAllEntities(x, y, block, self) then return true end
+		end, function(_, x, y, dx, dy)
+			if apply then apply(x, y, dx, dy) end
 
-	self.fov = fov
-	self.fov_last_x = self.x
-	self.fov_last_y = self.y
-	self.fov_last_turn = game.turn
-	self.fov_last_change = game.turn
-	self.fov_computed = true
+			-- Note actors
+			local a = map(x, y, Map.ACTOR)
+			if a and a ~= self and not a.dead then
+				local t = {x=x,y=y, dx=dx, dy=dy, sqdist=dx*dx+dy*dy}
+				fov.actors[a] = t
+				fov.actors_dist[#fov.actors_dist+1] = a
+				a:updateFOV(self, t.sqdist)
+			end
+		end, self)
+
+		-- Sort actors by distance (squared but we do not care)
+		table.sort(fov.actors_dist, function(a, b) return fov.actors[a].sqdist < fov.actors[b].sqdist end)
+		for i = 1, #fov.actors_dist do fov.actors_dist[i].i = i end
+--		print("Computed FOV for", self.uid, self.name, ":: seen ", #fov.actors_dist, "actors closeby")
+
+		self.fov = fov
+		self.fov_last_x = self.x
+		self.fov_last_y = self.y
+		self.fov_last_turn = game.turn
+		self.fov_last_change = game.turn
+		self.fov_computed = true
+	end
 end
 
 --- Update our fov to include the given actor at the given dist
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 463d04adadaab84ff084ac0277445307dd9f7ab4..9aa46860247e79e112db5b5ab3437d60cd411a9b 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -10,6 +10,7 @@ require "engine.interface.ActorTalents"
 require "engine.interface.ActorResource"
 require "engine.interface.ActorQuest"
 require "engine.interface.BloodyDeath"
+require "engine.interface.ActorFOV"
 require "mod.class.interface.Combat"
 local Map = require "engine.Map"
 
@@ -25,6 +26,7 @@ module(..., package.seeall, class.inherit(
 	engine.interface.ActorResource,
 	engine.interface.ActorQuest,
 	engine.interface.BloodyDeath,
+	engine.interface.ActorFOV,
 	mod.class.interface.Combat
 ))
 
@@ -89,6 +91,7 @@ function _M:init(t, no_default)
 	engine.interface.ActorTalents.init(self, t)
 	engine.interface.ActorResource.init(self, t)
 	engine.interface.ActorLevel.init(self, t)
+	engine.interface.ActorFOV.init(self, t)
 end
 
 function _M:act()
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index d8e15a8c33a77813edbbba046d9a107114e8a7e6..3ec6a511a08c2fd5ffd24dec0c3fb3ed04d20f3a 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -245,31 +245,32 @@ function _M:display()
 	if self.level and self.level.map and self.level.map.finished then
 		-- Display the map and compute FOV for the player if needed
 		if self.level.map.changed then
-			self.level.map:fovESP(self.player.x, self.player.y, self.player.esp.range or 10)
-			self.level.map:fov(self.player.x, self.player.y, 20)
-			if self.player.lite > 0 then self.level.map:fovLite(self.player.x, self.player.y, self.player.lite) end
+			-- Compute FOV, if needed
+			self.level.map:cleanFOV()
+			self.player:computeFOV(self.player.esp.range or 10, "block_esp", function(x, y) self.level.map:applyESP(x, y) end, true, true)
+			self.player:computeFOV(self.player.sight or 20, "block_sight", function(x, y) self.level.map:apply(x, y) end, true)
+			if self.player.lite > 0 then self.player:computeFOV(self.player.life, "block_sight", function(x, y) self.level.map:applyLite(x, y) end, true, true) end
 
 			--
 			-- Handle Sense spell
 			--
 			if self.player:attr("detect_range") then
-				core.fov.calc_circle(self.player.x, self.player.y, self.player:attr("detect_range"), function(map, lx, ly)
-					if game.level.map:checkEntity(lx, ly, engine.Map.TERRAIN, "block_sense") then return true end
-				end, function(map, lx, ly)
+				self.player:computeFOV(self.player:attr("detect_range"), "block_sense", function(x, y)
 					local ok = false
-					if game.player:attr("detect_actor") and game.level.map(lx, ly, game.level.map.ACTOR) then ok = true end
-					if game.player:attr("detect_object") and game.level.map(lx, ly, game.level.map.OBJECT) then ok = true end
-					if game.player:attr("detect_trap") and game.level.map(lx, ly, game.level.map.TRAP) then
-						game.level.map(lx, ly, game.level.map.TRAP):setKnown(self.player, true)
+					if self.player:attr("detect_actor") and self.level.map(x, y, self.level.map.ACTOR) then ok = true end
+					if self.player:attr("detect_object") and self.level.map(x, y, self.level.map.OBJECT) then ok = true end
+					if self.player:attr("detect_trap") and self.level.map(x, y, self.level.map.TRAP) then
+						self.level.map(x, y, self.level.map.TRAP):setKnown(self.player, true)
 						ok = true
 					end
 
 					if ok then
-						game.level.map.seens(lx, ly, true)
+						self.level.map.seens(x, y, true)
 					end
-				end, self)
+				end, true, true)
 			end
 		end
+
 		self.level.map:display()
 
 		-- Display the targetting system if active
@@ -278,19 +279,9 @@ function _M:display()
 		-- Display a tooltip if available
 		local mx, my = core.mouse.get()
 		local tmx, tmy = self.level.map:getMouseTile(mx, my)
-		local tt = self.level.map:checkEntity(tmx, tmy, Map.ACTOR, "tooltip") or
-				self.level.map:checkEntity(tmx, tmy, Map.OBJECT, "tooltip") or
-				self.level.map:checkEntity(tmx, tmy, Map.TRAP, "tooltip") or
-				self.level.map:checkEntity(tmx, tmy, Map.TERRAIN, "tooltip")
-		if tt and self.level.map.seens(tmx, tmy) then
-			self.tooltip:set("%s", tt)
-			local t = self.tooltip:display()
-			mx = mx - self.tooltip.w
-			my = my - self.tooltip.h
-			if mx < 0 then mx = 0 end
-			if my < 0 then my = 0 end
-			if t then t:toScreen(mx, my) end
-		end
+		self.tooltip:displayAtMap(tmx, tmy, mx, my)
+
+		-- Move target around
 		if self.old_tmx ~= tmx or self.old_tmy ~= tmy then
 			self.target.target.x, self.target.target.y = tmx, tmy
 		end
diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua
index 84c6118a4ee9a33c58707f8f42b9c4019dcdc11e..739e4336b5be13c3676f2f037a853eeeaa7d0e79 100644
--- a/game/modules/tome/class/NPC.lua
+++ b/game/modules/tome/class/NPC.lua
@@ -1,27 +1,25 @@
 require "engine.class"
 local ActorAI = require "engine.interface.ActorAI"
-local ActorFOV = require "engine.interface.ActorFOV"
 require "mod.class.Actor"
 
-module(..., package.seeall, class.inherit(mod.class.Actor, engine.interface.ActorAI, engine.interface.ActorFOV))
+module(..., package.seeall, class.inherit(mod.class.Actor, engine.interface.ActorAI))
 
 function _M:init(t, no_default)
 	mod.class.Actor.init(self, t, no_default)
 	ActorAI.init(self, t)
-	ActorFOV.init(self, t)
 end
 
 function _M:act()
 	-- Do basic actor stuff
 	if not mod.class.Actor.act(self) then return end
 
+	-- Compute FOV, if needed
+	self:computeFOV(self.sight or 20)
+
 	-- Let the AI think .... beware of Shub !
 	-- If AI did nothing, use energy anyway
 	self:doAI()
 	if not self.energy.used then self:useEnergy() end
-
-	-- Compute FOV, if needed
-	self:computeFOV(self.sight or 20)
 end
 
 --- Called by ActorLife interface
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index c6639a8753bcea3eba7f7f9203592c3c82a7d95e..6adcbfb0a0df6ae148c48f09f3066eae2d480b63 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -4,7 +4,6 @@ require "engine.interface.PlayerRest"
 require "engine.interface.PlayerRun"
 require "engine.interface.PlayerHotkeys"
 require "engine.interface.PlayerSlide"
-local ActorFOV = require "engine.interface.ActorFOV"
 local Map = require "engine.Map"
 local Dialog = require "engine.Dialog"
 local ActorTalents = require "engine.interface.ActorTalents"
@@ -20,8 +19,7 @@ module(..., package.seeall, class.inherit(
 	engine.interface.PlayerRest,
 	engine.interface.PlayerRun,
 	engine.interface.PlayerHotkeys,
-	engine.interface.PlayerSlide,
-	engine.interface.ActorFOV
+	engine.interface.PlayerSlide
 ))
 
 function _M:init(t, no_default)
@@ -40,7 +38,6 @@ function _M:init(t, no_default)
 	}
 	mod.class.Actor.init(self, t, no_default)
 	engine.interface.PlayerHotkeys.init(self, t)
-	ActorFOV.init(self, t)
 	self.player = true
 	self.type = "humanoid"
 	self.subtype = "player"
@@ -92,9 +89,6 @@ end
 function _M:act()
 	if not mod.class.Actor.act(self) then return end
 
-	-- Compute FOV, if needed
-	self:computeFOV(self.sight or 20)
-
 	-- Clean log flasher
 	game.flash:empty()