Skip to content
Snippets Groups Projects
Commit ffd75a5f authored by dg's avatar dg
Browse files

New Summoning Advanced tree for summoners

git-svn-id: http://svn.net-core.org/repos/t-engine4@4622 51575b47-30f0-44d4-a5cc-537603b46e54
parent a70b5061
No related branches found
No related tags found
No related merge requests found
Showing
with 522 additions and 16 deletions
......@@ -2796,7 +2796,9 @@ function _M:getTalentCooldown(t)
if self.talent_cd_reduction[t.id] then cd = cd - self.talent_cd_reduction[t.id] end
if self.talent_cd_reduction.all then cd = cd - self.talent_cd_reduction.all end
if t.is_spell then
return math.ceil(cd * (1 - self.spell_cooldown_reduction or 0))
return math.ceil(cd * (1 - (self.spell_cooldown_reduction or 0)))
elseif t.is_summon then
return math.ceil(cd * (1 - (self.summon_cooldown_reduction or 0)))
else
return cd
end
......
......@@ -561,7 +561,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
if hitted and game.level.data.zero_gravity and rng.percent(util.bound(dam, 0, 100)) then
target:knockback(self.x, self.y, math.ceil(math.log(dam)))
end
if hitted and not target.dead then
-- Curse of Madness: Twisted Mind
if self.hasEffect and self:hasEffect(self.EFF_CURSE_OF_MADNESS) then
......@@ -574,7 +574,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam)
local def = target.tempeffect_def[target.EFF_CURSE_OF_MADNESS]
def.doConspirator(target, eff, self)
end
-- Curse of Nightmares: Suffocate
if self.hasEffect and self:hasEffect(self.EFF_CURSE_OF_NIGHTMARES) then
local eff = self:hasEffect(self.EFF_CURSE_OF_NIGHTMARES)
......@@ -899,7 +899,7 @@ function _M:getOffHandMult(mult)
offmult = offmult + ((mult or 1) * def.getOffHandMultChange(eff.level) / 100)
end
end
return offmult
end
......@@ -919,6 +919,11 @@ function _M:combatSpellSpeed()
return 1 / self.combat_spellspeed
end
--- Gets mindcrit
function _M:combatMindCrit()
return self.combat_mindcrit + (self:getCun() - 10) * 0.3 + (self:getLck() - 50) * 0.30 + 1
end
--- Gets summon speed
function _M:combatSummonSpeed()
return math.max(1 - ((self:attr("fast_summons") or 0) / 100), 0.1)
......@@ -1008,6 +1013,24 @@ function _M:spellFriendlyFire()
return chance
end
--- Computes mind crit for a damage
function _M:mindCrit(dam, add_chance)
if self:isTalentActive(self.T_STEALTH) and self:knowTalent(self.T_SHADOWSTRIKE) then
return dam * (1.5 + self:getTalentLevel(self.T_SHADOWSTRIKE) / 7), true
end
local chance = self:combatMindCrit() + (add_chance or 0)
local crit = false
print("[MIND CRIT %]", chance)
if rng.percent(chance) then
dam = dam * (1.5 + (self.combat_critical_power or 0) / 100)
crit = true
game.logSeen(self, "#{bold}#%s's power attains critical effect!#{normal}#", self.name:capitalize())
end
return dam, crit
end
--- Gets mindpower
function _M:combatMindpower(mod)
mod = mod or 1
......@@ -1172,7 +1195,7 @@ function _M:hasCursedWeapon()
end
local t = self:getTalentFromId(self.T_DEFILING_TOUCH)
if not t.canCurseItem(self, t, weapon) then return nil end
return weapon
end
......@@ -1189,7 +1212,7 @@ function _M:hasCursedOffhandWeapon()
end
local t = self:getTalentFromId(self.T_DEFILING_TOUCH)
if not t.canCurseItem(self, t, weapon) then return nil end
return weapon
end
......
......@@ -66,6 +66,7 @@ newBirthDescriptor{
["wild-gift/summon-distance"]={true, 0.3},
["wild-gift/summon-utility"]={true, 0.3},
["wild-gift/summon-augmentation"]={false, 0.3},
["wild-gift/summon-advanced"]={false, 0.3},
["cunning/survival"]={true, 0},
["technique/combat-techniques-active"]={false, 0},
["technique/combat-techniques-passive"]={false, 0},
......
......@@ -810,6 +810,27 @@ newDamageType{
end,
}
-- Fireburn damage + repulsion; checks for mind power against physical resistance
newDamageType{
name = "fire knockback mind", type = "FIREKNOCKBACK_MIND",
projector = function(src, x, y, type, dam, tmp)
local target = game.level.map(x, y, Map.ACTOR)
if _G.type(dam) ~= "table" then dam = {dam=dam, dist=3} end
tmp = tmp or {}
if target and not tmp[target] then
tmp[target] = true
DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam.dam)
if target:checkHit(src:combatMindpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then
target:knockback(src.x, src.y, dam.dist)
target:crossTierEffect(target.EFF_OFFBALANCE, src:combatMindpower())
game.logSeen(target, "%s is knocked back!", target.name:capitalize())
else
game.logSeen(target, "%s resists the punch!", target.name:capitalize())
end
end
end,
}
-- Darkness damage + repulsion; checks for spell power against mental resistance
newDamageType{
name = "darkness knockback", type = "DARKKNOCKBACK",
......@@ -893,6 +914,25 @@ newDamageType{
end,
}
-- Fear check + repulsion; checks for mind power against physical resistance
newDamageType{
name = "fear knockback", type = "FEARKNOCKBACK",
projector = function(src, x, y, type, dam, tmp)
local target = game.level.map(x, y, Map.ACTOR)
tmp = tmp or {}
if target and not tmp[target] then
tmp[target] = true
if target:checkHit(src:combatMindpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("fear") then
target:knockback(dam.x, dam.y, dam.dist)
target:crossTierEffect(target.EFF_BRAINLOCKED, src:combatMindpower())
game.logSeen(target, "%s is knocked back!", target.name:capitalize())
else
game.logSeen(target, "%s resists the frightening sight!", target.name:capitalize())
end
end
end,
}
-- Poisoning damage
newDamageType{
name = "poison", type = "POISON",
......@@ -1851,3 +1891,19 @@ newDamageType{
end
end,
}
-- Generic apply temporary effect
newDamageType{
name = "temp effect", type = "TEMP_EFFECT",
projector = function(src, x, y, type, dam)
local target = game.level.map(x, y, Map.ACTOR)
if target then
local ok = false
if dam.friends then if src:reactionToward(target) >= 0 then ok = true end
elseif dam.foes then if src:reactionToward(target) < 0 then ok = true end
else ok = true
end
if ok then target:setEffect(dam.eff, dam.dur, table.clone(dam.p)) end
end
end,
}
game/modules/tome/data/gfx/effects/lower_cold_resist.png

2.7 KiB

game/modules/tome/data/gfx/effects/lower_fire_resist.png

2.23 KiB

game/modules/tome/data/gfx/effects/lower_nature_resist.png

2.72 KiB

game/modules/tome/data/gfx/effects/lower_physical_resist.png

2.38 KiB

game/modules/tome/data/gfx/talents/grand_arrival.png

5.95 KiB

game/modules/tome/data/gfx/talents/master_summoner.png

4 KiB

game/modules/tome/data/gfx/talents/nature_cycle.png

5.34 KiB

game/modules/tome/data/gfx/talents/wild_summon.png

5.08 KiB

......@@ -55,6 +55,26 @@ gifts_req5 = {
stat = { wil=function(level) return 44 + (level-1) * 2 end },
level = function(level) return 16 + (level-1) end,
}
gifts_req_high1 = {
stat = { wil=function(level) return 22 + (level-1) * 2 end },
level = function(level) return 10 + (level-1) end,
}
gifts_req_high2 = {
stat = { wil=function(level) return 30 + (level-1) * 2 end },
level = function(level) return 14 + (level-1) end,
}
gifts_req_high3 = {
stat = { wil=function(level) return 38 + (level-1) * 2 end },
level = function(level) return 18 + (level-1) end,
}
gifts_req_high4 = {
stat = { wil=function(level) return 46 + (level-1) * 2 end },
level = function(level) return 22 + (level-1) end,
}
gifts_req_high5 = {
stat = { wil=function(level) return 54 + (level-1) * 2 end },
level = function(level) return 26 + (level-1) end,
}
load("/data/talents/gifts/call.lua")
load("/data/talents/gifts/harmony.lua")
......@@ -140,12 +160,31 @@ function setupSummon(self, m, x, y, no_control)
p.dur = p.dur - 1
if p.dur <= 0 then self:removeEffect(self.EFF_FRANTIC_SUMMONING) end
end
if m.wild_gift_detonate and self:isTalentActive(self.T_MASTER_SUMMONER) and self:knowTalent(self.T_GRAND_ARRIVAL) then
local dt = self:getTalentFromId(m.wild_gift_detonate)
if dt.on_arrival then
dt.on_arrival(self, self:getTalentFromId(self.T_GRAND_ARRIVAL), m)
end
end
if m.wild_gift_detonate and self:isTalentActive(self.T_MASTER_SUMMONER) and self:knowTalent(self.T_NATURE_CYCLE) then
local t = self:getTalentFromId(self.T_NATURE_CYCLE)
for _, tid in ipairs{self.T_RAGE, self.T_DETONATE, self.T_WILD_SUMMON} do
if self.talents_cd[tid] and rng.percent(t.getChance(self, t)) then
self.talents_cd[tid] = self.talents_cd[tid] - t.getReduction(self, t)
if self.talents_cd[tid] <= 0 then self.talents_cd[tid] = nil end
self.changed = true
end
end
end
end
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/summon-advanced.lua")
load("/data/talents/gifts/earthen-power.lua")
load("/data/talents/gifts/earthen-vines.lua")
-- 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 = "Master Summoner",
type = {"wild-gift/summon-advanced", 1},
require = gifts_req_high1,
mode = "sustained",
points = 5,
sustain_equilibrium = 20,
cooldown = 10,
range = 10,
tactical = { BUFF = 2 },
getCooldownReduction = function(self, t) return util.bound(self:getTalentLevelRaw(t) / 15, 0.05, 0.3) end,
activate = function(self, t)
game:playSoundNear(self, "talents/heal")
return {
cd = self:addTemporaryValue("summon_cooldown_reduction", t.getCooldownReduction(self, t)),
}
end,
deactivate = function(self, t, p)
self:removeTemporaryValue("summon_cooldown_reduction", p.cd)
return true
end,
info = function(self, t)
local cooldownred = t.getCooldownReduction(self, t)
return ([[Reduces the cooldown of all summons by %d%%.]]):
format(cooldownred * 100)
end,
}
newTalent{
name = "Grand Arrival",
type = {"wild-gift/summon-advanced", 2},
require = gifts_req_high2,
points = 5,
mode = "passive",
radius = function(self, t)
return 1 + math.floor(self:getTalentLevel(t) / 2)
end,
info = function(self, t)
local radius = self:getTalentRadius(t)
return ([[While Master Summoner is active, when a creature you summon appears in the world it will trigger a wild effect:
- Ritch Flamespitter: Reduce fire resistance of all foes in a radius
- Hydra: Generates a cloud of lingering poison
- Rimebark: Reduce cold resistance of all foes in a radius
- Fire Drake: Appears with one fire drake hatchling
- War Hound: Reduce physical resistance of all foes in a radius
- Jelly: Reduce nature resistance of all foes in a radius
- Minotaur: Reduces movement speed of all foes in a radius
- Stone Golem: Dazes all foes in a radius
- Turtle: Heals all friendly targets in a radius
- Spider: The spider is so hideous that foes around it are repelled
The effects improves with your Willpower.
Radius for effects is %d.]]):format(radius)
end,
}
newTalent{
name = "Nature's Cycle", short_name = "NATURE_CYCLE",
type = {"wild-gift/summon-advanced", 3},
require = gifts_req_high3,
mode = "passive",
points = 5,
getChance = function(self, t) return math.min(100, 30 + self:getTalentLevel(t) * 15) end,
getReduction = function(self, t) return math.ceil(self:getTalentLevel(t) / 2) end,
info = function(self, t)
return ([[While Master Summoner is active each new summons will reduce the remaining cooldown of Rage, Detonate and Wild Summon.
%d%% chance to reduce them by %d.]]):format(t.getChance(self, t), t.getReduction(self, t))
end,
}
newTalent{
name = "Wild Summon",
type = {"wild-gift/summon-advanced", 4},
require = gifts_req_high4,
points = 5,
equilibrium = 9,
cooldown = 25,
range = 10,
tactical = { BUFF = 5 },
no_energy = true,
on_pre_use = function(self, t, silent)
return self:isTalentActive(self.T_MASTER_SUMMONER)
end,
action = function(self, t)
self:setEffect(self.EFF_WILD_SUMMON, math.floor(self:getTalentLevel(t)), {chance=100})
game:playSoundNear(self, "talents/teleport")
return true
end,
info = function(self, t)
return ([[For %d turn(s) you have 100%% chance that your summons appear as a wild version.
Each turn the chance disminishes.
Wild creatures have one more talent/power than the base versions:
- Ritch Flamespitter: sends a blast of flames around it, knocking foes away
- Hydra: Can disengage from melee range
- Rimebark: Becomes more resistant to magic damage
- Fire Drake: Can emit a powerful roar to silence its foes
- War Hound: Can rage, inreasing its critical chance and armour penetration
- Jelly: Can swallow foes that are low on life, regenerating your equilibrium
- Minotaur: Can rush toward its target
- Stone Golem: Melee blows can deal a small area of effect damage
- Turtle: Can force all foes in a radius into melee range
- Spider: Can project an insidious poison at its foes, reducing their healing
This talent requires Master Summoner to be active to be used.]])
end,
}
......@@ -31,7 +31,7 @@ newTalent{ short_name = "RITCH_FLAMESPITTER_BOLT",
local tg = {type="bolt", range=self:getTalentRange(t), talent=t}
local x, y = self:getTarget(tg)
if not x or not y then return nil end
self:project(tg, x, y, DamageType.FIRE, self:spellCrit(self:combatTalentSpellDamage(t, 8, 120)), {type="flame"})
self:project(tg, x, y, DamageType.FIRE, self:mindCrit(self:combatTalentMindDamage(t, 8, 120)), {type="flame"})
game:playSoundNear(self, "talents/fire")
return true
end,
......@@ -41,6 +41,36 @@ newTalent{ short_name = "RITCH_FLAMESPITTER_BOLT",
end,
}
newTalent{
name = "Flame Fury", image = "talents/blastwave.png",
type = {"wild-gift/other",1},
points = 5,
eqilibrium = 5,
cooldown = 5,
tactical = { ATTACKAREA = 2, DISABLE = 2, ESCAPE = 2 },
direct_hit = true,
requires_target = true,
range = 0,
radius = function(self, t) return 1 + self:getTalentLevelRaw(t) end,
target = function(self, t)
return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
end,
getDamage = function(self, t) return self:combatTalentMindDamage(t, 28, 180) end,
action = function(self, t)
local tg = self:getTalentTarget(t)
local grids = self:project(tg, self.x, self.y, DamageType.FIREKNOCKBACK_MIND, {dist=3, dam=self:mindCrit(t.getDamage(self, t))})
game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_fire", {radius=tg.radius})
game:playSoundNear(self, "talents/fire")
return true
end,
info = function(self, t)
local damage = t.getDamage(self, t)
local radius = self:getTalentRadius(t)
return ([[A wave of fire emanates from you with radius %d, knocking back anything caught inside and setting them ablaze and doing %0.2f fire damage over 3 turns.
The damage will increase with your Mindpower.]]):format(radius, damDesc(self, DamageType.FIRE, damage))
end,
}
newTalent{
name = "Acid Breath",
type = {"wild-gift/other",1},
......@@ -199,6 +229,10 @@ newTalent{
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.FIREBURN, self:combatTalentMindDamage(t, 30, 300), {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.TEMP_EFFECT, {friends=true, eff=self.EFF_LOWER_FIRE_RESIST, dur=4+self:getTalentLevelRaw(t), p={power=self:combatTalentMindDamage(t, 15, 70)}}, {type="flame"})
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)
......@@ -224,7 +258,7 @@ newTalent{
ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10},
ai_tactic = resolvers.tactic"ranged",
stats = {str=0, dex=0, con=0, cun=0, wil=0, mag=0},
inc_stats = { mag=15 + self:getWil() * self:getTalentLevel(t) / 5, wil=10 + self:getTalentLevel(t) * 2, con=10+ self:getTalentLevelRaw(self.T_RESILIENCE)*2, },
inc_stats = { wil=15 + self:getWil() * self:getTalentLevel(t) / 5, cun=10 + self:getTalentLevel(t) * 2, con=10+ self:getTalentLevelRaw(self.T_RESILIENCE)*2, },
level_range = {self.level, self.level}, exp_worth = 0,
max_life = resolvers.rngavg(5,10),
......@@ -245,6 +279,10 @@ newTalent{
summon_time = math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_FLAME_FURY]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......@@ -253,9 +291,9 @@ newTalent{
end,
info = function(self, t)
return ([[Summon a Ritch Flamespitter for %d turns to burn your foes to death. Flamespitters are really weak in melee and die easily, but they can burn your foes from afar.
It will get %d magic, %d willpower and %d constitution.
It will get %d willpower, %d cunning and %d constitution.
Your summons inherit some of your stats: increased damage%%, stun/pin/confusion/blindness resistance, armour penetration.
Magic stat will increase with your Willpower stat.]])
Willpower stat will increase with your Willpower stat.]])
:format(math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
15 + self:getWil() * self:getTalentLevel(t) / 5,
10 + self:getTalentLevel(t) * 2,
......@@ -284,6 +322,18 @@ newTalent{
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, rng.table{DamageType.LIGHTNING,DamageType.ACID,DamageType.POISON}, self:combatTalentMindDamage(t, 30, 250), {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.TEMP_EFFECT, {foes=true, eff=self.EFF_LOWER_FIRE_RESIST, dur=4+self:getTalentLevelRaw(t), p={power=self:combatTalentMindDamage(t, 15, 70)}}, {type="flame"})
game.level.map:addEffect(self,
m.x, m.y, 6,
DamageType.POISON, self:combatTalentMindDamage(t, 10, 40),
self:getTalentRadius(t),
5, nil,
{type="vapour"},
nil, false
)
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)
......@@ -331,6 +381,10 @@ newTalent{
summon_time = math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_DISENGAGE]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......@@ -369,6 +423,10 @@ newTalent{
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.ICE, self:combatTalentMindDamage(t, 30, 300), {type="freeze"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.TEMP_EFFECT, {foes=true, eff=self.EFF_LOWER_COLD_RESIST, dur=4+self:getTalentLevelRaw(t), p={power=self:combatTalentMindDamage(t, 15, 70)}}, {type="flame"})
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)
......@@ -417,6 +475,10 @@ newTalent{
summon_time = math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_RESOLVE]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......@@ -462,6 +524,41 @@ newTalent{
nil, true
)
end,
on_arrival = function(self, t, m)
for i = 1, math.max(1, math.floor(self:getTalentLevel(t) / 2)) do
-- Find space
local x, y = util.findFreeGrid(m.x, m.y, 5, true, {[Map.ACTOR]=true})
if not x then return end
local NPC = require "mod.class.NPC"
local mh = NPC.new{
type = "dragon", subtype = "fire",
display = "d", color=colors.RED, image = "npc/dragon_fire_fire_drake_hatchling.png",
name = "fire drake hatchling", faction = self.faction,
desc = [[A mighty fire drake.]],
autolevel = "none",
ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10},
stats = {str=0, dex=0, con=0, cun=0, wil=0, mag=0},
inc_stats = { str=15 + self:getWil() * self:getTalentLevel(t) / 6, wil=38, con=20 + self:getTalentLevel(t) * 3 + self:getTalentLevelRaw(self.T_RESILIENCE) * 2, },
level_range = {self.level, self.level}, exp_worth = 0,
max_life = resolvers.rngavg(40, 60),
life_rating = 10,
infravision = 10,
combat_armor = 0, combat_def = 0,
combat = { dam=resolvers.levelup(resolvers.rngavg(25,40), 1, 0.6), atk=resolvers.rngavg(25,60), apr=25, dammod={str=1.1} },
on_melee_hit = {[DamageType.FIRE]=resolvers.mbonus(7, 2)},
resists = { [DamageType.FIRE] = 100, },
summoner = self, summoner_gain_exp=true, wild_gift_summon=true,
summon_time = m.summon_time,
ai_target = {actor=m.ai_target.actor}
}
setupSummon(self, mh, x, y)
end
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)
......@@ -511,6 +608,10 @@ newTalent{
summon_time = math.ceil(self:getTalentLevel(t)) + 2 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_AURA_OF_SILENCE]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......
......@@ -38,6 +38,10 @@ newTalent{
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.PHYSICAL, self:combatTalentMindDamage(t, 30, 250), {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.TEMP_EFFECT, {foes=true, eff=self.EFF_LOWER_PHYSICAL_RESIST, dur=4+self:getTalentLevelRaw(t), p={power=self:combatTalentMindDamage(t, 15, 70)}}, {type="flame"})
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)
......@@ -79,6 +83,10 @@ newTalent{
summon_time = math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_TOTAL_THUGGERY]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......@@ -118,6 +126,10 @@ newTalent{
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.SLIME, self:combatTalentMindDamage(t, 30, 200), {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.TEMP_EFFECT, {foes=true, eff=self.EFF_LOWER_NATURE_RESIST, dur=4+self:getTalentLevelRaw(t), p={power=self:combatTalentMindDamage(t, 15, 70)}}, {type="flame"})
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)
......@@ -170,6 +182,10 @@ newTalent{
return value - p
end,
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_SWALLOW]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......@@ -209,6 +225,10 @@ newTalent{
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.BLEED, self:combatTalentMindDamage(t, 30, 350), {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.TEMP_EFFECT, {foes=true, eff=self.EFF_SLOW_MOVE, dur=4+self:getTalentLevelRaw(t), p={power=0.1+self:combatTalentMindDamage(t, 5, 500)/1000}}, {type="flame"})
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)
......@@ -257,6 +277,10 @@ newTalent{
summon_time = self:getTalentLevel(t) + 2 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_RUSH]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......@@ -294,6 +318,10 @@ newTalent{
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.PHYSKNOCKBACK, {dam=self:combatTalentMindDamage(t, 30, 150), dist=4}, {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.TEMP_EFFECT, {foes=true, eff=self.EFF_DAZED, dur=1+self:getTalentLevelRaw(t)/2, p={}}, {type="flame"})
end,
requires_target = true,
action = function(self, t)
local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t}
......@@ -342,8 +370,13 @@ newTalent{
faction = self.faction,
summoner = self, summoner_gain_exp=true, wild_gift_summon=true,
summon_time = math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
ai_target = {actor=target},
resolvers.sustains_at_birth(),
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_SHATTERING_IMPACT]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......
......@@ -110,6 +110,14 @@ newTalent{
target:setEffect(target.EFF_SHELL_SHIELD, 4, {power=self:combatTalentMindDamage(t, 10, 35)})
end, nil, {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, function(px, py)
local target = game.level.map(px, py, Map.ACTOR)
if not target or self:reactionToward(target) < 0 then return end
target:heal(30 + self:combatTalentMindDamage(t, 10, 350))
end, nil, {type="acid"})
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)
......@@ -156,6 +164,10 @@ newTalent{
summon_time = math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.talents{ [self.T_BATTLE_CALL]=self:getTalentLevelRaw(t) }
end
setupSummon(self, m, x, y)
......@@ -200,6 +212,10 @@ newTalent{
end
end, nil, {type="flame"})
end,
on_arrival = function(self, t, m)
local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t, x=m.x, y=m.y}
self:project(tg, m.x, m.y, DamageType.FEARKNOCKBACK, {dist=1+self:getTalentLevelRaw(t), x=m.x, y=m.y}, {type="acid"})
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)
......@@ -246,6 +262,10 @@ newTalent{
summon_time = math.ceil(self:getTalentLevel(t)) + 5 + self:getTalentLevelRaw(self.T_RESILIENCE),
ai_target = {actor=target}
}
if self:attr("wild_summon") and rng.percent(self:attr("wild_summon")) then
m.name = m.name.." (wild summon)"
m[#m+1] = resolvers.inscription("INFUSION:_INSIDIOUS_POISON", {cooldown=12, range=6, heal_factor=0.6, power=self:getTalentLevel(t) * 60})
end
setupSummon(self, m, x, y)
......
......@@ -270,7 +270,7 @@ newEffect{
end,
deactivate = function(self, eff)
self:removeParticles(eff.particle)
self:removeTemporaryValue("stunned", eff.tmpid)
self:removeTemporaryValue("no_talents_cooldown", eff.tcdid)
self:removeTemporaryValue("movement_speed", eff.speedid)
......@@ -893,7 +893,7 @@ newEffect{
end,
deactivate = function(self, eff)
self:removeParticles(eff.particle)
self:removeTemporaryValue("stunned", eff.tmpid)
self:removeTemporaryValue("no_talents_cooldown", eff.tcdid)
self:removeTemporaryValue("movement_speed", eff.speedid)
......@@ -1553,3 +1553,24 @@ newEffect{
self:removeTemporaryValue("fast_summons", eff.speedid)
end,
}
newEffect{
name = "WILD_SUMMON", image = "talents/wild_summon.png",
desc = "Wild Summon",
long_desc = function(self, eff) return ("%d%% chances to get a more powerful summon."):format(eff.chance) end,
type = "mental",
subtype = { summon=true },
status = "beneficial",
parameters = { chance=100 },
activate = function(self, eff)
eff.tid = self:addTemporaryValue("wild_summon", eff.chance)
end,
on_timeout = function(self, eff)
eff.chance = math.floor(eff.chance * 0.66)
self:removeTemporaryValue("wild_summon", eff.tid)
eff.tid = self:addTemporaryValue("wild_summon", eff.chance)
end,
deactivate = function(self, eff)
self:removeTemporaryValue("wild_summon", eff.tid)
end,
}
......@@ -1445,6 +1445,24 @@ newEffect{
end,
}
newEffect{
name = "SLOW_MOVE",
desc = "Slow movement", image = "talents/slow.png",
long_desc = function(self, eff) return ("Movement speed is reduced by %d%%."):format(eff.power*100) end,
type = "physical",
subtype = { nature=true },
status = "detrimental",
parameters = {power = 1},
on_gain = function(self, err) return nil, "+Slow movement" end,
on_lose = function(self, err) return nil, "-Slow movement" end,
activate = function(self, eff)
eff.speedid = self:addTemporaryValue("movement_speed", -eff.power)
end,
deactivate = function(self, eff)
self:removeTemporaryValue("movement_speed", eff.speedid)
end,
}
newEffect{
name = "WEAKENED",
desc = "Weakened", image = "talents/ruined_earth.png",
......@@ -1462,3 +1480,72 @@ newEffect{
self:removeTemporaryValue("inc_damage", eff.incDamageId)
end,
}
newEffect{
name = "LOWER_FIRE_RESIST",
desc = "Lowered fire resistance",
long_desc = function(self, eff) return ("The target fire resistance is reduced by %d%%."):format(eff.power) end,
type = "physical",
subtype = { nature=true },
status = "detrimental",
parameters = { power=20 },
on_gain = function(self, err) return "#Target# becomes more vulnerable to fire.", "+Low. fire resist" end,
on_lose = function(self, err) return "#Target# is less vulnerable to fire.", "-Low. fire resist" end,
activate = function(self, eff)
eff.pid = self:addTemporaryValue("resists", {[DamageType.FIRE]=-eff.power})
end,
deactivate = function(self, eff)
self:removeTemporaryValue("resists", eff.pid)
end,
}
newEffect{
name = "LOWER_COLD_RESIST",
desc = "Lowered cold resistance",
long_desc = function(self, eff) return ("The target cold resistance is reduced by %d%%."):format(eff.power) end,
type = "physical",
subtype = { nature=true },
status = "detrimental",
parameters = { power=20 },
on_gain = function(self, err) return "#Target# becomes more vulnerable to cold.", "+Low. cold resist" end,
on_lose = function(self, err) return "#Target# is less vulnerable to cold.", "-Low. cold resist" end,
activate = function(self, eff)
eff.pid = self:addTemporaryValue("resists", {[DamageType.COLD]=-eff.power})
end,
deactivate = function(self, eff)
self:removeTemporaryValue("resists", eff.pid)
end,
}
newEffect{
name = "LOWER_NATURE_RESIST",
desc = "Lowered nature resistance",
long_desc = function(self, eff) return ("The target nature resistance is reduced by %d%%."):format(eff.power) end,
type = "physical",
subtype = { nature=true },
status = "detrimental",
parameters = { power=20 },
on_gain = function(self, err) return "#Target# becomes more vulnerable to nature.", "+Low. nature resist" end,
on_lose = function(self, err) return "#Target# is less vulnerable to nature.", "-Low. nature resist" end,
activate = function(self, eff)
eff.pid = self:addTemporaryValue("resists", {[DamageType.NATURE]=-eff.power})
end,
deactivate = function(self, eff)
self:removeTemporaryValue("resists", eff.pid)
end,
}
newEffect{
name = "LOWER_PHYSICAL_RESIST",
desc = "Lowered physical resistance",
long_desc = function(self, eff) return ("The target physical resistance is reduced by %d%%."):format(eff.power) end,
type = "physical",
subtype = { nature=true },
status = "detrimental",
parameters = { power=20 },
on_gain = function(self, err) return "#Target# becomes more vulnerable to physical.", "+Low. physical resist" end,
on_lose = function(self, err) return "#Target# is less vulnerable to physical.", "-Low. physical resist" end,
activate = function(self, eff)
eff.pid = self:addTemporaryValue("resists", {[DamageType.PHYSICAL]=-eff.power})
end,
deactivate = function(self, eff)
self:removeTemporaryValue("resists", eff.pid)
end,
}
......@@ -218,7 +218,7 @@ function _M:atEnd(v)
--[[ Award talent points based on the highest available level of the talent
This is in the potential case of a player selecting a race with two points in phase door
and Archmage as his class. Archmage starts with one point in phase door. Cases like this may
result in a conflict of what the player might expect to get back in points. The highest
result in a conflict of what the player might expect to get back in points. The highest
amount of points is always awarded to the player (two, in this case).
]]
if (unlearned_talents[talent] == nil) then
......@@ -273,8 +273,8 @@ function _M:makeDefault()
self:setDescriptor("permadeath", "Adventure")
self:setDescriptor("race", "Human")
self:setDescriptor("subrace", "Higher")
self:setDescriptor("class", "Warrior")
self:setDescriptor("subclass", "Berserker")
self:setDescriptor("class", "Wilder")
self:setDescriptor("subclass", "Summoner")
__module_extra_info.no_birth_popup = true
self:atEnd("created")
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment