diff --git a/game/engines/default/engine/Module.lua b/game/engines/default/engine/Module.lua
index d1ce9aba8467d828a57a5da67cf05bba3709dc95..9a1d896b8717c1faa5b9cbf2fde97a20f995967a 100644
--- a/game/engines/default/engine/Module.lua
+++ b/game/engines/default/engine/Module.lua
@@ -556,6 +556,7 @@ function _M:loadAddons(mod, saveuse)
 	if saveuse then saveuse = table.reverse(saveuse) end
 
 	local force_remove_addons = {}
+	local beta_removed = {}
 
 	-- Filter based on settings
 	for i = #adds, 1, -1 do
@@ -585,6 +586,10 @@ function _M:loadAddons(mod, saveuse)
 					print("Removing addon "..add.short_name..": not allowed by config")
 					table.remove(adds, i) removed = true
 				end
+			elseif not config.settings.cheat and not engine.beta_allow_addon(add) then
+				print("Removing addon "..add.short_name..": game beta forbids")
+				table.remove(adds, i) removed = true
+				beta_removed[#beta_removed+1] = add.long_name
 			else
 				-- Forbidden by version
 				if not add.natural_compatible then
@@ -627,6 +632,12 @@ You may try to force loading if you are sure the savefile does not use that addo
 			end
 		end
 	end
+	if #beta_removed > 0 then
+		mod.post_load_exec = mod.post_load_exec or {}
+		mod.post_load_exec[#mod.post_load_exec+1] = function()
+			require("engine.ui.Dialog"):simpleLongPopup(_t"Beta Addons Disabled", _t"This beta version is meant to be tested without addons, as such the following ones are currently disabled:\n#GREY#"..table.concat(beta_removed, '#LAST#, #GREY#').."#LAST#\n\n".._t"#{italic}##PINK#Addons developers can still test their addons by enabling developer mode.#{normal}#", 600)
+		end
+	end
 
 	-- Let addons disable addons!
 	for i = #adds, 1, -1 do
@@ -1144,6 +1155,8 @@ function _M:instanciate(mod, name, new_game, no_reboot, extra_module_info)
 	core.display.resetAllFonts("normal")
 
 	if mod.short_name ~= "boot" then profile:noMoreAuthWait() end
+
+	if mod.post_load_exec then for _, fct in ipairs(mod.post_load_exec) do fct() end end
 end
 
 --- Setup write dir for a module
diff --git a/game/engines/default/engine/interface/ActorTalents.lua b/game/engines/default/engine/interface/ActorTalents.lua
index 1de866091e3bfc7aea4447be10575dab9e83f5ee..2c45266b27ca488347b74e68634841dc5cc03285 100644
--- a/game/engines/default/engine/interface/ActorTalents.lua
+++ b/game/engines/default/engine/interface/ActorTalents.lua
@@ -422,12 +422,13 @@ end
 -- "def" can have a field "ignore_energy" to not consume energy; other parameters can be passed and handled by an overload of this method.  
 -- Object activation interface calls this method with an "ignore_ressources" parameter
 function _M:forceUseTalent(t, def)
+	if type(t) == "table" then t = t.id end -- Ugh
 	local oldpause = game.paused
 	local oldenergy = self.energy.value
 	if def.ignore_energy then self.energy.value = 10000 end
 
 	if def.ignore_ressources then self:attr("force_talent_ignore_ressources", 1) end
-	self:setCurrentTalentMode("forced", t.id)
+	self:setCurrentTalentMode("forced", t)
 	local ret = {self:useTalent(t, def.force_who, def.force_level, def.ignore_cd or def.ignore_cooldown, def.force_target, def.silent, true)}
 	self:setCurrentTalentMode(nil)
 	if def.ignore_ressources then self:attr("force_talent_ignore_ressources", -1) end
@@ -894,22 +895,20 @@ end
 --- Talent level, 0 if not known
 function _M:getTalentLevelRaw(id)
 	if type(id) == "table" then id = id.id end
-	local lvl = self.talents[id] or 0
-	if lvl > 0 and not self.disable_talents_add_levels then lvl = self:alterTalentLevelRaw(_M.talents_def[id], lvl) end
-	return lvl
+	return self.talents[id] or 0
 end
 
 --- Talent level, 0 if not known
 -- Includes mastery (defaults to 1)
 function _M:getTalentLevel(id)
 	local t
+	if type(id) == "table" then t, id = id, id.id
+	else t = _M.talents_def[id] end
+	if not t then return 0 end
 
-	if type(id) == "table" then
-		t, id = id, id.id
-	else
-		t = _M.talents_def[id]
-	end
-	return t and (self:getTalentLevelRaw(id)) * (self:getTalentMastery(t) or 0) or 0
+	local lvl = self:getTalentLevelRaw(id)
+	if lvl > 0 then lvl = self:alterTalentLevelRaw(t, lvl) end
+	return lvl * (self:getTalentMastery(t) or 0)
 
 end
 
diff --git a/game/engines/default/engine/version.lua b/game/engines/default/engine/version.lua
index eecff72c45ba015222d7f6c9629b5b9d22a63899..896342f38a7bdc1d9304831cd9deeac323804ae9 100644
--- a/game/engines/default/engine/version.lua
+++ b/game/engines/default/engine/version.lua
@@ -110,6 +110,22 @@ end
 --- Check if we are running as beta
 function engine.version_hasbeta()
 	if fs.exists("/engine/version_beta.lua") then
-		return dofile("/engine/version_beta.lua")
+		local beta = dofile("/engine/version_beta.lua")
+		return beta
+	end
+end
+
+--- Check if we are running as beta
+function engine.beta_allow_addon(add)
+	if fs.exists("/engine/version_beta.lua") then
+		local beta, allowed_addons = dofile("/engine/version_beta.lua")
+		if not beta or not allowed_addons then return true end
+		for _, test in ipairs(allowed_addons) do
+			if type(test) == "function" then return test(add)
+			elseif add.short_name == test then return true
+			elseif add.short_name:find(test) then return true end
+		end
+	else
+		return true
 	end
 end
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index aa2e65a81f7dcccc98c58795b88d8d9af067bfac..71d12cdd1882e5250d27c1a042f53316750d6f05 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -3129,10 +3129,10 @@ function _M:die(src, death_note)
 		local sx, sy = game.level.map:getTileToScreen(self.x, self.y, true)
 		game.flyers:add(sx, sy, 30, (rng.range(0,2)-1) * 0.5, -3, _t"RESURRECT!", {255,120,0})
 
-		local effs = {}
-
 		self:removeEffectsSustainsFilter(self, nil, nil, nil, {no_resist=true})
 
+		local effs = {}
+
 		self.life = self.max_life
 		self.mana = self.max_mana
 		self.stamina = self.max_stamina
@@ -3455,6 +3455,9 @@ function _M:die(src, death_note)
 	if src and src.fireTalentCheck then src:fireTalentCheck("callbackOnKill", self, death_note) end
 	if src and src.summoner and src.summoner.fireTalentCheck then src.summoner:fireTalentCheck("callbackOnSummonKill", src, self, death_note) end
 
+	-- We do it at the end so that effects can detect death
+	self:removeEffectsSustainsFilter(self, nil, nil, nil, {no_resist=true})
+
 	return true
 end
 
@@ -6750,7 +6753,7 @@ function _M:getTalentFullDescription(t, addlevel, config, fake_mastery)
 	self:triggerHook{"Actor:getTalentFullDescription", str=d, t=t, addlevel=addlevel, config=config, fake_mastery=fake_mastery}
 
 	d:add({"color",0x6f,0xff,0x83}, _t"Description: ", {"color",0xFF,0xFF,0xFF})
-	d:merge(t.info(self, t):toTString():tokenize(" ()[]"))
+	d:merge(t.info(self, t):toTString():tokenize(" ()[],"))
 
 	self.talents[t.id] = old
 
@@ -6847,7 +6850,7 @@ end
 
 --- Called if a talent level is > 0
 function _M:alterTalentLevelRaw(t, lvl)
-	if t.no_unlearn_last then return lvl end -- Those are dangerous, do not change them
+	-- if t.no_unlearn_last then return lvl end -- Those are dangerous, do not change them
 	if self.talents_add_levels and self.talents_add_levels[t.id] then lvl = lvl + self.talents_add_levels[t.id] end
 	if self:attr("all_talents_bonus_level") then lvl = lvl + self:attr("all_talents_bonus_level") end
 	if self:attr("spells_bonus_level") and t.is_spell then lvl = lvl + self:attr("spells_bonus_level") end
@@ -7078,6 +7081,27 @@ function _M:removeEffectsFilter(src, t, nb, silent, force, check_remove, allow_i
 	return #eff_ids
 end
 
+--- Force sustains off and on again to account for level/mastery/... changes
+function _M:udpateSustains()
+	local reset = {}
+	local remaining = {}
+	for tid, act in pairs(self.sustain_talents) do if act and self:knowTalent(tid) then
+		local t = self:getTalentFromId(tid)
+		if not t.no_sustain_autoreset then
+			reset[#reset+1] = tid
+		else
+			remaining[#remaining+1] = tid
+		end
+	end end
+	self.turn_procs.resetting_talents = true
+	for i, tid in ipairs(reset) do
+		self:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true, no_talent_fail=true})
+		self:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true, no_talent_fail=true, talent_reuse=true})
+	end
+	self.turn_procs.resetting_talents = nil
+	return remaining
+end
+
 -- Mix in sustains
 local function getSustainType(talent_def)
 	if talent_def.is_mind then return "mental"
@@ -7183,7 +7207,7 @@ function _M:dispel(effid_or_tid, src, allow_immunity, params)
 	-- Effect
 	if effid_or_tid:find("^EFF_") then
 		local eff = self:getEffectFromId(effid_or_tid)
-		if not eff or eff.type == "other" then return end -- NEVER touch other
+		if (not eff or eff.type == "other") and not params.force then return end -- NEVER touch other
 		if not self:hasEffect(effid_or_tid) then return end
 
 		if allow_immunity then
@@ -7193,7 +7217,7 @@ function _M:dispel(effid_or_tid, src, allow_immunity, params)
 			if self:fireTalentCheck("callbackOnDispel", "effect", effid_or_tid, src, allow_immunity) then allowed = false end
 		end
 		if allowed then
-			self:removeEffect(effid_or_tid, params.force)
+			self:removeEffect(effid_or_tid, params.silent, params.force)
 			self:fireTalentCheck("callbackOnDispelled", "effect", effid_or_tid, src, allow_immunity)
 			return true
 		else
diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua
index 70f22f9d984eef6086430ead677106e332f0494b..fa6ce75b1c2bc97a4c3cce318c0b3aed5b124db1 100644
--- a/game/modules/tome/class/GameState.lua
+++ b/game/modules/tome/class/GameState.lua
@@ -2176,14 +2176,14 @@ function _M:applyRandomClass(b, data, instant)
 		local nb_focus, nb_shallow = 0, 0
 		local rank = b.rank
 		if rank <= 3.2 then 	--rare
-			nb_focus = math.floor(0.2 + rng.float(0.25, 0.35)*(math.max(0,data.level))^0.55) -- first around 8-10, second around 25-35, third around 50-70
-			nb_shallow = 2 + math.floor(0.25 + rng.float(0.1, 0.2)*(math.max(0,data.level))^0.6) -- third around 12-30, fourth 40-80
+			nb_focus = math.floor(0.2 + rng.float(0.22, 0.35)*(math.max(0,data.level-3))^0.5)
+			nb_shallow = 2 + math.floor(0.25 + rng.float(0.08, 0.2)*(math.max(0,data.level-6))^0.5)
 		elseif rank >= 4 then 	--boss/elite boss 
-			nb_focus = 1 + math.floor(0.25 + rng.float(0.18, 0.33)*(math.max(0,data.level-4))^0.5) -- second around 11-23, third around 35-75, fourth around 80-90 rarely
-			nb_shallow = 1 + math.floor(0.33 + rng.float(0.125, 0.2)*(math.max(0,data.level-3))^0.6) -- second around 12-20, third 40-80
+			nb_focus = 1 + math.floor(0.25 + rng.float(0.15, 0.35)*(math.max(0,data.level-6))^0.5)
+			nb_shallow = 1 + math.floor(0.3 + rng.float(0.1, 0.2)*(math.max(0,data.level-4))^0.5)
 		else 					--unique
-			nb_focus = 1 + math.floor(0.2 + rng.float(0.15, 0.3)*(math.max(0,data.level-10))^0.5) -- second around 20-40, third around 50-90 
-			nb_shallow = 1 + math.floor(0.7 + rng.float(0.125, 0.2)*(math.max(0,data.level-8))^0.6) -- second around 11-14, third around 30-60, fourth around 70-90 rarely
+			nb_focus = 1 + math.floor(0.2 + rng.float(0.15, 0.3)*(math.max(0,data.level-10))^0.5)
+			nb_shallow = 1 + math.floor(0.55 + rng.float(0.1, 0.2)*(math.max(0,data.level-8))^0.5)
 		end
 		print("Adding "..nb_focus.." primary trees to boss")
 		print("Adding "..nb_shallow.." secondary trees to boss")
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index 7a096e27c74671bbd696d49654184ce7be7c70a1..d90af0e8634e3e22c2e900e5fdff5c7a3d0505ec 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -182,7 +182,7 @@ function _M:onEnterLevel(zone, level)
 			if type(self.tempeffect_def[eff_id].cancel_on_level_change) == "function" then self.tempeffect_def[eff_id].cancel_on_level_change(self, p) end
 		end
 	end
-	for i, eff_id in ipairs(effs) do self:removeEffect(eff_id) end
+	for i, eff_id in ipairs(effs) do self:removeEffect(eff_id, nil, true) end
 
 	-- Clear existing player created effects on the map
 	for i, eff in ipairs(level.map.effects) do
diff --git a/game/modules/tome/class/Store.lua b/game/modules/tome/class/Store.lua
index dba27a5093f70af67db2bfc972c1e4578c05995e..f056a9e7e5631fb072a64f532312dc00629f9b3d 100644
--- a/game/modules/tome/class/Store.lua
+++ b/game/modules/tome/class/Store.lua
@@ -280,6 +280,12 @@ end
 --- Actor interacts with the store
 -- @param who the actor who interacts
 function _M:interact(who, name)
+	-- Nice try
+	if who.no_inventory_access then
+		game.logPlayer(who, "This entity can not access inventories.") 
+		return
+	end
+
 	-- Lore-ize me?
 	if who.level < (self.store.minimum_level or 0) then 
 		game.logPlayer(who, "You must be level %d to access this shop.", self.store.minimum_level or 0) 
diff --git a/game/modules/tome/data/autolevel_schemes.lua b/game/modules/tome/data/autolevel_schemes.lua
index c208f242fea9c473881e6d657e7cff331f2a0097..dfb5a266880e95dada346ae443767b7b42d3edcb 100644
--- a/game/modules/tome/data/autolevel_schemes.lua
+++ b/game/modules/tome/data/autolevel_schemes.lua
@@ -58,6 +58,10 @@ Autolevel:registerScheme{ name = "caster", levelup = function(self)
 	self:learnStats{ self.STAT_MAG, self.STAT_MAG, self.STAT_WIL }
 end}
 
+Autolevel:registerScheme{ name = "wisecaster", levelup = function(self)
+	self:learnStats{ self.STAT_MAG, self.STAT_WIL }
+end}
+
 Autolevel:registerScheme{ name = "warriormage", levelup = function(self)
 	self:learnStats{ self.STAT_MAG, self.STAT_MAG, self.STAT_WIL, self.STAT_STR, self.STAT_STR, self.STAT_DEX }
 end}
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index fb4762a40bd4dbe0979bf2189c5fd033406723a9..69472d20119f7e79684a72c398be69780e40b9ea 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -55,7 +55,7 @@ setDefaultProjector(function(src, x, y, type, dam, state)
 	local crit_power = state.crit_power
 
 	local add_dam = 0
-	if not src.turn_procs.damage_type_fix_type then
+	if not src.turn_procs or not src.turn_procs.damage_type_fix_type then
 		if src:attr("all_damage_convert") and src:attr("all_damage_convert_percent") and src.all_damage_convert ~= type then
 			local ndam = dam * src.all_damage_convert_percent / 100
 			dam = dam - ndam
@@ -676,7 +676,7 @@ setDefaultProjector(function(src, x, y, type, dam, state)
 						target:triggerTalent(target.T_NATURE_S_DEFIANCE, nil, src, t)
 					end
 				end
-				if t.is_spell and src.knowTalent and src:knowTalent(src.T_BORN_INTO_MAGIC) then
+				if t.is_spell and src.knowTalent and src:knowTalent(src.T_BORN_INTO_MAGIC) and type ~= DamageType.THAUM then
 					src:triggerTalent(target.T_BORN_INTO_MAGIC, nil, type)
 				end
 
diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua
index 4c29dc1f52e52e945a33eaab9c626eeca829a6f0..964c8eb1e56260b05fc3d3006004bdb1fadc77e4 100644
--- a/game/modules/tome/data/general/objects/world-artifacts.lua
+++ b/game/modules/tome/data/general/objects/world-artifacts.lua
@@ -4129,6 +4129,9 @@ newEntity{ base = "BASE_CLOTH_ARMOR", --Thanks Grayswandir!
 			["spell/water"] = 0.3,
 			["spell/ice"] = 0.3,
 			["spell/frost-alchemy"] = 0.3, --more!
+			["spell/grave"] = 0.3, --more!
+			["spell/glacial-waste"] = 0.3, --more!
+			["spell/rime-wraith"] = 0.3, --more!
  		},
 	},
 	talent_on_spell = {
diff --git a/game/modules/tome/data/maps/vaults/renegade-wyrmics.lua b/game/modules/tome/data/maps/vaults/renegade-wyrmics.lua
index ad33d126bfa3f11f5cfa60b2dcddc02b40680dd5..173f9620c4d0230db41e68482f1ece510ddc8684 100644
--- a/game/modules/tome/data/maps/vaults/renegade-wyrmics.lua
+++ b/game/modules/tome/data/maps/vaults/renegade-wyrmics.lua
@@ -81,15 +81,15 @@ defineTile('C', "ICY_FLOOR", {random_filter={add_levels=25, tome_mod="uvault"}},
 			[Talents.T_BODY_OF_ICE]={base=3, every=15, max=8},
 			[Talents.T_UTTERCOLD]={base=3, every=15, max=7},}
 			e:resolve()
-		 return e end, random_filter={add_levels=25, name = "ice wyrm", random_boss={name_scheme=_t"#rng# the Fozen Terror", nb_classes=2, class_filter=function(d) return d.power_source and (d.power_source.nature or d.power_source.technique) and d.name ~= "Wyrmic" end, loot_quality="store", loot_quantity=1, no_loot_randart=true, loot_unique=true, ai_move="move_complex", rank=4, force_classes={Wyrmic=true}}}} )
+		 return e end, random_filter={add_levels=25, name = "ice wyrm", random_boss={name_scheme=_t"#rng# the Frozen Terror", nb_classes=2, class_filter=function(d) return d.power_source and (d.power_source.nature or d.power_source.technique) and d.name ~= "Wyrmic" end, loot_quality="store", loot_quantity=1, no_loot_randart=true, loot_unique=true, ai_move="move_complex", rank=4, force_classes={Wyrmic=true}}}} )
 defineTile('c', "ICY_FLOOR", {random_filter={add_levels=20, type="money"}}, {random_filter={add_levels=12, name = "cold drake"}} )
 defineTile('V', "SLIME_FLOOR", {random_filter={add_levels=25, tome_mod="uvault"}}, {entity_mod=function(e) 
 		e[#e+1] = resolvers.talents{
-			[Talents.T_INDISCERNIBLE_ANATOMY]={base=4, every=12, max=10},
-			[Talents.T_GRAND_ARRIVAL]=3,
-			[Talents.T_WILD_SUMMON]=4,
-			[Talents.T_ACIDIC_SOIL]={base=3, every=15, max=7},
-			[Talents.T_UNSTOPPABLE_NATURE]={base=3, every=15, max=7},}
+			[Talents.T_INDISCERNIBLE_ANATOMY]={base=2, every=15, max=8},
+			[Talents.T_GRAND_ARRIVAL]=2,
+			[Talents.T_WILD_SUMMON]=3,
+			[Talents.T_ACIDIC_SOIL]={base=3, every=15, max=5},
+			[Talents.T_UNSTOPPABLE_NATURE]={base=3, every=15, max=5},}
 			e:resolve()
 		 return e end, random_filter={add_levels=25, name = "venom wyrm", random_boss={name_scheme=_t"#rng# the Caustic Terror", nb_classes=2, class_filter=function(d) return d.power_source and (d.power_source.nature) and d.name ~= "Oozemancer" end, loot_quality="store", loot_quantity=1, ai_move="move_complex", rank=4, force_classes={Oozemancer=true}}}} )
 defineTile('v', "SLIME_FLOOR", {random_filter={add_levels=20, type="money"}}, {random_filter={add_levels=12, name = "venom drake"}} )
