diff --git a/game/engines/default/engine/Birther.lua b/game/engines/default/engine/Birther.lua index ebf578a8b100c0891f9366653e522c0e37bc8e81..6205e6f13104d1e8fd825c935224323d7f58896e 100644 --- a/game/engines/default/engine/Birther.lua +++ b/game/engines/default/engine/Birther.lua @@ -87,6 +87,7 @@ function _M:init(title, actor, order, at_end, quickbirth, w, h) Dialog.init(self, title and title or ("Character Creation: "..actor.name), w or 600, h or 400) self.descriptors = {} + self.descriptors_by_type = {} self.c_tut = Textzone.new{width=math.floor(self.iw / 2 - 10), height=1, auto_height=true, no_color_bleed=true, text=[[ Keyboard: #00FF00#up key/down key#FFFFFF# to select an option; #00FF00#Enter#FFFFFF# to accept; #00FF00#Backspace#FFFFFF# to go back. @@ -183,7 +184,7 @@ function _M:selectType(type) print("[BIRTHER] checking allowance for ", d.name) for j, od in ipairs(self.descriptors) do if od.descriptor_choices and od.descriptor_choices[type] then - local what = util.getval(od.descriptor_choices[type][d.name]) or util.getval(od.descriptor_choices[type].__ALL__) + local what = util.getval(od.descriptor_choices[type][d.name], self) or util.getval(od.descriptor_choices[type].__ALL__, self) if what and what == "allow" then allowed = true elseif what and (what == "never" or what == "disallow") then @@ -235,6 +236,7 @@ function _M:prev() end if not self.list then return end self.changed = true + self.descriptors_by_type[self.current_type] = nil table.remove(self.descriptors) self.cur_order = self.cur_order - 1 self:selectType(self.order[self.cur_order]) @@ -248,6 +250,7 @@ end function _M:next() self.changed = true if self.list then + self.descriptors_by_type[self.current_type] = self.list[self.sel] or "none" table.insert(self.descriptors, self.list[self.sel] or "none") if self.list[self.sel] and self.list[self.sel].on_select then self.list[self.sel]:on_select() end diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 5e5cbba41847a78695d2d4aba5c9160b3e7b6ba5..28c6effee39e5dfb0d6cefd775e4a7ae30f898f3 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -246,6 +246,10 @@ function _M:actTurn() local t = self:getTalentFromId(self.T_THUNDERSTORM) t.do_storm(self, t) end + if self:isTalentActive(self.T_STONE_VINES) then + local t = self:getTalentFromId(self.T_STONE_VINES) + t.do_vines(self, t) + end if self:isTalentActive(self.T_BODY_OF_FIRE) then local t = self:getTalentFromId(self.T_BODY_OF_FIRE) t.do_fire(self, t) diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua index f1a3a4a50c094314ff0fc48ee41a753f900109ee..5864630daee9afef664e2d156c606d3cd7bd71ec 100644 --- a/game/modules/tome/class/interface/Combat.lua +++ b/game/modules/tome/class/interface/Combat.lua @@ -127,14 +127,16 @@ function _M:attackTarget(target, damtype, mult, noenergy) if self:getInven(self.INVEN_OFFHAND) then local offmult = self:getOffHandMult(mult) for i, o in ipairs(self:getInven(self.INVEN_OFFHAND)) do - if o.combat and not o.archery then + local combat = o.combat + if o.special_combat and o.subtype == "shield" and self:knowTalent(self.T_STONESHIELD) then combat = o.special_combat end + if combat and not o.archery then print("[ATTACK] attacking with", o.name) - local s, h = self:attackTargetWith(target, o.combat, damtype, offmult) + local s, h = self:attackTargetWith(target, combat, damtype, offmult) speed = math.max(speed or 0, s) hit = hit or h - if hit and not sound then sound = o.combat.sound - elseif not hit and not sound_miss then sound_miss = o.combat.sound_miss end - if not o.combat.no_stealth_break then break_stealth = true end + if hit and not sound then sound = combat.sound + elseif not hit and not sound_miss then sound_miss = combat.sound_miss end + if not combat.no_stealth_break then break_stealth = true end end end end @@ -400,6 +402,13 @@ function _M:attackTargetWith(target, weapon, damtype, mult) if hitted and not target.dead and target:attr("mana_regen_on_hit") then target:incMana(target.mana_regen_on_hit) end if hitted and not target.dead and target:attr("equilibrium_regen_on_hit") then target:incEquilibrium(-target.equilibrium_regen_on_hit) end + if hitted and not target.dead and target:knowTalent(target.T_STONESHIELD) then + local t = target:getTalentFromId(target.T_STONESHIELD) + local m, mm, e, em = t.getValues(self, t) + target:incMana(math.min(dam * m, mm)) + target:incEquilibrium(-math.min(dam * e, em)) + end + -- Ablative Armor if hitted and not target.dead and target:attr("carbon_spikes") then if target.carbon_armor >= 1 then diff --git a/game/modules/tome/data/birth/classes/wilder.lua b/game/modules/tome/data/birth/classes/wilder.lua index 6895b0208e3eb2134e0fc3d4c78fd68d331cb105..0d5b4e15e26b1b8174b0d6a09452bb91d6220ddc 100644 --- a/game/modules/tome/data/birth/classes/wilder.lua +++ b/game/modules/tome/data/birth/classes/wilder.lua @@ -31,6 +31,7 @@ newBirthDescriptor{ __ALL__ = "disallow", Summoner = function() return profile.mod.allow_build.wilder_summoner and "allow" or "disallow" end, Wyrmic = function() return profile.mod.allow_build.wilder_wyrmic and "allow" or "disallow" end, + ["Stone Warden"] = function(birth) return birth.descriptors_by_type.race and birth.descriptors_by_type.race.name == "Dwarf" and profile.mod.allow_build.wilder_stone_warden and "allow" or "disallow" end, }, }, copy = { @@ -121,33 +122,37 @@ newBirthDescriptor{ type = "subclass", name = "Stone Warden", desc = { - "", + "Stone Wardens are dwarves trained in both the eldritch arts and the worship of nature.", + "While other races are stuck in their belief that arcane forces and natural forces are meant to oppose, dwarves have found a way to combine them in harmony.", + "Stone Wardens are armoured fighters, using a shield to channel many of their powers.", "#GOLD#Stat modifiers:", - "#LIGHT_BLUE# * +3 Strength, +0 Dexterity, +0 Constitution", - "#LIGHT_BLUE# * +3 Magic, +3 Willpower, +0 Cunning", + "#LIGHT_BLUE# * +2 Strength, +0 Dexterity, +0 Constitution", + "#LIGHT_BLUE# * +4 Magic, +3 Willpower, +0 Cunning", }, - stats = { str=3, wil=3, mag=3, }, + stats = { str=2, wil=3, mag=4, }, talents_types = { ["wild-gift/call"]={true, 0.2}, - ["wild-gift/stone-mastery"]={true, 0.3}, - ["spell/earth"]={true, 0.3}, - ["spell/stone"]={true, 0.3}, - ["cunning/survival"]={false, 0}, - ["technique/shield-offense"]={true, 0.1}, - ["technique/combat-techniques-passive"]={true, 0}, + ["wild-gift/earthen-stone"]={true, 0.3}, + ["wild-gift/earthen-vines"]={true, 0.3}, + ["spell/arcane-shield"]={true, 0.3}, + ["spell/earth"]={true, 0.2}, + ["spell/stone"]={false, 0.2}, + ["cunning/survival"]={true, 0}, ["technique/combat-training"]={true, 0}, }, talents = { - [ActorTalents.T_ICE_CLAW] = 1, - [ActorTalents.T_MEDITATION] = 1, + [ActorTalents.T_STONE_VINES] = 1, + [ActorTalents.T_STONESHIELD] = 1, + [ActorTalents.T_ELDRITCH_BLOW] = 1, + [ActorTalents.T_ARMOUR_TRAINING] = 3, [ActorTalents.T_WEAPONS_MASTERY] = 1, - [ActorTalents.T_WEAPON_COMBAT] = 1, }, copy = { max_life = 110, resolvers.equip{ id=true, - {type="weapon", subtype="battleaxe", name="iron battleaxe", autoreq=true, ego_chance=-1000}, - {type="armor", subtype="light", name="rough leather armour", autoreq=true, ego_chance=-1000} + {type="weapon", subtype="mace", name="iron mace", autoreq=true, ego_chance=-1000, ego_chance=-1000}, + {type="armor", subtype="shield", name="iron shield", autoreq=true, ego_chance=-1000, ego_chance=-1000}, + {type="armor", subtype="heavy", name="iron mail armour", autoreq=true, ego_chance=-1000, ego_chance=-1000} }, }, copy_add = { diff --git a/game/modules/tome/data/birth/worlds.lua b/game/modules/tome/data/birth/worlds.lua index 8f4bdaa2350fe9d707b86a4d519096ead27c0623..3645fb802825be512b4202c899b186e2e52c3336 100644 --- a/game/modules/tome/data/birth/worlds.lua +++ b/game/modules/tome/data/birth/worlds.lua @@ -19,6 +19,7 @@ local default_eyal_descriptors = function(add) local base = { + race = { __ALL__ = "disallow", diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua index cda4b8af8c872de95978cbb3bb274da0028fe8c1..183f504cf336d6427437ca3cc145b5ff4375895e 100644 --- a/game/modules/tome/data/damage_types.lua +++ b/game/modules/tome/data/damage_types.lua @@ -88,6 +88,10 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) dam = t.css_on_damage(target, t, type, dam) end + if type ~= DamageType.PHYSICAL and target.knowTalent and target:knowTalent(target.T_STONE_FORTRESS) and target:hasEffect(target.EFF_DWARVEN_RESILIENCE) then + dam = math.max(0, dam - target:combatArmor() * (50 + target:getTalentLevel(target.T_STONE_FORTRESS) * 10) / 100) + end + -- Reduce damage with resistance if target.resists then local pen = 0 diff --git a/game/modules/tome/data/general/encounters/maj-eyal-npcs.lua b/game/modules/tome/data/general/encounters/maj-eyal-npcs.lua index caf07ac2c2afd48908a096d861aa0ef8a215d557..b81230d8d3c44a9ce201d37e9fb9e75aff6cc7f6 100644 --- a/game/modules/tome/data/general/encounters/maj-eyal-npcs.lua +++ b/game/modules/tome/data/general/encounters/maj-eyal-npcs.lua @@ -92,7 +92,7 @@ newEntity{ type="ambush", width=14, height=14, - nb={2, 4}, + nb={2, 3}, filters={{special_rarity="humanoid_random_boss", random_boss={ nb_classes=1, rank=3, diff --git a/game/modules/tome/data/general/npcs/aquatic_critter.lua b/game/modules/tome/data/general/npcs/aquatic_critter.lua index a17278976cae7912222bcb6b0035a25043f797dc..31a59b67e4213e82308a2e226423db29f1fafe15 100644 --- a/game/modules/tome/data/general/npcs/aquatic_critter.lua +++ b/game/modules/tome/data/general/npcs/aquatic_critter.lua @@ -75,7 +75,7 @@ newEntity{ base = "BASE_NPC_AQUATIC_CRITTER", newEntity{ base = "BASE_NPC_AQUATIC_CRITTER", name = "ancient dragon turtle", color=colors.DARK_SEA_GREEN, - desc = "A snake-like being, radiating electricity.", + desc = "A huge, elongated sea-green reptile, it looks old and impenetrable.", level_range = {20, nil}, exp_worth = 1, rarity = 10, rank = 3, diff --git a/game/modules/tome/data/general/npcs/bone-giant.lua b/game/modules/tome/data/general/npcs/bone-giant.lua index 5c4a0cd4f784aacbbcd8270542f60b6ee7001abd..70e1d3057630b3c7790e893cc8e5976e677267f8 100644 --- a/game/modules/tome/data/general/npcs/bone-giant.lua +++ b/game/modules/tome/data/general/npcs/bone-giant.lua @@ -62,6 +62,7 @@ newEntity{ base = "BASE_NPC_BONE_GIANT", name = "bone giant", color=colors.WHITE, desc = [[A towering creature, made from the bones of dozens of dead bodies. It is covered by an unholy aura.]], level_range = {25, nil}, exp_worth = 1, + resolvers.nice_tile{image="invis.png", add_mos = {{image="npc/undead_giant_bone_giant.png", display_h=2, display_y=-1}}}, rarity = 1, max_life = resolvers.rngavg(100,120), combat_armor = 20, combat_def = 0, diff --git a/game/modules/tome/data/general/npcs/construct.lua b/game/modules/tome/data/general/npcs/construct.lua index 6e31bff62a3eabab170c41001da018e82ed3ff7b..028f20f809d05f50027c4909e381d69d6d0cf422 100644 --- a/game/modules/tome/data/general/npcs/construct.lua +++ b/game/modules/tome/data/general/npcs/construct.lua @@ -54,7 +54,7 @@ newEntity{ } newEntity{ base = "BASE_NPC_CONSTRUCT", - name = "broken golem", color=colors.LIGHT_UMBER, image = "npc/summoner_golem.png", + name = "broken golem", color=colors.LIGHT_UMBER, desc = [[This golem is badly damaged.]], level_range = {6, nil}, exp_worth = 1, rarity = 1, diff --git a/game/modules/tome/data/general/npcs/humanoid_random_boss.lua b/game/modules/tome/data/general/npcs/humanoid_random_boss.lua index f35e502e3f9e899897d6f2fa0543e974a0c6e462..ff56f688f36a2326274f39e48bd3e708a71a2f7f 100644 --- a/game/modules/tome/data/general/npcs/humanoid_random_boss.lua +++ b/game/modules/tome/data/general/npcs/humanoid_random_boss.lua @@ -54,7 +54,7 @@ newEntity{ base = "BASE_NPC_HUMANOID_RANDOM_BOSS", } newEntity{ base = "BASE_NPC_HUMANOID_RANDOM_BOSS", - name = "halflint", subtype = "halfling", color=colors.BLUE, + name = "halfling", subtype = "halfling", color=colors.BLUE, humanoid_random_boss = 1, resolvers.racial(), } diff --git a/game/modules/tome/data/gfx/particles/stonevine.lua b/game/modules/tome/data/gfx/particles/stonevine.lua new file mode 100644 index 0000000000000000000000000000000000000000..56e42c176af34fe1736e8e4109df46867f4e164c --- /dev/null +++ b/game/modules/tome/data/gfx/particles/stonevine.lua @@ -0,0 +1,81 @@ +-- 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 + +-- Make the 2 main forks +local nb = 0 +local forks = {{}, {}} +local m1 = forks[1] +local m2 = forks[2] +local tiles = math.ceil(math.sqrt(tx*tx+ty*ty)) +local tx = tx * engine.Map.tile_w +local ty = ty * engine.Map.tile_h +local breakdir = math.rad(rng.range(-8, 8)) +m1.bx = 0 +m1.by = 0 +m1.thick = 5 +m1.dir = math.atan2(ty, tx) + breakdir +m1.size = math.sqrt(tx*tx+ty*ty) / 2 + +m2.bx = m1.size * math.cos(m1.dir) +m2.by = m1.size * math.sin(m1.dir) +m2.thick = 5 +m2.dir = math.atan2(ty, tx) - breakdir +m2.size = math.sqrt(tx*tx+ty*ty) / 2 + +-- Add more forks +for i = 1, math.min(math.max(3, m1.size / 5), 20) do + local m = rng.percent(50) and forks[1] or forks[2] + if rng.percent(60) then m = rng.table(forks) end + local f = {} + f.thick = 2 + f.dir = m.dir + math.rad(rng.range(-30,30)) + f.size = rng.range(6, 25) + local br = rng.range(1, m.size) + f.bx = br * math.cos(m.dir) + m.bx + f.by = br * math.sin(m.dir) + m.by + forks[#forks+1] = f +end + +-- Populate the lightning based on the forks +return { generator = function() + local f = rng.table(forks) + local a = f.dir + local rad = rng.range(-3,3) + local ra = math.rad(rad) + local r = rng.range(1, f.size) + + return { + life = life or 4, + size = f.thick, sizev = 0, sizea = 0, + + x = r * math.cos(a) + 3 * math.cos(ra) + f.bx, xv = 0, xa = 0, + y = r * math.sin(a) + 3 * math.sin(ra) + f.by, yv = 0, ya = 0, + dir = 0, dirv = 0, dira = 0, + vel = 0, velv = 0, vela = 0, + + r = 0xD7/255, rv = 0, ra = 0, + g = 0x8E/255, gv = 0, ga = 0, + b = 0x45/255, bv = 0, ba = 0, + a = rng.range(230, 255)/255, av = 0, aa = 0, + } +end, }, +function(self) + if nb < 4 then self.ps:emit(20*tiles) nb = nb + 1 end +end, +4*(20)*tiles diff --git a/game/modules/tome/data/gfx/particles/stonevine_static.lua b/game/modules/tome/data/gfx/particles/stonevine_static.lua new file mode 100644 index 0000000000000000000000000000000000000000..0d865c3cae2ebffa95dcd22af05e1b50d1f39828 --- /dev/null +++ b/game/modules/tome/data/gfx/particles/stonevine_static.lua @@ -0,0 +1,46 @@ +-- 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 + +base_size = 32 + +return { generator = function() + local ad = rng.range(0, 360) + local a = math.rad(ad) + local dir = math.rad(ad) + local r = rng.range(8, 18) + + return { + life = 10, + size = 1, sizev = 0.3, sizea = -0.01, + + x = r * math.cos(a), xv = 0, xa = 0, + y = r * math.sin(a), yv = 0, ya = 0, + dir = 0, dirv = 0, dira = 0, + vel = 0, velv = 0, vela = 0, + + r = 0xD7/255, rv = 0, ra = 0, + g = 0x8E/255, gv = 0, ga = 0, + b = 0x45/255, bv = 0, ba = 0, + a = rng.range(100, 220)/255, av = 0.05, aa = 0, + } +end, }, +function(self) + self.ps:emit(2) +end, +10 diff --git a/game/modules/tome/data/gfx/shockbolt/invis.png b/game/modules/tome/data/gfx/shockbolt/invis.png new file mode 100644 index 0000000000000000000000000000000000000000..4d828ca986e40aeb43a1fa001bfd876541370d63 Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/invis.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/npc/animal_bird_phoenix.png b/game/modules/tome/data/gfx/shockbolt/npc/animal_bird_phoenix.png new file mode 100644 index 0000000000000000000000000000000000000000..a1f3e334eb48fa612ea5654571e127b4588208a9 Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/npc/animal_bird_phoenix.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/npc/construct_golem_broken_golem.png b/game/modules/tome/data/gfx/shockbolt/npc/construct_golem_broken_golem.png new file mode 100644 index 0000000000000000000000000000000000000000..12fe6e2a9be025e89fc3af7582f169c58bad1038 Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/npc/construct_golem_broken_golem.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/npc/dragon_cold_cold_drake_hatchling.png b/game/modules/tome/data/gfx/shockbolt/npc/dragon_cold_cold_drake_hatchling.png new file mode 100644 index 0000000000000000000000000000000000000000..d774be02a586201a4d3b394e2a3b5800c50760e1 Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/npc/dragon_cold_cold_drake_hatchling.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/npc/humanoid_shalore_elven_mage.png b/game/modules/tome/data/gfx/shockbolt/npc/humanoid_shalore_elven_mage.png new file mode 100644 index 0000000000000000000000000000000000000000..99f2cbc0d77dace46907ad24e45b4b149c769636 Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/npc/humanoid_shalore_elven_mage.png differ diff --git a/game/modules/tome/data/gfx/shockbolt/npc/undead_giant_bone_giant.png b/game/modules/tome/data/gfx/shockbolt/npc/undead_giant_bone_giant.png new file mode 100644 index 0000000000000000000000000000000000000000..4063d8a76f014e20db48c06f3f8cedecf2fc503d Binary files /dev/null and b/game/modules/tome/data/gfx/shockbolt/npc/undead_giant_bone_giant.png differ diff --git a/game/modules/tome/data/quests/escort-duty.lua b/game/modules/tome/data/quests/escort-duty.lua index 775eab120965357f7f235c82ab5aa1e3c90de36e..bf9b3888ba9c26391cf1543a1a7337b59796db60 100644 --- a/game/modules/tome/data/quests/escort-duty.lua +++ b/game/modules/tome/data/quests/escort-duty.lua @@ -47,7 +47,7 @@ local possible_types = { { name="lost warrior", random="male", chance=70, text = [[Please help me! I am afraid I lost myself in this place. I know there is a recall portal left around here by a friend, but I have fought too many battles, and I fear I will not make it. Would you help me?]], actor = { - type = "humanoid", subtype = "human", + type = "humanoid", subtype = "human", image = "player/higher_male.png", display = "@", color=colors.UMBER, name = "%s, the lost warrior", desc = [[He looks tired and wounded.]], @@ -75,7 +75,7 @@ local possible_types = { text = [[Please help me! I am afraid I lost myself in this place. I know there is a recall portal left around here by a friend, but I will not be able to continue the road alone. Would you help me?]], actor = { name = "%s, the injured seer", - type = "humanoid", subtype = "elf", female=true, + type = "humanoid", subtype = "elf", female=true, image = "player/halfling_female.png", display = "@", color=colors.LIGHT_BLUE, desc = [[She looks tired and wounded.]], autolevel = "caster", @@ -101,7 +101,7 @@ local possible_types = { text = [[Please help me! I am afraid I lost myself in this place. I know there is a recall portal left around here by a friend, but I have fought too many battles, and I fear I will not make it. Would you help me?]], actor = { name = "%s, the repented thief", - type = "humanoid", subtype = "halfling", + type = "humanoid", subtype = "halfling", image = "player/cornac_male.png", display = "@", color=colors.BLUE, desc = [[He looks tired and wounded.]], autolevel = "rogue", @@ -128,7 +128,7 @@ local possible_types = { text = [[Please help me! I am afraid I lost myself in this place. I know there is a recall portal left around here by a friend, but I have fought too many battles, and I fear I will not make it. Would you help me?]], actor = { name = "%s, the lone alchemist", - type = "humanoid", subtype = "human", + type = "humanoid", subtype = "human", image = "player/shalore_male.png", display = "@", color=colors.AQUAMARINE, desc = [[He looks tired and wounded.]], autolevel = "rogue", @@ -154,7 +154,7 @@ local possible_types = { text = [[Please help me! I am afraid I lost myself in this place. I know there is a recall portal left around here by a friend, but I have fought too many battles, and I fear I will not make it. Would you help me?]], actor = { name = "%s, the lost sun paladin", - type = "humanoid", subtype = "human", female=true, + type = "humanoid", subtype = "human", female=true, image = "player/higher_female.png", display = "@", color=colors.GOLD, desc = [[She looks tired and wounded.]], autolevel = "warriormage", @@ -181,7 +181,7 @@ local possible_types = { text = [[Please help me! I am afraid I lost myself in this place. I know there is a recall portal left around here by a friend, but I have fought too many battles, and I fear I will not make it. Would you help me?]], actor = { name = "%s, the lost anorithil", - type = "humanoid", subtype = "human", female=true, + type = "humanoid", subtype = "human", female=true, image = "player/higher_female.png", display = "@", color=colors.YELLOW, desc = [[She looks tired and wounded.]], autolevel = "caster", @@ -208,7 +208,7 @@ local possible_types = { text = [[Please help me! I am afraid I lost myself in this place. I know there is a recall portal left around here by a friend, but I have fought too many battles, and I fear I will not make it. Would you help me?]], actor = { name = "%s, the worried loremaster", - type = "humanoid", subtype = "human", female=true, + type = "humanoid", subtype = "human", female=true, image = "player/thalore_female.png", display = "@", color=colors.LIGHT_GREEN, desc = [[She looks tired and wounded.]], autolevel = "wildcaster", diff --git a/game/modules/tome/data/talents/gifts/earthen-power.lua b/game/modules/tome/data/talents/gifts/earthen-power.lua new file mode 100644 index 0000000000000000000000000000000000000000..bab1522f2951eaa808954424dcab053d501605aa --- /dev/null +++ b/game/modules/tome/data/talents/gifts/earthen-power.lua @@ -0,0 +1,127 @@ +-- 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 + +newTalent{ + name = "Stoneshield", + type = {"wild-gift/earthen-power", 1}, + mode = "passive", + require = gifts_req1, + points = 5, + getValues = function(self, t) + return + (5 + self:getTalentLevel(t) * 2) / 100, + 5 + self:getTalentLevel(t), + (5 + self:getTalentLevel(t) * 1.7) / 100, + 4 + self:getTalentLevel(t) + end, + info = function(self, t) + local m, mm, e, em = t.getValues(self, t) + return ([[Each time you get hit you regenerate %d%% of the damage dealt as mana (up to a maximun of %0.2f) and %d%% as equilibrium (up to %0.2f). + Also makes all your melee attack also do a shield bash.]]):format(100 * m, mm, 100 * e, em) + end, +} + +newTalent{ + name = "Stone Fortress", + type = {"wild-gift/earthen-power", 2}, + require = gifts_req2, + points = 5, + mode = "passive", + info = function(self, t) + return ([[When you use your Resilience of the Dwarves racial power your skin becomes so thick that it even absorbs damage from non physical attacks. + Non physical damages are reduced by %d%% of your armour value (ignoring hardiness).]]): + format(50 + self:getTalentLevel(t) * 10) + end, +} + +newTalent{ + name = "Shards", + type = {"wild-gift/earthen-power", 3}, + require = gifts_req3, + points = 5, + equilibrium = 4, + cooldown = 30, + tactical = { ATTACK = 2 }, + range = 10, + direct_hit = true, + proj_speed = 8, + action = function(self, t) + local tg = {type="bolt", range=self:getTalentRange(t), display={particle="bolt_arcane"}} + local x, y = self:getTarget(tg) + if not x or not y then return nil end + self:projectile(tg, x, y, DamageType.SLIME, self:combatTalentStatDamage(t, "dex", 30, 290), {type="slime"}) + game:playSoundNear(self, "talents/stone") + return true + end, + info = function(self, t) + return ([[Spit slime at your target doing %0.2f nature damage and slowing it down by 30%% for 3 turns. + The damage will increase with the Dexterity stat]]):format(damDesc(self, DamageType.NATURE, self:combatTalentStatDamage(t, "dex", 30, 290))) + end, +} + +newTalent{ + name = "Eldritch Stone", + type = {"wild-gift/earthen-power", 4}, + require = gifts_req4, + points = 5, + equilibrium = 5, + cooldown = 20, + tactical = { CLOSEIN = 2 }, + requires_target = true, + range = function(self, t) + return 5 + self:getTalentLevel(t) + end, + radius = function(self, t) + return util.bound(4 - self:getTalentLevel(t) / 2, 1, 4) + end, + getDuration = function(self, t) + return util.bound(7 - self:getTalentLevel(t) / 2, 2, 7) + end, + action = function(self, t) + local range = self:getTalentRange(t) + local radius = self:getTalentRadius(t) + local tg = {type="ball", nolock=true, pass_terrain=true, nowarning=true, range=range, radius=radius, requires_knowledge=false} + local x, y = self:getTarget(tg) + if not x then return nil end + -- Target code does not restrict the self coordinates to the range, it lets the project function do it + -- but we cant ... + local _ _, x, y = self:canProject(tg, x, y) + game.level.map:particleEmitter(self.x, self.y, 1, "slime") + self:teleportRandom(x, y, self:getTalentRadius(t)) + game.level.map:particleEmitter(self.x, self.y, 1, "slime") + + local duration = t.getDuration(self, t) + + for tid, lev in pairs(self.talents) do + local t = self:getTalentFromId(tid) + if t.mode == "activated" and not t.innate then + self.talents_cd[t.id] = duration + end + end + game:playSoundNear(self, "talents/stone") + return true + end, + info = function(self, t) + local range = self:getTalentRange(t) + local radius = self:getTalentRadius(t) + local duration = t.getDuration(self, t) + return ([[You extend slimy roots into the ground, follow them, and re-appear somewhere else in a range of %d with error margin of %d. + The process is quite a strain on your body and all your talents will be put on cooldown for %d turns.]]):format(range, radius, duration) + end, +} diff --git a/game/modules/tome/data/talents/gifts/earthen-vines.lua b/game/modules/tome/data/talents/gifts/earthen-vines.lua new file mode 100644 index 0000000000000000000000000000000000000000..b5dd3df410504c082a7093224bc040a0e29380e4 --- /dev/null +++ b/game/modules/tome/data/talents/gifts/earthen-vines.lua @@ -0,0 +1,167 @@ +-- 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 + +newTalent{ + name = "Stone Vines", + type = {"wild-gift/earthen-vines", 1}, + require = gifts_req1, + points = 5, + mode = "sustained", + sustain_equilibrium = 15, + cooldown = 30, + tactical = { ATTACK = 2, BUFF = 2, DISABLE = 2 }, + radius = function(self, t) return 4 + math.ceil(self:getTalentLevel(t) / 2) end, + getValues = function(self, t) return 4 + self:getTalentLevelRaw(t), self:combatTalentStatDamage(t, "wil", 3, 50) end, + do_vines = function(self, t) + local p = self:isTalentActive(t.id) + local rad = self:getTalentRadius(t) + + local tgts = {} + local grids = core.fov.circle_grids(self.x, self.y, rad, 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 and not a:hasEffect(a.EFF_STONE_VINE) then + tgts[#tgts+1] = a + end + end end + if #tgts <= 0 then return end + + -- Randomly take targets + local tg = {type="hit", range=self:getTalentRange(t), talent=t} + local a, id = rng.table(tgts) + local hit, chance = a:checkHit(self:combatTalentStatDamage(t, "wil", 5, 110), a:combatPhysicalResist(), 0, 95, 5) + if a:canBe("pin") and hit then + local turns, dam = t.getValues(self, t) + a:setEffect(a.EFF_STONE_VINE, turns, {dam=dam, src=self, free=rad*2, free_chance=100-chance}) + game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(a.x-self.x), math.abs(a.y-self.y)), "stonevine", {tx=a.x-self.x, ty=a.y-self.y}) + game:playSoundNear(self, "talents/stone") + end + end, + activate = function(self, t) + return { + movid = self:addTemporaryValue("movement_speed", -0.5), + particle = self:addParticles(Particles.new("stonevine_static", 1, {})), + } + end, + deactivate = function(self, t, p) + self:removeTemporaryValue("movement_speed", p.movid) + self:removeParticles(p.particle) + return true + end, + info = function(self, t) + local rad = self:getTalentRadius(t) + local turns, dam = t.getValues(self, t) + return ([[Living stone vines extend from your feet, each turn the vines will randomly target a creature in a radius of %d. + Affected creatures are pinned to the ground and take %0.2f physical damage for %d turns. + Targets will be free from the vines if they are at least %d grids away from you. + While earthen vines are active your movement speed is reduced by 50%%. + Each turn a creature entangled by the vines will have a chance to break free. + The damage will increase with Willpower stats.]]): + format(rad, damDesc(self, DamageType.PHYSICAL, dam), turns, rad*2) + end, +} + +newTalent{ + name = "Eldritch Vines", + type = {"wild-gift/earthen-vines", 2}, + require = gifts_req2, + points = 5, + mode = "passive", + info = function(self, t) + return ([[Each time a vine deal damage to a creature it will restore %0.2f equilibrium and %0.2f mana.]]) + :format(self:getTalentLevel(t) / 4, self:getTalentLevel(t) / 3) + end, +} + +newTalent{ + name = "Rockwalk", + type = {"wild-gift/earthen-vines", 3}, + require = gifts_req3, + points = 5, + equilibrium = 15, + cooldown = 10, + requires_target = true, + range = 20, + tactical = { HEAL = 2, CLONEIN = 2 }, + action = function(self, t) + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) + if not x or not y or not target then return nil end + if not target:hasEffect(target.EFF_STONE_VINE) then return nil end + + self:heal(100 + self:combatTalentStatDamage(t, "wil", 40, 630)) + local tx, ty = util.findFreeGrid(x, y, 2, true, {[Map.ACTOR]=true}) + if tx and ty then + local ox, oy = self.x, self.y + self:move(tx, ty, true) + if config.settings.tome.smooth_move > 0 then + self:resetMoveAnim() + self:setMoveAnim(ox, oy, 8, 5) + end + end + + return true + end, + info = function(self, t) + return ([[Merge with a stone vine, travelling alongside it to reappear near an entangled creature. + Merging with the stone is beneficial for you, healing %0.2f life. + Healing will increase with Willpower.]]) + :format(100 + self:combatTalentStatDamage(t, "wil", 40, 630)) + end, +} + +newTalent{ + name = "Rockswallow", + type = {"wild-gift/earthen-vines", 4}, + require = gifts_req4, + points = 5, + equilibrium = 15, + cooldown = 10, + requires_target = true, + range = 20, + tactical = { ATTACK = 2, CLONEIN = 2 }, + action = function(self, t) + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) + if not x or not y or not target then return nil end + if not target:hasEffect(target.EFF_STONE_VINE) then return nil end + + DamageType:get(DamageType.PHYSICAL).projector(self, target.x, target.y, DamageType.PHYSICAL, 80 + self:combatTalentStatDamage(t, "wil", 40, 330)) + + if target.dead then return end + + local tx, ty = util.findFreeGrid(self.x, self.y, 2, true, {[Map.ACTOR]=true}) + if tx and ty then + local ox, oy = target.x, target.y + target:move(tx, ty, true) + if config.settings.tome.smooth_move > 0 then + target:resetMoveAnim() + target:setMoveAnim(ox, oy, 8, 5) + end + end + + return true + end, + info = function(self, t) + return ([[Merge your target with a stone vine, forcing it to travel alongside it to reappear near you. + Merging with the stone is detrimental for the target, dealing %0.2f physical damage. + Damage will increase with Willpower.]]) + :format(80 + self:combatTalentStatDamage(t, "wil", 40, 330)) + end, +} diff --git a/game/modules/tome/data/talents/gifts/gifts.lua b/game/modules/tome/data/talents/gifts/gifts.lua index e836daf5ce2d891007733812ab5a9f9a74e6f944..f357049946bcf9a0b2c5af614ee04fff5f5480c0 100644 --- a/game/modules/tome/data/talents/gifts/gifts.lua +++ b/game/modules/tome/data/talents/gifts/gifts.lua @@ -29,6 +29,8 @@ newTalentType{ allow_random=true, type="wild-gift/sand-drake", name = "sand drak newTalentType{ allow_random=true, type="wild-gift/fire-drake", name = "fire drake aspect", description = "Take on the defining aspects of a Fire Drake." } newTalentType{ allow_random=true, type="wild-gift/cold-drake", name = "cold drake aspect", description = "Take on the defining aspects of a Cold Drake." } newTalentType{ allow_random=true, type="wild-gift/storm-drake", name = "storm drake aspect", description = "Take on the defining aspects of a Storm Drake." } +newTalentType{ allow_random=true, type="wild-gift/earthen-power", name = "earthen power", description = "Dwarves have learned to imbue their shields with the power of stone itself." } +newTalentType{ allow_random=true, type="wild-gift/earthen-vines", name = "earthen vines", description = "Control the stone itself and bring it alive in the form of dreadful vines." } -- Generic requires for gifts based on talent level gifts_req1 = { @@ -131,3 +133,6 @@ load("/data/talents/gifts/summon-melee.lua") load("/data/talents/gifts/summon-distance.lua") load("/data/talents/gifts/summon-utility.lua") load("/data/talents/gifts/summon-augmentation.lua") + +load("/data/talents/gifts/earthen-power.lua") +load("/data/talents/gifts/earthen-vines.lua") diff --git a/game/modules/tome/data/talents/spells/arcane-shield.lua b/game/modules/tome/data/talents/spells/arcane-shield.lua new file mode 100644 index 0000000000000000000000000000000000000000..410cf2edd2e18772dbc0274cf11afc313897bfea --- /dev/null +++ b/game/modules/tome/data/talents/spells/arcane-shield.lua @@ -0,0 +1,161 @@ +-- 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 + +newTalent{ + name = "Eldritch Blow", + type = {"spell/arcane-shield", 1}, + require = spells_req1, + points = 5, + equilibrium = 3, + mana = 10, + cooldown = 6, + range = 1, + tactical = { ATTACK = 2, DISABLE = 2 }, + requires_target = true, + pre_use = function(self, t, silent) local shield = self:hasShield() if not shield then if not silent then game.logPlayer(self, "You cannot use Eldricth Blow without a shield!") end return false end return true end, + action = function(self, t) + local shield = self:hasShield() + + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) + if not x or not y or not target then return nil end + if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end + + -- First attack with both weapon & shield (since we have the Stoneshield talent) + local hit = self:attackTarget(target, DamageType.ARCANE, self:combatTalentWeaponDamage(t, 0.6, (100 + self:combatTalentSpellDamage(t, 50, 300)) / 100), true) + + -- Try to stun ! + if hit then + if target:checkHit(self:combatAttackStr(shield.special_combat), target:combatSpellResist(), 0, 95, 5) and target:canBe("stun") then + target:setEffect(target.EFF_STUNNED, 2 + math.floor(self:getTalentLevel(t) / 2), {}) + else + game.logSeen(target, "%s resists the stun!", target.name:capitalize()) + end + end + + return true + end, + info = function(self, t) + return ([[Channel eldritch forces in your attack, hitting the target with your weapon and shield doing %d%% arcane damage. + If the any of the attacks hit, the target is stunned for %d turns. + The stun is considered a magical attack and thus is resisted with spell save, not physical save.]]) + :format(100 * self:combatTalentWeaponDamage(t, 0.6, (100 + self:combatTalentSpellDamage(t, 50, 300)) / 100), 2 + math.floor(self:getTalentLevel(t) / 2)) + end, +} + +newTalent{ + name = "Eldritch Infusion", + type = {"spell/arcane-shield", 2}, + require = spells_req2, + points = 5, + mode = "sustained", + sustain_equilibrium = 15, + sustain_mana = 15, + cooldown = 30, + tactical = { ATTACK = 3, BUFF = 2 }, + activate = function(self, t) + local power = 5 * self:getTalentLevel(t) + (self:getWil() + self:getMag()) / 5 + return { + onhit = self:addTemporaryValue("melee_project", {[DamageType.ARCANE]=power}), + } + end, + deactivate = function(self, t, p) + self:removeTemporaryValue("melee_project", p.onhit) + return true + end, + info = function(self, t) + return ([[Imbues your weapon with arcane power, dealing %0.2f arcane damage with each attacks. + The damage will increase with Willpower and Magic stats.]]):format(damDesc(self, DamageType.ARCANE, 5 * self:getTalentLevel(t) + (self:getWil() + self:getMag()) / 5)) + end, +} + +newTalent{ + name = "Eldritch Fury", + type = {"spell/arcane-shield", 3}, + require = spells_req3, + points = 5, + equilibrium = 20, + mana = 30, + cooldown = 12, + requires_target = true, + tactical = { ATTACK = 3, DISABLE = 1 }, + range = 1, + pre_use = function(self, t, silent) local shield = self:hasShield() if not shield then if not silent then game.logPlayer(self, "You cannot use Eldricth Fury without a shield!") end return false end return true end, + action = function(self, t) + local shield = self:hasShield() + + local tg = {type="hit", range=self:getTalentRange(t)} + local x, y, target = self:getTarget(tg) + if not x or not y or not target then return nil end + if math.floor(core.fov.distance(self.x, self.y, x, y)) > 1 then return nil end + + -- First attack with both weapon & shield (since we have the Stoneshield talent) + local hit1 = self:attackTarget(target, DamageType.NATURE, self:combatTalentWeaponDamage(t, 0.6, 1.6), true) + local hit2 = self:attackTarget(target, DamageType.NATURE, self:combatTalentWeaponDamage(t, 0.6, 1.6), true) + local hit3 = self:attackTarget(target, DamageType.NATURE, self:combatTalentWeaponDamage(t, 0.6, 1.6), true) + + -- Try to stun ! + if hit then + if target:checkHit(self:combatAttackStr(shield.special_combat), target:combatSpellResist(), 0, 95, 5) and target:canBe("stun") then + target:setEffect(target.EFF_DAZED, 3 + math.floor(self:getTalentLevel(t)), {}) + else + game.logSeen(target, "%s resists the dazing blows!", target.name:capitalize()) + end + end + + return true + end, + info = function(self, t) + return ([[Channel eldritch forces to speed up your attacks, hitting the target three times with your weapon and shield doing %d%% nature damage. + If the any of the attacks hit, the target is dazed for %d turns. + The daze is considered a magical attack and thus is resisted with spell save, not physical save.]]) + :format(100 * self:combatTalentWeaponDamage(t, 0.6, 1.6), 3 + math.floor(self:getTalentLevel(t))) + end, +} + +newTalent{ + name = "Eldritch Slam", + type = {"spell/arcane-shield", 4}, + require = spells_req4, + points = 5, + equilibrium = 10, + mana = 30, + cooldown = 20, + tactical = { ATTACKAREA = 3 }, + requires_target = true, + range = 1, + radius = function(self, t) return 1 + self:getTalentLevelRaw(t) end, + pre_use = function(self, t, silent) local shield = self:hasShield() if not shield then if not silent then game.logPlayer(self, "You cannot use Eldritch Slam without a shield!") end return false end return true end, + action = function(self, t) + local shield = self:hasShield() + + local tg = {type="ball", radius=self:getTalentRadius(t)} + self:project(tg, self.x, self.y, function(px, py) + local target = game.level.map(px, py, Map.ACTOR) + if not target or target == self then return end + self:attackTargetWith(target, shield.special_combat, nil, self:combatTalentWeaponDamage(t, 1.3, 2.6), true) + end) + + return true + end, + info = function(self, t) + return ([[Slam your shield on the ground, doing %d%% damage in a radius of %d.]]) + :format(100 * self:combatTalentWeaponDamage(t, 1.3, 2.6), self:getTalentRadius(t)) + end, +} diff --git a/game/modules/tome/data/talents/spells/spells.lua b/game/modules/tome/data/talents/spells/spells.lua index 352e5e0a1dbd460c930c602cc414bd423b787b9a..7c019bb2b35cfe923d0c5dfc25346ff54639716f 100644 --- a/game/modules/tome/data/talents/spells/spells.lua +++ b/game/modules/tome/data/talents/spells/spells.lua @@ -52,6 +52,9 @@ newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="spell/st newTalentType{ type="golem/fighting", name = "fighting", description = "Golem melee capacity." } newTalentType{ type="golem/arcane", name = "arcane", description = "Golem arcane capacity." } +-- Stone Warden spells +newTalentType{ allow_random=true, no_silence=true, is_spell=true, type="spell/arcane-shield", name = "arcane shield", description = "Infuse arcane forces in your shield." } + -- Generic requires for spells based on talent level spells_req1 = { stat = { mag=function(level) return 12 + (level-1) * 2 end }, @@ -119,3 +122,5 @@ load("/data/talents/spells/staff-combat.lua") load("/data/talents/spells/fire-alchemy.lua") load("/data/talents/spells/stone-alchemy.lua") load("/data/talents/spells/golem.lua") + +load("/data/talents/spells/arcane-shield.lua") diff --git a/game/modules/tome/data/timed_effects.lua b/game/modules/tome/data/timed_effects.lua index 31bcf9ffc8c297c722ead5e6d432f4649b47d1e1..c0e8a73420c4ee3036fe3377d3086493262badba 100644 --- a/game/modules/tome/data/timed_effects.lua +++ b/game/modules/tome/data/timed_effects.lua @@ -435,7 +435,7 @@ newEffect{ eff.tmpid = self:addTemporaryValue("never_move", 1) end, on_timeout = function(self, eff) - if math.floor(core.fov.distance(self.x, self.y, eff.src.x, eff.src.y)) > 1 or eff.src.dead then + if math.floor(core.fov.distance(self.x, self.y, eff.src.x, eff.src.y)) > 1 or eff.src.dead or not game.level:hasEntity(eff.src) then return true end self:suffocate(eff.power, eff.src) @@ -2961,7 +2961,7 @@ newEffect{ on_gain = function(self, err) return "#Target# speeds up.", "+Quick" end, on_lose = function(self, err) return "#Target# slows down.", "-Quick" end, activate = function(self, eff) - eff.tmpid = self:addTemporaryValue("movement_speed", {mod=eff.power}) + eff.tmpid = self:addTemporaryValue("movement_speed", eff.power) end, deactivate = function(self, eff) self:removeTemporaryValue("movement_speed", eff.tmpid) @@ -3841,3 +3841,42 @@ newEffect{ self:removeTemporaryValue("movement_speed", eff.tmpid) end, } + +newEffect{ + name = "STONE_VINE", + desc = "Stone Vine", + long_desc = function(self, eff) return ("A living stone vine holds the target on the ground and doing %0.2f physical damage per turn."):format(eff.dam) end, + type = "physical", + status = "detrimental", + parameters = { dam=10 }, + on_gain = function(self, err) return "#Target# is grabbed by a stone vine.", "+Stone Vine" end, + on_lose = function(self, err) return "#Target# is free from the stone vine.", "-Stone Vine" end, + activate = function(self, eff) + eff.last_x = eff.src.x + eff.last_y = eff.src.y + eff.tmpid = self:addTemporaryValue("never_move", 1) + eff.particle = self:addParticles(Particles.new("stonevine_static", 1, {})) + end, + deactivate = function(self, eff) + self:removeTemporaryValue("never_move", eff.tmpid) + self:removeParticles(eff.particle) + end, + on_timeout = function(self, eff) + local severed = false + if math.floor(core.fov.distance(self.x, self.y, eff.src.x, eff.src.y)) >= eff.free or eff.src.dead or not game.level:hasEntity(eff.src) then severed = true end + if rng.percent(eff.free_chance) then severed = true end + + if severed then + return true + else + DamageType:get(DamageType.PHYSICAL).projector(eff.src or self, self.x, self.y, DamageType.PHYSICAL, eff.dam) + if eff.src:knowTalent(eff.src.T_ELDRITCH_VINE) then + local l = eff.src:getTalentLevel(eff.src.T_ELDRITCH_VINE) + eff.src:incEquilibrium(-l / 4) + eff.src:incMana(l / 3) + end + end + eff.last_x = eff.src.x + eff.last_y = eff.src.y + end, +} diff --git a/game/modules/tome/data/zones/reknor-escape/npcs.lua b/game/modules/tome/data/zones/reknor-escape/npcs.lua index 89f499ac3942366c0af41bdc6bc341c1c5f9519e..ad3e2062cb15b84e7139f1889d4ccffe5c9d5b56 100644 --- a/game/modules/tome/data/zones/reknor-escape/npcs.lua +++ b/game/modules/tome/data/zones/reknor-escape/npcs.lua @@ -71,7 +71,7 @@ newEntity{ define_as = "BROTOQ", -- Your ally newEntity{ define_as = "NORGAN", type = "humanoid", subtype = "dwarf", unique = true, - name = "Norgan", + name = "Norgan", image = "player/dwarf_male.png", display = "@", color=colors.UMBER, faction = "iron-throne", desc = [[Norgan and you are the sole survivors of the Reknor expedition, your duty is to make sure the news come back to the Iron Council.]], diff --git a/game/modules/tome/data/zones/rhaloren-camp/npcs.lua b/game/modules/tome/data/zones/rhaloren-camp/npcs.lua index 940fd9df397857788e16dc416543e13c8fbfe194..6006b6d000bb5196c7334857ff593723b0318e89 100644 --- a/game/modules/tome/data/zones/rhaloren-camp/npcs.lua +++ b/game/modules/tome/data/zones/rhaloren-camp/npcs.lua @@ -31,8 +31,8 @@ newEntity{ define_as = "INQUISITOR", allow_infinite_dungeon = true, type = "humanoid", subtype = "elf", unique = true, name = "Rhaloren Inquisitor", - display = "p", color=colors.VIOLET, - desc = [[This tall elf rush to you, wielding both his greatsword and magical spells.]], + display = "p", color=colors.VIOLET, female = true, + desc = [[This tall elf rush to you, wielding both her greatsword and magical spells.]], level_range = {7, nil}, exp_worth = 2, max_life = 150, life_rating = 15, fixed_rating = true, rank = 4, diff --git a/game/modules/tome/resolvers.lua b/game/modules/tome/resolvers.lua index 2a43b3a5c9b44d7e079c5103b9b2aaeb90f4b365..6fa26a75d061afc3a64980ac03d52408d96dffde 100644 --- a/game/modules/tome/resolvers.lua +++ b/game/modules/tome/resolvers.lua @@ -530,3 +530,13 @@ function resolvers.calc.emote_random(t, e) end return def end + +function resolvers.nice_tile(def) + return {__resolver="nice_tile", def} +end +function resolvers.calc.nice_tile(t, e) + if engine.Map.tiles.nicer_tiles then + table.merge(e, t[1]) + end + return nil +end diff --git a/ideas/DLCs.ods b/ideas/DLCs.ods index 540891dc99367fa124192ebb74eaf789cf4fe578..574c9bde3d447f47500279037b7f23c37e6de32b 100644 Binary files a/ideas/DLCs.ods and b/ideas/DLCs.ods differ diff --git a/ideas/gifts.ods b/ideas/gifts.ods index dda424ad2b63212f47bfb6f43c4b1d961a1039f1..2838eca7b6fa49da33d8a4deebb83c1fa40f5dd7 100644 Binary files a/ideas/gifts.ods and b/ideas/gifts.ods differ diff --git a/ideas/spells.ods b/ideas/spells.ods index 8e18a080a028a93e25d61023426bf6128bfafc6b..713e083834f0693c4e52e1381145b8a1e420842f 100644 Binary files a/ideas/spells.ods and b/ideas/spells.ods differ