diff --git a/game/engines/default/engine/Store.lua b/game/engines/default/engine/Store.lua index e2caaa818a3291b8e3180efaaf0ed45e6ccdbc18..cec31a6b21087ba2a865fd3f0706605417264b12 100644 --- a/game/engines/default/engine/Store.lua +++ b/game/engines/default/engine/Store.lua @@ -86,7 +86,7 @@ function _M:interact(who) else if o:getNumber() > 1 then local q - q = GetQuantity.new(nil, nil, o:getNumber(), o:getNumber(), function(qty) print("plop", qty) self:doSell(who, o, item, qty, d) end) + q = GetQuantity.new(nil, nil, o:getNumber(), o:getNumber(), function(qty) self:doSell(who, o, item, qty, d) end) game:registerDialog(q) else self:doSell(who, o, item, 1, d) @@ -100,22 +100,23 @@ function _M:interact(who) game:registerDialog(d) end +function _M:transfer(src, dest, item, nb) + local src_inven, dest_inven = src:getInven("INVEN"), dest:getInven("INVEN") + for i = 1, nb do + local o = src:removeObject(src_inven, item) + dest:addObject(dest_inven, o) + end + self:sortInven(store) + who:sortInven(inven) +end + function _M:doBuy(who, o, item, nb, store_dialog) - local max_nb = o:getNumber() - nb = math.min(nb, max_nb) + nb = math.min(nb, o:getNumber()) nb = self:tryBuy(who, o, item, nb) if nb then Dialog:yesnoPopup("Buy", ("Buy %d %s"):format(nb, o:getName{do_color=true, no_count=true}), function(ok) if ok then self:onBuy(who, o, item, nb, true) - local store, inven = self:getInven("INVEN"), who:getInven("INVEN") - for i = 1, nb do - local o = self:removeObject(store, item) - who:addObject(inven, o) - end - self:sortInven(store) - who:sortInven(inven) - self.changed = true - who.changed = true + self:transfer(self, who, item, nb) self:onBuy(who, o, item, nb, false) if store_dialog then store_dialog:updateStore() end end end, "Buy", "Cancel") @@ -123,21 +124,12 @@ function _M:doBuy(who, o, item, nb, store_dialog) end function _M:doSell(who, o, item, nb, store_dialog) - local max_nb = o:getNumber() - nb = math.min(nb, max_nb) + nb = math.min(nb, o:getNumber()) nb = self:trySell(who, o, item, nb) if nb then Dialog:yesnoPopup("Sell", ("Sell %d %s"):format(nb, o:getName{do_color=true, no_count=true}), function(ok) if ok then self:onSell(who, o, item, nb, true) - local store, inven = self:getInven("INVEN"), who:getInven("INVEN") - for i = 1, nb do - local o = who:removeObject(inven, item) - self:addObject(store, o) - end - self:sortInven(store) - who:sortInven(inven) - self.changed = true - who.changed = true + self:transfer(who, self, item, nb) self:onSell(who, o, item, nb, false) if store_dialog then store_dialog:updateStore() end end end, "Sell", "Cancel") diff --git a/game/engines/default/engine/interface/ActorInventory.lua b/game/engines/default/engine/interface/ActorInventory.lua index a7c4c1195329ff2d43592abc5979ee51751a9c9e..aba61105f80d35a89f98a1cda639b9847fae4bcb 100644 --- a/game/engines/default/engine/interface/ActorInventory.lua +++ b/game/engines/default/engine/interface/ActorInventory.lua @@ -409,6 +409,7 @@ function _M:sortInven(inven) return ta < tb end end) + self.changed = true end --- Finds an object by name in an inventory diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 90bc7fca4c52440f4a1bcad87cbfc4602f301702..510b3d1ffe332ec364d3abc8a88a45e4ad7b792b 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -292,6 +292,10 @@ function _M:move(x, y, force) end end end + if moved and self:isTalentActive(self.T_BODY_OF_STONE) then + self:forceUseTalent(self.T_BODY_OF_STONE, {ignore_energy=true}) + end + return moved end diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua index 1e9628b5bc684c0cff621aed262811676d57ddf5..b359d006504ed2ef8b389ca0b56be3bc3f5e1801 100644 --- a/game/modules/tome/class/NPC.lua +++ b/game/modules/tome/class/NPC.lua @@ -80,7 +80,7 @@ function _M:onTakeHit(value, src) self.ai_target.actor = src end - if Faction:get(self.faction) and Faction:get(self.faction).hostile_on_attack then + if src and Faction:get(self.faction) and Faction:get(self.faction).hostile_on_attack then Faction:setFactionReaction(self.faction, src.faction, Faction:factionReaction(self.faction, src.faction) - self.rank * 5, true) end @@ -88,7 +88,7 @@ function _M:onTakeHit(value, src) end function _M:die(src) - if Faction:get(self.faction) and Faction:get(self.faction).hostile_on_attack then + if src and Faction:get(self.faction) and Faction:get(self.faction).hostile_on_attack then Faction:setFactionReaction(self.faction, src.faction, Faction:factionReaction(self.faction, src.faction) - self.rank * 15, true) end diff --git a/game/modules/tome/class/Store.lua b/game/modules/tome/class/Store.lua index 299b977b631dc9036b42cf486848599f22bb94d2..d9a33b464800fc15afc3cdede1c3cb3452feacaa 100644 --- a/game/modules/tome/class/Store.lua +++ b/game/modules/tome/class/Store.lua @@ -30,7 +30,6 @@ function _M:loadStores(f) end function _M:init(t, no_default) - t.allow_sell = function() Dialog:simplePopup("Can not sell", "Do you really think I will buy your filthy wreckages found in the wilds? Ah!") end t.buy_percent = t.buy_percent or 10 t.sell_percent = t.sell_percent or 100 Store.init(self, t, no_default) @@ -47,7 +46,7 @@ end function _M:tryBuy(who, o, item, nb) local price = o:getPrice() * self.sell_percent / 100 if who.money >= price * nb then - return nb + return nb, price * nb --FINISH ME !!!! else Dialog:simplePopup("Not enough gold", "You do not have enough gold!") end @@ -62,7 +61,7 @@ end function _M:trySell(who, o, item, nb) local price = o:getPrice() * self.buy_percent / 100 if price <= 0 or nb <= 0 then return end - return nb + return nb, price end --- Called on object purchase @@ -95,6 +94,34 @@ function _M:onSell(who, o, item, nb, before) who:incMoney(price * nb) end +--- Override the default +function _M:doBuy(who, o, item, nb, store_dialog) + nb = math.min(nb, o:getNumber()) + nb = self:tryBuy(who, o, item, nb) + if nb then + Dialog:yesnoPopup("Buy", ("Buy %d %s for %0.2f gold"):format(nb, o:getName{do_color=true, no_count=true}), function(ok) if ok then + self:onBuy(who, o, item, nb, true) + self:transfer(self, who, item, nb) + self:onBuy(who, o, item, nb, false) + if store_dialog then store_dialog:updateStore() end + end end, "Buy", "Cancel") + end +end + +--- Override the default +function _M:doSell(who, o, item, nb, store_dialog) + nb = math.min(nb, o:getNumber()) + nb = self:trySell(who, o, item, nb) + if nb then + Dialog:yesnoPopup("Sell", ("Sell %d %s for %0.2f gold"):format(nb, o:getName{do_color=true, no_count=true}), function(ok) if ok then + self:onSell(who, o, item, nb, true) + self:transfer(who, self, item, nb) + self:onSell(who, o, item, nb, false) + if store_dialog then store_dialog:updateStore() end + end end, "Sell", "Cancel") + end +end + --- Called to describe an object, being to sell or to buy -- @param who the actor -- @param what either "sell" or "buy" diff --git a/game/modules/tome/data/birth/classes/mage.lua b/game/modules/tome/data/birth/classes/mage.lua index e562350f42326f0f857f94100885b86b8430ad7a..2a3c94ef011e4cad0938d169849bc2ad71545ab8 100644 --- a/game/modules/tome/data/birth/classes/mage.lua +++ b/game/modules/tome/data/birth/classes/mage.lua @@ -33,6 +33,7 @@ newBirthDescriptor{ Pyromancer = function() return profile.mod.allow_build.mage_pyromancer and "allow" or "disallow" end, Cryomancer = function() return profile.mod.allow_build.mage_cryomancer and "allow" or "disallow" end, Tempest = function() return profile.mod.allow_build.mage_tempest and "allow" or "disallow" end, + Geomancer = function() return profile.mod.allow_build.mage_geomancer and "allow" or "disallow" end, }, }, copy = { @@ -318,3 +319,54 @@ newBirthDescriptor{ life_rating = -4, }, } + +newBirthDescriptor{ + type = "subclass", + name = "Geomancer", + desc = { + "A Geomancer is an archmage specialized in earth and stone magic.", + "They gain access to the special Stone talents whose main purpose is to crush and destroy.", + "They can even learn to pierce through physical resistance and immunity.", + "Most archmagi lack basic skills that others take for granted (like general fighting sense), but they make up for it by their raw magical power.", + "Archmagi know all schools of magic but the more intricate (Temporal and Meta) from the start. They however usually refuse to have anything to do with Necromancy.", + "All archmagi have been trained in the secret town of Angolwen and posses a unique spell to teleport to it directly.", + "Their most important stats are: Magic and Willpower", + "#GOLD#Stats modifiers:", + "#LIGHT_BLUE# * +0 Strength, +0 Dexterity, +0 Constitution", + "#LIGHT_BLUE# * +5 Magic, +3 Willpower, +1 Cunning", + }, + stats = { mag=5, wil=3, cun=1, }, + talents_types = { + ["spell/arcane"]={true, 0.2}, + ["spell/earth"]={true, 0.3}, + ["spell/stone"]={true, 0.4}, + ["spell/water"]={true, 0.2}, + ["spell/phantasm"]={true, 0.3}, + ["spell/temporal"]={false, 0.3}, + ["spell/meta"]={false, 0.3}, + ["spell/divination"]={true, 0.3}, + ["spell/conveyance"]={true, 0.3}, + ["cunning/survival"]={false, -0.1}, + }, + talents = { + [ActorTalents.T_ARCANE_POWER] = 1, + [ActorTalents.T_STONE_SKIN] = 1, + [ActorTalents.T_STALACTITIC_MISSILES] = 1, + [ActorTalents.T_PHASE_DOOR] = 1, + [ActorTalents.T_TELEPORT_ANGOLWEN]=1, + }, + copy = { + -- All mages are of angolwen faction + faction = "angolwen", + max_life = 90, + life_rating = -4, + resolvers.equip{ id=true, + {type="weapon", subtype="staff", name="elm staff", autoreq=true}, + {type="armor", subtype="cloth", name="linen robe", autoreq=true}, + }, + resolvers.inventory{ id=true, + {type="potion", subtype="potion", name="potion of lesser mana", ego_chance=-1000}, + {type="potion", subtype="potion", name="potion of lesser mana", ego_chance=-1000}, + }, + }, +} diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua index 07b986124245edeba186a042e4540f39bc8c4393..5c0b6f36b9659d801e1bd3c380936767b0b366df 100644 --- a/game/modules/tome/data/damage_types.lua +++ b/game/modules/tome/data/damage_types.lua @@ -841,3 +841,34 @@ newDamageType{ hideMessage=true, hideFlyer=true } + +-- Physical + Stun Chance +newDamageType{ + name = "physical stun", type = "PHYSICAL_STUN", + projector = function(src, x, y, type, dam) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam) + local target = game.level.map(x, y, Map.ACTOR) + if target and rng.percent(25) then + if target:checkHit(src:combatSpellpower(), target:combatSpellResist(), 0, 95, 15) and target:canBe("stun") then + target:setEffect(target.EFF_STUNNED, 2, {src=src}) + else + game.logSeen(target, "%s resists!", target.name:capitalize()) + end + end + end, +} + +-- Physical Damage/Cut Split +newDamageType{ + name = "split bleed", type = "SPLIT_BLEED", + projector = function(src, x, y, type, dam) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 12) + dam = dam - dam / 12 + local target = game.level.map(x, y, Map.ACTOR) + if target and target:canBe("cut") then + -- Set on fire! + target:setEffect(target.EFF_CUT, 5, {src=src, power=dam / 11}) + end + end, +} diff --git a/game/modules/tome/data/general/grids/sand.lua b/game/modules/tome/data/general/grids/sand.lua index fb83ee1d48f013c41b5ea611535de9531fe901c0..4bfd4354e7967aff82091aca5d39cedd87b15291 100644 --- a/game/modules/tome/data/general/grids/sand.lua +++ b/game/modules/tome/data/general/grids/sand.lua @@ -50,7 +50,7 @@ newEntity{ if a then game.logPlayer(a, "You are crushed by the collapsing tunnel! You suffocate!") a:suffocate(30, self) - engine.DamageType:get(engine.DamageType.PHYSICAL).projector(self, self.x, self.y, engine.DamageType.PHYSICAL, a.life / 2) + engine.DamageType:get(engine.DamageType.PHYSICAL).projector(self, self.x, self.y, engine.DamageType.PHYSICAL, a.life / 4) end end end diff --git a/game/modules/tome/data/gfx/particles/crystalline_focus.lua b/game/modules/tome/data/gfx/particles/crystalline_focus.lua new file mode 100644 index 0000000000000000000000000000000000000000..185190aa714f9fd9c74f89616780f6565803378e --- /dev/null +++ b/game/modules/tome/data/gfx/particles/crystalline_focus.lua @@ -0,0 +1,45 @@ +-- ToME - Tales of Middle-Earth +-- Copyright (C) 2009, 2010 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 + +return { generator = function() + local ad = rng.range(0, 360) + local a = math.rad(ad) + local dir = math.rad(ad) + local r = rng.range(18, 22) + local dirchance = rng.chance(2) + + return { + life = 20, + size = 4, sizev = -0.05, sizea = 0, + + x = r * math.cos(a), xv = 0, xa = 0, + y = r * math.sin(a), yv = 0, ya = 0, + dir = dir, dirv = 0.1, dira = 0, + vel = dirchance and 0.2 or -0.2, velv = 0, vela = dirchance and -0.02 or 0.02, + + r = rng.range(0, 0)/255, rv = rng.range(0, 10)/100, ra = 0, + g = rng.range(80, 200)/255, gv = 0.005, ga = 0.0005, + b = 0, bv = 0, ba = 0, + a = rng.range(70, 255)/255, av = 0, aa = 0, + } +end, }, +function(self) + self.ps:emit(4) +end, +80 diff --git a/game/modules/tome/data/gfx/particles/quake.lua b/game/modules/tome/data/gfx/particles/quake.lua new file mode 100644 index 0000000000000000000000000000000000000000..d83f105e6a1a7000262b5893a7635d0a21d36579 --- /dev/null +++ b/game/modules/tome/data/gfx/particles/quake.lua @@ -0,0 +1,46 @@ +-- ToME - Tales of Middle-Earth +-- Copyright (C) 2009, 2010 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 + +return { generator = function() + local ad = rng.range(0, 360) + local a = math.rad(ad) + local dir = math.rad(ad + 90) + local r = rng.range(1, 20) + local dirv = math.rad(1) + + return { + trail = 1, + life = 10, + size = 1, sizev = 0.5, sizea = 0, + + x = r * math.cos(a), xv = -0.1, xa = 0, + y = r * math.sin(a), yv = -0.1, ya = 0, + dir = math.rad(rng.range(0, 360)), dirv = 0, dira = 0, + vel = 0.1, velv = 0, vela = 0, + + r = rng.range(200, 230)/255, rv = 0, ra = 0, + g = rng.range(130, 160)/255, gv = 0, ga = 0, + b = rng.range(50, 70)/255, bv = 0, ba = 0, + a = rng.range(25, 220)/255, av = 0, aa = 0, + } +end, }, +function(self) + self.ps:emit(4) +end, +40 diff --git a/game/modules/tome/data/gfx/particles/stone_shards.lua b/game/modules/tome/data/gfx/particles/stone_shards.lua new file mode 100644 index 0000000000000000000000000000000000000000..c9e70e781bc2d033f31fa66d844c4bba1584d8c6 --- /dev/null +++ b/game/modules/tome/data/gfx/particles/stone_shards.lua @@ -0,0 +1,50 @@ +-- ToME - Tales of Middle-Earth +-- Copyright (C) 2009, 2010 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +local starts = {} +for i = 1, 4 do + starts[#starts+1] = { a = math.rad(rng.range(0, 360)), r = rng.range(6, 20) } +end + +-- Populate the beam based on the forks +return { generator = function() + local rad = rng.range(-3,3) + local s = rng.table(starts) + local ra = s.a + local r = s.r + + return { + life = 4, + size = rng.range(4, 6), sizev = -0.1, sizea = 0, + + x = 2 * math.cos(ra), xv = 0, xa = 0, + y = 2 * math.sin(ra), 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(30 * 4) +end, +4*30*4 diff --git a/game/modules/tome/data/lore/tol-falas.lua b/game/modules/tome/data/lore/tol-falas.lua index 7818208be70323eb14e40fc3ea37f75b2c6485dd..77221ba37546288ee7acec15a7c487d146aff365 100644 --- a/game/modules/tome/data/lore/tol-falas.lua +++ b/game/modules/tome/data/lore/tol-falas.lua @@ -26,7 +26,7 @@ newLore{ name = "note from the Master", lore = [[MINIONS: Perhaps you feel your Master has been lax or absent? Well, I shall amend that. I have been studying an object of great import. It is of much greater interest than your foolish unlives. But do not think that I will let you get away with things because of this. -Skeletons, you have been getting noticeably behind in your adventurer slaughtering quotas. The next skeleton archer I see drinking coffee and chatting with the wights shall be rended limb from limb and fed to the orcs. Also, as a punishment for your general laxness, 1,000 skeletons shall be remanded down to Amun Sul as punishment. A further 250 shall be slaughtered. These orders to be carried out by myself tomorrow at 3am.]], +Skeletons, you have been getting noticeably behind in your adventurer slaughtering quotas. The next skeleton archer I see drinking coffee and chatting with the wights shall be rent limb from limb and fed to the orcs. Also, as a punishment for your general laxness, 1,000 skeletons shall be remanded down to Amun Sul as punishment. A further 250 shall be slaughtered. These orders to be carried out by myself tomorrow at 3am.]], } newLore{ diff --git a/game/modules/tome/data/talents/spells/spells.lua b/game/modules/tome/data/talents/spells/spells.lua index 20ef23ac389623079ebe954b45260a8716cbe386..8ccf812714df89451baf44bfebc11d2b6a442850 100644 --- a/game/modules/tome/data/talents/spells/spells.lua +++ b/game/modules/tome/data/talents/spells/spells.lua @@ -24,6 +24,7 @@ newTalentType{ no_silence=true, is_spell=true, type="spell/arcane", name = "arca newTalentType{ no_silence=true, is_spell=true, type="spell/fire", name = "fire", description = "Harness the power of fire to burn your foes to ashes." } newTalentType{ no_silence=true, is_spell=true, type="spell/wildfire", name = "wildfire", description = "Harness the power of wildfire to burn your foes to ashes." } newTalentType{ no_silence=true, is_spell=true, type="spell/earth", name = "earth", description = "Harness the power of the earth to protect and destroy." } +newTalentType{ no_silence=true, is_spell=true, type="spell/stone", name = "stone", description = "Harness the power of the stone to protect and destroy." } newTalentType{ no_silence=true, is_spell=true, type="spell/water", name = "water", description = "Harness the power of water to drown your foes." } newTalentType{ no_silence=true, is_spell=true, type="spell/ice", name = "ice", description = "Harness the power of ice to freeze and shatter your foes." } newTalentType{ no_silence=true, is_spell=true, type="spell/air", name = "air", description = "Harness the power of the air to fry your foes." } @@ -75,6 +76,7 @@ load("/data/talents/spells/arcane.lua") load("/data/talents/spells/fire.lua") load("/data/talents/spells/wildfire.lua") load("/data/talents/spells/earth.lua") +load("/data/talents/spells/stone.lua") load("/data/talents/spells/water.lua") load("/data/talents/spells/ice.lua") load("/data/talents/spells/air.lua") diff --git a/game/modules/tome/data/talents/spells/stone.lua b/game/modules/tome/data/talents/spells/stone.lua new file mode 100644 index 0000000000000000000000000000000000000000..096e56f58b4f2124b96dda9eec845692688060f8 --- /dev/null +++ b/game/modules/tome/data/talents/spells/stone.lua @@ -0,0 +1,189 @@ +-- ToME - Tales of Middle-Earth +-- Copyright (C) 2009, 2010 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 = "Stalactitic Missiles", + type = {"spell/stone",1}, + require = spells_req1, + points = 5, + random_ego = "attack", + mana = 10, + cooldown = 3, + tactical = { + ATTACK = 10, + }, + range = 20, + direct_hit = true, + reflectable = true, + proj_speed = 20, + requires_target = true, + action = function(self, t) + local tg = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="stone_shards", trail="earthtrail"}} + local x, y = self:getTarget(tg) + if not x or not y then return nil end + self:projectile(tg, x, y, DamageType.SPLIT_BLEED, self:spellCrit(self:combatTalentSpellDamage(t, 20, 120)), nil) + game:playSoundNear(self, "talents/earth") + --missile #2 (Talent Level 3 Bonus Missile) + if self:getTalentLevel(t) >= 3 then + local tg2 = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="stone_shards", trail="earthtrail"}} + local x, y = self:getTarget(tg2) + if not x or not y then return nil end + self:projectile(tg2, x, y, DamageType.SPLIT_BLEED, self:spellCrit(self:combatTalentSpellDamage(t, 20, 120)), nil) + game:playSoundNear(self, "talents/earth") + else end + --missile #3 (Talent Level 5 Bonus Missile) + if self:getTalentLevel(t) >= 5 then + local tg3 = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="stone_shards", trail="earthtrail"}} + local x, y = self:getTarget(tg3) + if not x or not y then return nil end + self:projectile(tg3, x, y, DamageType.SPLIT_BLEED, self:spellCrit(self:combatTalentSpellDamage(t, 20, 120)), nil) + game:playSoundNear(self, "talents/earth") + else end + return true + end, + info = function(self, t) + return ([[Conjures stalactite shaped rocks that you fire individually at any target or targets in range. Each missile deals %0.2f physical damage and an additional %0.2f bleeding damage over six turns. + At talent level 1 you conjure a single missile, at talent level 3 two missiles, and at talent level 5 three missiles. + The damage will increase with the Magic stat]]):format(damDesc(self, DamageType.PHYSICAL, self:combatTalentSpellDamage(t, 20, 120)/2), damDesc(self, DamageType.PHYSICAL, self:combatTalentSpellDamage(t, 20, 120)/2)) + end, +} + +newTalent{ + name = "Body of Stone", + type = {"spell/stone",2}, + require = spells_req2, + points = 5, + mode = "sustained", + sustain_mana = 70, + cooldown = 12, + activate = function(self, t) + local fire = self:combatTalentSpellDamage(t, 5, 80) + local light = self:combatTalentSpellDamage(t, 5, 50) + local phys = self:combatTalentSpellDamage(t, 5, 20) + local kb = self:getTalentLevel(t)/10 + local cdr = self:getTalentLevel(t)/2 + local rad = 5 + self:combatSpellpower(0.1) * self:getTalentLevel(t) + game:playSoundNear(self, "talents/earth") + return { + particle = self:addParticles(Particles.new("stone_skin", 1)), + move = self:addTemporaryValue("never_move", 1), + knock = self:addTemporaryValue("knockback_immune", kb), + detect = self:addTemporaryValue("detect_range", rad), + tremor = self:addTemporaryValue("detect_actor", 1), + cdred = self:addTemporaryValue("talent_cd_reduction", { + [self.T_STALACTITIC_MISSILES] = cdr, + [self.T_STRIKE] = cdr, + [self.T_EARTHQUAKE] = cdr, + }), + res = self:addTemporaryValue("resists", { + [DamageType.FIRE] = fire, + [DamageType.LIGHTNING] = light, + [DamageType.PHYSICAL] = phys, + }), + } + end, + deactivate = function(self, t, p) + self:removeParticles(p.particle) + self:removeTemporaryValue("never_move", p.move) + self:removeTemporaryValue("knockback_immune", p.knock) + self:removeTemporaryValue("detect_actor", p.tremor) + self:removeTemporaryValue("detect_range", p.detect) + self:removeTemporaryValue("talent_cd_reduction", p.cdred) + self:removeTemporaryValue("resists", p.res) + return true + end, + info = function(self, t) + return ([[You root yourself into the earth and transform your flesh into stone. While this spell is sustained you may not move and any forced movement will end the effect. + Your stoned form and your affinity with the earth while the spell is active has the following effects: + * Reduces the cooldown of Stalactitic Missiles, Earthquake, and Strike by %d + * Grants %d%% Fire Resistance, %d%% Lightning Resistance, %d%% Physical Resistance, and %d%% Knockback Resistance + * Sense foes around you in a radius of %d. + Resistances and Sense radius scale with the Magic Stat.]]) + :format((self:getTalentLevel(t)/2), self:combatTalentSpellDamage(t, 5, 80), self:combatTalentSpellDamage(t, 5, 50), self:combatTalentSpellDamage(t, 5, 20), (self:getTalentLevel(t)*10), (5 + self:combatSpellpower(0.1) * self:getTalentLevel(t))) + end, +} + +newTalent{ + name = "Earthquake", + type = {"spell/stone",3}, + require = spells_req3, + points = 5, + random_ego = "attack", + mana = 50, + cooldown = 30, + tactical = { + ATTACKAREA = 40, + }, + range = 20, + direct_hit = true, + requires_target = true, + action = function(self, t) + local duration = 3 + self:getTalentLevel(t) + local radius = 2 + (self:getTalentLevel(t)/2) + local dam = self:combatTalentSpellDamage(t, 15, 70) + local tg = {type="ball", range=self:getTalentRange(t), radius=radius} + 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, duration, + DamageType.PHYSICAL_STUN, dam, + radius, + 5, nil, + {type="quake"}, + nil, self:spellFriendlyFire() + ) + + game:playSoundNear(self, "talents/earth") + return true + end, + info = function(self, t) + return ([[Causes a violent earthquake that deals %0.2f physical damage in a radius of %d each turn for %d turns and potentially stuns all creatures it affects. + The damage and duration will increase with the Magic stat]]):format(damDesc(self, DamageType.PHYSICAL, self:combatTalentSpellDamage(t, 15, 70)), 2 + (self:getTalentLevel(t)/2), 3 + self:getTalentLevel(t)) + end, +} + +newTalent{ + name = "Crystalline Focus", + type = {"spell/stone",4}, + require = spells_req4, + points = 5, + mode = "sustained", + sustain_mana = 80, + cooldown = 30, + activate = function(self, t) + game:playSoundNear(self, "talents/earth") + return { + dam = self:addTemporaryValue("inc_damage", {[DamageType.PHYSICAL] = self:getTalentLevelRaw(t) * 2}), + resist = self:addTemporaryValue("resists_pen", {[DamageType.PHYSICAL] = self:getTalentLevelRaw(t) * 10}), + particle = self:addParticles(Particles.new("crystalline_focus", 1)), + } + end, + deactivate = function(self, t, p) + self:removeParticles(p.particle) + self:removeTemporaryValue("inc_damage", p.dam) + self:removeTemporaryValue("resists_pen", p.resist) + return true + end, + info = function(self, t) + return ([[Concentrate on maintaining a Crystalline Focus, increasing all your physical damage by %d%% and ignoring %d%% physical resistance of your targets.]]) + :format(self:getTalentLevelRaw(t) * 2, self:getTalentLevelRaw(t) * 10) + end, +}