diff --git a/game/engine/interface/PlayerHotkeys.lua b/game/engine/interface/PlayerHotkeys.lua
new file mode 100644
index 0000000000000000000000000000000000000000..fac3acbc747f92587b3ae19069fab947741f0704
--- /dev/null
+++ b/game/engine/interface/PlayerHotkeys.lua
@@ -0,0 +1,41 @@
+require "engine.class"
+
+--- Handles player hotkey interface
+-- This provides methods to bind and manage hotkeys as well as using them<br/>
+-- This interface is designed to work with the engine.HotkeysDisplay class to display current hotkeys to the player
+module(..., package.seeall, class.make)
+
+function _M:init(t)
+	self.hotkey = {}
+	self.hotkey_page = 1
+end
+
+--- Uses an hotkeyed talent
+-- This requires the ActorTalents interface to use talents and a method player:playerUseItem(o, item) to use inventory objects
+function _M:activateHotkey(id)
+	if self.hotkey[id] then
+		if self.hotkey[id][1] == "talent" then
+			self:useTalent(self.hotkey[id][2])
+		elseif self.hotkey[id][1] == "inventory" then
+			local o, item = self:findInInventory(self:getInven("INVEN"), self.hotkey[id][2])
+			if not o then
+				Dialog:simplePopup("Item not found", "You do not have any "..self.hotkey[id][2]..".")
+			else
+				self:playerUseItem(o, item)
+			end
+		end
+	else
+		Dialog:simplePopup("Hotkey not defined", "You may define a hotkey by pressing 'm' and following the inscructions there.")
+	end
+end
+
+--- Switch to previous hotkey page
+function _M:prevHotkeyPage()
+	self.hotkey_page = util.boundWrap(self.hotkey_page - 1, 1, 3)
+	self.changed = true
+end
+--- Switch to next hotkey page
+function _M:nextHotkeyPage()
+	self.hotkey_page = util.boundWrap(self.hotkey_page + 1, 1, 3)
+	self.changed = true
+end
diff --git a/game/modules/tome/data/birth/classes.lua b/game/modules/tome/data/birth/classes.lua
index 2f684d2a78a7cb462741ce75124e9da0a06781aa..0bf7c5e5034bcc633f1d29a4d70340cef97509fb 100644
--- a/game/modules/tome/data/birth/classes.lua
+++ b/game/modules/tome/data/birth/classes.lua
@@ -32,10 +32,10 @@ newBirthDescriptor{
 	},
 	stats = { str=3, con=2, dex=1, },
 	talents_types = {
-		["physical/shield"]={true, 0.3},
-		["physical/2hweapon"]={true, 0.3},
-		["physical/combat-training"]={true, 0.3},
-		["physical/weapon-training"]={true, 0.3},
+		["technique/shield"]={true, 0.3},
+		["technique/2hweapon"]={true, 0.3},
+		["technique/combat-training"]={true, 0.3},
+		["technique/weapon-training"]={true, 0.3},
 	},
 	talents = {
 		[ActorTalents.T_SHIELD_BASH] = 1,
@@ -80,9 +80,9 @@ newBirthDescriptor{
 	},
 	stats = { dex=2, str=1, cun=3, },
 	talents_types = {
-		["physical/dualweapon"]={true, 0.3},
-		["physical/combat-training"]={true, 0},
-		["physical/weapon-training"]={true, 0},
+		["technique/dualweapon"]={true, 0.3},
+		["technique/combat-training"]={true, 0},
+		["technique/weapon-training"]={true, 0},
 		["cunning/stealth"]={true, 0.3},
 		["cunning/traps"]={true, 0.3},
 		["cunning/dirty"]={true, 0.3},
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index 0bf269cb3bab6de918e33d6193d7c129692ac8e3..3a862093c41d5cf9d4792d2a086e7d39e7b50306 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -231,6 +231,18 @@ newDamageType{
 	end,
 }
 
+-- Slime damage
+newDamageType{
+	name = "slime", type = "SLIME",
+	projector = function(src, x, y, type, dam)
+		DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam)
+		local target = game.level.map(x, y, Map.ACTOR)
+		if target then
+			target:setEffect(target.EFF_SLOW, 3, {power=0.3})
+		end
+	end,
+}
+
 -- Poisoning damage
 newDamageType{
 	name = "dig", type = "DIG",
diff --git a/game/modules/tome/data/general/npcs/bear.lua b/game/modules/tome/data/general/npcs/bear.lua
index 7fcb95a77d025a6a4e09504ab2fc24129aac3660..d4dd9b20858d78ffad74386bdff94c0431b044be 100644
--- a/game/modules/tome/data/general/npcs/bear.lua
+++ b/game/modules/tome/data/general/npcs/bear.lua
@@ -16,7 +16,7 @@ newEntity{
 	combat_armor = 1, combat_def = 1,
 	combat = { dam=resolvers.rngavg(12,25), atk=10, apr=10, physspeed=2 },
 	life_rating = 13,
-	tmasteries = resolvers.tmasteries{ ["physical/other"]=0.25 },
+	tmasteries = resolvers.tmasteries{ ["technique/other"]=0.25 },
 
 	resists = { [DamageType.FIRE] = 20, [DamageType.COLD] = 20, [DamageType.POISON] = 20 },
 }
diff --git a/game/modules/tome/data/general/npcs/skeleton.lua b/game/modules/tome/data/general/npcs/skeleton.lua
index dd24826b56e772d5d3da95ddd046bd5ce3fdb16e..18f8af864e267c4346033e02bc89464d7c316491 100644
--- a/game/modules/tome/data/general/npcs/skeleton.lua
+++ b/game/modules/tome/data/general/npcs/skeleton.lua
@@ -16,7 +16,7 @@ newEntity{
 	energy = { mod=1 },
 	stats = { str=14, dex=12, mag=10, con=12 },
 
-	tmasteries = resolvers.tmasteries{ ["physical/other"]=0.3, ["physical/2hweapon"]=0.3 },
+	tmasteries = resolvers.tmasteries{ ["technique/other"]=0.3, ["technique/2hweapon"]=0.3 },
 
 	blind_immune = 1,
 	see_invisible = 2,
diff --git a/game/modules/tome/data/general/npcs/troll.lua b/game/modules/tome/data/general/npcs/troll.lua
index 55d3e991a76891726a97e0a794fb7886e7b0ad20..84555ba7d070198a153028b8d4e10e6c6a653ecc 100644
--- a/game/modules/tome/data/general/npcs/troll.lua
+++ b/game/modules/tome/data/general/npcs/troll.lua
@@ -19,7 +19,7 @@ newEntity{
 	energy = { mod=1 },
 	stats = { str=20, dex=8, mag=6, con=16 },
 
-	tmasteries = resolvers.tmasteries{ ["physical/other"]=0.3 },
+	tmasteries = resolvers.tmasteries{ ["technique/other"]=0.3 },
 
 	resists = { [DamageType.FIRE] = -50 },
 }
diff --git a/game/modules/tome/data/general/objects/potions.lua b/game/modules/tome/data/general/objects/potions.lua
index ec95af19323745eb0c317a69e576e6ef99c3f2d6..ed01b9d61aa1e67ff46cda49b4e335371529d8b3 100644
--- a/game/modules/tome/data/general/objects/potions.lua
+++ b/game/modules/tome/data/general/objects/potions.lua
@@ -159,10 +159,10 @@ newEntity{ base = "BASE_POTION",
 	cost = 0.01,
 
 	use_simple = { name="quaff", use = function(self, who)
-		game.logSeen(who, "%s quaff the slime juice. Yuck.", who.name:capitalize())
+		game.logSeen(who, "%s quaffs the slime juice. Yuck.", who.name:capitalize())
 		-- 1% chance of gaining slime mold powers
 		if rng.percent(1) then
-			who:learnTalentType("slime/slime", true)
+			who:learnTalentType("gift/slime", true)
 			game.logSeen(who, "%s is transformed by the slime mold juice.", who.name:capitalize())
 			game.logPlayer(who, "#00FF00#You gain an affinity for the molds. You can now learn new slime talents (press G).")
 		end
diff --git a/game/modules/tome/data/general/objects/scrolls.lua b/game/modules/tome/data/general/objects/scrolls.lua
index 54ecd1f33472178f35ddec9ed514703c0c7b88fc..cc86decc7d03aaefa1860852cfd1988c6a378215 100644
--- a/game/modules/tome/data/general/objects/scrolls.lua
+++ b/game/modules/tome/data/general/objects/scrolls.lua
@@ -23,6 +23,28 @@ newEntity{ base = "BASE_SCROLL",
 	end}
 }
 
+newEntity{ base = "BASE_SCROLL",
+	name = "scroll of identify",
+	level_range = {1, 50},
+	rarity = 6,
+	cost = 1,
+
+	use_simple = { name="identify one object (or all with high magic stat)", use = function(self, who)
+		if who:getMag() < 28 then
+			who:showInventory("Identify object", who:getInven(who.INVEN_INVEN), nil, function(o, item)
+				o:identify(true)
+				game.logPlayer(who, "You identify: "..o:getName())
+			end)
+		else
+			for i, o in ipairs(who:getInven("INVEN")) do
+				o:identify(true)
+			end
+			game.logPlayer(who, "You identify all your inventory.")
+		end
+		return "destroy", true
+	end}
+}
+
 newEntity{ base = "BASE_SCROLL",
 	name = "scroll of phase door",
 	level_range = {1, 30},
diff --git a/game/modules/tome/data/gfx/particles/slime.lua b/game/modules/tome/data/gfx/particles/slime.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1377b0d4f3d2e18c41333faffd4b7f831baafaa5
--- /dev/null
+++ b/game/modules/tome/data/gfx/particles/slime.lua
@@ -0,0 +1,19 @@
+return {
+	base = 1000,
+
+	angle = { 0, 360 }, anglev = { 2000, 4000 }, anglea = { 20, 60 },
+
+	life = { 5, 10 },
+	size = { 4, 7 }, sizev = {0, 0}, sizea = {0, 0},
+
+	r = {0, 0}, rv = {0, 0}, ra = {0, 0},
+	g = {80, 200}, gv = {0, 10}, ga = {0, 0},
+	b = {0, 0}, bv = {0, 0}, ba = {0, 0},
+	a = {155, 255}, av = {0, 0}, aa = {0, 0},
+
+}, function(self)
+	self.nb = (self.nb or 0) + 1
+	if self.nb < 6 then
+		self.ps:emit(100)
+	end
+end
diff --git a/game/modules/tome/data/talents/misc/random.lua b/game/modules/tome/data/talents/misc/random.lua
index 71b28d73088ff8d328bd9d4dc00a361ac8f5f3fe..87afcb77c9089d6534518a80f8e26876003dcd74 100644
--- a/game/modules/tome/data/talents/misc/random.lua
+++ b/game/modules/tome/data/talents/misc/random.lua
@@ -12,17 +12,102 @@ newTalent{
 	message = "@Source@ releases poisonous spores at @target@.",
 	cooldown = 10,
 	range = 1,
+	require = {level = function(level) return 0 + (level-1)  end,},
+	tactical = {
+		ATTACK = 10,
+	},
 	action = function(self, t)
 		local t = {type="hit", range=self:getTalentRange(t)}
 		local x, y, target = self:getTarget(t)
 		if not x or not y or not target then return nil end
 		if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end
 		self.combat_apr = self.combat_apr + 1000
-		self:attackTarget(target, DamageType.POISON, 1.5 + self:getTalentLevel(t) / 5, true)
+		self:attackTarget(target, DamageType.POISON, 1.5 + self:getTalentLevel(t) / 4, true)
 		self.combat_apr = self.combat_apr - 1000
 		return true
 	end,
-	info = function(self)
-		return ([[Releases poisonous spores at the target.]])
+	info = function(self, t)
+		return ([[Releases poisonous spores at the target doing %d%% weapon damage.]]):format(100 * (1.5 + self:getTalentLevel(t) / 4))
+	end,
+}
+
+newTalent{
+	name = "Acidic Skin",
+	type = {"gift/slime", 2},
+	points = 5,
+	mode = "sustained",
+	message = "The skin of @Source@ starts dripping acid.",
+	cooldown = 10,
+	range = 1,
+	require = {level = function(level) return 4 + (level-1)  end,},
+	tactical = {
+		DEFEND = 10,
+	},
+	activate = function(self, t)
+		local power = 10 + 5 * self:getTalentLevel(t)
+		return {
+			onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.ACID]=power}),
+		}
+	end,
+	deactivate = function(self, t, p)
+		self:removeTemporaryValue("on_melee_hit", p.onhit)
+		return true
+	end,
+	info = function(self, t)
+		return ([[Your skin drips with acid, damaging all that hits your for %d acid damage.]]):format(10 + 5 * self:getTalentLevel(t))
+	end,
+}
+
+newTalent{
+	name = "Slime Spit",
+	type = {"gift/slime", 3},
+	points = 5,
+	cooldown = 30,
+	tactical = {
+		ATTACK = 10,
+	},
+	range = 20,
+	require = {level = function(level) return 8 + (level-1)  end,},
+	action = function(self, t)
+		local tg = {type="bolt", range=self:getTalentRange(t)}
+		local x, y = self:getTarget(tg)
+		if not x or not y then return nil end
+		self:project(tg, x, y, DamageType.SLIME, 20 + (self:getMag() * self:getTalentLevel(t)) * 0.3, {type="slime"})
+		return true
+	end,
+	info = function(self, t)
+		return ([[Spit slime at your target doing %0.2f nature damage and slowing it down for 3 turns.
+		The damage will increase with the Dexterity stat]]):format(20 + (self:getMag() * self:getTalentLevel(t)) * 0.3)
+	end,
+}
+
+newTalent{
+	name = "Slime Roots",
+	type = {"gift/slime", 4},
+	points = 5,
+	cooldown = 20,
+	tactical = {
+		MOVEMENT = 10,
+	},
+	range = 20,
+	require = {level = function(level) return 12 + (level-1)  end,},
+	action = function(self, t)
+		local x, y = self:getTarget{type="ball", range=20 + self:getTalentLevel(t), radius=7 - self:getTalentLevel(t)}
+		if not x then return nil end
+		-- Target code doesnot restrict the self coordinates to the range, it lets the poject function do it
+		-- but we cant ...
+		x, y = game.target:pointAtRange(self.x, self.y, x, y, 20 + self:getTalentLevel(t))
+		game.level.map:particleEmitter(self.x, self.y, 1, "slime")
+		self:teleportRandom(x, y, 7 - self:getTalentLevel(t))
+		game.level.map:particleEmitter(self.x, self.y, 1, "slime")
+
+		-- Stunned!
+		self:setEffect(self.EFF_STUNNED, util.bound(5 - self:getTalentLevel(t) / 2, 2, 7), {})
+		return true
+	end,
+	info = function(self, t)
+		return ([[You extend slimy roots into the ground, follow them and re-appear somewhere else in a range of %d.
+		The process is quite a strain on your body and you will be stunned for %d turns.
+		The damage will increase with the Dexterity stat]]):format(20 + (self:getMag() * self:getTalentLevel(t)) * 0.3, util.bound(5 - self:getTalentLevel(t) / 2, 2, 7))
 	end,
 }
diff --git a/game/modules/tome/data/talents/spells/divination.lua b/game/modules/tome/data/talents/spells/divination.lua
index 4df82f51815ac0b151b25c4a6b2981fa39a68faa..298718c80db4568d629fba032e1d8989d1c80974 100644
--- a/game/modules/tome/data/talents/spells/divination.lua
+++ b/game/modules/tome/data/talents/spells/divination.lua
@@ -38,6 +38,7 @@ newTalent{
 		if self:getTalentLevel(t) < 3 then
 			self:showInventory("Identify object", self:getInven(self.INVEN_INVEN), nil, function(o, item)
 				o:identify(true)
+				game.logPlayer(who, "You identify: "..o:getName())
 			end)
 			return true
 		end
@@ -46,14 +47,18 @@ newTalent{
 			for i, o in ipairs(self:getInven("INVEN")) do
 				o:identify(true)
 			end
+			game.logPlayer(who, "You identify all your inventory.")
 		end
 
 		if self:getTalentLevel(t) >= 4 then
+			local idx = 1
 			while true do
 				local o = game.level.map:getObject(self.x, self.y, idx)
 				if not o then break end
 				o:identify(true)
+				idx = idx + 1
 			end
+			game.logPlayer(who, "You identify everything around you.")
 		end
 
 		return true
diff --git a/ideas/cunning.ods b/ideas/cunning.ods
index c14f4360c3d4e193e6a1ee70c7619a64487496e6..24bf3e185f6822db83fd7cea59519b8519a8dfd3 100644
Binary files a/ideas/cunning.ods and b/ideas/cunning.ods differ
diff --git a/ideas/gifts.ods b/ideas/gifts.ods
new file mode 100644
index 0000000000000000000000000000000000000000..7644b1dc773d57163957e1abdd81a67e13242e4d
Binary files /dev/null and b/ideas/gifts.ods differ
diff --git a/ideas/technics.ods b/ideas/technics.ods
index 0c1cf26af327085c07b5e8a250c3683a293eb8f8..37da15a8978da0673e576921a1797a5f638ed0d9 100644
Binary files a/ideas/technics.ods and b/ideas/technics.ods differ