diff --git a/game/engines/default/engine/Entity.lua b/game/engines/default/engine/Entity.lua
index df65e87de70e818c4715129ba1b3422ecb9bf19d..9be9f9051278d3f7e56bec57e615a18c672a40b0 100644
--- a/game/engines/default/engine/Entity.lua
+++ b/game/engines/default/engine/Entity.lua
@@ -386,7 +386,7 @@ function _M:getEntityFinalSurface(tiles, w, h)
 
 	local mos = {}
 	local list = {}
-	print("===final surface for", self.uid, self.namself, self.x, self.y, self.type, self.subtype)
+	print("===final surface for", self.uid, self.name, self.x, self.y, self.type, self.subtype)
 	self:getMapObjects(tiles, mos, 1)
 	for i = 1, Map.zdepth do
 		if mos[i] then list[#list+1] = mos[i] end
diff --git a/game/engines/default/engine/interface/ActorTalents.lua b/game/engines/default/engine/interface/ActorTalents.lua
index aa38b7cff6d0efcfd957ae471bf809e2c8f5880b..57442bc1f911e396680d0af2193fad1d1c2f7f53 100644
--- a/game/engines/default/engine/interface/ActorTalents.lua
+++ b/game/engines/default/engine/interface/ActorTalents.lua
@@ -302,23 +302,27 @@ end
 --- Actor forgets a talent
 -- @param t_id the id of the talent to learn
 -- @return true if the talent was unlearnt, nil and an error message otherwise
-function _M:unlearnTalent(t_id)
+function _M:unlearnTalent(t_id, nb)
 	if not self:knowTalent(t_id) then return false, "talent not known" end
 
 	local t = _M.talents_def[t_id]
 
-	if self.talents[t_id] and self.talents[t_id] == 1 then
-		if self.hotkey then
-			for i, known_t_id in pairs(self.hotkey) do
-				if known_t_id[1] == "talent" and known_t_id[2] == t_id then self.hotkey[i] = nil end
+	nb = math.min(nb or 1, self.talents[t_id])
+
+	for j = 1, nb do
+		if self.talents[t_id] and self.talents[t_id] == 1 then
+			if self.hotkey then
+				for i, known_t_id in pairs(self.hotkey) do
+					if known_t_id[1] == "talent" and known_t_id[2] == t_id then self.hotkey[i] = nil end
+				end
 			end
 		end
-	end
 
-	self.talents[t_id] = self.talents[t_id] - 1
-	if self.talents[t_id] == 0 then self.talents[t_id] = nil end
+		self.talents[t_id] = self.talents[t_id] - 1
+		if self.talents[t_id] == 0 then self.talents[t_id] = nil end
 
-	if t.on_unlearn then t.on_unlearn(self, t) end
+		if t.on_unlearn then t.on_unlearn(self, t) end
+	end
 
 	self.talents_auto[t_id] = nil
 
diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua
index 513cde4ac560d74d58170dd195eada5cefaebcfa..1d66fbfe635c4b65dd657889660ce48132ac109d 100644
--- a/game/engines/default/engine/utils.lua
+++ b/game/engines/default/engine/utils.lua
@@ -57,6 +57,20 @@ function table.print(src, offset)
 	end
 end
 
+function table.iprint(src, offset)
+	offset = offset or ""
+	for k, e in ipairs(src) do
+		-- Deep copy subtables, but not objects!
+		if type(e) == "table" and not e.__CLASSNAME then
+			print(("%s[%s] = {"):format(offset, tostring(k)))
+			table.print(e, offset.."  ")
+			print(("%s}"):format(offset))
+		else
+			print(("%s[%s] = %s"):format(offset, tostring(k), tostring(e)))
+		end
+	end
+end
+
 --- Returns a clone of a table
 -- @param tbl The original table to be cloned
 -- @param deep Boolean to determine if recursive cloning occurs
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 78f34d690b981e77763eaa25a757176cc5ea9e4a..be5a5e721223ea23f7088e7eb651ce253a196048 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -2640,7 +2640,7 @@ function _M:unlearnItemTalent(o, tid, level)
 		if self.item_talent_surplus_levels[tid] > 0 then
 			self.item_talent_surplus_levels[tid] = self.item_talent_surplus_levels[tid] - 1
 		else
-			self:unlearnTalent(tid, true, 1)
+			self:unlearnTalent(tid)
 		end
 	end
 end
@@ -2704,8 +2704,8 @@ end
 --- Actor forgets a talent
 -- @param t_id the id of the talent to learn
 -- @return true if the talent was unlearnt, nil and an error message otherwise
-function _M:unlearnTalent(t_id)
-	if not engine.interface.ActorTalents.unlearnTalent(self, t_id, force) then return false end
+function _M:unlearnTalent(t_id, nb)
+	if not engine.interface.ActorTalents.unlearnTalent(self, t_id, nb) then return false end
 
 	local t = _M.talents_def[t_id]
 
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index d20ca60b0b5923a9fc2da00124d31eedbe223c8e..e971c68d51a402b9e39b109fb958eafcdbad8dc3 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -192,7 +192,7 @@ function _M:newGame()
 		end
 
 		for i = 1, 50 do
-			local o = self.state:generateRandart(true)
+			local o = self.state:generateRandart{add_pool=true}
 			self.zone.object_list[#self.zone.object_list+1] = o
 		end
 
@@ -1167,7 +1167,10 @@ function _M:setupCommands()
 			end end
 		end end,
 		[{"_g","ctrl"}] = function() if config.settings.cheat then
-			self:registerDialog(require("mod.dialogs.DownloadCharball").new())
+--			self:registerDialog(require("mod.dialogs.DownloadCharball").new())
+			local o = game.state:generateRandart{lev=50, egos=0, power_points_factor=8, nb_powers_add=6}
+			o:identify(true)
+			game.zone:addEntity(game.level,o,"object",game.player.x,game.player.y)
 		end end,
 		[{"_f","ctrl"}] = function() if config.settings.cheat then
 			self.player.quests["love-melinda"] = nil
diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua
index 522f4a11ad53fccee1b70c186f374ff9b487c14c..4488e5771dbc089e72cf95fac0d819a09a9d451e 100644
--- a/game/modules/tome/class/GameState.lua
+++ b/game/modules/tome/class/GameState.lua
@@ -229,19 +229,20 @@ local randart_name_rules = {
 }
 
 --- Generate randarts for this state
-function _M:generateRandart(add, base, lev, nb_egos)
+function _M:generateRandart(data)
+
 	if not self.randart_powers then self.randart_powers = engine.Object:loadList("/data/general/objects/random-artifacts.lua") end
 	local powers_list = self.randart_powers
 
 	-- Setup level
-	lev = lev or rng.range(12, 50)
+	local lev = data.lev or rng.range(12, 50)
 	local oldlev = game.level.level
 	local oldclev = resolvers.current_level
 	game.level.level = lev
 	resolvers.current_level = math.ceil(lev * 1.4)
 
 	-- Get a base object
-	base = base or game.zone:makeEntity(game.level, "object", {ingore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}, special=function(e)
+	local base = data.base or game.zone:makeEntity(game.level, "object", {ingore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}, special=function(e)
 		return (not e.unique and e.randart_able) and (not e.material_level or e.material_level >= 2) and true or false
 	end}, nil, true)
 	if not base then game.level.level = oldlev resolvers.current_level = oldclev return end
@@ -259,8 +260,8 @@ function _M:generateRandart(add, base, lev, nb_egos)
 	-----------------------------------------------------------
 	-- Determine power
 	-----------------------------------------------------------
-	local points = math.ceil((lev * 0.7 + rng.range(5, 15)) / 2)
-	local nb_powers = 1 + rng.dice(math.max(1, lev / 17), 2)
+	local points = math.ceil((lev * 0.7 + rng.range(5, 15)) / 2) * (data.power_points_factor or 1)
+	local nb_powers = 1 + rng.dice(math.max(1, lev / 17), 2) + (data.nb_powers_add or 0)
 	local powers = {}
 
 	o.cost = o.cost + points * 7
@@ -276,6 +277,7 @@ function _M:generateRandart(add, base, lev, nb_egos)
 			powers[#powers+1] = p
 		end
 	end
+	print("Selected powers:") table.print(powers)
 	power_themes = table.listify(power_themes)
 	table.sort(power_themes, function(a, b) return a[2] < b[2] end)
 
@@ -311,7 +313,8 @@ function _M:generateRandart(add, base, lev, nb_egos)
 	-----------------------------------------------------------
 	-- Add ego properties
 	-----------------------------------------------------------
-	if o.egos then
+	local nb_egos = data.egos or 3
+	if o.egos and nb_egos > 0 then
 		local legos = {}
 		local been_greater = 0
 		table.insert(legos, game.level:getEntitiesList("object/"..o.egos..":prefix"))
@@ -345,7 +348,7 @@ function _M:generateRandart(add, base, lev, nb_egos)
 					print("table.mergeAddAppendArray failed at creating a randart, retrying")
 					game.level.level = oldlev
 					resolvers.current_level = oldclev
-					return self:generateRandart(add, base, lev, nb_egos)
+					return self:generateRandart(data)
 				end
 			end
 		end
@@ -391,7 +394,7 @@ function _M:generateRandart(add, base, lev, nb_egos)
 				merger(o.wielder, p.wielder)
 			end
 			if p.copy then merger(o, p.copy) end
---			print(" * adding power: "..p.name)
+			print(" * adding power: "..p.name)
 		end
 		hpoints = hpoints - p.points
 	end
@@ -413,7 +416,7 @@ function _M:generateRandart(add, base, lev, nb_egos)
 				merger(o.wielder, p.wielder)
 			end
 			if p.copy then merger(o, p.copy) end
---			print(" * adding power: "..p.name)
+			print(" * adding bias power: "..p.name)
 		end
 		hpoints = hpoints - (p and p.points or 1) * 2
 	end
@@ -421,7 +424,7 @@ function _M:generateRandart(add, base, lev, nb_egos)
 	-- Setup the name
 	o.name = name
 
-	if add then self:addWorldArtifact(o) end
+	if data.add_pool then self:addWorldArtifact(o) end
 
 	game.level.level = oldlev
 	resolvers.current_level = oldclev
@@ -1653,6 +1656,7 @@ function _M:createRandomBoss(base, data)
 	end
 
 	b.rnd_boss_on_added_to_level = b.on_added_to_level
+	b._rndboss_resources_boost = data.resources_boost
 	b.on_added_to_level = function(self, ...)
 		self:check("birth_create_alchemist_golem")
 		for tid, lev in pairs(self.learn_tids) do
@@ -1666,10 +1670,10 @@ function _M:createRandomBoss(base, data)
 		self.on_added_to_level = nil
 
 		-- Cheat a bit with ressources
-		self.max_mana = self.max_mana * (data.resources_boost or 3) self.mana_regen = self.mana_regen + 1
-		self.max_vim = self.max_vim * (data.resources_boost or 3) self.vim_regen = self.vim_regen + 1
-		self.max_stamina = self.max_stamina * (data.resources_boost or 3) self.stamina_regen = self.stamina_regen + 1
-		self.max_psi = self.max_psi * (data.resources_boost or 3) self.psi_regen = self.psi_regen + 2
+		self.max_mana = self.max_mana * (self._rndboss_resources_boost or 3) self.mana_regen = self.mana_regen + 1
+		self.max_vim = self.max_vim * (self._rndboss_resources_boost or 3) self.vim_regen = self.vim_regen + 1
+		self.max_stamina = self.max_stamina * (self._rndboss_resources_boost or 3) self.stamina_regen = self.stamina_regen + 1
+		self.max_psi = self.max_psi * (self._rndboss_resources_boost or 3) self.psi_regen = self.psi_regen + 2
 		self.equilibrium_regen = self.equilibrium_regen - 2
 		self:resetToFull()
 	end
diff --git a/game/modules/tome/data/autolevel_schemes.lua b/game/modules/tome/data/autolevel_schemes.lua
index 1a9cba3f0e9913905be792a8d3e0dcebeedbc877..c78f1e391a230d6e4d63a82421d3e7e6dfe142ae 100644
--- a/game/modules/tome/data/autolevel_schemes.lua
+++ b/game/modules/tome/data/autolevel_schemes.lua
@@ -99,5 +99,5 @@ Autolevel:registerScheme{ name = "warriorwill", levelup = function(self)
 end}
 
 Autolevel:registerScheme{ name = "random_boss", levelup = function(self)
-	self:learnStats(self.auto_stats)
+	pcall(function() self:learnStats(self.auto_stats) end)
 end}
diff --git a/game/modules/tome/data/birth/classes/psionic.lua b/game/modules/tome/data/birth/classes/psionic.lua
index efadffd7acb0c6c03ecf7c7fdf7c69d1581d5954..229387a4876ef6cb8063687290612e479c64c515 100644
--- a/game/modules/tome/data/birth/classes/psionic.lua
+++ b/game/modules/tome/data/birth/classes/psionic.lua
@@ -31,6 +31,7 @@ newBirthDescriptor{
 		{
 			__ALL__ = "disallow",
 			Mindslayer = "allow",
+			Psion = "allow",
 		},
 	},
 	copy = {
@@ -110,3 +111,36 @@ newBirthDescriptor{
 		life_rating = -4,
 	},
 }
+
+newBirthDescriptor{
+	type = "subclass",
+	name = "Psion",
+	locked = function() return profile.mod.allow_build.psionic_psion end,
+	locked_desc = "TODO",
+	desc = {
+		"blahblah",
+		"Their most important stats are: Willpower and Cunning",
+		"#GOLD#Stat modifiers:",
+		"#LIGHT_BLUE# * +1 Strength, +0 Dexterity, +0 Constitution",
+		"#LIGHT_BLUE# * +0 Magic, +4 Willpower, +4 Cunning",
+	},
+	power_source = {psionic=true},
+	stats = { str=0, wil=5, cun=4, },
+	talents_types = {
+		["psionic/possession"]={true, 0.3},
+	},
+	talents = {
+		[ActorTalents.T_POSSESS] = 1,
+	},
+	copy = {
+		max_life = 90,
+		resolvers.equip{ id=true,
+			{type="armor", subtype="cloth", name="linen robe", autoreq=true, ego_chance=-1000},
+			{type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
+			{type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
+		},
+	},
+	copy_add = {
+		life_rating = -4,
+	},
+}
diff --git a/game/modules/tome/data/birth/classes/wilder.lua b/game/modules/tome/data/birth/classes/wilder.lua
index ed754b02802094aca03bbe2ab90bebba48491e3f..a4356021aa1a0b841b16f528b7e744a22236dd11 100644
--- a/game/modules/tome/data/birth/classes/wilder.lua
+++ b/game/modules/tome/data/birth/classes/wilder.lua
@@ -34,6 +34,7 @@ newBirthDescriptor{
 			Summoner = "allow",
 			Wyrmic = "allow",
 			["Stone Warden"] = "allow",
+			Oozemancer = "allow",
 		},
 	},
 	copy = {
@@ -183,3 +184,35 @@ newBirthDescriptor{
 		life_rating = 2,
 	},
 }
+
+newBirthDescriptor{
+	type = "subclass",
+	name = "Oozemancer",
+	locked = function() return profile.mod.allow_build.wilder_oozemancer end,
+	locked_desc = "TODO",
+	desc = {
+		"Bla bla",
+		"Their most important stats are: Willpower and Cunning",
+		"#GOLD#Stat modifiers:",
+		"#LIGHT_BLUE# * +0 Strength, +0 Dexterity, +0 Constitution",
+		"#LIGHT_BLUE# * +0 Magic, +5 Willpower, +4 Cunning",
+	},
+	power_source = {nature=true},
+	stats = { wil=5, cun=4, },
+	talents_types = {
+		["wild-gift/call"]={true, 0.2},
+		["wild-gift/harmony"]={false, 0.1},
+		["wild-gift/mindstar-mastery"]={true, 0.3},
+	},
+	talents = {
+		[ActorTalents.T_PSIBLADES] = 1,
+	},
+	copy = {
+		max_life = 90,
+		resolvers.equip{ id=true,
+			{type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
+			{type="weapon", subtype="mindstar", name="mossy mindstar", autoreq=true, ego_chance=-1000},
+			{type="armor", subtype="light", name="rough leather armour", autoreq=true, ego_chance=-1000},
+		},
+	},
+}
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 557ae44591e724fb10434306bbd3288016356784..055dc6683a57891e44c45d3c658ff5863fd17ba3 100644
--- a/game/modules/tome/data/chats/last-hope-lost-merchant.lua
+++ b/game/modules/tome/data/chats/last-hope-lost-merchant.lua
@@ -78,13 +78,13 @@ local maker_list = function()
 		local o = game.zone:makeEntity(game.level, "object", {name=name, ingore_material_restriction=true, no_tome_drops=true, ego_filter={keep_egos=true, ego_chance=-1000}}, nil, true)
 		if o then
 			l[#l+1] = {o:getName{force_id=true, do_color=true, no_count=true}, action=function(npc, player)
-				local art = game.state:generateRandart(nil, o, 70, 4)
+				local art = game.state:generateRandart{base=o, lev=70, egos=4}
 				if art then
 					art:identify(true)
 					player:addObject(player.INVEN_INVEN, art)
 					player:incMoney(-4000)
 					-- clear chrono worlds and their various effects
-					if game._chronoworlds then 
+					if game._chronoworlds then
 						game.log("#CRIMSON#Your timetravel has no effect on pre-determined outcomes such as this.")
 						game._chronoworlds = nil
 					end
diff --git a/game/modules/tome/data/general/objects/egos/totems.lua b/game/modules/tome/data/general/objects/egos/totems.lua
index 4df05747541e49b7d324da6a5d82dfe344568017..88b51deb7a66fb6aec3dd9c077c4de5d80acc0ec 100644
--- a/game/modules/tome/data/general/objects/egos/totems.lua
+++ b/game/modules/tome/data/general/objects/egos/totems.lua
@@ -100,7 +100,7 @@ newEntity{
 	level_range = {30, 50},
 	rarity = 12,
 	greater_ego = 1,
-	cost = 5,
+	cost = 15,
 
 	wielder = {
 		talent_cd_reduction={[Talents.T_INVOKE_TENTACLE]=-5},
diff --git a/game/modules/tome/data/general/objects/random-artifacts.lua b/game/modules/tome/data/general/objects/random-artifacts.lua
index 74171ddcbef414aa8beb0887d1c88d6dc7fd6288..ffa27e1c1b5a538a1fb835460e707cb98aceb6a7 100644
--- a/game/modules/tome/data/general/objects/random-artifacts.lua
+++ b/game/modules/tome/data/general/objects/random-artifacts.lua
@@ -33,6 +33,19 @@ newEntity{ theme={spell=true, sorcerous=true}, name="spell crit magnitude", poin
 	wielder = { combat_critical_power = resolvers.randartmax(1, 12), },
 }
 
+----------------------------------------------------------------
+-- Mindpower
+----------------------------------------------------------------
+newEntity{ theme={mind=true, mindcraft=true}, name="mindpower", points = 1, rarity = 8, level_range = {1, 50},
+	wielder = { combat_mindpower = resolvers.randartmax(1, 28), },
+}
+newEntity{ theme={mind=true, mindcraft=true}, name="mindcrit", points = 1, rarity = 10, level_range = {1, 50},
+	wielder = { combat_mindcrit = resolvers.randartmax(1, 15), },
+}
+newEntity{ theme={mind=true, mindcraft=true}, name="mind crit magnitude", points = 1, rarity = 15, level_range = {1, 50},
+	wielder = { combat_critical_power = resolvers.randartmax(1, 12), },
+}
+
 ----------------------------------------------------------------
 -- Physical damage
 ----------------------------------------------------------------
@@ -163,34 +176,34 @@ newEntity{ theme={attack=true, psionic=true}, name="inc damage mind", points = 1
 -- Immunes
 ----------------------------------------------------------------
 newEntity{ theme={def=true, unyielding=true}, name="immune stun", points = 1, rarity = 7, level_range = {1, 50},
-	wielder = { stun_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { stun_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, brawny=true, unyielding=true}, name="immune knockback", points = 1, rarity = 14, level_range = {1, 50},
-	wielder = { knockback_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { knockback_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, sorcerous=true}, name="immune blind", points = 1, rarity = 14, level_range = {1, 50},
-	wielder = { blind_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { blind_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, psionic=true}, name="immune confusion", points = 1, rarity = 14, level_range = {1, 50},
-	wielder = { confusion_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { confusion_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, brawny=true}, name="immune pin", points = 1, rarity = 14, level_range = {1, 50},
-	wielder = { pin_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { pin_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, venom=true, nature=true}, name="immune poison", points = 1, rarity = 14, level_range = {1, 50},
-	wielder = { poison_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { poison_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, venom=true, nature=true}, name="immune disease", points = 1, rarity = 14, level_range = {1, 50},
-	wielder = { disease_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { disease_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, sorcerous=true}, name="immune silence", points = 1, rarity = 11, level_range = {1, 50},
-	wielder = { silence_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { silence_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, nimble=true, unyielding=true}, name="immune disarm", points = 1, rarity = 11, level_range = {1, 50},
-	wielder = { disarm_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { disarm_immune = resolvers.randartmax(0.05, 0.5), },
 }
 newEntity{ theme={def=true, nimble=true}, name="immune cut", points = 1, rarity = 14, level_range = {1, 50},
-	wielder = { cut_immune = resolvers.randartmax(0.05, 1), },
+	wielder = { cut_immune = resolvers.randartmax(0.05, 0.5), },
 }
 
 ----------------------------------------------------------------
diff --git a/game/modules/tome/data/talents/cursed/shadows.lua b/game/modules/tome/data/talents/cursed/shadows.lua
index db98743a12e52c019265f703319cdcd2e652ed71..3af3d9d06593969a4cea478e4950f070382833b6 100644
--- a/game/modules/tome/data/talents/cursed/shadows.lua
+++ b/game/modules/tome/data/talents/cursed/shadows.lua
@@ -305,7 +305,7 @@ local function createShadow(self, level, tCallShadows, tShadowWarriors, tShadowM
 			if self:knowTalent(self.T_SHADOW_FADE) and not self:isTalentCoolingDown(self.T_SHADOW_FADE) then
 				self:forceUseTalent(self.T_SHADOW_FADE, {ignore_energy=true})
 			end
-			
+
 			return mod.class.Actor.onTakeHit(self, value, src)
 		end,
 	}
@@ -324,7 +324,7 @@ newTalent{
 		return self.level
 	end,
 	getMaxShadows = function(self, t)
-		return math.max(1, math.floor(self:getTalentLevel(t) * 0.55))
+		return math.min(4, math.max(1, math.floor(self:getTalentLevel(t) * 0.55)))
 	end,
 	getPhaseDoorLevel = function(self, t)
 		return self:getTalentLevelRaw(t)
@@ -387,7 +387,7 @@ newTalent{
 		level = t.getLevel(self, t)
 		local tShadowWarriors = self:knowTalent(self.T_SHADOW_WARRIORS) and self:getTalentFromId(self.T_SHADOW_WARRIORS) or nil
 		local tShadowMages = self:knowTalent(self.T_SHADOW_MAGES) and self:getTalentFromId(self.T_SHADOW_MAGES) or nil
-		
+
 		local shadow = createShadow(self, level, t, tShadowWarriors, tShadowMages, 1000, nil)
 
 		shadow:resolve()
diff --git a/game/modules/tome/data/talents/psionic/possession.lua b/game/modules/tome/data/talents/psionic/possession.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3e5a2933932c321aeb14d358190bcf04e7b3d027
--- /dev/null
+++ b/game/modules/tome/data/talents/psionic/possession.lua
@@ -0,0 +1,160 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012 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
+
+newTalent{
+	name = "Possess",
+	type = {"psionic/possession", 1},
+	require = psi_wil_req1,
+	points = 5,
+	cooldown = 30,
+	psi = 30,
+	no_npc_use = true,
+	range = 3,
+	requires_target = true,
+	allowedTypes = function(self, t, type)
+		if type == "animal" then return true end
+		if type == "humanoid" then return true end
+		if type == "giant" then return true end
+		return false
+	end,
+	getMaxTalents = function(self, t) return math.ceil(self:getTalentLevel(t)) end,
+	target = function(self, t) return {type="hit", range=self:getTalentRange(t), selffire=false, talent=t} end,
+	action = function(self, t)
+		local tg = self:getTalentTarget(t)
+		local tx, ty = self:getTarget(tg)
+		if not tx or not ty then return nil end
+		local _ _, tx, ty = self:canProject(tg, tx, ty)
+		target = game.level.map(tx, ty, Map.ACTOR)
+		if not target or target == self then return nil end
+
+		if target == self.summoner then
+			game.party:setPlayer(self.summoner, true)
+			return true
+		end
+
+		if not t.allowedTypes(self, t, target.type) then game.logPlayer(self, "You may not possess this kind of creature.") return nil end
+--		if target.life > target.max_life * 0.25 then game.logPlayer(self, "You may not possess this creature yet its life is too high.") return nil end
+		if target.dead then game.logPlayer(self, "This creature is dead!") return nil end
+
+		if not self:checkHit(self:combatMindpower(), target:combatMentalResist(), 0, 95, 5) then -- or not target:canBe("instakill") then
+			game.logPlayer(self, "You fail to shatter %s mind, leaving you unable to possess its body.", target.name)
+			return true
+		end
+
+		self.ai = "none"
+
+		target.faction = self.faction
+		target.ai = "none"
+		target.ai_state = target.ai_state or {}
+		target.ai_state.tactic_leash = 100
+		target.remove_from_party_on_death = true
+		target.no_inventory_access = true
+		target.move_others = true
+		target.summoner = self
+		target.summoner_gain_exp = true
+		target.on_die = function(self, src) if self.summoner then self.summoner:die(src) end end
+		target.no_leave_control = true
+
+		-- Remove & adjust talents
+		local nb = t.getMaxTalents(self, t)
+		local remove = {}
+		for tid, lev in pairs(target.talents) do
+			local t = self:getTalentFromId(tid)
+			if t.mode ~= "passive" then
+				table.insert(remove, tid)
+			end
+		end
+		local keep = {}
+		for i = 1, nb do
+			if #remove == 0 then break end
+			table.insert(keep, rng.tableRemove(remove))
+		end
+		for _, tid in ipairs(remove) do target:unlearnTalent(tid, target:getTalentLevelRaw(tid)) end
+
+		-- Give a way to go back
+		target:learnTalent(target.T_POSSESS, true)
+
+		-- Adjust mental stats
+		target.stats[target.STAT_MAG] = self.stats[self.STAT_MAG]
+		target.inc_stats[target.STAT_MAG] = self.inc_stats[self.STAT_MAG]
+		target.stats[target.STAT_WIL] = self.stats[self.STAT_WIL]
+		target.inc_stats[target.STAT_WIL] = self.inc_stats[self.STAT_WIL]
+		target.stats[target.STAT_CUN] = self.stats[self.STAT_CUN]
+		target.inc_stats[target.STAT_CUN] = self.inc_stats[self.STAT_CUN]
+
+		-- Countdown to death
+		target:setEffect(target.EFF_POSSESSION, 100, {})
+
+		game.party:addMember(target, {
+			control="full",
+			type="possesed",
+			title="Possessed Husk",
+			orders = {leash=true, follow=true},
+			on_control = function(self)
+				self:hotkeyAutoTalents()
+			end,
+		})
+		game.party:setPlayer(target, true)
+
+		return true
+	end,
+	info = function(self, t)
+		return ([[]]):
+		format()
+	end,
+}
+
+newTalent{
+	name = "Physical Possession",
+	type = {"psionic/possession", 2},
+	require = psi_wil_req2,
+	points = 5,
+	mode = "passive",
+	no_npc_use = true,
+	info = function(self, t)
+		return ([[]]):
+		format()
+	end,
+}
+
+newTalent{
+	name = "Wild Possession",
+	type = {"psionic/possession", 3},
+	require = psi_wil_req3,
+	mode = "passive",
+	points = 5,
+	no_npc_use = true,
+	info = function(self, t)
+		return ([[]]):
+		format()
+	end,
+}
+
+newTalent{
+	name = "Arcane Possession",
+	type = {"psionic/possession", 4},
+	require = psi_wil_req4,
+	mode = "passive",
+	points = 5,
+	no_npc_use = true,
+	info = function(self, t)
+		return ([[]]):
+		format()
+	end,
+}
diff --git a/game/modules/tome/data/talents/psionic/psionic.lua b/game/modules/tome/data/talents/psionic/psionic.lua
index 4a183c1bba31f21574118fef7697ae9da92c40e3..5792ff0ce7532ec88e5d3a360a862650a917ae25 100644
--- a/game/modules/tome/data/talents/psionic/psionic.lua
+++ b/game/modules/tome/data/talents/psionic/psionic.lua
@@ -39,6 +39,8 @@ newTalentType{ allow_random=true, type="psionic/brainstorm", name = "brainstorm"
 newTalentType{ allow_random=true, type="psionic/psychic-assault", name = "psychic assault", description = "Directly attack your opponents minds." }
 -- Generic Solipsist Trees
 
+newTalentType{ allow_random=true, type="psionic/possession", name = "possession", description = "You have learnt to shed away your body, allowing you to possess any other." }
+
 
 -- Level 0 wil tree requirements:
 psi_absorb = {
@@ -167,4 +169,7 @@ load("/data/talents/psionic/psi-archery.lua")
 load("/data/talents/psionic/grip.lua")
 
 -- Solipsist
-load("/data/talents/psionic/psychic-assault.lua")
\ No newline at end of file
+load("/data/talents/psionic/psychic-assault.lua")
+
+load("/data/talents/psionic/possession.lua")
+
diff --git a/game/modules/tome/data/talents/psionic/voracity.lua b/game/modules/tome/data/talents/psionic/voracity.lua
index d17fdfee600d0a203f0384b613863b772e1aabee..cea080f63cd0e2e39e39ef1aca503cec72e5d452 100644
--- a/game/modules/tome/data/talents/psionic/voracity.lua
+++ b/game/modules/tome/data/talents/psionic/voracity.lua
@@ -171,7 +171,7 @@ newTalent{
 		local range = self:getTalentRadius(t)
 		local en = t.getLeech(self, t)
 		local dam = damDesc(self, DamageType.LIGHTNING, t.getDam(self, t))
-		return ([[You pull electric potential from all targets around you in a radius of %d, gaining %d energy for each one affected and giving them a nasty shock in the process. Deals between %d and %d damage.]]):format(range, en, dam / 3, dam)
+		return ([[You pull electric potential from all targets around you in a radius of %d, gaining %d energy for each one affected and giving them a nasty shock in the process. Deals between %d and %d damage nad has a chance to daze.]]):format(range, en, dam / 3, dam)
 	end,
 }
 newTalent{
diff --git a/game/modules/tome/data/talents/spells/meta.lua b/game/modules/tome/data/talents/spells/meta.lua
index 44d9b0296cb3373d1f7cd09bd3ac585a852503d3..7f78662b4a2dc8fb65494c5828a5dc93abe9c856 100644
--- a/game/modules/tome/data/talents/spells/meta.lua
+++ b/game/modules/tome/data/talents/spells/meta.lua
@@ -50,18 +50,27 @@ newTalent{
 		local effs = {}
 
 		-- Go through all spell effects
-		for eff_id, p in pairs(target.tmp) do
-			local e = target.tempeffect_def[eff_id]
-			if e.type == "magical" then
-				effs[#effs+1] = {"effect", eff_id}
+		if self:reactionToward(target) < 0 then
+			for eff_id, p in pairs(target.tmp) do
+				local e = target.tempeffect_def[eff_id]
+				if e.type == "magical" and e.status == "beneficial" then
+					effs[#effs+1] = {"effect", eff_id}
+				end
 			end
-		end
 
-		-- Go through all sustained spells
-		for tid, act in pairs(target.sustain_talents) do
-			if act then
-				local talent = target:getTalentFromId(tid)
-				if talent.is_spell then effs[#effs+1] = {"talent", tid} end
+			-- Go through all sustained spells
+			for tid, act in pairs(target.sustain_talents) do
+				if act then
+					local talent = target:getTalentFromId(tid)
+					if talent.is_spell then effs[#effs+1] = {"talent", tid} end
+				end
+			end
+		else
+			for eff_id, p in pairs(target.tmp) do
+				local e = target.tempeffect_def[eff_id]
+				if e.type == "magical" and e.status == "detrimental" then
+					effs[#effs+1] = {"effect", eff_id}
+				end
 			end
 		end
 
@@ -80,7 +89,7 @@ newTalent{
 	end,
 	info = function(self, t)
 		local count = t.getRemoveCount(self, t)
-		return ([[Removes up to %d magical effects (both good and bad) from the target.
+		return ([[Removes up to %d magical effects (good effects from foes and bad effects from friends) from the target.
 		At level 3 it can be targeted.]]):
 		format(count)
 	end,
diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua
index b2e5182b4f5a9d3312fbe30a753c8c3dcfb4904e..51bd8969f70ca11a50ec46e9ef506c7e2c5c4552 100644
--- a/game/modules/tome/data/timed_effects/other.lua
+++ b/game/modules/tome/data/timed_effects/other.lua
@@ -1518,4 +1518,21 @@ newEffect{
 		-- always remove
 		return true
 	end,
-}
\ No newline at end of file
+}
+
+newEffect{
+	name = "POSSESSION", image = "talents/possess.png",
+	desc = "Psionic Consume",
+	long_desc = function(self, eff) return "This creature's mind has been destroyed and a possessor is now controlling the husk. However the intense psionic energies are burning the body away, it will soon disappear." end,
+	type = "other",
+	subtype = { psionic=true, possess=true },
+	status = "detrimental",
+	no_stop_resting = true,
+	parameters = { },
+	activate = function(self, eff)
+	end,
+	deactivate = function(self, eff)
+		self.summoner = nil
+		self:die(self)
+	end,
+}
diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua
index d7e07ed56c4923bdf84b065adfdbe2f9e003aecc..38bd2fabc0b83068b81a5f675666fb6d8fc1b8db 100644
--- a/game/modules/tome/data/timed_effects/physical.lua
+++ b/game/modules/tome/data/timed_effects/physical.lua
@@ -244,7 +244,9 @@ newEffect{
 	activate = function(self, eff)
 	end,
 	deactivate = function(self, eff)
-		self:setEffect(self.EFF_STONED, eff.stone, {})
+		if target:canBe("stun") and target:canBe("stone") and target:canBe("instakill") then
+			self:setEffect(self.EFF_STONED, eff.stone, {})
+		end
 	end,
 }
 
diff --git a/game/modules/tome/data/zones/valley-moon/npcs.lua b/game/modules/tome/data/zones/valley-moon/npcs.lua
index a4a284f0859f0124eb2ef1c1327edfe57294225e..bb7c010035deaf8e912f97ca5cbbc9dde01dc36d 100644
--- a/game/modules/tome/data/zones/valley-moon/npcs.lua
+++ b/game/modules/tome/data/zones/valley-moon/npcs.lua
@@ -104,6 +104,7 @@ newEntity{ define_as = "LIMMIR",
 	resolvers.sustains_at_birth(),
 
 	can_talk = "limmir-valley-moon",
+	never_anger = true,
 	can_craft = true,
 	on_die = function(self, who)
 		game.level.turn_counter = nil
diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua
index cff1ed3a03a9c41ccccfe9c0e86fcd0e0934a169..60b92c9abc8834d45875aade4139413c8e3c027b 100644
--- a/game/modules/tome/resolvers.lua
+++ b/game/modules/tome/resolvers.lua
@@ -180,7 +180,7 @@ function resolvers.calc.drop_randart(t, e)
 		end
 	end
 
-	local o = game.state:generateRandart(false, base, resolvers.current_level)
+	local o = game.state:generateRandart{base=base, lev=resolvers.current_level}
 	if o then
 --		print("Zone made us a randart drop according to filter!", o:getName{force_id=true})
 		e:addObject(e.INVEN_INVEN, o)