diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index f98564c7162882c8ff02259cd4f5aa3bf3442490..c6dd50ca6c822859692959f017863da85d2fb200 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -1797,6 +1797,9 @@ function _M:onHeal(value, src)
 		end
 	end
 
+	local ret = self:fireTalentCheck("callbackOnHeal", value, src)
+	if ret then value = ret.value end
+
 --	print("[HEALING]", self.uid, self.name, "for", value)
 	if (not self.resting and (not game.party:hasMember(self) or not game:getPlayer(true).resting)) and value + psi_heal >= 1 and not self:attr("silent_heal") then
 		if game.level.map.seens(self.x, self.y) then
@@ -4357,6 +4360,8 @@ local sustainCallbackCheck = {
 	callbackOnArcheryMiss = "talents_on_archery_miss",
 	callbackOnCrit = "talents_on_crit",
 	callbackOnStatChange = "talents_on_stat_change",
+	callbackOnTakeDamage = "talents_on_take_damage",
+	callbackOnHeal = "talents_on_heal",
 }
 _M.sustainCallbackCheck = sustainCallbackCheck
 
diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua
index aba4b3029da7fa20ef50576fe06a4d73b1e42a06..23ef08edd7099f6c7f957054296298c79cf6da24 100644
--- a/game/modules/tome/data/general/objects/world-artifacts.lua
+++ b/game/modules/tome/data/general/objects/world-artifacts.lua
@@ -548,7 +548,7 @@ newEntity{ base = "BASE_LIGHT_ARMOR",
 		for eff_id, p in pairs(who.tmp) do
 			-- p only has parameters, we need to get the effect definition (e) to check subtypes
 			local e = who.tempeffect_def[eff_id]
-			if e.subtype and (e.subtype.bleed or e.subtype.poison or e.subtype.wound) then	
+			if e.status == "detrimental" and e.subtype and (e.subtype.bleed or e.subtype.poison or e.subtype.wound) then	
 				
 				-- Copy the effect parameters then change only the source
 				-- This will preserve everything passed to the debuff in setEffect but will use the new source for +damage%, etc
@@ -571,9 +571,12 @@ newEntity{ base = "BASE_LIGHT_ARMOR",
 							game.logPlayer(who, "#CRIMSON#Rogue Plight transfers an effect to a nearby enemy!")
 							return true
 						end		
-			end end end end		
+					end
+				end
+			end
+		end	
 		return true	
-		end,
+	end,
 }
 
 newEntity{
diff --git a/game/modules/tome/data/gfx/talents/blood_splash.png b/game/modules/tome/data/gfx/talents/blood_splash.png
new file mode 100644
index 0000000000000000000000000000000000000000..e8ef910a1308e32407017dd235ee0d9dde2743de
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/blood_splash.png differ
diff --git a/game/modules/tome/data/gfx/talents/elemental_discord.png b/game/modules/tome/data/gfx/talents/elemental_discord.png
new file mode 100644
index 0000000000000000000000000000000000000000..ec283fcd6f140de02dee01b0064d35e8853ecfe9
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/elemental_discord.png differ
diff --git a/game/modules/tome/data/gfx/talents/healing_inversion.png b/game/modules/tome/data/gfx/talents/healing_inversion.png
new file mode 100644
index 0000000000000000000000000000000000000000..a251145d2a9ac678dde9936a14af440d3631fd12
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/healing_inversion.png differ
diff --git a/game/modules/tome/data/gfx/talents/vile_transplant.png b/game/modules/tome/data/gfx/talents/vile_transplant.png
new file mode 100644
index 0000000000000000000000000000000000000000..7257e6fcd25046955ac9ed99ad13ab0c8fd6fe06
Binary files /dev/null and b/game/modules/tome/data/gfx/talents/vile_transplant.png differ
diff --git a/game/modules/tome/data/talents/corruptions/vile-life.lua b/game/modules/tome/data/talents/corruptions/vile-life.lua
index c4ac2f25c543cb7fd86738c7a78ad1c57e304f5b..7064b7210712abda81195a587161b8b2e5fe5280 100644
--- a/game/modules/tome/data/talents/corruptions/vile-life.lua
+++ b/game/modules/tome/data/talents/corruptions/vile-life.lua
@@ -59,34 +59,63 @@ newTalent{
 	points = 5,
 	cooldown = 20,
 	vim = 30,
-	range = 10,
-	radius = 2,
-	tactical = { DISABLE = 2 },
-	direct_hit = true,
-	requires_target = true,
-	target = function(self, t)
-		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t}
+	mode = "sustained",
+	tactical = { BUFF = 2 },
+	getFire = function(self, t) return self:combatTalentSpellDamage(t, 10, 400) end,
+	getCold = function(self, t) return self:combatTalentSpellDamage(t, 10, 500) end,
+	getLightning = function(self, t) return math.floor(self:combatTalentLimit(t, 8, 3, 5)) end,
+	getAcid = function(self, t) return math.floor(self:combatTalentLimit(t, 8, 2, 5)) end,
+	getNature = function(self, t) return self:combatTalentLimit(t, 60, 15, 45) end,
+	callbackOnTakeDamage = function(self, t, src, x, y, type, dam, tmp, no_martyr)
+		local p = self:isTalentActive(t.id)
+		if not p then return end
+		if not src.setEffect then return end
+		if not p.last_turn[type] or game.turn - p.last_turn[type] < 100 then return end
+
+		if type == DamageType.FIRE then
+			src:setEffect(src.EFF_BURNING, 5, {src=self, apply_power=self:combatSpellpower(), power=t.getFire(self, t) / 5})
+		elseif type == DamageType.COLD then
+			src:setEffect(src.EFF_FROZEN, 3, {apply_power=self:combatSpellpower(), hp=t.getCold(self, t)})
+		elseif type == DamageType.ACID then
+			src:setEffect(src.EFF_BLINDED, t.getAcid(self, t), {apply_power=self:combatSpellpower(), hp=t.getCold(self, t)})
+		elseif type == DamageType.LIGHTNING then
+			src:setEffect(src.EFF_DAZED, t.getLightning(self, t), {apply_power=self:combatSpellpower()})
+		elseif type == DamageType.NATURE then
+			src:setEffect(src.EFF_SLOW, 4, {apply_power=self:combatSpellpower(), power=t.getNature(self, t) / 100})
+		end
+		p.last_turn[type] = game.turn
 	end,
-	getCDincrease = function(self, t) return self:combatTalentScale(t, 0.15, 0.5) end,
-	action = function(self, t)
-		local tg = self:getTalentTarget(t)
-		local x, y = self:getTarget(tg)
-		if not x or not y then return nil end
-		self:project(tg, x, y, function(tx, ty)
-			local target = game.level.map(tx, ty, Map.ACTOR)
-			if not target or target == self then return end
-			target:setEffect(target.EFF_BURNING_HEX, 20, {src=self, dam=self:spellCrit(self:combatTalentSpellDamage(t, 4, 90)), power=1 + t.getCDincrease(self, t), apply_power=self:combatSpellpower()})
-		end)
-		local _ _, _, _, x, y = self:canProject(tg, x, y)
-		game.level.map:particleEmitter(x, y, tg.radius, "circle", {oversize=0.7, g=100, b=100, a=90, limit_life=8, appear=8, speed=2, img="blight_circle", radius=self:getTalentRadius(t)})
+	activate = function(self, t)
 		game:playSoundNear(self, "talents/slime")
+		return {
+			last_turn = { 
+				[DamageType.FIRE] = game.turn - 100,
+				[DamageType.COLD] = game.turn - 100,
+				[DamageType.ACID] = game.turn - 100,
+				[DamageType.LIGHTNING] = game.turn - 100,
+				[DamageType.NATURE] = game.turn - 100,
+			},
+		}
+	end,
+	deactivate = function(self, t, p)
 		return true
 	end,
 	info = function(self, t)
-		return ([[Hexes your target and everything within a radius 2 ball around it for 20 turns. Each time an affected target uses a resource (stamina, mana, vim, ...), it takes %0.2f fire damage.
-		In addition, the cooldown of any talent used while so hexed is increased by %d%% + 1 turn.
+		return ([[Use elemental damage deal to you to trigger terrible effects on the source:
+		- Fire: burn for %0.2f fire damage over 5 turns
+		- Cold: freeze for 3 turns with %d iceblock power
+		- Acid: blind for %d turns
+		- Lightning: daze for %d turns
+		- Nature: %d%% slow for 4 turns
+		This effect can only happen once every 10 turns per damage type.
 		The damage will increase with your Spellpower.]]):
-		format(damDesc(self, DamageType.FIRE, self:combatTalentSpellDamage(t, 4, 90)), t.getCDincrease(self, t)*100)
+		format(
+			damDesc(self, DamageType.FIRE, t.getFire(self, t)),
+			t.getCold(self, t),
+			t.getAcid(self, t),
+			t.getLightning(self, t),
+			t.getNature(self, t)
+		)
 	end,
 }
 
@@ -95,17 +124,14 @@ newTalent{
 	type = {"corruption/vile-life", 3},
 	require = corrs_req3,
 	points = 5,
-	cooldown = 20,
-	vim = 30,
-	range = 10,
-	radius = 2,
+	cooldown = 15,
+	vim = 16,
+	range = 5,
 	tactical = { DISABLE = 2 },
 	direct_hit = true,
 	requires_target = true,
-	target = function(self, t)
-		return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t}
-	end,
-	recoil = function(self,t) return self:combatLimit(self:combatTalentSpellDamage(t, 4, 20), 100, 0, 0, 12.1, 12.1) end, -- Limit to <100%
+	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
+	getPower = function(self,t) return self:combatLimit(self:combatTalentSpellDamage(t, 4, 100), 100, 0, 0, 18.1, 18.1) end, -- Limit to <100%
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
@@ -113,16 +139,15 @@ newTalent{
 		self:project(tg, x, y, function(tx, ty)
 			local target = game.level.map(tx, ty, Map.ACTOR)
 			if not target or target == self then return end
-			target:setEffect(target.EFF_EMPATHIC_HEX, 20, {power=t.recoil(self,t), apply_power=self:combatSpellpower()})
+			target:setEffect(target.EFF_HEALING_INVERSION, 5, {apply_power=self:combatSpellpower(), power=t.getPower(self, t)})
 		end)
-		local _ _, _, _, x, y = self:canProject(tg, x, y)
-		game.level.map:particleEmitter(x, y, tg.radius, "circle", {oversize=0.7, r=100, b=100, a=90, limit_life=8, appear=8, speed=2, img="blight_circle", radius=self:getTalentRadius(t)})
 		game:playSoundNear(self, "talents/slime")
 		return true
 	end,
 	info = function(self, t)
-		return ([[Hexes your target and everything within a radius 2 ball around it. Each time they do damage, they take %d%% of the same damage for 20 turns.
-		The damage will increase with your Spellpower.]]):format(t.recoil(self,t))
+		return ([[You manipulate the vim of your target to temporarily invert all healing done to it (but not regeneration).
+		For 5 turns all healing will instead damage them for %d%% of the healing done as blight.
+		The effect will increase with your Spellpower.]]):format(t.getPower(self,t))
 	end,
 }
 
@@ -131,16 +156,14 @@ newTalent{
 	type = {"corruption/vile-life", 4},
 	require = corrs_req4,
 	points = 5,
-	cooldown = 20,
-	vim = 30,
-	range = 10,
-	no_npc_use = true,
+	cooldown = 10,
+	vim = 18,
 	direct_hit = true,
 	requires_target = true,
-	target = function(self, t)
-		return {type="hit", range=self:getTalentRange(t), talent=t}
-	end,
-	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
+	range = 1,
+	target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
+	getNb = function(self, t) return math.floor(self:combatTalentScale(t, 2, 9)) end,
+	getDam = function(self, t) return 4 end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local x, y = self:getTarget(tg)
@@ -148,8 +171,32 @@ newTalent{
 		self:project(tg, x, y, function(tx, ty)
 			local target = game.level.map(tx, ty, Map.ACTOR)
 			if not target or target == self then return end
-			if target:canBe("instakill") then
-				target:setEffect(target.EFF_DOMINATION_HEX, t.getDuration(self, t), {src=self, apply_power=self:combatSpellpower(), faction = self.faction})
+
+			local list = {}
+			local nb = t.getNb(self, t)
+			for eff_id, p in pairs(self.tmp) do
+				local e = self.tempeffect_def[eff_id]
+				if (e.type == "physical" or e.type == "magical") and e.status == "detrimental" then
+					list[#list+1] = eff_id
+				end
+			end
+
+			local dam = t.getDam(self, t) * self.life / 100
+			while #list > 0 and nb > 0 do
+				if self:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, 95, 5) then
+					local eff_id = rng.tableRemove(list)
+					local p = self.tmp[eff_id]
+					local e = self.tempeffect_def[eff_id]
+					local effectParam = self:copyEffect(eff_id)
+					effectParam.src = self
+						
+					target:setEffect(eff_id, p.dur, effectParam)
+					self:removeEffect(eff_id)
+					local dead, val = self:takeHit(dam, self, {source_talent=t})
+					target:heal(val, self)
+					game.logPlayer(self, "#CRIMSON#%s transfers an effect (%s) to %s!", self.name:capitalize(), e.desc, target.name)
+				end
+				nb = nb - 1
 			end
 		end)
 		local _ _, _, _, x, y = self:canProject(tg, x, y)
@@ -158,7 +205,8 @@ newTalent{
 		return true
 	end,
 	info = function(self, t)
-		return ([[Hexes your target, forcing it to be your thrall for %d turns.
-		If you damage the target, it will be freed from the hex.]]):format(t.getDuration(self, t))
+		return ([[You touch a nearby creature to transfer up to %d physical or magical detrimental effects currently affecting you.
+		The transfer takes %d%% of your remaining life and heals the target for the same value.]]):
+		format(t.getNb(self, t), t.getDam(self, t))
 	end,
 }
diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua
index 4d7ac4e8d551bdfe291fa66e2c3a16af97a796ac..3131703aacd90374fc6b33a696e2ed739691a58c 100644
--- a/game/modules/tome/data/timed_effects/magical.lua
+++ b/game/modules/tome/data/timed_effects/magical.lua
@@ -2636,7 +2636,7 @@ newEffect{
 	name = "ILLUMINATION",
 	desc = "Illumination ", image = "talents/illumination.png",
 	long_desc = function(self, eff) return ("The target glows in the light, reducing its stealth and invisibility power by %d, defense by %d and looses all evasion bonus from being unseen."):format(eff.power, eff.def) end,
-	type = "physical",
+	type = "magical",
 	subtype = { sun=true },
 	status = "detrimental",
 	parameters = { power=20, def=20 },
@@ -2654,7 +2654,7 @@ newEffect{
 	name = "LIGHT_BURST",
 	desc = "Light Burst ", image = "talents/light_burst.png",
 	long_desc = function(self, eff) return ("The is invigorated when dealing damage with Searing Sight."):format() end,
-	type = "physical",
+	type = "magical",
 	subtype = { sun=true },
 	status = "beneficial",
 	parameters = { max=1 },
@@ -2664,9 +2664,9 @@ newEffect{
 
 newEffect{
 	name = "LIGHT_BURST_SPEED",
-	desc = "Light Burst Speed ", image = "effects/light_burst_speed.png",
-	long_desc = function(self, eff) return ("The is invigorated from Searing Sight, increasing movement speed by %d%%."):format(eff.charges * 10) end,
-	type = "physical",
+	desc = "Light Burst Speed", image = "effects/light_burst_speed.png",
+	long_desc = function(self, eff) return ("The target is invigorated from Searing Sight, increasing movement speed by %d%%."):format(eff.charges * 10) end,
+	type = "magical",
 	subtype = { sun=true },
 	status = "beneficial",
 	parameters = {},
@@ -2690,3 +2690,26 @@ newEffect{
 		self:removeTemporaryValue("movement_speed", eff.tmpid)
 	end,
 }
+
+newEffect{
+	name = "HEALING_INVERSION",
+	desc = "Healing Inversion", image = "talents/healing_inversion.png",
+	long_desc = function(self, eff) return ("All healing done to the target will instead turn into %d%% blight damage."):format(eff.power) end,
+	type = "magical",
+	subtype = { heal=true },
+	status = "detrimental",
+	parameters = { power=10 },
+	on_gain = function(self, err) return nil, "+Healing Inversion" end,
+	on_lose = function(self, err) return nil, "-Healing Inversion" end,
+	callbackOnHeal = function(self, eff, value, src)
+		local dam = value * eff.power / 100
+		DamageType:get(DamageType.BLIGHT).projector(eff.src or self, self.x, self.y, DamageType.BLIGHT, dam)
+		return {value=0}
+	end,
+	activate = function(self, eff)
+		eff.particle = self:addParticles(Particles.new("circle", 1, {oversize=0.7, a=90, appear=8, speed=-2, img="necromantic_circle", radius=0}))
+	end,
+	deactivate = function(self, eff)
+		self:removeParticles(eff.particle)
+	end,
+}
diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua
index e0df7d189c717df976e56a1f2fde48b71983a892..fcff508d5c57d3a156033cdae0057b899e41e471 100644
--- a/game/modules/tome/data/timed_effects/physical.lua
+++ b/game/modules/tome/data/timed_effects/physical.lua
@@ -513,7 +513,7 @@ newEffect{
 newEffect{
 	name = "SLOW", image = "talents/slow.png",
 	desc = "Slow",
-	long_desc = function(self, eff) return ("Reduces global action speed by %d%%."):format( eff.power * 100) end,
+	long_desc = function(self, eff) return ("Reduces global action speed by %d%%."):format(eff.power * 100) end,
 	type = "physical",
 	subtype = { slow=true },
 	status = "detrimental",
diff --git a/game/modules/tome/data/zones/mark-spellblaze/grids.lua b/game/modules/tome/data/zones/mark-spellblaze/grids.lua
index 7268f5fc1f0ad09e474e36ae7987b28c57377a55..29a577b8173dade99ddb17bac98dc71a0995e1fb 100644
--- a/game/modules/tome/data/zones/mark-spellblaze/grids.lua
+++ b/game/modules/tome/data/zones/mark-spellblaze/grids.lua
@@ -35,8 +35,8 @@ newEntity{ base = "ALTAR",
 			who:removeObject(inven, item, true)
 			local o = game.zone:makeEntityByName(game.level, "object", "CORRUPTED_SANDQUEEN_HEART", true)
 			o:identify(true)
-			who:addObject(inven, o)
-			who:sortInven(inven)
+			who:addObject(who.INVEN_INVEN, o)
+			who:sortInven(who.INVEN_INVEN)
 			game.log("#GREEN#You put the heart on the altar. The heart shrivels and shakes, vibrating with new corrupt forces.")
 		end, "Cancel", "Corrupt", nil, true)
 	end,
diff --git a/game/modules/tome/data/zones/sandworm-lair/objects.lua b/game/modules/tome/data/zones/sandworm-lair/objects.lua
index 05877ad72282b8bbc008144e224313362bad18f9..687bd22c784b5b75af688e65b1b138782d5a20aa 100644
--- a/game/modules/tome/data/zones/sandworm-lair/objects.lua
+++ b/game/modules/tome/data/zones/sandworm-lair/objects.lua
@@ -35,7 +35,8 @@ newEntity{
 	type = "corpse", subtype = "heart", image = "object/artifact/queen_heart.png",
 	name = "Heart of the Sandworm Queen", unique=true, unided_name="pulsing organ",
 	display = "*", color=colors.VIOLET,
-	desc = [[The heart of the Sandworm Queen, ripped from her dead body. You could ... consume it, should you feel mad enough.]],
+	desc = [[The heart of the Sandworm Queen, ripped from her dead body.
+You could ... consume it, should you feel mad enough or you could try to corrupt it somewhere.]],
 	cost = 3000,
 	quest = 1,
 
diff --git a/src/core_lua.c b/src/core_lua.c
index b5047a9e433f5ef0fb0c25eb8772fc48a63e09c8..08fbbdc04ac46ec676398cf493269ffc1c547478 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -429,7 +429,7 @@ static int lua_key_get_clipboard(lua_State *L)
 		if (str)
 		{
 			lua_pushstring(L, str);
-			free(str);
+			SDL_free(str);
 		}
 		else
 			lua_pushnil(L);
@@ -786,7 +786,7 @@ static int sdl_surface_drawstring_newsurface_aa(lua_State *L)
 	return 1;
 }
 
-static font_make_texture_line(lua_State *L, SDL_Surface *s, int id, bool is_separator, int id_real_line, char *line_data, int line_data_size, bool direct_uid_draw, int realsize)
+static void font_make_texture_line(lua_State *L, SDL_Surface *s, int id, bool is_separator, int id_real_line, char *line_data, int line_data_size, bool direct_uid_draw, int realsize)
 {
 	lua_createtable(L, 0, 9);
 
@@ -1018,7 +1018,7 @@ static int sdl_font_draw(lua_State *L)
 					}
 				}
 				// Extra data
-				else if ((*(next+1) == '&')) {
+				else if (*(next+1) == '&') {
 					line_data = next + 2;
 					line_data_size = codestop - (next+2);
 				}
diff --git a/src/map.c b/src/map.c
index 520255678466215fe65fd5d34b0b8fa5ad4e9e3f..432c6e3db551aaa5e2580af63eb9c7b8ec6c9e31 100644
--- a/src/map.c
+++ b/src/map.c
@@ -57,6 +57,7 @@ static int lua_is_hex(lua_State *L)
 		lua_settable(L, LUA_REGISTRYINDEX);
 		lua_pushnumber(L, 0);
 	}
+	return 1;
 }
 
 static int map_object_new(lua_State *L)
diff --git a/src/music.c b/src/music.c
index e8b137fc174d8252adc7fc992d9b35cfaaf80a51..4f3a60d33cfa29329cec5449f32307362bb8ccf3 100644
--- a/src/music.c
+++ b/src/music.c
@@ -76,7 +76,7 @@ void openal_get_devices()
 	char *defaultDevice=NULL;
 	char *deviceList=NULL;
 
-	if (alcIsExtensionPresent(NULL, (ALubyte*)"ALC_ENUMERATION_EXT") == AL_TRUE)
+	if (alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE)
 	{ // try out enumeration extension
 		deviceList = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
 
diff --git a/src/web.c b/src/web.c
index 6dcef3f459f0e78b10e61bacb443f76d99822ff4..21cf4d183a3f5fba4d7054cf20b0fee8c831be14 100644
--- a/src/web.c
+++ b/src/web.c
@@ -369,6 +369,8 @@ static void handle_event(WebEvent *event) {
 				lua_pop(he_L, 1);
 			}
 			break;
+		case TE4_WEB_EVENT_DELETE_TEXTURE:
+			break;
 	}
 }