diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 561de56aec07fa8d40e4da427bec71b771c60e7d..cf9bda41c7d06f2a6c798954099986126a098a13 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -1003,19 +1003,13 @@ function _M:onTakeHit(value, src) end end end - -- Randomly take targets - -- local tg = {type="hit"} - for i = 1, 1 do - if #tgts <= 0 then break end - local a, id = rng.table(tgts) - table.remove(tgts, id) - - if a then - game.logSeen(self, "Some of the damage has been displaced onto %s!", a.name:capitalize()) - a:takeHit(value / 2, src) - value = value / 2 - end + local a = rng.table(tgts) + if a then + game.logSeen(self, "Some of the damage has been displaced onto %s!", a.name:capitalize()) + a:takeHit(value / 2, self) + value = value / 2 end + end if self:attr("disruption_shield") then diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua index 1b8cc3206df1a97524e6b7e05ff28486f56abde8..9e5ba58cfb6cca70583eea69df916d5431b32b11 100644 --- a/game/modules/tome/class/Object.lua +++ b/game/modules/tome/class/Object.lua @@ -743,6 +743,10 @@ function _M:getTextualDesc(compare_with) compare_fields(w, compare_with, field, "size_category", "%+d", "Size category: ") + if w.undead then + desc:add("The wearer is treated as an undead.", true) + end + if w.speaks_shertul then desc:add("Allows you to speak and read the old Sher'Tul language.", true) end diff --git a/game/modules/tome/data/birth/descriptors.lua b/game/modules/tome/data/birth/descriptors.lua index 635f776567e9ff150c122b457d5cf1f01012121b..b18760d2460ca2788ed658945f33d46fd8655626 100644 --- a/game/modules/tome/data/birth/descriptors.lua +++ b/game/modules/tome/data/birth/descriptors.lua @@ -211,7 +211,7 @@ newBirthDescriptor{ newBirthDescriptor{ type = "permadeath", name = "Adventure", - selection_default = config.settings.tome.default_birth and config.settings.tome.default_birth.permadeath == "Adventure", + selection_default = (not config.settings.tome.default_birth) or (config.settings.tome.default_birth and config.settings.tome.default_birth.permadeath == "Adventure"), desc = { "#GOLD##{bold}#Adventure mode#WHITE#", diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua index d68a13abf4a9f493e64396e41405969b3d3ae1e7..d4b6c107530757e5dc6a8461e8105348e2142b08 100644 --- a/game/modules/tome/data/damage_types.lua +++ b/game/modules/tome/data/damage_types.lua @@ -1680,3 +1680,31 @@ newDamageType{ end end, } + +newDamageType{ + name = "abyssal shroud", type = "ABYSSAL_SHROUD", + projector = function(src, x, y, type, dam) + --make it dark + game.level.map.remembers(x, y, false) + game.level.map.lites(x, y, false) + + local target = game.level.map(x, y, Map.ACTOR) + local reapplied = false + if target then + -- silence the apply message it if the target already has the effect + for eff_id, p in pairs(target.tmp) do + local e = target.tempeffect_def[eff_id] + if e.desc == "Abyssal Shroud" then + reapplied = true + end + end + if target:checkHit(src:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) then + target:setEffect(target.EFF_ABYSSAL_SHROUD, 2, {power=dam.power, lite=dam.lite}, reapplied) + else + game.logSeen(target, "%s resists the shroud!", target.name:capitalize()) + end + + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam) + end + end, +} diff --git a/game/modules/tome/data/general/npcs/horror.lua b/game/modules/tome/data/general/npcs/horror.lua index c91db1534b150e62712436b099da00c1a04fd3cc..a4a55676a6f773f59edef3aae5fd7c179d27fb9b 100644 --- a/game/modules/tome/data/general/npcs/horror.lua +++ b/game/modules/tome/data/general/npcs/horror.lua @@ -144,6 +144,7 @@ newEntity{ base = "BASE_NPC_HORROR", name = "nightmare horror", color=colors.DARK_GREY, desc ="A shifting form of darkest night that seems to reflect your deepest fears.", level_range = {30, nil}, exp_worth = 1, + mana_regen = 10, negative_regen = 10, hate_regen = 1, rarity = 5, @@ -153,9 +154,11 @@ newEntity{ base = "BASE_NPC_HORROR", autolevel = "caster", stats = { str=15, dex=20, mag=20, wil=20, con=15 }, combat_armor = 1, combat_def = 30, - combat = { dam=resolvers.levelup(20, 1, 1.1), atk=20, apr=50, dammod={mag=1}, damtype=DamageType.DARKNESS}, + combat = { dam=resolvers.levelup(20, 1, 1.1), atk=20, apr=50, dammod={mag=1}, damtype=DamageType.DARKSTUN}, - ai = "dumb_talented_simple", ai_state = { ai_target="target_player_radius", sense_radius=10, talent_in=2, }, + ai = "tactical", + ai_tactic = resolvers.tactic"ranged", + ai_state = { ai_target="target_player_radius", sense_radius=10, talent_in=1, }, dont_pass_target = true, can_pass = {pass_wall=20}, @@ -172,8 +175,10 @@ newEntity{ base = "BASE_NPC_HORROR", [Talents.T_TORMENT]={base=3, every=12, max=8}, [Talents.T_DOMINATE]={base=3, every=12, max=8}, [Talents.T_LIFE_LEECH]={base=5, every=12, max=9}, - [Talents.T_SHADOW_BLAST]={base=4, every=8, max=8}, - [Talents.T_HYMN_OF_SHADOWS]={base=3, every=9, max=8}, + [Talents.T_INVOKE_DARKNESS]={base=5, every=8, max=10}, + [Talents.T_WAKING_NIGHTMARE]={base=3, every=8, max=10}, + [Talents.T_ABYSSAL_SHROUD]={base=3, every=8, max=8}, + [Talents.T_INNER_DEMONS]={base=3, every=8, max=10}, }, resolvers.inscriptions(1, {"shielding rune"}), @@ -614,10 +619,12 @@ newEntity{ base = "BASE_NPC_HORROR", rarity = 4, rank = 2, size_category = 2, - max_life = resolvers.rngavg(20,50), - autolevel = "warriormage", - ai = "dumb_talented_simple", ai_state = { ai_move="move_dmap", talent_in=2, }, + max_life = resolvers.rngavg(80, 120), + life_rating = 10, + autolevel = "summoner", + ai = "dumb_talented_simple", ai_state = { talent_in=1, ai_move="move_snake" }, combat_armor = 1, combat_def = 10, + combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={wil=0.8}, damtype=DamageType.TEMPORAL }, on_melee_hit = { [DamageType.TEMPORAL] = resolvers.mbonus(20, 10), }, stun_immune = 1, @@ -627,8 +634,11 @@ newEntity{ base = "BASE_NPC_HORROR", resists = {[DamageType.TEMPORAL] = 50}, resolvers.talents{ - [Talents.T_DISPERSE_MAGIC]={base=3, every=7, max=5}, + [Talents.T_ENERGY_ABSORPTION]={base=3, every=7, max=5}, + [Talents.T_ENERGY_DECOMPOSITION]={base=3, every=7, max=5}, [Talents.T_ENTROPIC_FIELD]={base=3, every=7, max=5}, + [Talents.T_ECHOES_FROM_THE_VOID]={base=3, every=7, max=5}, + [Talents.T_VOID_SHARDS]={base=2, every=7, max=5}, }, -- Random Anomaly on Death on_die = function(self, who) @@ -637,7 +647,7 @@ newEntity{ base = "BASE_NPC_HORROR", if t.type[1] == "chronomancy/anomalies" then ts[#ts+1] = id end end self:forceUseTalent(rng.table(ts), {ignore_energy=true}) - game.logSeen(self, "%s has collapsed in upon itself.", self.name) + game.logSeen(self, "%s has collapsed in upon itself.", self.name:capitalize()) end, resolvers.sustains_at_birth(), diff --git a/game/modules/tome/data/general/objects/boss-artifacts.lua b/game/modules/tome/data/general/objects/boss-artifacts.lua index e0e47b34140a6fba307cfa792b1ab8572a796b0d..3c8320c525538a9d2b8ef653a8dd4ec79656577e 100644 --- a/game/modules/tome/data/general/objects/boss-artifacts.lua +++ b/game/modules/tome/data/general/objects/boss-artifacts.lua @@ -397,7 +397,7 @@ newEntity{ base = "BASE_CLOTH_ARMOR", power_source = {arcane=true}, define_as = "BLACK_ROBE", rarity=false, name = "Black Robe", unique=true, - unided_name = "black robe", color=colors.DARK_GREY, + unided_name = "black robe", color=colors.DARK_GREY, image = "object/artifact/robe_black_robe.png", desc = [[A silk robe, darker than the darkest night sky, it radiates power.]], level_range = {40, 50}, rarity = 280, diff --git a/game/modules/tome/data/general/objects/world-artifacts.lua b/game/modules/tome/data/general/objects/world-artifacts.lua index bead5994891e29f58c7ad06c7409ca83b6048058..8f29bf6b4e8094793df5a6c27d9cee8a25e01b6b 100644 --- a/game/modules/tome/data/general/objects/world-artifacts.lua +++ b/game/modules/tome/data/general/objects/world-artifacts.lua @@ -150,7 +150,7 @@ newEntity{ base = "BASE_STAFF", newEntity{ base = "BASE_STAFF", power_source = {arcane=true}, unique = true, - name = "Bolbum's Big Knocker", + name = "Bolbum's Big Knocker", image = "object/artifact/staff_bolbums_big_knocker.png", unided_name = "thick staff", level_range = {20, 35}, color=colors.UMBER, @@ -1040,7 +1040,7 @@ newEntity{ base = "BASE_GREATMAUL", newEntity{ base = "BASE_MACE", power_source = {technique=true}, unique = true, - name = "Crooked Club", color = colors.GREEN, + name = "Crooked Club", color = colors.GREEN, image = "object/artifact/weapon_crooked_club.png", unided_name = "weird club", desc = [[An oddly twisted club with a hefty weight on the end.]], level_range = {3, 12}, diff --git a/game/modules/tome/data/gfx/shockbolt/object/artifact/bindings_of_eternal_night.png b/game/modules/tome/data/gfx/shockbolt/object/artifact/bindings_of_eternal_night.png new file mode 100644 index 0000000000000000000000000000000000000000..1b28e7daa36fdc7f709f9884265631216e0bde21 Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/object/artifact/bindings_of_eternal_night.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/object/artifact/celias_heart.png b/game/modules/tome/data/gfx/shockbolt/object/artifact/celias_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..494258c50ade3ed1f0735c3a12a716adebde6fce Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/object/artifact/celias_heart.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/object/artifact/robe_black_robe.png b/game/modules/tome/data/gfx/shockbolt/object/artifact/robe_black_robe.png new file mode 100644 index 0000000000000000000000000000000000000000..81c8354db870176c08664be108c606c8da79fa4a Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/object/artifact/robe_black_robe.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/object/artifact/staff_bolbums_big_knocker.png b/game/modules/tome/data/gfx/shockbolt/object/artifact/staff_bolbums_big_knocker.png new file mode 100644 index 0000000000000000000000000000000000000000..b4fd9fb590e79a2534d945bdbbf34f260ada634e Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/object/artifact/staff_bolbums_big_knocker.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/object/artifact/weapon_crooked_club.png b/game/modules/tome/data/gfx/shockbolt/object/artifact/weapon_crooked_club.png new file mode 100644 index 0000000000000000000000000000000000000000..12de49c60fc6b4ef0b4f855c3aed50041671123a Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/object/artifact/weapon_crooked_club.png differ diff --git a/game/modules/tome/data/talents/misc/horrors.lua b/game/modules/tome/data/talents/misc/horrors.lua new file mode 100644 index 0000000000000000000000000000000000000000..7006a395ffd9785810c254db3caebb92f15a729f --- /dev/null +++ b/game/modules/tome/data/talents/misc/horrors.lua @@ -0,0 +1,332 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010, 2011 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 + +newTalentType{ type="technique/horror", name = "horror techniques", hide = true, description = "Physical talents of the various horrors of the world." } +newTalentType{ no_silence=true, is_spell=true, type="spell/horror", name = "horror spells", hide = true, description = "Spell talents of the various horrors of the world." } +newTalentType{ type="other/horror", name = "horror powers", hide = true, description = "Unclassified talents of the various horrors of the world." } + +local oldTalent = newTalent +local newTalent = function(t) if type(t.hide) == "nil" then t.hide = true end return oldTalent(t) end + + +-- Nightmare Horror Powers +newTalent{ + name = "Inner Demons", + type = {"spell/horror", 1}, + points = 5, + cooldown = 10, + mana = 16, + range = 10, + direct_hit = true, + requires_target = true, + tactical = { ATTACK = 3 }, + getChance = function(self, t) return self:combatTalentSpellDamage(t, 5, 50) end, + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 5, 50) end, + getDuration = function(self, t) return 8 + math.ceil(self:getTalentLevel(t) * 4) end, + summon_inner_demons = function(self, target, t) + -- Find space + local x, y = util.findFreeGrid(target.x, target.y, 1, true, {[Map.ACTOR]=true}) + if not x then + return + end + + local m = target:clone{ + shader = "shadow_simulacrum", + no_drops = true, + faction = self.faction, + summoner = self, summoner_gain_exp=true, + summon_time = 10, + ai_target = {actor=target}, + ai = "summoned", ai_real = "tactical", + name = ""..target.name.."'s Inner Demon", + desc = [[A hideous, demonic entity that resembles the creature it came from.]], + } + m:removeAllMOs() + m.make_escort = nil + m.on_added_to_level = nil + + mod.class.NPC.castAs(m) + engine.interface.ActorAI.init(m, m) + + m.energy.value = 0 + m.player = nil + m.max_life = m.max_life / 2 + m.life = util.bound(m.life, 0, m.max_life) + m.inc_damage.all = (m.inc_damage.all or 0) - 50 + m.forceLevelup = function() end + m.on_die = nil + m.on_acquire_target = nil + m.seen_by = nil + m.can_talk = nil + m.clone_on_hit = nil + + -- Remove some talents + local tids = {} + for tid, _ in pairs(m.talents) do + local t = m:getTalentFromId(tid) + if t.no_npc_use then tids[#tids+1] = t end + end + for i, t in ipairs(tids) do + if t.mode == "sustained" and m:isTalentActive(t.id) then m:forceUseTalent(t.id, {ignore_energy=true}) end + m.talents[t.id] = nil + end + + -- nil the Inner Demons effect to squelch combat log spam + m.tmp[m.EFF_INNER_DEMONS] = nil + + -- remove detrimental timed effects + local effs = {} + for eff_id, p in pairs(m.tmp) do + local e = m.tempeffect_def[eff_id] + if e.status == "detrimental" then + effs[#effs+1] = {"effect", eff_id} + end + end + + while #effs > 0 do + local eff = rng.tableRemove(effs) + if eff[1] == "effect" then + m:removeEffect(eff[2]) + end + end + + + game.zone:addEntity(game.level, m, "actor", x, y) + game.level.map:particleEmitter(x, y, 1, "shadow") + + game.logSeen(target, "%s's Inner Demon manifests!", target.name:capitalize()) + + end, + action = function(self, t) + local tg = {type="hit", range=self:getTalentRange(t), talent=t} + local x, y = self:getTarget(tg) + if not x or not y then return nil end + local _ _, x, y = self:canProject(tg, x, y) + if not x or not y then return nil end + local target = game.level.map(x, y, Map.ACTOR) + if not target then return nil end + + if target:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) and target:canBe("fear") then + target:setEffect(target.EFF_INNER_DEMONS, t.getDuration(self, t), {src = self, chance=t.getChance(self, t), dam=t.getDamage(self, t)}) + else + game.logSeen(target, "%s resists the demons!", target.name:capitalize()) + end + + return true + end, + info = function(self, t) + return ([[Brings the targets inner demons to the surface. Each turn there's a chance that one will be summoned. If the summoning is resisted the effect will end early.]]) + end, +} + +newTalent{ + name = "Waking Nightmare", + type = {"spell/horror", 1}, + points = 5, + cooldown = 10, + mana = 16, + range = 10, + direct_hit = true, + requires_target = true, + tactical = { ATTACK = 2, DISABLE = 3 }, + getChance = function(self, t) return 10 + self:combatTalentSpellDamage(t, 5, 50) end, + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 5, 50) end, + getDuration = function(self, t) return 4 + math.ceil(self:getTalentLevel(t)) end, + action = function(self, t) + local tg = {type="hit", range=self:getTalentRange(t), talent=t} + local x, y = self:getTarget(tg) + if not x or not y then return nil end + local _ _, x, y = self:canProject(tg, x, y) + if not x or not y then return nil end + local target = game.level.map(x, y, Map.ACTOR) + if not target then return nil end + + if target:checkHit(self:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) and target:canBe("fear") then + target:setEffect(target.EFF_WAKING_NIGHTMARE, t.getDuration(self, t), {src = self, chance=t.getChance(self, t), dam=t.getDamage(self, t)}) + else + game.logSeen(target, "%s resists the nightmare!", target.name:capitalize()) + end + + return true + end, + info = function(self, t) + return ([[Darkness damage and a chance to randomly blind, stun, or confuse each turn.]]) + end, +} + +newTalent{ + name = "Abyssal Shroud", + type = {"spell/horror", 1}, + points = 5, + cooldown = 10, + mana = 30, + cooldown = 12, + tactical = { ATTACKAREA = 2, DISABLE = 3 }, + range = 6, + radius = 3, + direct_hit = true, + requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false} + end, + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 15, 40) end, + getDarknessPower = function(self, t) return self:combatTalentSpellDamage(t, 15, 40) end, + getLiteReduction = function(self, t) return self:getTalentLevelRaw(t) end, + getDuration = function(self, t) return 4 + math.ceil(self:getTalentLevel(t)) 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 + local _ _, _, _, x, y = self:canProject(tg, x, y) + -- Add a lasting map effect + game.level.map:addEffect(self, + x, y, t.getDuration(self, t), + DamageType.ABYSSAL_SHROUD, {dam=t.getDamage(self, t), power=t.getDarknessPower(self, t), lite=t.getLiteReduction(self, t)}, + self:getTalentRadius(t), + 5, nil, + {type="circle_of_death"}, + nil, false + ) + + game:playSoundNear(self, "talents/fire") + return true + end, + info = function(self, t) + return ([[An area of effect that causes darkness damage and reduces the lite radius and darkness resistance of those within.]]) + end, +} + +-- Void Horror Powers +newTalent{ + name = "Echoes From The Void", + type = {"other/horror", 1}, + points = 5, + message = "@Source@ shows @Target@ the madness of the void.", + cooldown = 10, + range = 10, + requires_target = true, + tactical = { ATTACK = 4 }, + direct_hit = true, + requires_target = true, + getDamage = function(self, t) return self:combatTalentMindDamage(t, 10, 100) end, + action = function(self, t) + local tg = {type="hit", range=self:getTalentRange(t), talent=t} + local x, y = self:getTarget(tg) + if not x or not y then return nil end + local _ _, x, y = self:canProject(tg, x, y) + if not x or not y then return nil end + local target = game.level.map(x, y, Map.ACTOR) + if not target then return nil end + + if target:checkHit(src:combatMindpower(), target:combatMentalResist(), 0, 95, 15) and target:canBe("fear") then + target:setEffect(target.EFF_VOID_ECHOES, 6, {src= self, power=t.getDamage(self, t)}) + else + game.logSeen(target, "%s resists the void!", target.name:capitalize()) + end + + game:playSoundNear(self, "talents/arcane") + return true + end, + info = function(self, t) + return ([[Causes the void echoes status effect which does mind and resource damage every turn the target fails a mental save.]]) + end, +} + +newTalent{ + name = "Void Shards", + type = {"other/horror", 1}, + points = 5, + message = "@Source@ summons void shards.", + cooldown = 20, + range = 10, + requires_target = true, + tactical = { ATTACK = 4 }, + requires_target = true, + is_summon = true, + getDamage = function(self, t) return self:combatTalentMindDamage(t, 5, 50) end, + getExplosion = function(self, t) return self:combatTalentMindDamage(t, 20, 300) end, + getSummonTime = function(self, t) return 6 + math.ceil(self:getTalentLevel(t)) end, + action = function(self, t) + local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} + local tx, ty, target = self:getTarget(tg) + if not tx or not ty then return nil end + local _ _, tx, ty = self:canProject(tg, tx, ty) + target = game.level.map(tx, ty, Map.ACTOR) + if target == self then target = nil end + + if self:getTalentLevel(t) < 5 then self:setEffect(self.EFF_SUMMON_DESTABILIZATION, 500, {power=5}) end + + for i = 1, self:getTalentLevelRaw(t) do + -- Find space + local x, y = util.findFreeGrid(tx, ty, 5, true, {[Map.ACTOR]=true}) + if not x then + game.logPlayer(self, "Not enough space to summon!") + break + end + + local NPC = require "mod.class.NPC" + local m = NPC.new{ + type = "horror", subtype = "temporal", + display = "h", color=colors.GREY, image = "npc/horror_temporal_void_horror.png", + name = "void shard", faction = self.faction, + desc = [[It looks like a small hole in the fabric of spacetime.]], + stats = { str=22, dex=20, wil=15, con=15 }, + + --level_range = {self.level, self.level}, + exp_worth = 0, + max_life = resolvers.rngavg(5,10), + life_rating = 2, + rank = 2, + size_category = 1, + + autolevel = "summoner", + ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=2, ai_move="move_snake" }, + combat_armor = 1, combat_def = 1, + combat = { dam=resolvers.levelup(resolvers.mbonus(40, 15), 1, 1.2), atk=15, apr=15, dammod={wil=0.8}, damtype=DamageType.TEMPORAL }, + on_melee_hit = { [DamageType.TEMPORAL] = resolvers.mbonus(20, 10), }, + + infravision = 10, + no_breath = 1, + fear_immune = 1, + stun_immune = 1, + confusion_immune = 1, + silence_immune = 1, + + ai_target = {actor=target} + } + + m.faction = self.faction + m.summoner = self + m.summoner_gain_exp=true + m.summon_time = t.getSummonTime(self, t) + + m:resolve() m:resolve(nil, true) + m:forceLevelup(self.level) + game.zone:addEntity(game.level, m, "actor", x, y) + game.level.map:particleEmitter(x, y, 1, "summon") + m:setEffect(m.EFF_TEMPORAL_DESTABILIZATION, 5, {src=self, dam=t.getDamage(self, t), explosion=self:spellCrit(t.getExplosion(self, t))}) + + end + game:playSoundNear(self, "talents/spell_generic") + return true + end, + info = function(self, t) + return ([[Summons shards of explosive doom!]]) + end, +} \ No newline at end of file diff --git a/game/modules/tome/data/talents/misc/misc.lua b/game/modules/tome/data/talents/misc/misc.lua index d5aa4f460db8823d081daea29c825da8c57929fd..e287231b004cf67bff5459eee5ceff508066962f 100644 --- a/game/modules/tome/data/talents/misc/misc.lua +++ b/game/modules/tome/data/talents/misc/misc.lua @@ -27,6 +27,7 @@ newTalentType{ is_spell=true, no_silence=true, type="inscriptions/taints", name -- Load other misc things load("/data/talents/misc/inscriptions.lua") load("/data/talents/misc/npcs.lua") +load("/data/talents/misc/horrors.lua") load("/data/talents/misc/races.lua") -- Default melee attack diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua index cb7b3a9e259a2e83c6ef5f87124929ad9a0896bb..05339dd7a629415f47eafe387e524a28a5d8c3dc 100644 --- a/game/modules/tome/data/timed_effects.lua +++ b/game/modules/tome/data/timed_effects.lua @@ -2638,13 +2638,10 @@ newEffect{ on_gain = function(self, err) return "The fabric of time alters around #target#.", "+Damage Smearing" end, on_lose = function(self, err) return "The fabric of time around #target# stabilizes.", "-Damage Smearing" end, activate = function(self, eff) - -- eff.tmpid = self:addTemporaryValue("damage_smearing", eff.power) - --- Warning there can be only one time shield active at once for an actor eff.particle = self:addParticles(Particles.new("time_shield", 1)) end, deactivate = function(self, eff) self:removeParticles(eff.particle) - -- self:removeTemporaryValue("damage_smearing", eff.tmpid) end, } @@ -4441,3 +4438,97 @@ newEffect{ deactivate = function(self, eff) end, } + +newEffect{ + name = "VOID_ECHOES", + desc = "Void Echoes", + long_desc = function(self, eff) return ("The target is seeing echoes from the void and will take %0.2f mind damage as well as some resource damage each turn it fails a mental save."):format(eff.power) end, + type = "mental", + status = "detrimental", + parameters = { power=10 }, + on_gain = function(self, err) return "#Target# is being driven mad by the void.", "+Void Echoes" end, + on_lose = function(self, err) return "#Target# has survived the void madness.", "-Void Echoes" end, + on_timeout = function(self, eff) + local drain = DamageType:get(DamageType.MIND).projector(eff.src or self, self.x, self.y, DamageType.MIND, eff.power) / 2 + self:incMana(-drain) + self:incVim(-drain * 0.5) + self:incPositive(-drain * 0.25) + self:incNegative(-drain * 0.25) + self:incStamina(-drain * 0.65) + self:incHate(-drain * 0.05) + self:incPsi(-drain * 0.2) + end, +} + +newEffect{ + name = "WAKING_NIGHTMARE", + desc = "Waking Nightmare", + long_desc = function(self, eff) return ("The target is lost in a waking nightmare that deals %0.2f darkness damage each turn and has a %d%% chance to cause a random effect detrimental."):format(eff.dam, eff.chance) end, + type = "magical", + status = "detrimental", + parameters = { chance=10, dam = 10 }, + on_gain = function(self, err) return "#Target# is lost in a waking nightmare.", "+Waking Nightmare" end, + on_lose = function(self, err) return "#Target# is free from the nightmare.", "-Waking Nightmare" end, + on_timeout = function(self, eff) + DamageType:get(DamageType.DARKNESS).projector(eff.src or self, self.x, self.y, DamageType.DARKNESS, eff.dam) + if rng.percent(eff.chance) then + -- Pull random effect + local chance = rng.range(1, 3) + if chance == 1 then + if self:canBe("blind") then + self:setEffect(self.EFF_BLINDED, 3, {}) + end + elseif chance == 2 then + if self:canBe("stun") then + self:setEffect(self.EFF_STUNNED, 3, {}) + end + elseif chance == 3 then + if self:canBe("confusion") then + self:setEffect(self.EFF_CONFUSED, 3, {power=50}) + end + end + game.logSeen(self, "%s succumbs to the nightmare!", self.name:capitalize()) + end + end, +} + +newEffect{ + name = "ABYSSAL_SHROUD", + desc = "Abyssal Shroud", + long_desc = function(self, eff) return ("The target's lite radius has been reduced by %d and it's darkness resistance by %d%%."):format(eff.lite, eff.power) end, + type = "magical", + status = "detrimental", + parameters = {power=20}, + on_gain = function(self, err) return "#Target# feels closer to the abyss!", "+Abyssal Shroud" end, + on_lose = function(self, err) return "#Target# is free from the abyss.", "-Abyssal Shroud" end, + activate = function(self, eff) + eff.liteid = self:addTemporaryValue("lite", -eff.lite) + eff.darkid = self:addTemporaryValue("resists", { [DamageType.DARKNESS]= - eff.power }) + end, + deactivate = function(self, eff) + self:removeTemporaryValue("lite", eff.liteid) + self:removeTemporaryValue("resists", eff.darkid) + end, +} + +newEffect{ + name = "INNER_DEMONS", + desc = "Inner Demons", + long_desc = function(self, eff) return ("The target is plagued by inner demons and each turn there's a %d%% chance that one will appear. If the caster is killed or the target resists setting his demons loose the effect will end early."):format(eff.chance) end, + type = "magical", + status = "detrimental", + parameters = {}, + on_gain = function(self, err) return "#Target# is plagued by inner demons!", "+Inner Demons" end, + on_lose = function(self, err) return "#Target# is freed from the demons.", "-Inner Demons" end, + on_timeout = function(self, eff) + if eff.src.dead or not game.level:hasEntity(eff.src) then eff.dur = 0 return true end + if rng.percent(eff.chance) then + if self:checkHit(eff.src:combatSpellpower(), self:combatSpellResist(), 0, 95, 5) then + local t = eff.src:getTalentFromId(eff.src.T_INNER_DEMONS) + t.summon_inner_demons(eff.src, self, t) + else + eff.dur = 0 + end + end + end, +} \ No newline at end of file diff --git a/game/modules/tome/data/zones/ancient-elven-ruins/objects.lua b/game/modules/tome/data/zones/ancient-elven-ruins/objects.lua index b09200c6d119b5fd45d96e803ef97849730d5248..0d38d86a8b891bc974b28d3733e21c426a7ddd29 100644 --- a/game/modules/tome/data/zones/ancient-elven-ruins/objects.lua +++ b/game/modules/tome/data/zones/ancient-elven-ruins/objects.lua @@ -32,19 +32,19 @@ end local Stats = require "engine.interface.ActorStats" local Talents = require "engine.interface.ActorTalents" --- Random artifact -newEntity{ base = "BASE_MUMMY_WRAPPING", +newEntity{ base = "BASE_MUMMY_WRAPPING", define_as = "BINDINGS_ETERNAL_NIGHT", power_source = {arcane=true}, unique = true, - name = "Bindings of Eternal Night", + name = "Bindings of Eternal Night", image = "object/artifact/bindings_of_eternal_night.png", unided_name = "blackened, slithering mummy wrappings", desc = [[Woven through with fell magics of undeath, these bindings suck the light and life out of everything they touch. Any who don them will find themselves suspended in a nightmarish limbo between life and death.]], color = colors.DARK_GREY, level_range = {1, 50}, rarity = 130, cost = 200, - material_level = 1, + material_level = 3, wielder = { + combat_armor = 7, inc_stats = { [Stats.STAT_WIL] = 5, [Stats.STAT_MAG] = 5, }, resists = { [DamageType.BLIGHT] = 30, @@ -52,10 +52,55 @@ newEntity{ base = "BASE_MUMMY_WRAPPING", [DamageType.FIRE] = 30, }, on_melee_hit={[DamageType.BLIGHT] = 10}, - life_regen = -0.3, + life_regen = 0.3, lite = -1, + poison_immune = 1, + disease_immune = 1, + undead = 1, }, max_power = 80, power_regen = 1, - use_talent = { id = Talents.T_SPIT_POISON, level = 2, power = 50 }, + + set_list = { {"define_as","CROWN_ETERNAL_NIGHT"} }, + on_set_complete = function(self, who) + self.use_talent = { id = Talents.T_ABYSSAL_SHROUD, level = 2, power = 47 } + end, + on_set_broken = function(self, who) + self.use_talent = nil + end, } +newEntity{ base = "BASE_LEATHER_CAP", define_as = "CROWN_ETERNAL_NIGHT", + power_source = {arcane=true}, + unique = true, + name = "Crown of Eternal Night", image = "object/artifact/crown_of_eternal_night.png", + unided_name = "blackened crown", + desc = [[This crown looks useless, yet you can fell it woven with fell magics of undeath. Maybe it has a use.]], + color = colors.DARK_GREY, + level_range = {1, 50}, + cost = 100, + material_level = 3, + wielder = { + combat_armor = 3, + fatigue = 3, + inc_damage = {}, + melee_project = {}, + }, + max_power = 80, power_regen = 1, + + set_list = { {"define_as","BINDINGS_ETERNAL_NIGHT"} }, + on_set_complete = function(self, who) + self:specialSetAdd({"wielder","lite"}, -1) + self:specialSetAdd({"wielder","confusion_immune"}, 40) + self:specialSetAdd({"wielder","knockback_immune"}, 40) + self:specialSetAdd({"wielder","combat_mentalresist"}, 15) + self:specialSetAdd({"wielder","combat_spellresist"}, 15) + self:specialSetAdd({"wielder","melee_project"}, {[engine.DamageType.DARKNESS]=40}) + self:specialSetAdd({"wielder","inc_damage"}, {[engine.DamageType.DARKNESS]=20}) + self.use_talent = { id = Talents.T_RETCH, level = 2, power = 47 } + game.logSeen(who, "#ANTIQUE_WHITE#The Crown of Eternal Night seems to react with the Bindings, you feel tremounduous dark power.") + end, + on_set_broken = function(self, who) + game.logPlayer(who, "#ANTIQUE_WHITE#The powerful darkness aura you felt vanes away.") + self.use_talent = nil + end, +} diff --git a/game/modules/tome/data/zones/last-hope-graveyard/objects.lua b/game/modules/tome/data/zones/last-hope-graveyard/objects.lua index 16fe998f632c6edb26504c5d519d507068802232..9aa1f10a44f311999325f13174bdb99445c5f594 100644 --- a/game/modules/tome/data/zones/last-hope-graveyard/objects.lua +++ b/game/modules/tome/data/zones/last-hope-graveyard/objects.lua @@ -40,7 +40,7 @@ newEntity{ define_as = "CELIA_HEART", name = "Celia's Still Beating Heart", level_range = {20, 35}, rarity = false, - display = "*", color=colors.RED, image = "object/orc_heart.png", + display = "*", color=colors.RED, image = "object/artifact/celias_heart.png", encumber = 2, not_in_stores = true, desc = [[The living heart of the necromancer Celia, carved out of her chest and preserved with magic.]],