diff --git a/game/modules/tome/data/talents/chronomancy/anomalies.lua b/game/modules/tome/data/talents/chronomancy/anomalies.lua
index 1031d39ec9ed6148cba4fdd18775298eb934c19b..dc2a915bd638e4c3d2e1abb2b6669d23475ba859 100644
--- a/game/modules/tome/data/talents/chronomancy/anomalies.lua
+++ b/game/modules/tome/data/talents/chronomancy/anomalies.lua
@@ -148,7 +148,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		local radius = self:getTalentRadius(t)
@@ -198,7 +198,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		local range = self:getTalentRange(t)
@@ -261,7 +261,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[You swap locations with a random target.]]):tformat()
@@ -311,7 +311,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[50%% chance that damage the caster takes will be warped to a set target.
@@ -410,7 +410,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Creates a wormhole nearby and a second wormhole up to ten tiles away.]]):tformat()
@@ -458,7 +458,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Allows up to five targets in a radius of %d to travel up to %d tiles through walls.]]):
@@ -507,7 +507,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Up to five targets in a radius of %d are teleporting %d tiles every turn.]]):
@@ -622,7 +622,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Pulls innocent people into the fight.]]):tformat()
@@ -672,7 +672,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Slows up to five targets in a radius %d ball by %d%%.]]):
@@ -721,7 +721,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Increases global speed of up to five targets in a radius %d ball by %d%%.]]):
@@ -771,7 +771,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Stuns up to five targets in a radius %d ball.]]):
@@ -821,7 +821,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Time Prisons up to five targets in a radius %d ball.]]):
@@ -869,7 +869,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Time Shields up to five targets in a radius of %d.]]):
@@ -917,7 +917,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Invigorates up to five targets in a radius of %d.]]):
@@ -970,7 +970,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Clones a random creature within range.]]):tformat()
@@ -1014,7 +1014,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		local duration = self:combatScale(getParadoxSpellpower(self, t), 4, 10, 12, 100, 0.75)/2
@@ -1068,7 +1068,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Increases localized gravity, pulling in targets in a radius of %d.]]):tformat(self:getTalentRadius(t))
@@ -1106,7 +1106,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Digs out all terrain in a radius %d ball.]]):tformat(self:getTalentRadius(t))
@@ -1188,7 +1188,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Entombs a single target in a wall of stone.]]):tformat()
@@ -1252,7 +1252,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Places between three and six talents of up to 5 targets in a radius %d ball on cooldown for up to %d turns.]]):
@@ -1303,7 +1303,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Creates a gravity well in a radius %d ball, pinning up to five targets.]]):tformat(self:getTalentRadius(t))
@@ -1344,7 +1344,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Causes an earthquake in a radius of %d.]]):
@@ -1392,7 +1392,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Reduces the resistances of up to five targets in a ball of radius %d by %d%%.]]):tformat(self:getTalentRadius(t), getAnomalyEffectPower(self, t))
@@ -1459,7 +1459,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Summons three to six dust storms.]]):tformat()
@@ -1521,7 +1521,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Summons three to six blazing fires.]]):tformat()
@@ -1565,7 +1565,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Turns up to 5 targets in a radius %d ball to stone for %d turns.]]):
@@ -1610,7 +1610,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Teleports between 3 and 6 targets to the caster.]]):
@@ -1654,7 +1654,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Substantially toughens and hastes one target for %d turns.]]):tformat(getAnomalyDuration(self, t))
@@ -1697,7 +1697,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Clones the caster.]]):tformat(getAnomalyDuration(self, t))
@@ -1746,7 +1746,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Clones all creatures in a radius of 10.]]):tformat(getAnomalyDuration(self, t))
@@ -1782,7 +1782,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Digs out all terrain in between three and six radius %d balls.]]):tformat(self:getTalentRadius(t))
@@ -1842,7 +1842,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Summons a sphere of destruction.]]):tformat()
@@ -1921,7 +1921,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Summons three to six tornados.]]):tformat()
@@ -2017,7 +2017,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Causes a meteor to fall from the sky.]]):
@@ -2101,7 +2101,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Tears a hole in the fabric of spacetime.]]):
@@ -2153,7 +2153,7 @@ newTalent{
 		return true
 	end,
 	action = function(self, t, cancellable)
-		t.doAction(self, t, true)
+		return t.doAction(self, t, true)
 	end,
 	info = function(self, t)
 		return ([[Time elementals have been attracted to the timeline.]]):
diff --git a/game/modules/tome/data/talents/corruptions/shadowflame.lua b/game/modules/tome/data/talents/corruptions/shadowflame.lua
index 86f66491f295965af083ba09e4320ae0dda6a4a8..8bf55406ccf0675f9caab3aa36ead49052db654c 100644
--- a/game/modules/tome/data/talents/corruptions/shadowflame.lua
+++ b/game/modules/tome/data/talents/corruptions/shadowflame.lua
@@ -138,7 +138,10 @@ newTalent{
 	requires_target = true,
 	cooldown = 60,
 	no_sustain_autoreset = true,
-	random_boss_rarity = 10,
+	random_boss_rarity = 5,
+	rnd_boss_restrict = function(self, t, data)
+		return data.level < 20
+	end,
 	tactical = {
 		-- heals (negative attack) demons hurts others
 		ATTACKAREA = {FIRE = function(self, t, target) return target:attr("demon") and -2 or 2 end},
diff --git a/game/modules/tome/data/talents/gifts/antimagic.lua b/game/modules/tome/data/talents/gifts/antimagic.lua
index 66fc13d0397798f7e64ca98cf9e95d83ed9ae954..fb0dc99ac6e6a5c7568be647335746c4d279b7d2 100644
--- a/game/modules/tome/data/talents/gifts/antimagic.lua
+++ b/game/modules/tome/data/talents/gifts/antimagic.lua
@@ -67,6 +67,9 @@ newTalent{
 	equilibrium = 20,
 	cooldown = 12,
 	tactical = { DISABLE = { silence = 4 } },
+	rnd_boss_restrict = function(self, t, data) -- Restrict silencing until the player has the tools needed to deal with it
+		return data.level < 16
+	end,
 	range = 6,
 	radius = function(self, t) return 3 end,
 	getduration = function(self, t) return 3 end,
@@ -124,6 +127,9 @@ newTalent{
 	sustain_equilibrium = 30,
 	cooldown = 6,
 	tactical = { DEFEND = 2 },
+	rnd_boss_restrict = function(self, t, data) -- Flat damage reduction can be obnoxious early game
+		return data.level < 18
+	end,
 	getMax = function(self, t)
 		local v = combatTalentPhysicalMindDamage(self, t, 20, 85)
 		if self:knowTalent(self.T_TRICKY_DEFENSES) then
@@ -180,6 +186,9 @@ newTalent{
 	cooldown = 15,
 	range = 10,
 	tactical = { ATTACK = { ARCANE = 3 } },
+	rnd_boss_restrict = function(self, t, data) -- Restrict antimagic until the player has the tools to deal with it
+		return data.level < 22
+	end,
 	direct_hit = true,
 	requires_target = true,
 	getDamage = function(self, t) return combatTalentPhysicalMindDamage(self, t, 10, 460) end,
diff --git a/game/modules/tome/data/talents/spells/dreadmaster.lua b/game/modules/tome/data/talents/spells/dreadmaster.lua
index 151a909162737cfab69d8d8978894f4169edeae4..6a8d35d5eabc9448ca8ce49ce81846859e41e91e 100644
--- a/game/modules/tome/data/talents/spells/dreadmaster.lua
+++ b/game/modules/tome/data/talents/spells/dreadmaster.lua
@@ -40,7 +40,7 @@ newTalent{
 			sound_random = {"creatures/ghost/random%d", 1, 1},
 			level_range = {1, nil}, exp_worth = 0,
 			body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1, QUIVER=1 },
-			autolevel = "warriormage",
+			autolevel = "wisecaster",
 			ai = "dumb_talented_simple", ai_state = { ai_target="target_closest", ai_move="move_complex", talent_in=2, },
 			dont_pass_target = true,
 			stats = { str=14, dex=18, mag=20, con=12 },
@@ -90,7 +90,7 @@ newTalent{
 			sound_random = {"creatures/ghost/random%d", 1, 1},
 			level_range = {1, nil}, exp_worth = 0,
 			body = { INVEN = 10, MAINHAND=1, OFFHAND=1, BODY=1, QUIVER=1 },
-			autolevel = "warriormage",
+			autolevel = "wisecaster",
 			ai = "dumb_talented_simple", ai_state = { ai_target="target_closest", ai_move="move_complex", talent_in=2, },
 			dont_pass_target = true,
 			stats = { str=14, dex=18, mag=20, con=12 },
diff --git a/game/modules/tome/data/talents/spells/eradication.lua b/game/modules/tome/data/talents/spells/eradication.lua
index 1dc98d37db0ea0716d3dd89a95c2673cc3c72198..a9d3ec7369ee6d1fc42d5099eeb8fc4a83616ca1 100644
--- a/game/modules/tome/data/talents/spells/eradication.lua
+++ b/game/modules/tome/data/talents/spells/eradication.lua
@@ -113,7 +113,7 @@ newTalent{
 			if foe:canBe("teleport") and foe:checkHit(self:combatSpellpower(), foe:combatSpellResist(), 0, 95, 15) then
 				foe:forceMoveAnim(spot[1], spot[2])
 			else
-				game.logSeen(foe, "%s resists the call of the boneyard!")
+				game.logSeen(foe, "%s resists the call of the boneyard!", foe:getName():capitalize())
 			end
 		end
 
diff --git a/game/modules/tome/data/talents/spells/master-of-bones.lua b/game/modules/tome/data/talents/spells/master-of-bones.lua
index d834625c3774b8b69a116f383a64f3291fcb177e..671406f7eac37479fda8043dc14c8c195ffaece8 100644
--- a/game/modules/tome/data/talents/spells/master-of-bones.lua
+++ b/game/modules/tome/data/talents/spells/master-of-bones.lua
@@ -483,10 +483,10 @@ newTalent{
 	requires_target = true,
 	range = 10,
 	getLevel = function(self, t) return math.floor(self:combatScale(self:getTalentLevel(t), -6, 0.9, 2, 5)) end, -- -6 @ 1, +2 @ 5, +5 @ 8
-	on_pre_use = function(self, t) local stats = necroArmyStats(self) return stats.nb_skeleton >= 3 end,
+	on_pre_use = function(self, t) local stats = necroArmyStats(self) return stats.nb_skeleton >= (stats.lord_of_skulls and 4 or 3) end,
 	action = function(self, t)
 		local stats = necroArmyStats(self)
-		if stats.nb_skeleton < 3 then return end
+		if stats.nb_skeleton < (stats.lord_of_skulls and 4 or 3) then return end
 		if stats.bone_giant then stats.bone_giant:die(self) end
 
 		local list = {}
diff --git a/game/modules/tome/data/talents/spells/master-of-flesh.lua b/game/modules/tome/data/talents/spells/master-of-flesh.lua
index ab4de88d4d89ecb58868d1ddaa27c6b58e186087..b1dc0143fedecb9b3bf2d31e46b2b40be8096889 100644
--- a/game/modules/tome/data/talents/spells/master-of-flesh.lua
+++ b/game/modules/tome/data/talents/spells/master-of-flesh.lua
@@ -216,7 +216,7 @@ newTalent{
 		Ghouls, ghasts and ghoulkings last for %d turns.
 
 		#GREY##{italic}#Ghoul minions come in larger numbers than skeleton minions but are generally more frail and disposable.#{normal}#
-		]]):tformat(t:_getEvery(self), math.max(1, self.level + t:_getLevel(self)), t:_getNb(self), self:getTalentRadius(self, t), t:_getTurns(self))
+		]]):tformat(t:_getEvery(self), math.max(1, self.level + t:_getLevel(self)), t:_getNb(self), t:_getTurns(self))
 	end,
 }
 
@@ -316,7 +316,7 @@ newTalent{
 				e.duration = 10 -- Duration is fake, its handled by the sustain
 				return true
 			end,
-			false
+			false, false
 		)
 
 		return ret
diff --git a/game/modules/tome/data/talents/spells/phantasm.lua b/game/modules/tome/data/talents/spells/phantasm.lua
index f3bbe7783c6df8c7f49d6d8211b7a9e025841f48..68961f16ffb7ad51375b55764d655e657d060525 100644
--- a/game/modules/tome/data/talents/spells/phantasm.lua
+++ b/game/modules/tome/data/talents/spells/phantasm.lua
@@ -86,7 +86,7 @@ newTalent{
 	callbackOnHit = function(self, t, cb, src, dt)
 		local p = self:isTalentActive(t.id)
 		if not p then return end
-		if cb.value <= 0 then return end
+		if cb.value <= 0 or src == self then return end
 		if rng.percent(t.getEvade(self, t)) then
 			game:delayedLogDamage(src, self, 0, ("#YELLOW#(%d ignored)#LAST#"):format(cb.value), false)
 			cb.value = 0
@@ -237,7 +237,9 @@ newTalent{
 			on_die = function(self)
 				self.summoner:removeEffect(self.summoner.EFF_MIRROR_IMAGE_REAL, true, true)
 			end,
-			spellFriendlyFire = function() return 100 end,
+			spellFriendlyFire = function(self) return self.summoner:spellFriendlyFire() end,
+			archmage_widebeam = self.archmage_widebeam,
+			iceblock_pierce = self.iceblock_pierce,
 			no_breath = 1,
 			remove_from_party_on_death = true,
 		}
@@ -279,7 +281,7 @@ newTalent{
 		return true
 	end,
 	info = function(self, t)
-		return ([[Create a perfect lookalike of your own form made out of pure light near a creature or yourself if no creature is present.
+		return ([[Create a perfect lookalike of your own form made out of pure light near a creature.
 		This image has %d life and can never take more than 1 damage per creature per turn and is immune to any non direct damage (ground effects, damage over time, ...).
 		Whenever you cast a spell your mirror image will try to duplicate it at the same target for 66%% less damage, if possible. If it can it will loose 1 life, if not it will instead taunt a creature to focus its attention on itself.
 		While the image exists you receive the damage bonus from the Invisibility spell as if you were invisible.
diff --git a/game/modules/tome/data/talents/spells/spells.lua b/game/modules/tome/data/talents/spells/spells.lua
index 35f9f8db68c96f37ce6e4966cf59830aa9c81120..6b5f61b4404424f59d5b5eda3ff99903799c4985 100644
--- a/game/modules/tome/data/talents/spells/spells.lua
+++ b/game/modules/tome/data/talents/spells/spells.lua
@@ -193,7 +193,7 @@ function necroSetupSummon(self, def, x, y, level, turns, no_control)
 	m.unused_generics = 0
 	m.unused_talents_types = 0
 	m.silent_levelup = true
-	m.no_points_on_levelup = true
+	-- m.no_points_on_levelup = true
 	m.ai_state = m.ai_state or {}
 	m.ai_state.tactic_leash = 100
 	-- Try to use stored AI talents to preserve tweaking over multiple summons
diff --git a/game/modules/tome/data/talents/spells/thaumaturgy.lua b/game/modules/tome/data/talents/spells/thaumaturgy.lua
index c22e50dc91664c3e042a1f0100b191dffe66fc8d..306fd6182cbf5869aafe399e30de1aae895333dd 100644
--- a/game/modules/tome/data/talents/spells/thaumaturgy.lua
+++ b/game/modules/tome/data/talents/spells/thaumaturgy.lua
@@ -76,11 +76,15 @@ newTalent{
 		if not thaumaturgyCheck(self) then return end
 
 		local tids = {}
+		local is_aethar_avatar = self:hasEffect(self.EFF_AETHER_AVATAR)
 		for kind, list in pairs(t.spells_list) do
-			for _, tid in ipairs(list) do if self:knowTalent(tid) then
-				-- print(("[%s] %s : %d"):format(kind, tid, self:getTalentCooldown(self:getTalentFromId(tid), true)))
-				tids[#tids+1] = {tid=tid, cd=self:getTalentCooldown(self:getTalentFromId(tid), true)}
-			end end
+			for _, tid in ipairs(list) do
+				local tt = self:getTalentFromId(tid)
+				if self:knowTalent(tid) and (not is_aethar_avatar or (tt.use_only_arcane and self:getTalentLevel(self.T_AETHER_AVATAR) >= tt.use_only_arcane)) then
+					-- print(("[%s] %s : %d"):format(kind, tid, self:getTalentCooldown(self:getTalentFromId(tid), true)))
+					tids[#tids+1] = {tid=tid, cd=self:getTalentCooldown(tt, true)}
+				end
+			end
 		end
 		local choice = rng.rarityTable(tids, "cd")
 		if not choice then return end
@@ -97,7 +101,8 @@ newTalent{
 		return ([[Casting beam spells has become so instinctive for you that you can now easily weave in other spells at the same time.
 		Anytime you cast a beam spell there is a %d%% chance to automatically cast an offensive spell that you know. This can only happen once per turn.
 		Beam spells duplicated by the Orb of Thaumaturgy can also trigger this effect.
-		The additional cast will cost mana but no turn and will not active its cooldown.]]):
+		The additional cast will cost mana but no turn and will not active its cooldown.
+		During Aether Avatar only compatible spells are used.]]):
 		tformat(t:_getChance(self))
 	end,
 }
@@ -163,10 +168,17 @@ newTalent{
 	end,	
 	on_pre_use = thaumaturgyCheck,
 	activate = function(self, t)
-		local ret = { charges = t:_getNb(self) }
+		local ret = { charges = t:_getNb(self), max_charges = t:_getNb(self) }
+		-- I'm French and I like cheese but I'll still try to prevent it!
+		if self.turn_procs.resetting_talents then
+			ret.charges = ret.charges - self.turn_procs.slipstream_resetting
+			if ret.charges <= 0 then game:onTickEnd(function() self:forceUseTalent(t.id, {ignore_energy=true}) end) end
+		end
 		return ret
 	end,
-	deactivate = function(self, t)
+	deactivate = function(self, t, p)
+		-- I'm French and I like cheese but I'll still try to prevent it!
+		if self.turn_procs.resetting_talents then self.turn_procs.slipstream_resetting = p.max_charges - p.charges end
 		return true
 	end,
 	info = function(self, t)
diff --git a/game/modules/tome/data/talents/uber/mag.lua b/game/modules/tome/data/talents/uber/mag.lua
index 31997993baf98556b9e97a555694291d70eb7bc6..9939367d9bbe18777898b9c376d532bbcf6a4c16 100644
--- a/game/modules/tome/data/talents/uber/mag.lua
+++ b/game/modules/tome/data/talents/uber/mag.lua
@@ -431,7 +431,16 @@ uberTalent{
 	on_learn = function(self, t)
 		self:attr("greater_undead", 1) -- Set that here so that the player cant become an Exarch while waiting for their death to become a Lich
 		self:learnTalent(self.T_NEVERENDING_UNLIFE, true, 1)
-		game.bignews:say(120, "#DARK_ORCHID#You are on your way to Lichdom. #{bold}#Your next death will finish the ritual.#{normal}#")
+
+		-- Wait for death
+		if not self.no_resurrect then
+			game.bignews:say(120, "#DARK_ORCHID#You are on your way to Lichdom. #{bold}#Your next death will finish the ritual.#{normal}#")
+		-- We cant wait for death! do it now!
+		else
+			local dialog = require("mod.dialogs.DeathDialog").new(self)
+			t:_becomeLich(self)
+			game.level.map:particleEmitter(self.x, self.y, 1, "demon_teleport")
+		end
 	end,
 	on_unlearn = function(self, t)
 	end,
diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua
index 28cca64526098515f069009237cf3745ed794c0b..3d781468c322fc88b9b56614a5cc8e3f6102cdeb 100644
--- a/game/modules/tome/data/timed_effects/magical.lua
+++ b/game/modules/tome/data/timed_effects/magical.lua
@@ -5369,24 +5369,9 @@ newEffect{
 	parameters = {power=1},
 	on_gain = function(self, err) return _t"#Target# is overflowing with energy!", true end,
 	on_lose = function(self, err) return _t"#Target# is no more overflowing with energy.", true end,
-	udpateSustains = function(self)
-		local reset = {}
-		for tid, act in pairs(self.sustain_talents) do if act then
-				local t = self:getTalentFromId(tid)
-				if not t.no_sustain_autoreset and self:knowTalent(tid) then
-					reset[#reset+1] = tid
-				end
-		end end
-		self.turn_procs.resetting_talents = true
-		for i, tid in ipairs(reset) do
-			self:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true, no_talent_fail=true})
-			self:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true, no_talent_fail=true, talent_reuse=true})
-		end
-		self.turn_procs.resetting_talents = nil
-	end,
 	activate = function(self, eff, ed)
 		eff.tmpid = self:addTemporaryValue("spells_bonus_level", eff.power)
-		ed.udpateSustains(self)
+		self:udpateSustains()
 
 		if core.shader.allow("adv") then
 			eff.particle1, eff.particle2 = self:addParticles3D("volumetric", {kind="fast_sphere", appear=10, radius=1.2, twist=50, density=15, growSpeed=0.002, scrollingSpeed=0.008, img="continuum_01"})
@@ -5396,8 +5381,8 @@ newEffect{
 	end,
 	deactivate = function(self, eff, ed)
 		self:removeTemporaryValue("spells_bonus_level", eff.tmpid)
+		self:udpateSustains()
 		if eff.particle1 then self:removeParticles(eff.particle1) end
 		if eff.particle2 then self:removeParticles(eff.particle2) end
-		ed.udpateSustains(self)
 	end,
 }
diff --git a/game/modules/tome/dialogs/ArenaFinish.lua b/game/modules/tome/dialogs/ArenaFinish.lua
index 1f8e47440a87fcabf40c01969540a87c4245381e..3aca6dd753d7fd50f130839a4691f4f4fddf7a4c 100644
--- a/game/modules/tome/dialogs/ArenaFinish.lua
+++ b/game/modules/tome/dialogs/ArenaFinish.lua
@@ -18,38 +18,20 @@
 -- darkgod@te4.org
 
 require "engine.class"
-local Dialog = require "engine.ui.Dialog"
+local DeathDialog = require "mod.dialogs.DeathDialog"
 local Textzone = require "engine.ui.Textzone"
-local Separator = require "engine.ui.Separator"
-local List = require "engine.ui.List"
-local Savefile = require "engine.Savefile"
-local Map = require "engine.Map"
+local Shader = require "engine.Shader"
 
-module(..., package.seeall, class.inherit(Dialog))
+module(..., package.seeall, class.inherit(DeathDialog))
 
 function _M:init(actor)
-	self.actor = actor
-	Dialog.init(self, _t"Arena mode", 500, 300)
-
-	actor:saveUUID()
-
-	self:generateList()
-
-	self.c_desc = Textzone.new{width=self.iw, auto_height=true, text=self:printRanking() }
-	self.c_list = List.new{width=self.iw, nb_items=#self.list, list=self.list, fct=function(item) self:use(item) end}
-
-	self:loadUI{
-		{left=0, top=0, ui=self.c_desc},
-		{left=5, top=self.c_desc.h, padding_h=10, ui=Separator.new{dir="vertical", size=self.iw - 10}},
-		{left=0, bottom=0, ui=self.c_list},
-	}
-	self:setFocus(self.c_list)
-	self:setupUI(false, true)
+	DeathDialog.init(self, actor)
 end
 
 function _M:printRanking()
 	local scores = world.arena.scores
-	if not scores[1].name then return _t"#LIGHT_GREEN#No high scores. This should not happen."
+	if not scores[1].name then
+		return _t"#LIGHT_GREEN#No high scores. This should not happen."
 	else
 		local text = ""
 		local tmp = ""
@@ -65,102 +47,12 @@ function _M:printRanking()
 			end
 			i = i + 1
 		end
-	return text
-	end
-end
-
---- Clean the actor from debuffs/buffs
-function _M:cleanActor(actor)
-	local effs = {}
-
-	-- Go through all spell effects
-	for eff_id, p in pairs(actor.tmp) do
-		local e = actor.tempeffect_def[eff_id]
-		effs[#effs+1] = {"effect", eff_id}
-	end
-
-	-- Go through all sustained spells
-	for tid, act in pairs(actor.sustain_talents) do
-		if act then
-			effs[#effs+1] = {"talent", tid}
-		end
-	end
-
-	while #effs > 0 do
-		local eff = rng.tableRemove(effs)
-
-		if eff[1] == "effect" then
-			actor:removeEffect(eff[2])
-		else
-			actor:forceUseTalent(eff[2], {ignore_energy=true})
-		end
+		return text
 	end
 end
 
---- Restore resources
-function _M:restoreResources(actor)
-	if actor.resetToFull then
-		actor:resetToFull()
-		actor.energy.value = game.energy_to_act
-	end
-end
-
---- Basic resurrection
-function _M:resurrectBasic(actor)
-	actor.dead = false
-	actor.died = (actor.died or 0) + 1
-
-	local x, y = util.findFreeGrid(actor.x, actor.y, 20, true, {[Map.ACTOR]=true})
-	if not x then x, y = actor.x, actor.y end
-	actor.x, actor.y = nil, nil
-
-	actor:move(x, y, true)
-	game.level:addEntity(actor)
-	game:unregisterDialog(self)
-	game.level.map:redisplay()
-	actor.energy.value = game.energy_to_act
-	actor.changed = true
-	game.paused = true
-end
-
-function _M:use(item)
-	if not item then return end
-	local act = item.action
-
-	if act == "exit" then
-		game:getPlayer(true).dead = true
-		game:saveGame()
-
-		world:saveWorld()
-		if item.subaction == "none" then
-			util.showMainMenu()
-		elseif item.subaction == "restart" then
-			util.showMainMenu(false, engine.version[4], engine.version[1].."."..engine.version[2].."."..engine.version[3], game.__mod_info.short_name, game.save_name, true, ("auto_quickbirth=%q"):format(game:getPlayer(true).name))
-		elseif item.subaction == "restart-new" then
-			util.showMainMenu(false, engine.version[4], engine.version[1].."."..engine.version[2].."."..engine.version[3], game.__mod_info.short_name, game.save_name, true)
-		end
-	elseif act == "cheat" then
-		game.logPlayer(self.actor, "#LIGHT_BLUE#You resurrect! CHEATER !")
-
-		self:cleanActor(self.actor)
-		self:restoreResources(self.actor)
-		self:resurrectBasic(self.actor)
-	elseif act == "dump" then
-		game:registerDialog(require("mod.dialogs.CharacterSheet").new(self.actor))
-	elseif act == "log" then
-		game:registerDialog(require("mod.dialogs.ShowChatLog").new(_t"Message Log", 0.6, game.uiset.logdisplay, profile.chat))
-	end
-end
-
-function _M:generateList()
-	local list = {}
-
-	if config.settings.cheat then list[#list+1] = {name=_t"Resurrect by cheating", action="cheat"} end
-	list[#list+1] = {name=(not profile.auth and _t"Message Log" or _t"Message/Chat log (allows to talk)"), action="log"}
-	list[#list+1] = {name=_t"Character dump", action="dump"}
-	list[#list+1] = {name=_t"Restart the same character", action="exit", subaction="restart"}
-	list[#list+1] = {name=_t"Restart with a new character", action="exit", subaction="restart-new"}
-	list[#list+1] = {name=_t"Exit to main menu", action="exit", subaction="none"}
-
-	self.list = list
+function _M:setupDescription()
+	self.c_desc = Textzone.new{width=self.iw, auto_height=true, text=self:printRanking()}
+	self.c_desc:setTextShadow(1)
+	self.c_desc:setShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 1.2)
 end
diff --git a/game/modules/tome/dialogs/DeathDialog.lua b/game/modules/tome/dialogs/DeathDialog.lua
index 7d2fc20a80436c74f5fb89518aa40a6197df0bdf..39798b3241729b1edd97d7d3dca2328bfac3d46c 100644
--- a/game/modules/tome/dialogs/DeathDialog.lua
+++ b/game/modules/tome/dialogs/DeathDialog.lua
@@ -39,18 +39,9 @@ function _M:init(actor)
 	if self.dont_show then return end
 	if not config.settings.cheat then game:onTickEnd(function() game:saveGame() end) end
 
-	local text = _t[[Death in #{bold}#Tales of Maj'Eyal#{normal}# is usually permanent, but if you have a means of resurrection it will be proposed in the menu below.
-You can dump your character data to a file to remember her/him forever, or you can exit and try once again to survive in the wilds!
-]]
-
-	if #game.party.on_death_show_achieved > 0 then
-		self.c_achv = Textzone.new{width=self.iw, scrollbar=true, height=100, text=("#LIGHT_GREEN#During your game you#WHITE#:\n* %s"):tformat(table.concat(game.party.on_death_show_achieved, "\n* "))}
-	end
+	self:setupDescription()
 
 	self:setTitleShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 1.5)
-	self.c_desc = Textzone.new{width=self.iw, auto_height=true, text=text}
-	self.c_desc:setTextShadow(1)
-	self.c_desc:setShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 1.2)
 
 	self.c_list = List.new{width=self.iw, nb_items=#self.list, list=self.list, fct=function(item) self:use(item) end, select=function(item) self.cur_item = item end}
 
@@ -88,6 +79,18 @@ You can dump your character data to a file to remember her/him forever, or you c
 	self:setupUI(false, true)
 end
 
+function _M:setupDescription()
+	self.c_desc = Textzone.new{width=self.iw, auto_height=true, text=_t[[Death in #{bold}#Tales of Maj'Eyal#{normal}# is usually permanent, but if you have a means of resurrection it will be proposed in the menu below.
+You can dump your character data to a file to remember her/him forever, or you can exit and try once again to survive in the wilds!
+]]}
+	self.c_desc:setTextShadow(1)
+	self.c_desc:setShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 1.2)
+
+	if #game.party.on_death_show_achieved > 0 then
+		self.c_achv = Textzone.new{width=self.iw, scrollbar=true, height=100, text=("#LIGHT_GREEN#During your game you#WHITE#:\n* %s"):tformat(table.concat(game.party.on_death_show_achieved, "\n* "))}
+	end
+end
+
 --- Clean the actor from debuffs/buffs
 function _M:cleanActor(actor)
 	local effs = {}
@@ -180,9 +183,9 @@ function _M:eidolonPlane()
 		local is_exploration = game.permadeath == game.PERMADEATH_INFINITE
 		self:cleanActor(self.actor)
 		self:resurrectBasic(self.actor, "eidolon_plane")
-		for e, _ in pairs(game.party.members) do
+		for e, _ in pairs(game.party.members) do if e ~= self.actor then
 			self:cleanActor(e)
-		end
+		end end
 		for uid, e in pairs(game.level.entities) do
 			if not is_exploration or game.party:hasMember(e) then
 				self:restoreResources(e)
diff --git a/game/modules/tome/dialogs/LevelupDialog.lua b/game/modules/tome/dialogs/LevelupDialog.lua
index 5b727be261d1e2c37b5529da925f95859c9204d4..c384321013d607ff3ce43b9e2d18c242225156f8 100644
--- a/game/modules/tome/dialogs/LevelupDialog.lua
+++ b/game/modules/tome/dialogs/LevelupDialog.lua
@@ -55,7 +55,6 @@ end
 function _M:init(actor, on_finish, on_birth)
 	self.on_birth = on_birth
 	actor.is_dialog_talent_leveling = true
-	actor.disable_talents_add_levels = true
 	actor.no_last_learnt_talents_cap = true
 	self.actor = actor
 	self.unused_stats = self.actor.unused_stats
@@ -160,7 +159,6 @@ end
 function _M:unload()
 	self.actor.is_dialog_talent_leveling = nil
 	self.actor.no_last_learnt_talents_cap = nil
-	self.actor.disable_talents_add_levels = nil
 	self.actor:capLastLearntTalents("class")
 	self.actor:capLastLearntTalents("generic")
 end
@@ -194,26 +192,12 @@ function _M:finish()
 
 	local txt = _t"#LIGHT_BLUE#Warning: You have increased some of your statistics or talent. Talent(s) actually sustained: \n %s If these are dependent on one of the stats you changed, you need to re-use them for the changes to take effect."
 	local talents = ""
-	local reset = {}
-	for tid, act in pairs(self.actor.sustain_talents) do
-		if act then
-			local t = self.actor:getTalentFromId(tid)
-			if t.no_sustain_autoreset and self.actor:knowTalent(tid) then
-				talents = talents.."#GOLD# - "..t.name.."#LAST#\n"
-			else
-				reset[#reset+1] = tid
-			end
-		end
+	for _, tid in ipairs(self.actor:udpateSustains()) do
+		local t = self.actor:getTalentFromId(tid)
+		talents = talents.."#GOLD# - "..t.name.."#LAST#\n"
 	end
-	if talents ~= "" then
-		game.logPlayer(self.actor, txt:format(talents))
-	end
-	self.actor.turn_procs.resetting_talents = true
-	for i, tid in ipairs(reset) do
-		self.actor:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true, no_talent_fail=true})
-		if self.actor:knowTalent(tid) then self.actor:forceUseTalent(tid, {ignore_energy=true, ignore_cd=true, no_talent_fail=true, talent_reuse=true}) end
-	end
-	self.actor.turn_procs.resetting_talents = nil
+	if talents ~= "" then game.logPlayer(self.actor, txt:format(talents)) end
+
 	-- Prodigies
 	if self.on_finish_prodigies then
 		for tid, ok in pairs(self.on_finish_prodigies) do if ok then self.actor:learnTalent(tid, true, nil, {no_unlearn=true}) end end
@@ -985,15 +969,18 @@ function _M:getTalentDesc(item)
 		end
 
 		local traw = self.actor:getTalentLevelRaw(t.id)
+		local lvl_alt = self.actor:alterTalentLevelRaw(t, traw) - traw
 		if config.settings.tome.show_detailed_talents_desc then
 			local list = {}
 			for i = 1, 5 do
 				local d = self.actor:getTalentReqDesc(item.talent, i-traw):toTString():tokenize(" ()[]")
 				d:merge(self.actor:getTalentFullDescription(t, i-traw))
-				list[i] = d:tokenize(tokenize_number.decimal)
+				list[i] = d
+				-- list[i] = d:tokenize(tokenize_number.decimal)
 			end			
-			text:add({"font", "bold"}, _t"Current talent level: "..traw, {"font", "normal"})
-			text:add(true)
+			text:add({"font", "bold"}, _t"Current talent level: "..traw)
+			if lvl_alt ~= 0 then text:add((" (%+d bonus level)"):tformat(lvl_alt)) end
+			text:add({"font", "normal"}, true)
 			text:merge(tstring:diffMulti(list, function(diffs, res)
 				for i, d in ipairs(diffs) do
 					if i ~= traw then
@@ -1021,22 +1008,25 @@ function _M:getTalentDesc(item)
 			if traw == 0 then
 				local req = self.actor:getTalentReqDesc(item.talent, 1):toTString():tokenize(" ()[]")
 				text:add{"color","WHITE"}
-				text:add({"font", "bold"}, _t"First talent level: ", tostring(traw+1), {"font", "normal"})
-				text:add(true)
+				text:add({"font", "bold"}, _t"First talent level: ", tostring(traw+1))
+				if lvl_alt ~= 0 then text:add((" (%+d bonus level)"):tformat(lvl_alt)) end
+				text:add({"font", "normal"}, true)
 				text:merge(req)
 				text:merge(self.actor:getTalentFullDescription(t, 1000):diffWith(self.actor:getTalentFullDescription(t, 1), diff_color))
 			elseif traw < self:getMaxTPoints(t) then
 				local req = self.actor:getTalentReqDesc(item.talent):toTString():tokenize(" ()[]")
 				local req2 = self.actor:getTalentReqDesc(item.talent, 1):toTString():tokenize(" ()[]")
 				text:add{"color","WHITE"}
-				text:add({"font", "bold"}, traw == 0 and _t"Next talent level" or _t"Current talent level: ", tostring(traw), " [-> ", tostring(traw + 1), "]", {"font", "normal"})
-				text:add(true)
+				text:add({"font", "bold"}, traw == 0 and _t"Next talent level" or _t"Current talent level: ", tostring(traw), " [-> ", tostring(traw + 1), "]")
+				if lvl_alt ~= 0 then text:add((" (%+d bonus level)"):tformat(lvl_alt)) end
+				text:add({"font", "normal"}, true)
 				text:merge(req2:diffWith(req, diff_full))
 				text:merge(self.actor:getTalentFullDescription(t, 1):diffWith(self.actor:getTalentFullDescription(t), diff_full))
 			else
 				local req = self.actor:getTalentReqDesc(item.talent):toTString():tokenize(" ()[]")
-				text:add({"font", "bold"}, _t"Current talent level: "..traw, {"font", "normal"})
-				text:add(true)
+				text:add({"font", "bold"}, _t"Current talent level: "..traw)
+				if lvl_alt ~= 0 then text:add((" (%+d bonus level)"):tformat(lvl_alt)) end
+				text:add({"font", "normal"}, true)
 				text:merge(req)
 				text:merge(self.actor:getTalentFullDescription(t, 1000):diffWith(self.actor:getTalentFullDescription(t), diff_color))
 			end
diff --git a/utils/release.sh b/utils/release.sh
index 5828e614dd86971c916d13e0632eb673a75a8d2b..119c5599324cdfef0f502f1e47c4e05209347cdb 100755
--- a/utils/release.sh
+++ b/utils/release.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 if test $# -lt 1 ; then
-	echo "Usage: release.sh [version] [beta, if any]"
+	echo "Usage: release.sh [version] [beta, if any] [if beta, allowed addons list or 'all' or 'no-dlc' or 'with-dlc']"
 	exit
 fi
 
@@ -69,7 +69,21 @@ find . -name '*~' -or -name '.svn' -or -name '.keep' | xargs rm -rf
 echo "version_desc = '$ver'" >> game/engines/default/modules/boot/init.lua
 echo "version_desc = '$ver'" >> game/modules/tome/init.lua
 if test -n "$beta"; then
-	echo "return '$beta'" > game/engines/default/engine/version_beta.lua
+	if test $# -lt 3 ; then
+		echo "Usage: release.sh [version] [beta] [allowed addons list or 'all' or 'no-dlc' or 'with-dlc']"
+		exit
+	fi
+	addons="$3"
+	if test "$addons" = "all"; then
+		echo "return '$beta'" > game/engines/default/engine/version_beta.lua
+	elif test "$addons" = "no-dlc"; then
+		echo "return '$beta', "'{"possessors", "items-vault", "^cosmetic%-shimmer%-.+"}' > game/engines/default/engine/version_beta.lua
+	elif test "$addons" = "with-dlc"; then
+		echo "return '$beta', "'{"possessors", "items-vault", "^cosmetic%-shimmer%-.+", function(add) return add.id_dlc end}' > game/engines/default/engine/version_beta.lua
+	else
+		addons_check=`echo "$addons" | sed -e 's/\([^,]\+\)/"\1"/g' -e 's/^/{/' -e 's/$/}/'`
+		echo "return '$beta', '$addons_check'" > game/engines/default/engine/version_beta.lua
+	fi
 fi
 
 # create teae/teams