Skip to content
Snippets Groups Projects
Commit 8105cdfb authored by HousePet's avatar HousePet
Browse files

Reworked Chants and Hymns categories.

parent d1460bbb
No related branches found
No related tags found
No related merge requests found
Showing
with 518 additions and 133 deletions
......@@ -86,7 +86,7 @@ newBirthDescriptor{
talents = {
[ActorTalents.T_SUN_BEAM] = 1,
[ActorTalents.T_WEAPON_OF_LIGHT] = 1,
[ActorTalents.T_CHANT_OF_FORTITUDE] = 1,
[ActorTalents.T_CHANT_ACOLYTE] = 1,
[ActorTalents.T_ARMOUR_TRAINING] = 2,
},
copy = {
......@@ -140,7 +140,7 @@ newBirthDescriptor{
talents = {
[ActorTalents.T_SEARING_LIGHT] = 1,
[ActorTalents.T_MOONLIGHT_RAY] = 1,
[ActorTalents.T_HYMN_OF_SHADOWS] = 1,
[ActorTalents.T_HYMN_ACOLYTE] = 1,
[ActorTalents.T_TWILIGHT] = 1,
},
copy = {
......
game/modules/tome/data/gfx/talents/chant_acolyte.png

2.46 KiB

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

2.62 KiB

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

1.65 KiB

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

4.17 KiB

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

2.14 KiB

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

2.97 KiB

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

2.98 KiB

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

3.25 KiB

......@@ -17,11 +17,12 @@
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
-- Synergizes with melee classes (escort), Weapon of Wrath, healing mod (avoid overheal > healing efficiency), and low spellpower
-- Looks weaker than the other options, but extra life is a more universally useful stat and mind save is generally lower for celestial classes.
newTalent{
name = "Chant of Fortitude",
type = {"celestial/chants", 1},
mode = "sustained",
hide = true,
require = divi_req1,
points = 5,
cooldown = 12,
......@@ -29,138 +30,204 @@ newTalent{
no_energy = true,
dont_provide_pool = true,
tactical = { BUFF = 2 },
range = 10,
getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 70) end,
getLifePct = function(self, t) return self:combatTalentLimit(t, 1, 0.05, 0.20) end, -- Limit < 100% bonus
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
range = 0,
getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 60) end,
getLifePct = function(self, t) return self:combatTalentLimit(t, 1, 0.10, 0.25) end, -- Limit < 100% bonus
sustain_slots = 'celestial_chant',
activate = function(self, t)
local power = t.getResists(self, t)
game:playSoundNear(self, "talents/spell_generic2")
local ret = {
onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.LIGHT]=t.getDamageOnMeleeHit(self, t)}),
phys = self:addTemporaryValue("combat_physresist", power),
spell = self:addTemporaryValue("combat_spellresist", power),
life = self:addTemporaryValue("max_life", t.getLifePct(self, t)*self.max_life),
particle = self:addParticles(Particles.new("golden_shield", 1))
}
local ret = {}
self:talentTemporaryValue(ret, "combat_mentalresist", power)
self:talentTemporaryValue(ret, "max_life", t.getLifePct(self, t)*self.max_life)
ret.particle = self:addParticles(Particles.new("golden_shield", 1))
if self:knowTalent(self.T_HP_CHANT_ILLUMINATE) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_ILLUMINATE)
self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.LIGHT]=t2.getDamageOnMeleeHit(self, t2)})
self:talentTemporaryValue(ret, "mana_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "stamina_regen", t2.getBonusRegen(self, t2))
end
if self:knowTalent(self.T_HP_CHANT_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_ADEPT)
self:talentTemporaryValue(ret, "lite", t2.getBonusLight(self, t2))
t2.doCure(self, t2, "mental")
end
if self:knowTalent(self.T_HP_CHANT_RADIANT) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_RADIANT)
self:talentTemporaryValue(ret, "inc_damage", {[DamageType.LIGHT] = t2.getLightDamageIncrease(self, t2), [DamageType.FIRE] = t2.getLightDamageIncrease(self, t2)})
self:talentTemporaryValue(ret, "positive_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "positive_regen_ref", t2.getBonusRegen(self, t2))
end
return ret
end,
deactivate = function(self, t, p)
self:removeParticles(p.particle)
self:removeTemporaryValue("on_melee_hit", p.onhit)
self:removeTemporaryValue("combat_physresist", p.phys)
self:removeTemporaryValue("combat_spellresist", p.spell)
self:removeTemporaryValue("max_life", p.life)
return true
end,
info = function(self, t)
local saves = t.getResists(self, t)
local life = t.getLifePct(self, t)
local damageonmeleehit = t.getDamageOnMeleeHit(self, t)
return ([[You chant the glory of the Sun, granting you %d Physical Save and Spell Save and increasing your maximum life by %0.1f%% (Currently: %d).
In addition, this talent surrounds you with a shield of light, dealing %0.1f light damage to anything that hits you in melee.
return ([[You chant the glory of the Sun, granting you %d Mental Save and increasing your maximum life by %0.1f%% (Currently: %d).
You may only have one Chant active at once.
The saves and light damage will increase with your Spellpower and the life with talent level.]]):
format(saves, life*100, life*self.max_life, damDesc(self, DamageType.LIGHT, damageonmeleehit))
The effects will increase with your Spellpower.]]):
format(saves, life*100, life*self.max_life)
end,
}
-- Mostly the same code as Sanctuary
-- Just like Fortress we limit the interaction with spellpower a bit because this is an escort reward
-- This can be swapped to reactively with a projectile already in the air
-- Physical and weapon protection Chant.
newTalent{
name = "Chant of Fortress",
type = {"celestial/chants", 2},
type = {"celestial/chants", 1},
mode = "sustained",
require = divi_req2,
hide = true,
require = divi_req1,
points = 5,
cooldown = 12,
sustain_positive = 20,
no_energy = true,
dont_provide_pool = true,
tactical = { BUFF = 2 },
range = 10,
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
getDamageChange = function(self, t)
return -self:combatTalentLimit(t, 50, 14, 30) -- Limit < 50% damage reduction
end,
range = 0,
getPhysicalResistance = function(self, t) return math.floor(self:combatTalentSpellDamage(t, 10, 30)) end,
getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 60) end,
sustain_slots = 'celestial_chant',
activate = function(self, t)
local power = t.getResists(self, t)
game:playSoundNear(self, "talents/spell_generic2")
local ret = {
onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.LIGHT]=t.getDamageOnMeleeHit(self, t)}),
particle = self:addParticles(Particles.new("golden_shield", 1))
}
local ret = {}
self:talentTemporaryValue(ret, "resists", {[DamageType.PHYSICAL] = t.getPhysicalResistance(self, t)})
self:talentTemporaryValue(ret, "combat_physresist", power)
self:talentTemporaryValue(ret, "combat_armor", t.getPhysicalResistance(self, t))
self:talentTemporaryValue(ret, "combat_armor_hardiness", 10)
ret.particle = self:addParticles(Particles.new("golden_shield", 1))
if self:knowTalent(self.T_HP_CHANT_ILLUMINATE) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_ILLUMINATE)
self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.LIGHT]=t2.getDamageOnMeleeHit(self, t2)})
self:talentTemporaryValue(ret, "mana_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "stamina_regen", t2.getBonusRegen(self, t2))
end
if self:knowTalent(self.T_HP_CHANT_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_ADEPT)
self:talentTemporaryValue(ret, "lite", t2.getBonusLight(self, t2))
t2.doCure(self, t2, "physical")
end
if self:knowTalent(self.T_HP_CHANT_RADIANT) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_RADIANT)
self:talentTemporaryValue(ret, "inc_damage", {[DamageType.LIGHT] = t2.getLightDamageIncrease(self, t2), [DamageType.FIRE] = t2.getLightDamageIncrease(self, t2)})
self:talentTemporaryValue(ret, "positive_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "positive_regen_ref", t2.getBonusRegen(self, t2))
end
return ret
end,
deactivate = function(self, t, p)
self:removeParticles(p.particle)
self:removeTemporaryValue("on_melee_hit", p.onhit)
return true
end,
info = function(self, t)
local range = -t.getDamageChange(self, t)
local damageonmeleehit = t.getDamageOnMeleeHit(self, t)
return ([[You chant the glory of the Sun, reducing the damage enemies 3 or more spaces away deal by %d%%.
In addition, this talent surrounds you with a shield of light, dealing %0.1f light damage to anything that hits you in melee.
local physicalresistance = t.getPhysicalResistance(self, t)
local saves = t.getResists(self, t)
return ([[You chant the glory of the Sun, granting you %d%% physical damage resistance, %d physical save, %d armour and +10%% armour hardiness.
You may only have one Chant active at once.
The damage reduction will increase with talent level and light damage will increase with your Spellpower.]]):
format(range, damDesc(self, DamageType.LIGHT, damageonmeleehit))
The effects will increase with your Spellpower.]]):
format(physicalresistance, saves, physicalresistance)
end,
}
-- Escorts can't give this one so it should have the most significant spellpower scaling
-- Ideally at high spellpower this would almost always be the best chant to use, but we can't guarantee that while still differentiating the chants in interesting ways
-- People that don't want to micromanage/math out when the other chants are better will like this and it should still outperform Fortitude most of the time
-- Ranged and magic protection Chant
-- This can be swapped to reactively with a projectile already in the air
newTalent{
name = "Chant of Resistance",
type = {"celestial/chants",3},
type = {"celestial/chants",1},
mode = "sustained",
require = divi_req3,
hide = true,
require = divi_req1,
points = 5,
cooldown = 12,
sustain_positive = 20,
dont_provide_pool = true,
tactical = { BUFF = 2 },
no_energy = true,
range = 10,
getResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
range = 0,
getResists = function(self, t) return self:combatTalentSpellDamage(t, 10, 30) end,
getDamageChange = function(self, t)
return -self:combatTalentLimit(t, 50, 14, 30) -- Limit < 50% damage reduction
end,
getSpellResists = function(self, t) return self:combatTalentSpellDamage(t, 5, 60) end,
sustain_slots = 'celestial_chant',
callbackOnTakeDamage = function(self, t, src, x, y, type, dam, tmp, no_martyr)
if src and src.x and src.y then
-- assume instantaneous projection and check range to source
if core.fov.distance(self.x, self.y, src.x, src.y) > 2 then
dam = dam * (100 + t.getDamageChange(self, t)) / 100
print("[PROJECTOR] Chant of Resistance (source) dam", dam)
end
end
return {dam=dam}
end,
activate = function(self, t)
local power = t.getResists(self, t)
local elempower = t.getResists(self, t)
local spell = t.getSpellResists(self, t)
game:playSoundNear(self, "talents/spell_generic2")
local ret = {
onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.LIGHT]=t.getDamageOnMeleeHit(self, t)}),
res = self:addTemporaryValue("resists", {all = power}),
particle = self:addParticles(Particles.new("golden_shield", 1))
}
local ret = {}
self:talentTemporaryValue(ret, "resists", {
[DamageType.FIRE] = elempower,
[DamageType.LIGHTNING] = elempower,
[DamageType.ACID] = elempower,
[DamageType.COLD] = elempower,
})
self:talentTemporaryValue(ret, "combat_spellresist", spell)
ret.particle = self:addParticles(Particles.new("golden_shield", 1))
if self:knowTalent(self.T_HP_CHANT_ILLUMINATE) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_ILLUMINATE)
self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.LIGHT]=t2.getDamageOnMeleeHit(self, t2)})
self:talentTemporaryValue(ret, "mana_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "stamina_regen", t2.getBonusRegen(self, t2))
end
if self:knowTalent(self.T_HP_CHANT_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_ADEPT)
self:talentTemporaryValue(ret, "lite", t2.getBonusLight(self, t2))
t2.doCure(self, t2, "magical")
end
if self:knowTalent(self.T_HP_CHANT_RADIANT) then
local t2 = self:getTalentFromId(self.T_HP_CHANT_RADIANT)
self:talentTemporaryValue(ret, "inc_damage", {[DamageType.LIGHT] = t2.getLightDamageIncrease(self, t2), [DamageType.FIRE] = t2.getLightDamageIncrease(self, t2)})
self:talentTemporaryValue(ret, "positive_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "positive_regen_ref", t2.getBonusRegen(self, t2))
end
return ret
end,
deactivate = function(self, t, p)
self:removeParticles(p.particle)
self:removeTemporaryValue("on_melee_hit", p.onhit)
self:removeTemporaryValue("resists", p.res)
return true
end,
info = function(self, t)
local resists = t.getResists(self, t)
local damage = t.getDamageOnMeleeHit(self, t)
return ([[You chant the glory of the Sun, granting you %d%% resistance to all damage.
In addition, this talent surrounds you with a shield of light, dealing %0.1f light damage to anything that hits you in melee.
You may only have one Chant active at once.
The effects will increase with your Spellpower.]]):
format(resists, damDesc(self, DamageType.LIGHT, damage))
local saves = t.getSpellResists(self, t)
local range = -t.getDamageChange(self, t)
return ([[You chant the glory of the Sun, granting you %d%% fire, lightning, acid and cold damage resistance, %d spell save and reduces the damage from enemies 3 or more spaces away by %d%%.
You may only have one Chant active at once.
The effects will increase with your Spellpower.]]):
format(resists, saves, range)
end,
}
-- Extremely niche in the name of theme
-- A defensive chant is realistically always a better choice than an offensive one but we can mitigate this by giving abnormally high value at low talent investment
-- Depreciated, but retained for compatability.
newTalent{
name = "Chant of Light",
type = {"celestial/chants", 4},
type = {"celestial/other", 4},
mode = "sustained",
require = divi_req4,
points = 5,
......@@ -169,10 +236,10 @@ newTalent{
no_energy = true,
dont_provide_pool = true,
tactical = { BUFF = 2 },
range = 10,
range = 0,
getLightDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 20, 50) end,
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
getLite = function(self, t) return math.floor(self:combatTalentScale(t, 2, 6, "log")) end,
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
sustain_slots = 'celestial_chant',
activate = function(self, t)
game:playSoundNear(self, "talents/spell_generic2")
......@@ -203,3 +270,127 @@ newTalent{
format(damageinc, damDesc(self, DamageType.LIGHT, damage), lite)
end,
}
newTalent{
name = "Chant Acolyte",
type = {"celestial/chants", 1},
require = divi_req1,
points = 5,
mode = "passive",
on_learn = function(self, t)
self:learnTalent(self.T_CHANT_OF_FORTITUDE, true, nil, {no_unlearn=true})
self:learnTalent(self.T_CHANT_OF_FORTRESS, true, nil, {no_unlearn=true})
self:learnTalent(self.T_CHANT_OF_RESISTANCE, true, nil, {no_unlearn=true})
end,
on_unlearn = function(self, t)
self:unlearnTalent(self.T_CHANT_OF_FORTITUDE)
self:unlearnTalent(self.T_CHANT_OF_FORTRESS)
self:unlearnTalent(self.T_CHANT_OF_RESISTANCE)
end,
info = function(self, t)
local t1 = self:getTalentFromId(self.T_CHANT_OF_FORTITUDE)
local t2 = self:getTalentFromId(self.T_CHANT_OF_FORTRESS)
local t3 = self:getTalentFromId(self.T_CHANT_OF_RESISTANCE)
return ([[You have learned to sing the praises of the Sun, in the form of three defensive Chants.
Chant of Fortitute: Increases your mental save by %d and maximum life by %d%%.
Chant of Fortress: Increases your physical save by %d, your physical resistance by %d%%, your armour by %d and your armour hardiness by 10%%.
Chant of Resistance: Increases you spell save by %d, your fire/cold/lightning/acid resistances by %d%% and reduces all damage that comes from distant enemies by %d%%.
You may only have one Chant active at a time.]]):
format(t1.getResists(self, t1), t1.getLifePct(self, t1)*100, t2.getResists(self, t2), t2.getPhysicalResistance(self, t2), t2.getPhysicalResistance(self, t2), t3.getSpellResists(self, t3), t3.getResists(self, t3), t3.getDamageChange(self, t3))
end,
}
-- Mana regen is given to make it a little more attractive to Anorithils.
-- Might also make some people consider Chants as an escort reward.
newTalent{
name = "Chant Illuminate",
type = {"celestial/chants", 5},
require = divi_req2,
points = 5,
mode = "passive",
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 50) end,
getBonusRegen = function(self, t) return self:combatTalentSpellDamage(t, 10, 20) / 10 end,
info = function(self, t)
return ([[Your Chants now bathe you in a cloak of light, which increases your stamina and mana regenerations by %0.2f per turn and does %0.2f light damage to anyone who hits you in melee.
These values scale with your Spellpower.]]):format(t.getBonusRegen(self, t), damDesc(self, DamageType.LIGHT, t.getDamageOnMeleeHit(self, t)))
end,
}
-- Remember that Chants can be swapped instantly.
newTalent{
name = "Chant Adept",
type = {"celestial/chants", 6},
require = divi_req3,
points = 5,
mode = "passive",
getDebuffCures = function(self, t) return math.floor(self:combatTalentScale(t, 0.4, 1.8, 0.75)) end,
getBonusLight = function(self, t) return math.floor(self:combatTalentScale(t, 0.75, 3.5, 0.75)) end,
doCure = function(self, t, type)
local cures = t.getDebuffCures(self, t)
local effs = {}
local force = {}
local known = false
-- Go through all temporary effects
for eff_id, p in pairs(self.tmp) do
local e = self.tempeffect_def[eff_id]
if e.type == type and e.status == "detrimental" and e.subtype["cross tier"] then
force[#force+1] = {"effect", eff_id}
elseif e.type == type and e.status == "detrimental" then
effs[#effs+1] = {"effect", eff_id}
end
end
-- Cross tier effects are always removed and not part of the random game, otherwise it is a huge nerf to wild infusion
for i = 1, #force do
local eff = force[i]
if eff[1] == "effect" then
self:removeEffect(eff[2])
known = true
end
end
if cures > 0 then
for i = 1, cures do
if #effs == 0 then break end
local eff = rng.tableRemove(effs)
if eff[1] == "effect" then
self:removeEffect(eff[2])
known = true
end
end
end
if known then
game.logSeen(self, "%s is cured!", self.name:capitalize())
end
end,
info = function(self, t)
return ([[Your skill at Chanting now extends the cloak of light, increasing your light radius by %d.
Also, when you start a new Chant, you will be cured of all cross-teir effects and cured of up to %d debuffs.
Chant of Fortitude cures mental effects.
Chant of Fortress cures physical effects.
Chant of Resistance cures magical effects.]]):format(t.getBonusLight(self, t), t.getDebuffCures(self, t))
end,
}
newTalent{
name = "Chant Radiant",
type = {"celestial/chants", 7},
require = divi_req4,
points = 5,
mode = "passive",
getLightDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 20, 50) end,
getBonusRegen = function(self, t) return self:combatTalentScale(t, 0.7, 4.0, 0.75) / 10 end,
callbackOnRest = function(self, t)
if not self:knowTalent(self.T_POSITIVE_POOL) then return false end
if self.positive_regen > 0.1 and self.positive < self.max_positive then return true end
return false
end,
info = function(self, t)
return ([[Your passion for singing the praises of the Sun reaches its zenith.
Your Chanting now increases your light and fire damage by %d%% and increases your positive energy regeneration by %0.1f per turn.
These values scale with your Spellpower.]]):format(t.getLightDamageIncrease(self, t), t.getBonusRegen(self, t))
end,
}
......@@ -21,6 +21,7 @@ newTalent{
name = "Hymn of Shadows",
type = {"celestial/hymns", 1},
mode = "sustained",
hide = true,
require = divi_req1,
points = 5,
cooldown = 12,
......@@ -28,90 +29,141 @@ newTalent{
no_energy = true,
dont_provide_pool = true,
tactical = { BUFF = 2 },
range = 10,
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
getDarknessDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
range = 0,
moveSpeed = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
castSpeed = function(self, t) return self:combatTalentSpellDamage(t, 10, 30) end,
evade = function(self, t) return self:combatStatLimit(self:combatTalentSpellDamage(t, 10, 100), 90, 10, 40) end,
callbackOnActBase = function(self, t)
if self:knowTalent(self.T_HP_HYMN_NOCTURNALIST) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_NOCTURNALIST)
t2.do_beams(self, t2)
end
end,
sustain_slots = 'celestial_hymn',
activate = function(self, t)
game:playSoundNear(self, "talents/spell_generic2")
local ret = {
onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.DARKNESS]= t.getDamageOnMeleeHit(self, t)}),
phys = self:addTemporaryValue("inc_damage", {[DamageType.DARKNESS] = t.getDarknessDamageIncrease(self, t)}),
particle = self:addParticles(Particles.new("darkness_shield", 1))
}
local ret = {}
self:talentTemporaryValue(ret, "movement_speed", t.moveSpeed(self, t)/100)
self:talentTemporaryValue(ret, "combat_spellspeed", t.castSpeed(self, t)/100)
self:talentTemporaryValue(ret, "evasion", t.evade(self, t))
ret.particle = self:addParticles(Particles.new("darkness_shield", 1))
if self:knowTalent(self.T_HP_HYMN_INCANTOR) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_INCANTOR)
self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.DARKNESS]=t2.getDamageOnMeleeHit(self, t2)})
self:talentTemporaryValue(ret, "inc_damage", {[DamageType.DARKNESS] = t2.getDarkDamageIncrease(self, t2)})
end
if self:knowTalent(self.T_HP_HYMN_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_ADEPT)
self:talentTemporaryValue(ret, "infravision", t2.getBonusInfravision(self, t2))
end
if self:knowTalent(self.T_HP_HYMN_NOCTURNALIST) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_NOCTURNALIST)
self:talentTemporaryValue(ret, "negative_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "negative_regen_ref", t2.getBonusRegen(self, t2))
end
return ret
end,
deactivate = function(self, t, p)
self:removeParticles(p.particle)
self:removeTemporaryValue("on_melee_hit", p.onhit)
self:removeTemporaryValue("inc_damage", p.phys)
if self:knowTalent(self.T_HP_HYMN_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_ADEPT)
game:onTickEnd(function() self:setEffect(self.EFF_WILD_SPEED, 1, {power=t2.getSpeed(self, t2)}) end)
end
return true
end,
info = function(self, t)
local darknessinc = t.getDarknessDamageIncrease(self, t)
local darknessdamage = t.getDamageOnMeleeHit(self, t)
return ([[Chant the glory of the Moon, empowering your dark elemental attacks so that they do %d%% additional darkness damage.
In addition, this talent surrounds you with a shield of shadows, dealing %0.2f darkness damage to anything that attacks you.
return ([[Chant the glory of the Moon, gaining the agility of shadows.
This increases your movement speed by %d%%, your spell speed by %d%% and grant %d%% evasion.
You may only have one Hymn active at once.
The effects will increase with your Spellpower.]]):
format(darknessinc, damDesc(self, DamageType.DARKNESS, darknessdamage))
format(t.moveSpeed(self, t), t.castSpeed(self, t), t.evade(self, t))
end,
}
newTalent{
name = "Hymn of Detection",
type = {"celestial/hymns", 2},
type = {"celestial/hymns", 1},
mode = "sustained",
require = divi_req2,
hide = true,
require = divi_req1,
points = 5,
cooldown = 12,
sustain_negative = 20,
no_energy = true,
dont_provide_pool = true,
tactical = { BUFF = 2 },
range = 10,
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 25) end,
getSeeInvisible = function(self, t) return self:combatTalentSpellDamage(t, 2, 35) end,
getSeeStealth = function(self, t) return self:combatTalentSpellDamage(t, 2, 15) end,
getInfraVisionPower = function(self, t) return math.floor(self:combatTalentScale(t, 6, 10)) end,
range = 0,
sustain_slots = 'celestial_hymn',
getSeeInvisible = function(self, t) return self:combatTalentSpellDamage(t, 2, 25) end,
getSeeStealth = function(self, t) return self:combatTalentSpellDamage(t, 2, 25) end,
critPower = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
callbackOnActBase = function(self, t)
if self:knowTalent(self.T_HP_HYMN_NOCTURNALIST) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_NOCTURNALIST)
t2.do_beams(self, t2)
end
end,
activate = function(self, t)
game:playSoundNear(self, "talents/spell_generic2")
local ret = {
onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.DARKNESS]= t.getDamageOnMeleeHit(self, t)}),
invis = self:addTemporaryValue("see_invisible", t.getSeeInvisible(self, t)),
stealth = self:addTemporaryValue("see_stealth", t.getSeeStealth(self, t)),
infravision = self:addTemporaryValue("infravision", t.getInfraVisionPower(self, t)),
particle = self:addParticles(Particles.new("darkness_shield", 1))
}
local ret = {}
self:talentTemporaryValue(ret, "see_invisible", t.getSeeInvisible(self, t))
self:talentTemporaryValue(ret, "see_stealth", t.getSeeStealth(self, t))
self:talentTemporaryValue(ret, "blindfight", 1)
self:talentTemporaryValue(ret, "combat_critical_power", t.critPower(self, t))
ret.particle = self:addParticles(Particles.new("darkness_shield", 1))
if self:knowTalent(self.T_HP_HYMN_INCANTOR) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_INCANTOR)
self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.DARKNESS]=t2.getDamageOnMeleeHit(self, t2)})
self:talentTemporaryValue(ret, "inc_damage", {[DamageType.DARKNESS] = t2.getDarkDamageIncrease(self, t2)})
end
if self:knowTalent(self.T_HP_HYMN_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_ADEPT)
self:talentTemporaryValue(ret, "infravision", t2.getBonusInfravision(self, t2))
end
if self:knowTalent(self.T_HP_HYMN_NOCTURNALIST) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_NOCTURNALIST)
self:talentTemporaryValue(ret, "negative_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "negative_regen_ref", t2.getBonusRegen(self, t2))
end
return ret
end,
deactivate = function(self, t, p)
self:removeParticles(p.particle)
self:removeTemporaryValue("on_melee_hit", p.onhit)
self:removeTemporaryValue("infravision", p.infravision)
self:removeTemporaryValue("see_invisible", p.invis)
self:removeTemporaryValue("see_stealth", p.stealth)
if self:knowTalent(self.T_HP_HYMN_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_ADEPT)
self:setEffect(self.EFF_INVISIBILITY, t2.invisDur(self, t2), {power=t2.invisPower(self, t2), penalty=0.4})
end
return true
end,
info = function(self, t)
local infra = t.getInfraVisionPower(self, t)
local invis = t.getSeeInvisible(self, t)
local stealth = t.getSeeStealth(self, t)
local darknessdamage = t.getDamageOnMeleeHit(self, t)
return ([[Chant the glory of the Moon, granting you infravision up to %d grids, stealth detection (+%d power), and invisibility detection (+%d power).
In addition, this talent surrounds you with a shield of shadows, dealing %0.2f darkness damage to anything that attacks you.
return ([[Chant the glory of the Moon, granting you stealth detection (+%d power), and invisibility detection (+%d power).
You may also attack creatures you cannot see without penalty and your critical hits do %d%% more damage.
You may only have one Hymn active at once.
The stealth and invisibility detection, as well as the on-hit damage, will increase with your Spellpower.]]):
format(infra, stealth, invis, damDesc(self, DamageType.DARKNESS, darknessdamage))
The stealth and invisibility detection will increase with your Spellpower.]]):
format(stealth, invis, t.critPower(self, t))
end,
}
newTalent{
name = "Hymn of Perseverance",
type = {"celestial/hymns",3},
type = {"celestial/hymns",1},
mode = "sustained",
require = divi_req3,
hide = true,
require = divi_req1,
points = 5,
cooldown = 12,
sustain_negative = 20,
......@@ -119,43 +171,63 @@ newTalent{
dont_provide_pool = true,
tactical = { BUFF = 2 },
range = 10,
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 10, 50) end,
getImmunities = function(self, t) return self:combatTalentLimit(t, 1, 0.22, 0.5) end, -- Limit < 100%
getImmunities = function(self, t) return self:combatTalentLimit(t, 1, 0.16, 0.4) end, -- Limit < 100%
callbackOnActBase = function(self, t)
if self:knowTalent(self.T_HP_HYMN_NOCTURNALIST) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_NOCTURNALIST)
t2.do_beams(self, t2)
end
end,
sustain_slots = 'celestial_hymn',
activate = function(self, t)
local dam = self:combatTalentSpellDamage(t, 5, 25)
game:playSoundNear(self, "talents/spell_generic2")
local ret = {
onhit = self:addTemporaryValue("on_melee_hit", {[DamageType.DARKNESS]=t.getDamageOnMeleeHit(self, t)}),
stun = self:addTemporaryValue("stun_immune", t.getImmunities(self, t)),
confusion = self:addTemporaryValue("confusion_immune", t.getImmunities(self, t)),
blind = self:addTemporaryValue("blind_immune", t.getImmunities(self, t)),
particle = self:addParticles(Particles.new("darkness_shield", 1))
}
local ret = {}
self:talentTemporaryValue(ret, "stun_immune", t.getImmunities(self, t))
self:talentTemporaryValue(ret, "confusion_immune", t.getImmunities(self, t))
self:talentTemporaryValue(ret, "blind_immune", t.getImmunities(self, t))
ret.particle = self:addParticles(Particles.new("darkness_shield", 1))
if self:knowTalent(self.T_HP_HYMN_INCANTOR) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_INCANTOR)
self:talentTemporaryValue(ret, "on_melee_hit", {[DamageType.DARKNESS]=t2.getDamageOnMeleeHit(self, t2)})
self:talentTemporaryValue(ret, "inc_damage", {[DamageType.DARKNESS] = t2.getDarkDamageIncrease(self, t2)})
end
if self:knowTalent(self.T_HP_HYMN_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_ADEPT)
self:talentTemporaryValue(ret, "infravision", t2.getBonusInfravision(self, t2))
end
if self:knowTalent(self.T_HP_HYMN_NOCTURNALIST) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_NOCTURNALIST)
self:talentTemporaryValue(ret, "negative_regen", t2.getBonusRegen(self, t2))
self:talentTemporaryValue(ret, "negative_regen_ref", t2.getBonusRegen(self, t2))
end
return ret
end,
deactivate = function(self, t, p)
self:removeParticles(p.particle)
self:removeTemporaryValue("on_melee_hit", p.onhit)
self:removeTemporaryValue("stun_immune", p.stun)
self:removeTemporaryValue("confusion_immune", p.confusion)
self:removeTemporaryValue("blind_immune", p.blind)
if self:knowTalent(self.T_HP_HYMN_ADEPT) then
local t2 = self:getTalentFromId(self.T_HP_HYMN_ADEPT)
self:setEffect(self.EFF_DAMAGE_SHIELD, t2.shieldDur(self, t2), {power=t2.shieldPower(self, t2)})
end
return true
end,
info = function(self, t)
local immunities = t.getImmunities(self, t)
local darknessdamage = t.getDamageOnMeleeHit(self, t)
return ([[Chant the glory of the Moon, granting you %d%% stun, blindness and confusion resistance.
In addition, this talent surrounds you with a shield of shadows, dealing %0.2f darkness damage to anything that attacks you.
You may only have one Hymn active at once.
The on-hit damage will increase with your Spellpower.]]):
format(100 * (immunities), damDesc(self, DamageType.DARKNESS, darknessdamage))
You may only have one Hymn active at once.]]):
format(100 * (immunities))
end,
}
-- Depreciated, but retained for compatability.
newTalent{
name = "Hymn of Moonlight",
type = {"celestial/hymns",4},
type = {"celestial/other",1},
mode = "sustained",
require = divi_req4,
points = 5,
......@@ -172,7 +244,7 @@ newTalent{
if self:getNegative() < t.getNegativeDrain(self, t) then return end
local tgts = {}
local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true)
local grids = core.fov.circle_grids(self.x, self.y, 5, true)
for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
local a = game.level.map(x, y, Map.ACTOR)
if a and self:reactionToward(a) < 0 then
......@@ -219,3 +291,125 @@ newTalent{
format(targetcount, damDesc(self, DamageType.DARKNESS, damage), drain)
end,
}
newTalent{
name = "Hymn Acolyte",
type = {"celestial/hymns", 1},
require = divi_req1,
points = 5,
mode = "passive",
on_learn = function(self, t)
self:learnTalent(self.T_HYMN_OF_SHADOWS, true, nil, {no_unlearn=true})
self:learnTalent(self.T_HYMN_OF_DETECTION, true, nil, {no_unlearn=true})
self:learnTalent(self.T_HYMN_OF_PERSEVERANCE, true, nil, {no_unlearn=true})
end,
on_unlearn = function(self, t)
self:unlearnTalent(self.T_HYMN_OF_SHADOWS)
self:unlearnTalent(self.T_HYMN_OF_DETECTION)
self:unlearnTalent(self.T_HYMN_OF_PERSEVERANCE)
end,
info = function(self, t)
local t1 = self:getTalentFromId(self.T_HYMN_OF_SHADOWS)
local t2 = self:getTalentFromId(self.T_HYMN_OF_DETECTION)
local t3 = self:getTalentFromId(self.T_HYMN_OF_PERSEVERANCE)
return ([[You have learned to sing the praises of the Moons, in the form of three defensive Hymns.
Hymn of Shadows: Increases your movement speed by %d%%, your spell casting speed by %d%% and grants %d%% evasion.
Hymn of Detection: Increases your ability to see stealthy creatures by %d and invisible creatures by %d, and increases your critical power by %d%%.
Hymn of Perseverance: Increases your resistance to stun, confusion and blinding by %d%%.
You may only have one Hymn active at a time.]]):
format(t1.moveSpeed(self, t1), t1.castSpeed(self, t1), t1.evade(self, t1), t2.getSeeStealth(self, t2), t2.getSeeInvisible(self, t2), t2.critPower(self, t2), t3.getImmunities(self, t3)*100)
end,
}
newTalent{
name = "Hymn Incantor",
type = {"celestial/hymns", 5},
require = divi_req2,
points = 5,
mode = "passive",
getDamageOnMeleeHit = function(self, t) return self:combatTalentSpellDamage(t, 5, 50) end,
getDarkDamageIncrease = function(self, t) return self:combatTalentSpellDamage(t, 20, 50) end,
info = function(self, t)
return ([[Your Hymns now focus darkness near you, which increases your darkness damage by %d%% and does %0.2f darkness damage to anyone who hits you in melee.
These values scale with your Spellpower.]]):format(t.getDarkDamageIncrease(self, t), damDesc(self, DamageType.DARKNESS, t.getDamageOnMeleeHit(self, t)))
end,
}
-- Remember that Hymns can be swapped instantly.
newTalent{
name = "Hymn Adept",
type = {"celestial/hymns", 6},
require = divi_req3,
points = 5,
mode = "passive",
getBonusInfravision = function(self, t) return math.floor(self:combatTalentScale(t, 0.75, 3.5, 0.75)) end,
getSpeed = function(self, t) return self:combatTalentSpellDamage(t, 300, 600) end,
shieldDur = function(self, t) return self:combatTalentSpellDamage(t, 5, 10) end,
shieldPower = function(self, t) return self:combatTalentSpellDamage(t, 50, 400) end,
invisDur = function(self, t) return self:combatTalentSpellDamage(t, 5, 10) end,
invisPower = function(self, t) return self:combatTalentSpellDamage(t, 20, 30) end,
info = function(self, t)
return ([[Your skill in Hymns now improves your sight in darkness, increasing your infravision radius by %d.
Also, when you end a Hymn, you will gain a buff of a type based on which Hymn you ended.
Hymn of Shadows increases your movement speed by %d%% for one turn.
Hymn of Detection makes you invisible (power %d) for %d turns.
Hymn of Perseverance grants a damage shield (power %d) for %d turns.]]):format(t.getBonusInfravision(self, t), t.getSpeed(self, t),
t.invisPower(self, t), t.invisDur(self, t), t.shieldPower(self, t), t.shieldDur(self, t))
end,
}
newTalent{
name = "Hymn Nocturnalist",
type = {"celestial/hymns", 7},
require = divi_req4,
points = 5,
mode = "passive",
negative = 1, -- This is just to ensure they have a negative pool
range = 5,
getDamage = function(self, t) return self:combatTalentSpellDamage(t, 7, 80) end,
getTargetCount = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5)) end,
getNegativeDrain = function(self, t) return self:combatTalentLimit(t, 0, 5, 3) end,
getBonusRegen = function(self, t) return self:combatTalentScale(t, 0.7, 4.0, 0.75) / 10 end,
callbackOnRest = function(self, t)
if not self:knowTalent(self.T_NEGATIVE_POOL) then return false end
if self.negative_regen > 0.1 and self.negative < self.max_negative then return true end
return false
end,
do_beams = function(self, t)
if self:getNegative() < t.getNegativeDrain(self, t) then return end
local tgts = {}
local grids = core.fov.circle_grids(self.x, self.y, 5, true)
for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do
local a = game.level.map(x, y, Map.ACTOR)
if a and self:reactionToward(a) < 0 then
tgts[#tgts+1] = a
end
end end
if #tgts <= 0 then return end
local drain = t.getNegativeDrain(self, t)
local dam = rng.avg(1, self:spellCrit(t.getDamage(self, t)), 3)
-- Randomly take targets
local tg = {type="hit", range=self:getTalentRange(t), talent=t}
for i = 1, t.getTargetCount(self, t) do
if #tgts <= 0 then break end
if self:getNegative() - 1 < drain then break end
local a, id = rng.table(tgts)
table.remove(tgts, id)
self:project(tg, a.x, a.y, DamageType.DARKNESS_BLIND, dam)
game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(a.x-self.x), math.abs(a.y-self.y)), "shadow_beam", {tx=a.x-self.x, ty=a.y-self.y})
game:playSoundNear(self, "talents/spell_generic")
self:incNegative(-drain)
end
end,
info = function(self, t)
return ([[Your passion for singing the praises of the Moons reaches its zenith, increasing your negative energy regeneration by %0.1f per turn.
Your Hymns now fires shadowy beams that will hit up to %d of your foes within radius 5 for 1 to %0.2f damage, with a 20%% chance of blinding.
This powerful effect will drain %0.1f negative energy for each beam; no beam will fire if your negative energy is too low.
These values scale with your Spellpower.]]):format(t.getBonusRegen(self, t), t.getTargetCount(self, t), damDesc(self, DamageType.DARKNESS, t.getDamage(self, t)), t.getNegativeDrain(self, t))
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