-- ToME - Tales of Maj'Eyal -- Copyright (C) 2009 - 2019 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 . -- -- Nicolas Casalini "DarkGod" -- darkgod@te4.org uberTalent{ name = "Fast As Lightning", mode = "passive", not_listed = true, trigger = function(self, t, ox, oy) local dx, dy = (self.x - ox), (self.y - oy) if dx ~= 0 then dx = dx / math.abs(dx) end if dy ~= 0 then dy = dy / math.abs(dy) end local dir = util.coordToDir(dx, dy, 0) local eff = self:hasEffect(self.EFF_FAST_AS_LIGHTNING) if eff and eff.blink then if eff.dir ~= dir then self:removeEffect(self.EFF_FAST_AS_LIGHTNING) else return end end self:setEffect(self.EFF_FAST_AS_LIGHTNING, 1, {}) eff = self:hasEffect(self.EFF_FAST_AS_LIGHTNING) if not eff.dir then eff.dir = dir eff.nb = 0 end if eff.dir ~= dir then self:removeEffect(self.EFF_FAST_AS_LIGHTNING) self:setEffect(self.EFF_FAST_AS_LIGHTNING, 1, {}) eff = self:hasEffect(self.EFF_FAST_AS_LIGHTNING) eff.dir = dir eff.nb = 0 game.logSeen(self, "#LIGHT_BLUE#%s slows from critical velocity!", self:getName():capitalize()) end eff.nb = eff.nb + 1 if eff.nb >= 3 and not eff.blink then self:effectTemporaryValue(eff, "prob_travel", 5) game.logSeen(self, "#LIGHT_BLUE#%s reaches critical velocity!", self:getName():capitalize()) local sx, sy = game.level.map:getTileToScreen(self.x, self.y, true) game.flyers:add(sx, sy, 30, rng.float(-3, -2), (rng.range(0,2)-1) * 0.5, "CRITICAL VELOCITY!", {0,128,255}) eff.particle = self:addParticles(Particles.new("megaspeed", 1, {angle=util.dirToAngle((dir == 4 and 6) or (dir == 6 and 4 or dir))})) eff.blink = true game:playSoundNear(self, "talents/thunderstorm") end end, info = function(self, t) return ([[When moving over 800%% speed for at least 3 steps in the same direction, you become so fast you can blink through obstacles as if they were not there. While moving this fast you have 50%% chances to fully ignore an attack by displacing yourself (this may only happen once per turn). Changing direction will break the effect.]]) :tformat() end, } uberTalent{ name = "Tricky Defenses", mode = "passive", require = { special={desc=_t"Antimagic", fct=function(self) return self:knowTalentType("wild-gift/antimagic") end} }, -- called by getMax function in Antimagic shield talent definition mod.data.talents.gifts.antimagic.lua shieldmult = function(self) return self:combatStatScale("cun", 0.1, 0.5) end, info = function(self, t) return ([[You are full of tricks and surprises; your Antimagic Shield can absorb %d%% more damage. The increase scales with your Cunning.]]) :tformat(t.shieldmult(self)*100) end, } uberTalent{ name = "Endless Woes", mode = "passive", require = { special={desc=_t"Have dealt over 10000 acid, blight, darkness, mind or temporal damage", fct=function(self) return self.damage_log and ( (self.damage_log[DamageType.ACID] and self.damage_log[DamageType.ACID] >= 10000) or (self.damage_log[DamageType.BLIGHT] and self.damage_log[DamageType.BLIGHT] >= 10000) or (self.damage_log[DamageType.DARKNESS] and self.damage_log[DamageType.DARKNESS] >= 10000) or (self.damage_log[DamageType.MIND] and self.damage_log[DamageType.MIND] >= 10000) or (self.damage_log[DamageType.TEMPORAL] and self.damage_log[DamageType.TEMPORAL] >= 10000) ) end} }, getBlight = function(self, t) return self:combatStatScale("cun", 1, 20, 0.75), self:combatStatScale("cun", 5, 30, 0.75) end, getDarkness = function(self, t) return self:combatStatScale("cun", 1, 30, 0.75) end, getAcid = function(self, t) return self:combatStatScale("cun", 10, 100, 0.75) end, getTemporal = function(self, t) return self:combatStatScale("cun", 1, 40, 0.75) end, getMind = function(self, t) return util.bound(self:combatStatScale("cun", 1, 40, 0.75), 0, 50) end, range = 10, radius = 3, dts = {TEMPORAL=true, BLIGHT=true, ACID=true, DARKNESS=true, MIND=true, PHYSICAL=true}, getThreshold = function(self, t) return 16*self.level end, getDamage = function(self, t) return self:combatStatScale("cun", 10, 350) end, doProject = function(self, t, damtype, effect, part) local tgts = {} -- Find everything nearby and pick one at random local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true) for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do local a = game.level.map(x, y, Map.ACTOR) if a and self:reactionToward(a) < 0 then tgts[#tgts+1] = a end end end local target = rng.table(tgts) if not target then return end local eff = effect local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, friendlyfire=false, talent=t} game.level.map:particleEmitter(target.x, target.y, tg.radius, part, {radius=tg.radius}) self:project(tg, target.x, target.y, function(tx, ty) local target = game.level.map(tx, ty, Map.ACTOR) if not target or target == self then return end if not effect.params then return end local eff = table.clone(effect, true) if not effect.canbe or (effect.canbe and target:canBe(effect.canbe)) then eff.params.apply_power = math.max(self:combatSpellpower(), self:combatMindpower()) target:setEffect(target[effect.id], 5, eff.params) end self:projectSource({}, target.x, target.y, damtype, t.getDamage(self, t), nil, t) end) end, callbackOnRest = function(self, t) self.endless_woes = {} end, -- No storing damage out of combat callbackOnRun = function(self, t) self.endless_woes = {} end, callbackOnDealDamage = function(self, t, value, target, dead, death_note) if not death_note then return end if not death_note.damtype then return end local damtype = death_note.damtype if not t.dts[damtype] then return end self.endless_woes = self.endless_woes or {} self.endless_woes[damtype] = (self.endless_woes[damtype] or 0) + value if self.endless_woes[damtype] > t.getThreshold(self, t) then self.endless_woes[damtype] = 0 if damtype == DamageType.TEMPORAL and not self:hasProc("endless_woes_temporal") then self:setProc("endless_woes_temporal", true, 10) game.logSeen(self, "You unleash a blast of #LIGHT_STEEL_BLUE#temporal#LAST# energy!", self:getName():capitalize()) t.doProject(self, t, damtype, {id="EFF_SLOW", dur=5, params={power=t.getTemporal(self, t)/100}, canbe="slow"}, "ball_temporal") elseif damtype == DamageType.BLIGHT and not self:hasProc("endless_woes_blight") then self:setProc("endless_woes_blight", true, 10) game.logSeen(self, "You unleash a blast of #DARK_GREEN#virulent blight!#LAST#!", self:getName():capitalize()) local dam, stat = t.getBlight(self, t) t.doProject(self, t, damtype, {id="EFF_WOEFUL_DISEASE", dur=5, params = {src=self, dam=dam, str=stat, con=stat, dex=stat}, canbe="disease"}, "ball_blight") elseif damtype == DamageType.ACID and not self:hasProc("endless_woes_acid") then self:setProc("endless_woes_acid", true, 10) local dam = t.getAcid(self, t) game.logSeen(self, "You unleash a blast of #GREEN#acid#LAST#!", self:getName():capitalize()) t.doProject(self, t, damtype, {id="EFF_WOEFUL_CORROSION", dur=5, params={src=self, dam=dam}}, "ball_acid") elseif damtype == DamageType.DARKNESS and not self:hasProc("endless_woes_darkness") then self:setProc("endless_woes_darkness", true, 10) game.logSeen(self, "You unleash a blast of numbing #GREY#darkness#LAST#!", self:getName():capitalize()) t.doProject(self, t, damtype, {id="EFF_WOEFUL_DARKNESS", dur=5, params={reduce=t.getDarkness(self, t)}}, "shadow_flash") elseif damtype == DamageType.MIND and not self:hasProc("endless_woes_mind") then self:setProc("endless_woes_mind", true, 10) game.logSeen(self, "You unleash a confusing blast of #YELLOW#mental#LAST# energy!", self:getName():capitalize()) t.doProject(self, t, damtype, {id="EFF_CONFUSED", dur=5, params={power=t.getMind(self, t)}, canbe="confusion"}, "starfall") elseif damtype == DamageType.PHYSICAL and not self:hasProc("endless_woes_physical") then self:setProc("endless_woes_physical", true, 10) game.logSeen(self, "You unleash a crippling blast of earthen energy!", self:getName():capitalize()) t.doProject(self, t, damtype, {id="EFF_WOEFUL_CRIPPLE", dur=5, params={power=0.2}}, "ball_earth") end end end, info = function(self, t) local blight_dam, blight_disease = t.getBlight(self, t) local cooldowns = {} local str = "" -- Display the remaining cooldowns in the talent tooltip only if its learned if self:knowTalent(self.T_ENDLESS_WOES) then for dt, _ in pairs(t.dts) do local proc = self:hasProc("endless_woes_"..dt:lower()) if proc then cooldowns[#cooldowns+1] = DamageType:get(DamageType[dt]).name:capitalize()..": "..proc.turns end end str = _t"(Cooldowns)".."\n"..table.concat(cooldowns, "\n") end return ([[Surround yourself with a malevolent aura that stores damage you deal. Whenever you have stored %d damage of one type you unleash a powerful blast at a random enemy dealing %d damage of that type in radius %d and applying one of the following effects: Physical: Slows combat, mind, and spell speed by 20%%. #GREEN#Acid:#LAST# Deals %d acid damage each turn for 5 turns (%d total). #DARK_GREEN#Blight:#LAST# Deals %d blight damage each turn for 5 turns and reduces strength, constitution, and dexterity by %d. #GREY#Darkness:#LAST# Reduces damage dealt by %d%% for 5 turns. #LIGHT_STEEL_BLUE#Temporal:#LAST# Slows global action speed by %d%% for 5 turns. #ORANGE#Mind:#LAST# Confuses (power %d%%) for 5 turns. Each effect can only happen once per 10 player turns. This does not count as a typical cooldown. The damage and effect power increase with your Cunning, the threshold with your level, and the apply power is the highest of your mind or spell power. %s]]) :tformat(t.getThreshold(self, t), t.getDamage(self, t), self:getTalentRadius(t), damDesc(self, DamageType.ACID, t.getAcid(self, t)), damDesc(self, DamageType.ACID, t.getAcid(self, t)*5), blight_dam, blight_disease, t.getDarkness(self, t), t.getTemporal(self, t), t.getMind(self, t), str) end, } -- Item rarities uberTalent{ name = "Secrets of Telos", mode = "passive", require = { special={desc=_t"Possess Telos Top Half, Telos Bottom Half, and Telos Staff Crystal", fct=function(self) local o1 = self:findInAllInventoriesBy("define_as", "GEM_TELOS") local o2 = self:findInAllInventoriesBy("define_as", "TELOS_TOP_HALF") local o3 = self:findInAllInventoriesBy("define_as", "TELOS_BOTTOM_HALF") return o1 and o2 and o3 end} }, cant_steal = true, no_npc_use = true, on_learn = function(self, t) if not game.party:hasMember(self) then return end local list = mod.class.Object:loadList("/data/general/objects/special-artifacts.lua") local o = game.zone:makeEntityByName(game.level, list, "TELOS_SPIRE", true) if o then o:identify(true) self:addObject(self.INVEN_INVEN, o) local o1, item1, inven1 = self:findInAllInventoriesBy("define_as", "GEM_TELOS") if item1 and inven1 then self:removeObject(inven1, item1, true) end local o2, item2, inven2 = self:findInAllInventoriesBy("define_as", "TELOS_TOP_HALF") if item2 and inven2 then self:removeObject(inven2, item2, true) end local o3, item3, inven3 = self:findInAllInventoriesBy("define_as", "TELOS_BOTTOM_HALF") if item3 and inven3 then self:removeObject(inven3, item3, true) end self:sortInven() game.logSeen(self, "#VIOLET#%s assembles %s!", self:getName():capitalize(), o:getName{do_colour=true, no_count=true}) end end, info = function(self, t) return ([[You have obtained the three parts of the Staff of Telos and studied them carefully. You believe that you can merge them back into a single highly potent staff.]]) :tformat() end, } uberTalent{ name = "Elemental Surge", mode = "passive", require = { special={desc=_t"Have dealt over 10000 arcane, fire, cold, lightning, light or nature damage", fct=function(self) return self.damage_log and ( (self.damage_log[DamageType.ARCANE] and self.damage_log[DamageType.ARCANE] >= 10000) or (self.damage_log[DamageType.FIRE] and self.damage_log[DamageType.FIRE] >= 10000) or (self.damage_log[DamageType.COLD] and self.damage_log[DamageType.COLD] >= 10000) or (self.damage_log[DamageType.LIGHTNING] and self.damage_log[DamageType.LIGHTNING] >= 10000) or (self.damage_log[DamageType.LIGHT] and self.damage_log[DamageType.LIGHT] >= 10000) or (self.damage_log[DamageType.NATURE] and self.damage_log[DamageType.NATURE] >= 10000) ) end} }, dts = {PHYSICAL=true, ARCANE=true, LIGHT=true, COLD=true, LIGHTNING=true, FIRE=true, NATURE=true,}, getCold = function(self, t) return { armor = self:combatStatScale("cun", 10, 30, 0.75), dam = math.max(100, self:getCun()), } end, getLight = function(self, t) return 20 end, getLightning = function(self, t) return self:combatStatScale("cun", 200, 500, 0.75) end, getFire = function(self, t) return 30 end, range = 10, radius = 3, getThreshold = function(self, t) return 16*self.level end, getDamage = function(self, t) return self:combatStatScale("cun", 10, 350) end, doProject = function(self, t, damtype, part) local tgts = {} -- Find everything nearby and pick one at random local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true) for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do local a = game.level.map(x, y, Map.ACTOR) if a and self:reactionToward(a) < 0 then tgts[#tgts+1] = a end end end local target = rng.table(tgts) if not target then return end local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, friendlyfire=false, talent=t} game.level.map:particleEmitter(target.x, target.y, tg.radius, part, {radius=tg.radius}) self:projectSource(tg, target.x, target.y, damtype, t.getDamage(self, t), nil, t) end, callbackOnRest = function(self, t) self.elemental_surge = nil end, -- No storing damage out of combat callbackOnRun = function(self, t) self.elemental_surge = nil end, callbackOnDealDamage = function(self, t, value, target, dead, death_note) local damtype = death_note and death_note.damtype if not damtype then return end if not t.dts[damtype] then return end self.elemental_surge = self.elemental_surge or {} self.elemental_surge[damtype] = (self.elemental_surge[damtype] or 0) + value if self.elemental_surge[damtype] > t.getThreshold(self, t) then self.elemental_surge[damtype] = 0 if damtype == DamageType.PHYSICAL and not self:hasProc("elemental_surge_physical") then self:setProc("elemental_surge_physical", true, 10) game.logSeen(self, "%s surges with earthen power!", self:getName():capitalize()) self:removeEffectsFilter(self, {status="detrimental", type="physical", ignore_crosstier=true}, 1) self:setEffect(self.EFF_ELEMENTAL_SURGE_PHYSICAL, 2, {}) t.doProject(self, t, damtype, "ball_earth") elseif damtype == DamageType.ARCANE and not self:hasProc("elemental_surge_arcane") then self:setProc("elemental_surge_arcane", true, 10) game.logSeen(self, "%s surges with #PURPLE#arcane#LAST# power!", self:getName():capitalize()) self:setEffect(self.EFF_ELEMENTAL_SURGE_ARCANE, 3, {}) t.doProject(self, t, damtype, "ball_arcane") elseif damtype == DamageType.FIRE and not self:hasProc("elemental_surge_fire") then self:setProc("elemental_surge_fire", true, 10) game.logSeen(self, "%s surges with #LIGHT_RED#fiery#LAST# power!", self:getName():capitalize()) self:setEffect(self.EFF_ELEMENTAL_SURGE_FIRE, 3, {damage = t.getFire(self, t)}) t.doProject(self, t, damtype, "ball_fire") elseif damtype == DamageType.COLD and not self:hasProc("elemental_surge_cold") then self:setProc("elemental_surge_cold", true, 10) game.logSeen(self, "%s surges with #1133F3#icy#LAST# power!", self:getName():capitalize()) self:setEffect(self.EFF_ELEMENTAL_SURGE_COLD, 3, t.getCold(self, t) ) t.doProject(self, t, damtype, "ball_ice") elseif damtype == DamageType.LIGHTNING and not self:hasProc("elemental_surge_lightning") then self:setProc("elemental_surge_lightning", true, 10) game.logSeen(self, "%s surges with #ROYAL_BLUE#lightning#LAST# power!", self:getName():capitalize()) self:setEffect(self.EFF_ELEMENTAL_SURGE_LIGHTNING, 2, {move = t.getLightning(self, t)}) t.doProject(self, t, damtype, "ball_lightning") elseif damtype == DamageType.LIGHT and not self:hasProc("elemental_surge_light") then self:setProc("elemental_surge_light", true, 10) game.logSeen(self, "%s surges with #YELLOW#light#LAST# power!", self:getName():capitalize()) self:setEffect(self.EFF_ELEMENTAL_SURGE_LIGHT, 3, {cooldown = t.getLight(self, t)}) t.doProject(self, t, damtype, "ball_light") elseif damtype == DamageType.NATURE and not self:hasProc("elemental_surge_nature") then self:setProc("elemental_surge_nature", true, 10) game.logSeen(self, "%s surges with #LIGHT_GREEN#natural#LAST# power!", self:getName():capitalize()) self:removeEffectsFilter(self, {status="detrimental", type="magical", ignore_crosstier=true}, 1) self:setEffect(self.EFF_ELEMENTAL_SURGE_NATURE, 2, {}) t.doProject(self, t, damtype, "slime") end end end, info = function(self, t) local cooldowns = {} local str = "" local cold = t.getCold(self, t) -- Display the remaining cooldowns in the talent tooltip only if its learned if self:knowTalent(self.T_ELEMENTAL_SURGE) then for dt, _ in pairs(t.dts) do local proc = self:hasProc("elemental_surge_"..dt:lower()) if proc then cooldowns[#cooldowns+1] = DamageType:get(DamageType[dt]).name:capitalize()..": "..proc.turns end end str = _t"(Cooldowns)".."\n"..table.concat(cooldowns, "\n") end return ([[Surround yourself with an elemental aura that stores damage you deal. Whenever you have stored %d damage of one type you unleash a powerful blast at a random enemy dealing %d damage of that type in radius %d and granting you one of the following effects: Physical: Cleanses 1 physical debuff and grant immunity to physical debuffs for 2 turns. #PURPLE#Arcane:#LAST# Increases your mind and spell action speeds by 30%% for 3 turns. #LIGHT_RED#Fire:#LAST# Increases all damage dealt by %d%% for 3 turns. #1133F3#Cold:#LAST# Turns your skin into ice for 3 turns increasing armor by %d and dealing %d ice damage to attackers. #ROYAL_BLUE#Lightning:#LAST# Increases your movement speed by %d%% for 2 turns. #YELLOW#Light:#LAST# Reduces all cooldowns by 20%% for 3 turns. #LIGHT_GREEN#Nature:#LAST# Cleanses 1 magical debuff and grant immunity to magical debuffs for 2 turns. Each effect can only happen once per 10 player turns. This does not count as a typical cooldown. The damage and some effect powers increase with your Cunning and the threshold with your level. %s]]) :tformat(t.getThreshold(self, t), t.getDamage(self, t), self:getTalentRadius(t), t.getFire(self, t), cold.armor, cold.dam, t.getLightning(self, t), str) end, } eye_of_the_tiger_data = { physical = { desc = _t"All physical criticals reduce the remaining cooldown of a random technique or cunning talent by 2.", types = { "^technique/", "^cunning/" }, reduce = 2, }, spell = { desc = _t"All spell criticals reduce the remaining cooldown of a random spell/corruption/celestial/chronomancy talent by 2.", types = { "^spell/", "^corruption/", "^celestial/", "^chronomancy/" }, reduce = 2, }, mind = { desc = _t"All mind criticals reduce the remaining cooldown of a random wild gift/psionic/afflicted talent by 2.", types = { "^wild%-gift/", "^cursed/", "^psionic/" }, reduce = 2, }, } uberTalent{ name = "Eye of the Tiger", mode = "passive", trigger = function(self, t, kind) local kind_str = "eye_tiger_"..kind if self:hasProc(kind_str) then return end local tids = {} for tid, _ in pairs(self.talents_cd) do local t = self:getTalentFromId(tid) if not t.fixed_cooldown then local ok = false local d = eye_of_the_tiger_data[kind] if d then for _, check in ipairs(d.types) do if t.type[1]:find(check) then ok = true break end end end if ok then tids[#tids+1] = tid end end end if #tids == 0 then return end local tid = rng.table(tids) local d = eye_of_the_tiger_data[kind] self.talents_cd[tid] = self.talents_cd[tid] - (d and d.reduce or 1) if self.talents_cd[tid] <= 0 then self.talents_cd[tid] = nil end self.changed = true self:setProc(kind_str) end, info = function(self, t) local list = {} for _, d in pairs(eye_of_the_tiger_data) do list[#list+1] = d.desc end return ([[%s This can only happen once per turn per type, and cannot affect the talent that triggers it.]]) :tformat(table.concat(list, "\n")) end, } uberTalent{ name = "Worldly Knowledge", mode = "passive", cant_steal = true, no_npc_use = true, on_learn = function(self, t, kind) if not game.party:hasMember(self) then return end local Chat = require "engine.Chat" local chat = Chat.new("worldly-knowledge", {name=_t"Worldly Knowledge"}, self) chat:invoke() end, passives = function(self, t, tmptable) self:talentTemporaryValue(tmptable, "unused_generics", 5) end, getRewards = function(self, t) local EscortRewards = require("mod.class.EscortRewards") local ERewardsList = EscortRewards:listRewards() local r_all, r_normal, r_antimagic = {}, {}, {} for _, rewards in pairs(ERewardsList) do if rewards.types then if rewards.antimagic and rewards.antimagic.types then r_normal = table.merge(r_normal, rewards.types) r_antimagic = table.merge(r_antimagic, rewards.antimagic.types) else r_all = table.merge(r_all, rewards.types) end end end return { all=r_all, normal=r_normal, antimagic=r_antimagic } end, getRewardTexts = function(self, t) local rewards = t.getRewards(self, t) local t_all, t_normal, t_antimagic = "", "", "" local tt_to_string = function(tt) local tt_def = self:getTalentTypeFrom(tt) local cat = tt_def.type:gsub("/.*", "") return _t(cat, "talent category"):capitalize() .. " / " .. tt_def.name:capitalize() end local all_list = table.keys(rewards.all) table.sort(all_list) for _, tt in ipairs(all_list) do t_all = t_all .. ("- %s\n"):tformat(tt_to_string(tt)) end local normal_list = table.keys(rewards.normal) table.sort(normal_list) for _, tt in ipairs(normal_list) do t_normal = t_normal .. ("- %s\n"):tformat(tt_to_string(tt)) end local antimagic_list = table.keys(rewards.antimagic) table.sort(antimagic_list) for _, tt in ipairs(antimagic_list) do t_antimagic = t_antimagic .. ("- %s\n"):tformat(tt_to_string(tt)) end return t_all, t_normal, t_antimagic end, info = function(self, t) local t_all, t_normal, t_antimagic = t.getRewardTexts(self, t) return ([[Gain 5 generic talent points and learn a new talent category from one of the below at 1.0 mastery, unlocked. Group 1 categories are available to anyone; Group 2 are not available to magic users, and Group 3 are not available to antimagic characters. GROUP 1: %s GROUP 2: %s GROUP 3: %s]]) :tformat(t_all, t_antimagic, t_normal) end, } -- Re-used icon uberTalent{ name = "Adept", mode = "passive", cant_steal = true, info = function(self, t) return ([[You are adept at many different skills, granting you +1.5 to all known talent levels. This works on already known talents and those that you will learn afterwards.]]):tformat() end, passives = function(self, t, p) self:talentTemporaryValue(p, "all_talents_bonus_level", 1.5) if not self._updating_adept then self._updating_adept = true self:updateAllTalentsPassives() self._updating_adept = nil end end, } uberTalent{ name = "Tricks of the Trade", mode = "passive", cant_steal = true, require = { special={desc=_t"Have sided with the Assassin Lord", fct=function(self) return game.state.birth.ignore_prodigies_special_reqs or (self:isQuestStatus("lost-merchant", engine.Quest.COMPLETED, "evil")) end} }, on_learn = function(self, t) if self:knowTalentType("cunning/stealth") then self:setTalentTypeMastery("cunning/stealth", self:getTalentTypeMastery("cunning/stealth", true) + 0.2) elseif self:knowTalentType("cunning/stealth") == false then self:learnTalentType("cunning/stealth", true) end if self:knowTalentType("cunning/scoundrel") then self:setTalentTypeMastery("cunning/scoundrel", self:getTalentTypeMastery("cunning/scoundrel", true) + 0.1) else self:learnTalentType("cunning/scoundrel", true) self:setTalentTypeMastery("cunning/scoundrel", 0.9) end self.invisible_damage_penalty_divisor = (self.invisible_damage_penalty_divisor or 0) + 2 end, info = function(self, t) return ([[You have friends in low places and have learned some underhanded tricks. Gain 0.2 Category Mastery to the Cunning/Stealth Category (or unlock it, if you have the tree and it is locked), and either gain +0.1 to the Cunning/Scoundrel category or learn and unlock the category at 0.9 if you lack it. Additionally, all of your damage penalties from invisibility are permanently halved.]]): tformat() end, }