From cd0f2719c2a1261274809f119bd7c7ceb4a5a85e Mon Sep 17 00:00:00 2001
From: DarkGod <darkgod@net-core.org>
Date: Sun, 27 Apr 2014 20:12:12 +0200
Subject: [PATCH] New callbackOnHeal trigger

The Heart of the Sandworm Queen can now be corrupted to gain a new talent category: Vile Life
---
 game/modules/tome/class/Actor.lua             |   5 +
 .../data/general/objects/world-artifacts.lua  |   9 +-
 .../tome/data/gfx/talents/blood_splash.png    | Bin 0 -> 3874 bytes
 .../data/gfx/talents/elemental_discord.png    | Bin 0 -> 3660 bytes
 .../data/gfx/talents/healing_inversion.png    | Bin 0 -> 3458 bytes
 .../tome/data/gfx/talents/vile_transplant.png | Bin 0 -> 3615 bytes
 .../data/talents/corruptions/vile-life.lua    | 142 ++++++++++++------
 .../tome/data/timed_effects/magical.lua       |  33 +++-
 .../tome/data/timed_effects/physical.lua      |   2 +-
 .../tome/data/zones/mark-spellblaze/grids.lua |   4 +-
 .../tome/data/zones/sandworm-lair/objects.lua |   3 +-
 src/core_lua.c                                |   6 +-
 src/map.c                                     |   1 +
 src/music.c                                   |   2 +-
 src/web.c                                     |   2 +
 15 files changed, 146 insertions(+), 63 deletions(-)
 create mode 100644 game/modules/tome/data/gfx/talents/blood_splash.png
 create mode 100644 game/modules/tome/data/gfx/talents/elemental_discord.png
 create mode 100644 game/modules/tome/data/gfx/talents/healing_inversion.png
 create mode 100644 game/modules/tome/data/gfx/talents/vile_transplant.png

diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index f98564c716..c6dd50ca6c 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 aba4b3029d..23ef08edd7 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
GIT binary patch
literal 3874
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 3660
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 3458
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

literal 0
HcmV?d00001

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
GIT binary patch
literal 3615
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

literal 0
HcmV?d00001

diff --git a/game/modules/tome/data/talents/corruptions/vile-life.lua b/game/modules/tome/data/talents/corruptions/vile-life.lua
index c4ac2f25c5..7064b72107 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 4d7ac4e8d5..3131703aac 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 e0df7d189c..fcff508d5c 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 7268f5fc1f..29a577b817 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 05877ad722..687bd22c78 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 b5047a9e43..08fbbdc04a 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 5202556784..432c6e3db5 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 e8b137fc17..4f3a60d33c 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 6dcef3f459..21cf4d183a 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;
 	}
 }
 
-- 
GitLab