From 758e5bab8507d25ea5b9681b77ca9bf98c3cca86 Mon Sep 17 00:00:00 2001 From: DarkGod <darkgod@net-core.org> Date: Tue, 24 Dec 2013 15:53:33 +0100 Subject: [PATCH] New Doomed tree: One with Shadows --- game/modules/tome/class/Actor.lua | 21 +++ game/modules/tome/class/Player.lua | 18 +++ .../tome/data/birth/classes/afflicted.lua | 1 + .../data/gfx/particles/darkness_power.lua | 51 ++++++ .../tome/data/gfx/talents/shadow_decoy.png | Bin 0 -> 3474 bytes .../tome/data/gfx/talents/shadow_empathy.png | Bin 0 -> 3625 bytes .../tome/data/gfx/talents/shadow_senses.png | Bin 0 -> 5217 bytes .../data/gfx/talents/shadow_transposition.png | Bin 0 -> 4095 bytes .../tome/data/talents/cursed/cursed.lua | 23 +++ .../data/talents/cursed/one-with-shadows.lua | 147 ++++++++++++++++++ .../tome/data/talents/cursed/shadows.lua | 1 + .../tome/data/talents/misc/inscriptions.lua | 2 +- .../tome/data/timed_effects/mental.lua | 34 ++++ 13 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 game/modules/tome/data/gfx/particles/darkness_power.lua create mode 100644 game/modules/tome/data/gfx/talents/shadow_decoy.png create mode 100644 game/modules/tome/data/gfx/talents/shadow_empathy.png create mode 100644 game/modules/tome/data/gfx/talents/shadow_senses.png create mode 100644 game/modules/tome/data/gfx/talents/shadow_transposition.png create mode 100644 game/modules/tome/data/talents/cursed/one-with-shadows.lua diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 0418c80932..b7545e080b 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -1791,6 +1791,19 @@ function _M:onTakeHit(value, src, death_note) end end + if value > 0 and self:attr("shadow_empathy") then + -- Absorb damage into a random shadow + local shadow = self:callTalent(self.T_SHADOW_EMPATHY, "getRandomShadow") + if shadow then + game:delayedLogMessage(self, src, "displacement_shield"..(shadow.uid or ""), "#CRIMSON##Source# shares some damage with a shadow!") + local displaced = math.min(value * self.shadow_empathy / 100, shadow.life) + shadow:takeHit(displaced, src) + game:delayedLogDamage(src, self, 0, ("#PINK#(%d linked)#LAST#"):format(displaced), false) + game:delayedLogDamage(src, shadow, displaced, ("#PINK#%d linked#LAST#"):format(displaced), false) + value = value - displaced + end + end + if value > 0 and self:attr("displacement_shield") then -- Absorb damage into the displacement shield if rng.percent(self.displacement_shield_chance) then @@ -2149,6 +2162,14 @@ function _M:onTakeHit(value, src, death_note) game.level.map:particleEmitter(self.x, self.y, 1, "teleport_in") end end + + -- Shadow decoy + if value >= self.life and self:isTalentActive(self.T_SHADOW_DECOY) then + local t = self:getTalentFromId(self.T_SHADOW_DECOY) + if t.onDie(self, t, value, src) then + value = 0 + end + end if value <= 0 then return 0 end -- Vim leech diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index aea2345d56..26fba12e91 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -508,6 +508,24 @@ function _M:playerFOV() end end + if self:knowTalent(self.T_SHADOW_SENSE) then + local t = self:getTalentFromId(self.T_SHADOW_SENSE) + local range = self:getTalentRange(t) + local sqsense = range * range + + for shadow, _ in pairs(game.party.members) do if shadow.is_doomed_shadow and not shadow.dead then + local arr = shadow.fov.actors_dist + local tbl = shadow.fov.actors + local act + for i = 1, #arr do + act = arr[i] + if act and not act.dead and act.x and tbl[act] and shadow:canSee(act) and tbl[act].sqdist <= sqsense then + game.level.map.seens(act.x, act.y, 0.6) + end + end + end end + end + if not self:attr("blind") then -- Handle dark vision; same as infravision, but also sees past creeping dark -- this is treated as a sense, but is filtered by custom LOS code diff --git a/game/modules/tome/data/birth/classes/afflicted.lua b/game/modules/tome/data/birth/classes/afflicted.lua index e03304129f..a3f10a6829 100644 --- a/game/modules/tome/data/birth/classes/afflicted.lua +++ b/game/modules/tome/data/birth/classes/afflicted.lua @@ -129,6 +129,7 @@ newBirthDescriptor{ ["cursed/cursed-form"]={true, 0.0}, ["cunning/survival"]={false, 0.0}, ["cursed/fears"]={false, 0.0}, + ["cursed/one-with-shadows"]={false, 0.3}, }, talents = { [ActorTalents.T_UNNATURAL_BODY] = 1, diff --git a/game/modules/tome/data/gfx/particles/darkness_power.lua b/game/modules/tome/data/gfx/particles/darkness_power.lua new file mode 100644 index 0000000000..a16c384e3c --- /dev/null +++ b/game/modules/tome/data/gfx/particles/darkness_power.lua @@ -0,0 +1,51 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +base_size = 32 + +return { generator = function() + local ad = rng.range(0, 360) + local a = math.rad(ad) + local dir = math.rad(90) + local r = rng.range(18, 22) + local dirchance = rng.chance(2) + local x = rng.range(-16, 16) + local y = 16 - math.abs(math.sin(x / 16) * 8) + local c = rng.float(0, 0.3) + + return { + trail = 1, + life = rng.range(10, 18), + size = rng.range(2, 3), sizev = 0, sizea = 0.005, + + x = x, xv = 0, xa = 0, + y = y, yv = 0, ya = -0.2, + dir = 0, dirv = 0, dira = 0, + vel = 0, velv = 0, vela = 0, + + r = c, rv = 0, ra = 0, + g = c, gv = 0, ga = 0, + b = c, bv = 0, ba = 0, + a = rng.float(0.5, 1), av = 0, aa = 0, + } +end, }, +function(self) + self.ps:emit(4) +end, +40 diff --git a/game/modules/tome/data/gfx/talents/shadow_decoy.png b/game/modules/tome/data/gfx/talents/shadow_decoy.png new file mode 100644 index 0000000000000000000000000000000000000000..8b0804e2e7c0d8a5b899d21305138d0c10cbb380 GIT binary patch literal 3474 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 AZ~y=R literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/gfx/talents/shadow_empathy.png b/game/modules/tome/data/gfx/talents/shadow_empathy.png new file mode 100644 index 0000000000000000000000000000000000000000..66c17e50e42599029b9dec08ce2f3e0658802bf9 GIT binary patch literal 3625 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 literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/gfx/talents/shadow_senses.png b/game/modules/tome/data/gfx/talents/shadow_senses.png new file mode 100644 index 0000000000000000000000000000000000000000..d98a59dd2b98a6e1e7e34ae0c06563de52f9af89 GIT binary patch literal 5217 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 b|M>b}kUaN+?ky3*00000NkvXXu0mjfebyKh literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/gfx/talents/shadow_transposition.png b/game/modules/tome/data/gfx/talents/shadow_transposition.png new file mode 100644 index 0000000000000000000000000000000000000000..abc54b45763aaf48f9786ee2b165421b5f07cc24 GIT binary patch literal 4095 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 literal 0 HcmV?d00001 diff --git a/game/modules/tome/data/talents/cursed/cursed.lua b/game/modules/tome/data/talents/cursed/cursed.lua index 5b430729b6..d71b4422c1 100644 --- a/game/modules/tome/data/talents/cursed/cursed.lua +++ b/game/modules/tome/data/talents/cursed/cursed.lua @@ -31,6 +31,7 @@ newTalentType{ allow_random=true, is_mind=true, type="cursed/force-of-will", nam newTalentType{ allow_random=true, is_mind=true, type="cursed/darkness", name = "darkness", description = "Harness the power of darkness to envelop your foes." } newTalentType{ allow_random=true, is_mind=true, type="cursed/shadows", name = "shadows", description = "Summon shadows from the darkness to aid you." } newTalentType{ allow_random=true, is_mind=true, type="cursed/punishments", name = "punishments", description = "Your hate becomes punishment in the minds of your foes." } +newTalentType{ allow_random=true, is_mind=true, type="cursed/one-with-shadows", name = "one with shadows", min_lev = 10, description = "Harness your shadows to their full potential." } -- Generic newTalentType{ allow_random=true, is_mind=true, type="cursed/gestures", name = "gestures", generic = true, description = "Enhance the power of you mind with gestures." } @@ -102,6 +103,27 @@ cursed_cun_req5 = { level = function(level) return 16 + (level-1) end, } +cursed_req_high1 = { + stat = { cun=function(level) return 22 + (level-1) * 2 end }, + level = function(level) return 10 + (level-1) end, +} +cursed_req_high2 = { + stat = { cun=function(level) return 30 + (level-1) * 2 end }, + level = function(level) return 14 + (level-1) end, +} +cursed_req_high3 = { + stat = { cun=function(level) return 38 + (level-1) * 2 end }, + level = function(level) return 18 + (level-1) end, +} +cursed_req_high4 = { + stat = { cun=function(level) return 46 + (level-1) * 2 end }, + level = function(level) return 22 + (level-1) end, +} +cursed_req_high5 = { + stat = { cun=function(level) return 54 + (level-1) * 2 end }, + level = function(level) return 26 + (level-1) end, +} + cursed_lev_req1 = { level = function(level) return 0 + (level-1) end, } @@ -146,6 +168,7 @@ load("/data/talents/cursed/shadows.lua") load("/data/talents/cursed/darkness.lua") load("/data/talents/cursed/punishments.lua") load("/data/talents/cursed/gestures.lua") +load("/data/talents/cursed/one-with-shadows.lua") load("/data/talents/cursed/cursed-form.lua") load("/data/talents/cursed/cursed-aura.lua") diff --git a/game/modules/tome/data/talents/cursed/one-with-shadows.lua b/game/modules/tome/data/talents/cursed/one-with-shadows.lua new file mode 100644 index 0000000000..e41576d5a4 --- /dev/null +++ b/game/modules/tome/data/talents/cursed/one-with-shadows.lua @@ -0,0 +1,147 @@ +-- ToME - Tales of Middle-Earth +-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +local Emote = require "engine.Emote" + +newTalent{ + name = "Shadow Senses", + type = {"cursed/one-with-shadows", 1}, + require = cursed_cun_req_high1, + mode = "passive", + points = 5, + no_npc_use = true, + range = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, 1)) end, + info = function(self, t) + return ([[Your awareness extends to your shadows. + You always know exactly where your shadows are and can perceive any foe within %d tiles of their vision.]]) + :format(self:getTalentRange(t)) + end, +} + +newTalent{ + name = "Shadow Empathy", + type = {"cursed/one-with-shadows", 2}, + require = cursed_cun_req_high2, + points = 5, + hate = 10, + cooldown = 25, + getRandomShadow = function(self, t) + local shadows = {} + if game.party and game.party:hasMember(self) then + for act, def in pairs(game.party.members) do + if act.summoner and act.summoner == self and act.is_doomed_shadow and not act.dead then + shadows[#shadows+1] = act + end + end + else + for uid, act in pairs(game.level.entities) do + if act.summoner and act.summoner == self and act.is_doomed_shadow and not act.dead then + shadows[#shadows+1] = act + end + end + end + return #shadows > 0 and rng.table(shadows) + end, + getDur = function(self, t) return math.floor(self:combatTalentScale(t, 3, 10)) end, + getPower = function(self, t) return 5 + self:combatTalentMindDamage(t, 0, 300) / 8 end, + action = function(self, t) + self:setEffect(self.EFF_SHADOW_EMPATHY, t.getDur(self, t), {power=t.getPower(self, t)}) + return true + end, + info = function(self, t) + local power = t.getPower(self, t) + local duration = t.getDur(self, t) + return ([[You are linked to your shadows for %d turns, diverting %d%% of all damage you take to a random shadow. + Effect increases with Mindpower.]]): + format(duration, power) + end, +} + +newTalent{ + name = "Shadow Transposition", + type = {"cursed/one-with-shadows", 3}, + require = cursed_cun_req_high3, + points = 5, + hate = 6, + no_npc_use = true, + radius = function(self, t) return math.floor(self:combatTalentScale(t, 1, 15, 1)) end, + getNb = function(self, t) return math.floor(self:combatTalentScale(t, 1, 3, 1)) end, + action = function(self, t) + local tg = {type="hit", range=self:getTalentRadius(t)} + local x, y, target = self:getTarget(tg) + if not x or not y or not target then return nil end + if core.fov.distance(self.x, self.y, target.x, target.y) > self:getTalentRadius(t) then return nil end + if target.summoner ~= self or not target.is_doomed_shadow then return end + + -- Displace + local tx, ty, sx, sy = target.x, target.y, self.x, self.y + target.x = nil target.y = nil + self.x = nil self.y = nil + target:move(sx, sy, true) + self:move(tx, ty, true) + + self:removeEffectsFilter(function(t) return (t.type == "physical" or t.type == "magical") and t.status == "detrimental" end, t.getNb(self, t)) + + return true + end, + info = function(self, t) + return ([[Observers find it difficult to tell you and your shadows apart. + You can target a shadow in radius %d and instantly trade places with it. + %d random negative physical or magical effects are transferred from you to the chosen shadow in the process.]]) + :format(self:getTalentRadius(t), t.getNb(self, t)) + end, +} + +newTalent{ + name = "Shadow Decoy", + type = {"cursed/one-with-shadows", 4}, + require = cursed_cun_req_high4, + mode = "sustained", + cooldown = 10, + points = 5, + cooldown = 50, + sustain_hate = 40, + getPower = function(self, t) return 10 + self:combatTalentMindDamage(t, 0, 300) end, + onDie = function(self, t, value, src) + local shadow = self:callTalent(self.T_SHADOW_EMPATHY, "getRandomShadow") + if not shadow then return false end + + game:delayedLogDamage(src, self, 0, ("#GOLD#(%d decoy)#LAST#"):format(value), false) + game:delayedLogDamage(src, shadow, value, ("#GOLD#%d decoy#LAST#"):format(value), false) + shadow:takeHit(value, src) + self:setEffect(self.EFF_SHADOW_DECOY, 4, {power=t.getPower(self, t)}) + self:forceUseTalent(t.id, {ignore_energy=true}) + + if self.player then self:setEmote(Emote.new("Fools, you never killed me; that was only my shadow!", 45)) end + return true + end, + activate = function(self, t) + return {} + end, + deactivate = function(self, t, p) + return true + end, + info = function(self, t) + return ([[Your shadows guard you with their lifes. + When you would receive a fatal blow, you instantly transpose with a random shadow that takes the blow instead, putting this talent on cooldown. + For the next 4 turns you only die if you reach -%d life. However, when below 0 you cannot see how much life you have left. + Effect increases with Mindpower.]]): + format(t.getPower(self, t)) + end, +} diff --git a/game/modules/tome/data/talents/cursed/shadows.lua b/game/modules/tome/data/talents/cursed/shadows.lua index af46b97418..18b3fcafd8 100644 --- a/game/modules/tome/data/talents/cursed/shadows.lua +++ b/game/modules/tome/data/talents/cursed/shadows.lua @@ -194,6 +194,7 @@ local function createShadow(self, level, tCallShadows, tShadowWarriors, tShadowM exp_worth=0, hate_regen = 1, avoid_traps = 1, + is_doomed_shadow = true, max_life = resolvers.rngavg(3,12), life_rating = 5, stats = { -- affected by stat limits diff --git a/game/modules/tome/data/talents/misc/inscriptions.lua b/game/modules/tome/data/talents/misc/inscriptions.lua index d61739e8e1..d92ade3f3f 100644 --- a/game/modules/tome/data/talents/misc/inscriptions.lua +++ b/game/modules/tome/data/talents/misc/inscriptions.lua @@ -258,7 +258,7 @@ newInscription{ info = function(self, t) local data = self:getInscriptionData(t.short_name) return ([[Activate the infusion to increase three of your primary stats by %d for %d turns. - Also while Heroism is active, you will only die when reaching -%d life. However, when below 0 you cannot see how much life you have left, and you will die if you did not heal before the effect ends. + Also while Heroism is active, you will only die when reaching -%d life. However, when below 0 you cannot see how much life you have left. It will always increase your three highest stats.]]):format(data.power + data.inc_stat, data.dur, data.die_at + data.inc_stat * 30) end, short_info = function(self, t) diff --git a/game/modules/tome/data/timed_effects/mental.lua b/game/modules/tome/data/timed_effects/mental.lua index 5c9ce2c490..fdbcdf8945 100644 --- a/game/modules/tome/data/timed_effects/mental.lua +++ b/game/modules/tome/data/timed_effects/mental.lua @@ -2952,3 +2952,37 @@ newEffect{ eff.power = 2 end, } + +newEffect{ + name = "SHADOW_EMPATHY", image = "talents/shadow_empathy.png", + desc = "Shadow Empathy", + long_desc = function(self, eff) return ("%d%% of all damage is redirected to a random shadow."):format(eff.power) end, + type = "mental", + subtype = { mind=true, shield=true }, + status = "beneficial", + parameters = { power=10 }, + activate = function(self, eff) + self:effectTemporaryValue(eff, "shadow_empathy", eff.power) + eff.particle = self:addParticles(Particles.new("darkness_power", 1)) + end, + deactivate = function(self, eff) + self:removeParticles(eff.particle) + end, +} + +newEffect{ + name = "SHADOW_DECOY", image = "talents/shadow_decoy.png", + desc = "Shadow Decoy", + long_desc = function(self, eff) return ("A random shadow absorbed a fatal blow for you, granting you a negative shield of %d."):format(eff.power) end, + type = "mental", + subtype = { mind=true, shield=true }, + status = "beneficial", + parameters = { power=10 }, + activate = function(self, eff) + self:effectTemporaryValue(eff, "die_at", -eff.power) + eff.particle = self:addParticles(Particles.new("darkness_power", 1)) + end, + deactivate = function(self, eff) + self:removeParticles(eff.particle) + end, +} -- GitLab