diff --git a/game/engine/Map.lua b/game/engine/Map.lua
index 3df536ffe0b93c8670dce9dcc85ce3b8fb9175c9..15a9d9ce65029dba4e81423d318276ccce6f61f7 100644
--- a/game/engine/Map.lua
+++ b/game/engine/Map.lua
@@ -80,6 +80,7 @@ end
 --- Serialization
 function _M:save()
 	return class.save(self, {
+		_fov_esp = true,
 		_fov_lite = true,
 		_fov = true,
 		_map = true,
@@ -125,6 +126,7 @@ function _M:loaded()
 	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:redisplay()
@@ -154,6 +156,7 @@ end
 function _M:close()
 	self._fov = false
 	self._fov_lite = false
+	self._fov_esp = false
 end
 
 --- Runs the FOV algorithm on the map
@@ -184,6 +187,20 @@ function _M:fovLite(x, y, d)
 	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
+
 function _M:updateMap(x, y)
 	local g = self(x, y, TERRAIN)
 	local o = self(x, y, OBJECT)
@@ -192,7 +209,7 @@ function _M:updateMap(x, y)
 	if g then g = self.tiles:get(g.display, g.color_r, g.color_g, g.color_b, g.color_br, g.color_bg, g.color_bb, g.image) end
 	if o then o = self.tiles:get(o.display, o.color_r, o.color_g, o.color_b, o.color_br, o.color_bg, o.color_bb, o.image) end
 	if a then
-		-- Handles invisibility and telepathy and otehr such things
+		-- Handles invisibility and telepathy and other such things
 		if not self.actor_player or self.actor_player:canSee(a) then
 			a = self.tiles:get(a.display, a.color_r, a.color_g, a.color_b, a.color_br, a.color_bg, a.color_bb, a.image)
 		else
@@ -288,6 +305,14 @@ function _M:opaque(x, y)
 	if e and e:check("block_sight") then return true end
 end
 
+--- Sets checks if a grid lets ESP pass through
+-- Used by FOV ESP code
+function _M:opaqueESP(x, y)
+	if x < 0 or x >= self.w or y < 0 or y >= self.h then return false end
+	local e = self(x, y, TERRAIN)
+	if e and e:check("block_esp") then return true end
+end
+
 --- Sets a grid as seen and remembered
 -- Used by FOV code
 function _M:apply(x, y)
@@ -312,6 +337,18 @@ function _M:applyLite(x, y)
 	self._map:setSeen(x, y, true)
 end
 
+--- Sets a grid as seen if ESP'ed
+-- Used by FOV code
+function _M:applyESP(x, y)
+	if not self.actor_player then return end
+	if x < 0 or x >= self.w or y < 0 or y >= self.h then return end
+	local a = self(x, y, ACTOR)
+	if a and self.actor_player:canSee(a, false, 0) then
+		self.seens[x + y * self.w] = true
+		self._map:setSeen(x, y, true)
+	end
+end
+
 --- Check all entities of the grid for a property
 -- @param x position
 -- @param y position
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index c5c6b35c3d2d8be02f7b0746ac534779f0a06743..c3024a2c9cecd2522840d37a296cb81c55d935a4 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -52,6 +52,8 @@ function _M:init(t, no_default)
 	t.mana_rating = t.mana_rating or 10
 	t.stamina_rating = t.stamina_rating or 10
 
+	t.esp = {range=10}
+
 	-- Resistances
 	t.resists = t.resists or {}
 
@@ -335,7 +337,23 @@ end
 --- Can the actor see the target actor
 -- This does not check LOS or such, only the actual ability to see it.<br/>
 -- Check for telepathy, invisibility, stealth, ...
-function _M:canSee(actor)
+function _M:canSee(actor, def, def_pct)
+	-- ESP, see all, or only types/subtypes
+	if self:attr("esp") then
+		local esp = self:attr("esp")
+		-- Full ESP
+		if esp.all and esp.all > 0 then
+			if game.level then
+				game.level.map.seens(actor.x, actor.y, true)
+			end
+			return true, 100
+		end
+
+		-- Type based ESP
+		if esp[actor.type] and esp[actor.type] > 0 then return true, 100 end
+		if esp[actor.type.."/"..actor.subtype] and esp[actor.type.."/"..actor.subtype] > 0 then return true, 100 end
+	end
+
 	-- Blindness means can't see anything
 	if self:attr("blind") then return false, 0 end
 
@@ -343,7 +361,6 @@ function _M:canSee(actor)
 	if actor:attr("stealth") and actor ~= self then
 		local def = self.level / 2 + self:getCun(25)
 		local hit, chance = self:checkHit(def, actor:attr("stealth") + (actor:attr("inc_stealth") or 0), 0, 100)
-		print("Stealth", actor:attr("stealth") + (actor:attr("inc_stealth") or 0), "<:>", def, " ===> ", hit, chance)
 		if not hit then
 			return false, chance
 		end
@@ -358,7 +375,11 @@ function _M:canSee(actor)
 			return false, chance
 		end
 	end
-	return true, 100
+	if def ~= nil then
+		return def, def_pct
+	else
+		return true, 100
+	end
 end
 
 --- Can the target be applied some effects
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 99ff89acf2b916cfe7a14ccaf9c2a112039e4684..9caeba4055b93cb56cbb9c5a328c181e39191a7f 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -205,6 +205,7 @@ function _M:display()
 	if self.level and self.level.map 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
 		end
diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua
index 810a2e0e99837b4e2eacaf197bf55cdc4725ea9c..bcc4d5e40e817db85f3216ae256dc68b36f39c08 100644
--- a/game/modules/tome/class/Object.lua
+++ b/game/modules/tome/class/Object.lua
@@ -102,6 +102,22 @@ function _M:getDesc()
 		desc[#desc+1] = ("Increases resistances: %s."):format(table.concat(rs, ','))
 	end
 
+	if w.esp then
+		local rs = {}
+		for type, i in pairs(w.esp) do
+			if type == "all" then rs[#rs+1] = "all"
+			else
+				local _, _, t, st = type:find("^([^/]+)/?(.*)$")
+				if st then
+					rs[#rs+1] = st
+				else
+					rs[#rs+1] = t
+				end
+			end
+		end
+		desc[#desc+1] = ("Grants telepathy to %s."):format(table.concat(rs, ','))
+	end
+
 	if w.talents_types_mastery then
 		local tms = {}
 		for ttn, i in pairs(w.talents_types_mastery) do
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index 2a491ddd61289fc6bcf548b6abcb6f76f1d1703a..f686f4893a2440df5aca546c050e044a91c72681 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -32,6 +32,8 @@ function _M:init(t, no_default)
 	}
 	mod.class.Actor.init(self, t, no_default)
 	self.player = true
+	self.type = "humanoid"
+	self.subtype = "player"
 	self.faction = "players"
 
 	self.display='@'
diff --git a/game/modules/tome/data/birth/races/dwarf.lua b/game/modules/tome/data/birth/races/dwarf.lua
index aeb98a51c6a5a6547fbdc53ac98e9da65460f894..486e9f7ba1bd58ff67b42cd504e49deb3ad94509 100644
--- a/game/modules/tome/data/birth/races/dwarf.lua
+++ b/game/modules/tome/data/birth/races/dwarf.lua
@@ -27,6 +27,7 @@ newBirthDescriptor{
 		[ActorTalents.T_DWARF_RESILIENCE]=1,
 	},
 	copy = {
+		type = "humanoid", subtype="dwarf",
 		default_wilderness = {"wilderness/main", 41, 18},
 		life_rating=12,
 	},
diff --git a/game/modules/tome/data/birth/races/elf.lua b/game/modules/tome/data/birth/races/elf.lua
index 2ecb00f87e88803bfc934ef8ef9e93db42836442..cb2e2adf924d4af5e5a5082d60b2ed7876ad2dfe 100644
--- a/game/modules/tome/data/birth/races/elf.lua
+++ b/game/modules/tome/data/birth/races/elf.lua
@@ -22,6 +22,7 @@ newBirthDescriptor{
 --		[ActorTalents.T_IMPROVED_MANA_I]=1,
 	},
 	copy = {
+		type = "humanoid", subtype="elf",
 		default_wilderness = {"wilderness/main", 41, 18},
 	},
 	experience = 1.05,
diff --git a/game/modules/tome/data/birth/races/hobbit.lua b/game/modules/tome/data/birth/races/hobbit.lua
index 7ad3bab1d5070a8d8fd52d76e012c0bdf9828588..4947b49b8da0d4fc3d987ecf122e63779e04eaf8 100644
--- a/game/modules/tome/data/birth/races/hobbit.lua
+++ b/game/modules/tome/data/birth/races/hobbit.lua
@@ -36,6 +36,7 @@ newBirthDescriptor{
 		[ActorTalents.T_HOBBIT_LUCK]=1,
 	},
 	copy = {
+		type = "humanoid", subtype="hobbit",
 		life_rating = 12,
 		default_wilderness = {"wilderness/main", 41, 18},
 	},
diff --git a/game/modules/tome/data/birth/races/human.lua b/game/modules/tome/data/birth/races/human.lua
index 0fcdc247e84279d65c76b7981508e3784287fbcb..47a244156ed1f724e113d17bf271b3894bac6cc8 100644
--- a/game/modules/tome/data/birth/races/human.lua
+++ b/game/modules/tome/data/birth/races/human.lua
@@ -20,6 +20,9 @@ newBirthDescriptor{
 	},
 	talents = {},
 	experience = 1.0,
+	copy = {
+		type = "humanoid", subtype="human",
+	},
 }
 
 ---------------------------------------------------------
diff --git a/game/modules/tome/data/general/objects/egos/amulets.lua b/game/modules/tome/data/general/objects/egos/amulets.lua
index d3e45349b36aaeea600494f25546dd508c36597a..9cbcde650dd68abca624945d52c6ace89bf7b444 100644
--- a/game/modules/tome/data/general/objects/egos/amulets.lua
+++ b/game/modules/tome/data/general/objects/egos/amulets.lua
@@ -56,3 +56,21 @@ newEntity{
 		e.wielder.talents_types_mastery[tt] = (10 + rng.mbonus(30, resolvers.current_level, 50)) / 100
 	end),
 }
+newEntity{
+	name = " of greater telepathy",
+	level_range = {40, 50},
+	rarity = 15,
+	cost = 15,
+	wielder = {
+		esp = {all=1},
+	},
+}
+newEntity{
+	name = " of telepathic range",
+	level_range = {40, 50},
+	rarity = 15,
+	cost = 15,
+	wielder = {
+		esp = {range=10},
+	},
+}
diff --git a/game/modules/tome/data/zones/trollshaws/zone.lua b/game/modules/tome/data/zones/trollshaws/zone.lua
index e312827b65448e4db6d561814b1eb762b05766fc..1e64bfae787e5929de86d8a8425b0b0c9d054bf0 100644
--- a/game/modules/tome/data/zones/trollshaws/zone.lua
+++ b/game/modules/tome/data/zones/trollshaws/zone.lua
@@ -29,6 +29,8 @@ return {
 			class = "engine.generator.object.Random",
 			nb_object = {4, 6},
 			filters = { {type="potion" }, {type="potion" }, {type="potion" }, {type="scroll" }, {}, {} }
+--			nb_object = {400, 600},
+--			filters = { {type="jewelry", subtype="amulet" }, }
 		},
 	},
 	levels =
diff --git a/ideas/spells.ods b/ideas/spells.ods
index 6a0645a0ee65447286922de980654b36ecd11b4a..cc4e805cc25dbfea3d042b446556266f2ea2412e 100644
Binary files a/ideas/spells.ods and b/ideas/spells.ods differ