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; } }