Commit 110960b6e589b7b261c43e0097a313397c572bad

Authored by DarkGod
2 parents 48821c46 c7429097

Merge branch 'DefilerUpdates2' into 'master'

Defiler updates2

(CORRUPTOR)

- Torment unlocked base.  Feels weird that Reaver gets this but not Corruptor, and the tree really isn't good enough to be worth a category point.

(REAVER):  Corruptor is definitely an underpowered class but Reaver is considerably stronger, and both are benefitting from these changes.  The following are Reaver-specific birth tweaks to offset the improvements a bit.  Note that these changes are still a big net buff to Reaver overall.

- Life rating reduced by 1

- Plague mastery level reduced to 1.0 from 1.3.  There are a *lot* of disease synergies that Reaver has access to both from specific talents (Rot) and weapon itemization (ITEM_BLIGHT_DISEASE, Epidemic proc, disease tinker, Gnaw..).  While its unintuitive for a class with so much focus on disease to have a lower mastery in practice they still get more use out of it than Corruptor.

- Sanguisage mastery reduced to 1.0

- Vim mastery reduced to 1.0

(BONE)

Bone Spear: Redesigned. No longer causes bleed but deals more damage per magical debuff on every enemy hit and has higher base damage. Idea here is to better integrate with the rest of the Defiler talents since this is an off damage type. Bleeding has no synergy or theme relation to the class.

Bone Grab: If you target an adjacent enemy this now teleports them away from you randomly instead of bringing them to you. These classes could use more survival utility, and Bone Grab is particularly worthless on Corruptor at the moment.

Bone Nova: Removed. These classes do not need an off damage type PBAOE.

New Talent - Bone Spike: Passive. Casts a mini-Bone Spear at all enemies in LOS that have at least 2 magical debuffs at the end of your turn.

Bone Shield: Now only procs on damage over a threshold based on spellpower, cooldown reduced to 15 from 30, charges reduced. This is particularly important for Reaver since the game is full of melee retaliation damage, but even on Corruptor its too much. This should preserve the theme of being vulnerable to small hits without letting every little thing break your shield easily.

(CURSES)

Curse of Defenselessness: No longer has a save check but only lasts 5 turns. This should guarantee Corruptors can always land their debuffs at least some of the time.

(PLAGUE)

Virulent Disease:  Now passive and applies on non-disease blight damage dealt (prioritizing an enemy with the highest disease count).  This talent already feels like a proc since its an instant cast that you spam on cooldown all game.  This way, though, you do actually have to *do* something to get the effect.  This indirectly removes the range 5 limitation which will help it be more useful to Corruptor again.  Overall, this is a minor to moderate nerf but QoL improvement that should still maintain the functionality of the rest of the synergy talents in the tree.

Cyst Burst:  Cooldown reduced from 9 to 4, range increased from 8 to 10, cost increased to 25, damage increased from 15,85 to 15,120 (45,360 at 3 diseases), targeting changed to hit from bolt.  This helps add another short cooldown blight damage nuke for rotations trying to maximize the new Virulent Disease.  At 9 cooldown you're stuck having to save it for once you have all your diseases built up pre-catalepsy.  Targeting is simple QoL, its annoying when you can't use a combo setup talent because some dumb trash mob is in your path.

(ROT)

Infestation:  Now checked before Bone Shield to avoid antisynergy.

(SCOURGE):

Rend:  Removed.  Bleed is out of theme and not synergistic with Reaver, and since Reaver only gets 3 melee specific strikes I'd like them to have a fair amount of polish.

Dark Surprise:  Removed.  See above.

New talent - Virulent Strike:  Replacement for Rend.  Same damage but each hit increases the duration of a random disease on the target by 1..3.

New talent - Corruption Strike:  Applies a brief 100% disease immunity reduction, removes 2 nature sustains, then hits with both weapons for blight damage.  This is kind of a messy design.  The original plan was for a strike that stripped nature effects and sustains, but after talking it over with people adding more things that kill infusion buffs and such didn't seem like a great idea.  The disease immunity reduction is applied before the weapon attack making it pretty useful for applying the new VD or disease weapon procs on the same hit.

Acid Strike:  Radius now scales, damage on the splash increased, cost increased.

(BLIGHT)

Dark Ritual:  Crit mult reduced.

Corrossive Worm:  Resistance reduction reduced.

Poison Storm:  No longer ignores poison immunity, radius reduced by 1.

(VIM)

Dark Portal:  Swapped places with Vim Sense to give these classes mobility a bit faster.

Vim Sense:  Cooldown reduced from 25 to 15, blight resistance lowered, now also reduces saves, cost increased.  Since this is a not terribly impressive 2 talent combo with Leech it didn't make sense to have it on such a long cooldown.  Landing debuffs is a problem both Corruptor and Reaver have and since this talent needed love anyway it was a good place to put it.

Leech:  Values reduced.  These numbers were okay at 25 CD, but its a bit generous at 15.

(SANGUISAGE)

Drain:  Cooldown reduced to 5, no longer blocked by allies.  This is never a high impact talent so there isn't a good reason to limit it by cooldown so strictly.  Pets blocking it was really annoying.

Bloodcasting: Now passive. Anytime you cast a spell you don't have enough vim for you pay twice the cost in life instead.

Absorb Life:  Now instant cast.

Life Tap:  Redesigned.  Now gives lifesteal for 2 turns.  Use before a big Catalepsy, AoE bombs in general, etc.

(TORMENT)

Wilful Tormenter:  Numbers raised a bit, changed to passive instead of sustain.

Bloody Vengeance:  Now checked before Bone Shield.  Added log entry, clarified that it works on all talents not all spells.

(VILE LIFE)

Blood Splash: Both heals can now crit. Simple scaling improvement.

Vile Transplant: Range increased to 5 from 1. We don't need this talent being so melee-specific and this change also lets you more easily dump on random trash mobs if you can't beat the save of the stronger targets.

Healing Inversion:  Range increased to 10.

(BLOOD)

Blood Grasp: Now increases your max HP based on damage dealt, no longer has friendly fire. This is designed to help things like Leech and other healing not have strong anti-synergy with Bone Shield, but the numbers have been lowered to be suboptimal in a damage rotation.

Blood Boil:  Redesigned.  Now consumes 1 disease, bleed, or poison on enemies to deal damage and slow them healing you for each one.

(REAVING COMBAT)

Corrupted Strength:  Damage considerably reduced.  Just another part of refactoring class power to make room for the buffs.

Bloodlust:  Spellpower cap increased significantly, buildup time increased slightly.  The amount of time this takes to stack is not trivial, and with 1.5 numbers its underwhelming even if it just gave the spellpower passively.  Also, having spellpower available directly reduces the value of staves, though not that significantly.

Acid Splash:  Accuracy reduction removed, damage significantly increased.  The accuracy reduction feels random and out of place (were not a defense class) and this adds a bit more acid damage to the class.

(MISC)

- Add a disease effect coloring to Actor tooltips

- Clarified that Bloody Vengeance reduces all talent cooldowns not all spells

- Fix Rot Carrion Worms being hardcoded to attack the summoner

- Disable Worm Walk on NPCs as it currently has no tactical table and is a % of max HP healer which were planning to disable all variants of until they're rescaled to something else

- Fix Carrion Worms spamming the combat log with useless 0 damages

- Remove the combat log entry for Leech

- Fix Bloodlust stacking on self damage

- Fix Carrion Worms not properly inheriting spellpower

- Fixed Vile Life breaking on effects that get removed during iteration

- Change Healing Inversion to always use the effect source for projecting to fix various bugs

- Fix Cyst Burst and Epidemic not checking resists/saves properly 

- Fix Pestilent Blight breaking if the target is dead

- Fix Bone Shield not updating without reactivation

- Remove log spam from Bone Shield regeneration

- Fix Corrupted Negation tooltip

See merge request !482
... ... @@ -2022,7 +2022,11 @@ function _M:tooltip(x, y, seen_by)
2022 2022 if e.type == "physical" then
2023 2023 effphysical:add(true, "- ", {"color", "LIGHT_RED"}, desceffect(e, p, dur), {"color", "WHITE"} )
2024 2024 elseif e.type == "magical" then
2025   - effmagical:add(true, "- ", {"color", "DARK_ORCHID"}, desceffect(e, p, dur), {"color", "WHITE"} )
  2025 + if e.subtype and e.subtype.disease then
  2026 + effmagical:add(true, "- ", {"color", "DARK_GREEN"}, desceffect(e, p, dur), {"color", "WHITE"} )
  2027 + else
  2028 + effmagical:add(true, "- ", {"color", "DARK_ORCHID"}, desceffect(e, p, dur), {"color", "WHITE"} )
  2029 + end
2026 2030 elseif e.type == "mental" then
2027 2031 effmental:add(true, "- ", {"color", "YELLOW"}, desceffect(e, p, dur), {"color", "WHITE"} )
2028 2032 elseif e.type == "other" then
... ... @@ -2390,14 +2394,6 @@ function _M:onTakeHit(value, src, death_note)
2390 2394 end
2391 2395 end
2392 2396
2393   - if value > 0 and self:isTalentActive(self.T_BONE_SHIELD) then
2394   - local t = self:getTalentFromId(self.T_BONE_SHIELD)
2395   - if t.absorb(self, t, self:isTalentActive(self.T_BONE_SHIELD)) then
2396   - game:delayedLogDamage(src, self, 0, ("#SLATE#(%d to bones)#LAST#"):format(value), false)
2397   - value = 0
2398   - end
2399   - end
2400   -
2401 2397 if value <=0 then return 0 end
2402 2398 if self.knowTalent and (self:knowTalent(self.T_SEETHE) or self:knowTalent(self.T_GRIM_RESOLVE)) then
2403 2399 if not self:hasEffect(self.EFF_CURSED_FORM) then
... ... @@ -2587,7 +2583,7 @@ function _M:onTakeHit(value, src, death_note)
2587 2583 end
2588 2584
2589 2585 -- Bloodlust!
2590   - if value > 0 and src and src.knowTalent and src:knowTalent(src.T_BLOODLUST) then
  2586 + if value > 0 and src and not (src == self) and src.knowTalent and src:knowTalent(src.T_BLOODLUST) then
2591 2587 src:setEffect(src.EFF_BLOODLUST, 1, {})
2592 2588 end
2593 2589
... ... @@ -2726,7 +2722,7 @@ function _M:onTakeHit(value, src, death_note)
2726 2722 local vt = self:getTalentFromId(self.T_LEECH)
2727 2723 self:incVim(vt.getVim(self, vt))
2728 2724 self:heal(vt.getHeal(self, vt), src)
2729   - if self.player then src:logCombat(src, "#AQUAMARINE#You leech a part of #Target#'s vim.") end
  2725 + --if self.player then src:logCombat(src, "#AQUAMARINE#You leech a part of #Target#'s vim.") end
2730 2726 end
2731 2727
2732 2728 -- Invisible on hit
... ... @@ -5212,9 +5208,10 @@ end
5212 5208 local previous_incVim = _M.incVim
5213 5209 function _M:incVim(v)
5214 5210 if v < 0 and self:attr("bloodcasting") then
  5211 + local mult = self:attr("bloodcasting") / 100
5215 5212 local cost = math.abs(v)
5216 5213 if self.vim - cost < 0 then
5217   - local damage = cost - (self.vim or 0)
  5214 + local damage = (cost - (self.vim or 0)) * mult
5218 5215 self:incVim(-self.vim or 0)
5219 5216 self.life = self.life - damage
5220 5217 else
... ... @@ -5229,7 +5226,7 @@ end
5229 5226 local previous_getVim = _M.getVim
5230 5227 function _M:getVim()
5231 5228 if self:attr("bloodcasting") and self.on_preuse_checking_resources then
5232   - return self.life
  5229 + return math.max(self.vim, self.life)
5233 5230 else
5234 5231 return previous_getVim(self)
5235 5232 end
... ... @@ -5887,7 +5884,7 @@ function _M:postUseTalent(ab, ret, silent)
5887 5884 if #tgts > 0 then
5888 5885 self.turn_procs.corrupted_strength = true
5889 5886 DamageType:projectingFor(self, {project_type={talent=self:getTalentFromId(self.T_CORRUPTED_STRENGTH)}})
5890   - self:attackTarget(rng.table(tgts), DamageType.BLIGHT, self:combatTalentWeaponDamage(self.T_CORRUPTED_STRENGTH, 0.5, 1.1), true)
  5887 + self:attackTarget(rng.table(tgts), DamageType.BLIGHT, self:combatTalentWeaponDamage(self.T_CORRUPTED_STRENGTH, 0.2, 0.7), true)
5891 5888 DamageType:projectingFor(self, nil)
5892 5889 end
5893 5890 end
... ...
... ... @@ -64,15 +64,15 @@ newBirthDescriptor{
64 64 talents_types = {
65 65 ["technique/combat-training"]={true, 0.3},
66 66 ["cunning/survival"]={false, 0.1},
67   - ["corruption/sanguisuge"]={true, 0.3},
  67 + ["corruption/sanguisuge"]={true, 0.0},
68 68 ["corruption/reaving-combat"]={true, 0.3},
69 69 ["corruption/scourge"]={true, 0.3},
70   - ["corruption/plague"]={true, 0.3},
  70 + ["corruption/plague"]={true, 0.0},
71 71 ["corruption/hexes"]={false, 0.3},
72 72 ["corruption/curses"]={false, 0.3},
73 73 ["corruption/bone"]={true, 0.3},
74 74 ["corruption/torment"]={true, 0.3},
75   - ["corruption/vim"]={true, 0.3},
  75 + ["corruption/vim"]={true, 0.0},
76 76 ["corruption/rot"]={false, 0.3},
77 77 },
78 78 talents = {
... ... @@ -99,7 +99,7 @@ newBirthDescriptor{
99 99 },
100 100 },
101 101 copy_add = {
102   - life_rating = 2,
  102 + life_rating = 1,
103 103 },
104 104 }
105 105
... ... @@ -136,7 +136,7 @@ newBirthDescriptor{
136 136 ["corruption/blood"]={true, 0.3},
137 137 ["corruption/vim"]={true, 0.3},
138 138 ["corruption/blight"]={true, 0.3},
139   - ["corruption/torment"]={false, 0.3},
  139 + ["corruption/torment"]={true, 0.3},
140 140 },
141 141 talents = {
142 142 [ActorTalents.T_DRAIN] = 1,
... ...
... ... @@ -843,6 +843,9 @@ newDamageType{
843 843 if src and src.knowTalent and realdam > 0 and target and src:knowTalent(src.T_PESTILENT_BLIGHT) then
844 844 src:callTalent(src.T_PESTILENT_BLIGHT, "do_rot", target, realdam)
845 845 end
  846 + if src and src.knowTalent and realdam > 0 and target and src:knowTalent(src.T_VIRULENT_DISEASE) and (not state or not state.from_disease) then
  847 + src:callTalent(src.T_VIRULENT_DISEASE, "do_disease", target, realdam)
  848 + end
846 849 return realdam
847 850 end,
848 851 death_message = {"diseased", "poxed", "infected", "plagued", "debilitated by noxious blight before falling", "fouled", "tainted"},
... ... @@ -2443,6 +2446,22 @@ newDamageType{
2443 2446 end,
2444 2447 }
2445 2448
  2449 +-- Used by Blood Grasp, heal+temporary max life based on damage
  2450 +newDamageType{
  2451 + name = "sanguine blight", type = "SANGUINE", text_color = "#DARK_GREEN#",
  2452 + projector = function(src, x, y, type, dam, state)
  2453 + state = initState(state)
  2454 + useImplicitCrit(src, state)
  2455 + if _G.type(dam) == "number" then dam = {dam=dam} end
  2456 + local target = game.level.map(x, y, Map.ACTOR) -- Get the target first to make sure we heal even on kill
  2457 + local dealt = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam, state)
  2458 + if dealt > 0 then
  2459 + src:setEffect(src.EFF_BLOOD_GRASP, 7, {life = dealt * 0.5} )
  2460 + src:heal(dealt * 0.2, src)
  2461 + end
  2462 + return dealt
  2463 + end,
  2464 +}
2446 2465 -- Drain Vim
2447 2466 newDamageType{
2448 2467 name = "vim draining blight", type = "DRAIN_VIM", text_color = "#DARK_GREEN#",
... ...
... ... @@ -29,7 +29,7 @@ newTalent{
29 29 activate = function(self, t)
30 30 game:playSoundNear(self, "talents/slime")
31 31 local ret = {
32   - per = self:addTemporaryValue("combat_critical_power", self:combatTalentSpellDamage(t, 20, 60)),
  32 + per = self:addTemporaryValue("combat_critical_power", self:combatTalentSpellDamage(t, 20, 50)),
33 33 }
34 34 if core.shader.active() then
35 35 local h1x, h1y = self:attachementSpot("head", true) if h1x then self:talentParticles(ret, {type="circle", args={toback=true, shader=true, oversize=0.7, a=225, appear=8, speed=0, img="dark_ritual_aura", base_rot=0, radius=0, x=h1x, y=h1y}}) end
... ... @@ -43,7 +43,7 @@ newTalent{
43 43 info = function(self, t)
44 44 return ([[Increases your spell critical damage multiplier by %d%%.
45 45 The multiplier will increase with your Spellpower.]]):
46   - format(self:combatTalentSpellDamage(t, 20, 60))
  46 + format(self:combatTalentSpellDamage(t, 20, 50))
47 47 end,
48 48 }
49 49
... ... @@ -61,7 +61,7 @@ newTalent{
61 61 target = function(self, t)
62 62 return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t), talent=t}
63 63 end,
64   - getRemoveCount = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, "log")) end,
  64 + getRemoveCount = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5, "log")) end, -- Oh for the love of god no, fix me
65 65 action = function(self, t)
66 66 local tg = self:getTalentTarget(t)
67 67 local x, y = self:getTarget(tg)
... ... @@ -111,7 +111,7 @@ newTalent{
111 111 return true
112 112 end,
113 113 info = function(self, t)
114   - return ([[Project a corrupted blast of power that deals %0.2f blight damage and removes up to %d magical or physical effect(s) from any creatures caught in the radius 3 ball.
  114 + return ([[Project a corrupted blast of power that deals %0.2f blight damage and removes up to %d magical or physical sustains or effect(s) from any creatures caught in the radius 3 ball.
115 115 For each effect, the creature has a chance to resist based on its spell save.
116 116 The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 28, 120)), t.getRemoveCount(self, t))
117 117 end,
... ... @@ -125,7 +125,7 @@ newTalent{
125 125 cooldown = 12,
126 126 vim = 12,
127 127 range = 10,
128   - getResist = function(self, t) return math.ceil(self:combatTalentScale(t, 8, 35)) end,
  128 + getResist = function(self, t) return math.ceil(self:combatTalentScale(t, 3, 20)) end,
129 129 getPercent = function(self, t) return self:combatTalentSpellDamage(t, 12, 45) end, -- Scaling?
130 130 getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 60) end,
131 131 tactical = { ATTACK = {ACID = 2}, DISABLE = 1 },
... ... @@ -158,7 +158,7 @@ newTalent{
158 158 vim = 28,
159 159 cooldown = 24,
160 160 range = 0,
161   - radius = 5,
  161 + radius = 4,
162 162 tactical = { ATTACKAREA = {BLIGHT = 3}, DISABLE = 2 },
163 163 target = function(self, t)
164 164 return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)}
... ... @@ -172,7 +172,6 @@ newTalent{
172 172 local fail = 50*power/(power + 26) -- Limit < 50% chance
173 173 return power, heal_factor, fail
174 174 end,
175   - getPoisonPenetration = function(self, t) return self:combatTalentLimit(t, 100, 15, 75) end,
176 175 getPoison = function(self,t)
177 176 if self:getTalentLevel(t) >= 6 then return 4
178 177 elseif self:getTalentLevel(t) >= 4 then return 3
... ... @@ -189,7 +188,7 @@ newTalent{
189 188 -- Add a lasting map effect
190 189 game.level.map:addEffect(self,
191 190 self.x, self.y, duration,
192   - DamageType.BLIGHT_POISON, {dam=dam, power=power, heal_factor=heal_factor, fail=fail, penetration=t.getPoisonPenetration(self,t), poison=t.getPoison(self,t), apply_power=actor:combatSpellpower()},
  191 + DamageType.BLIGHT_POISON, {dam=dam, power=power, heal_factor=heal_factor, fail=fail, penetration=0, poison=t.getPoison(self,t), apply_power=actor:combatSpellpower()},
193 192 radius,
194 193 5, nil,
195 194 MapEffect.new{
... ... @@ -209,13 +208,13 @@ newTalent{
209 208 info = function(self, t)
210 209 local dam = damDesc(self, DamageType.BLIGHT, t.getDamage(self,t))
211 210 local power, heal_factor, fail = t.getEffects(self, t)
212   - return ([[A furious storm of blighted poison rages around the caster in a radius of %d for %d turns. Each creature hit by the storm takes %0.2f blight damage and is poisoned for %0.2f blight damage over 4 turns. The blight poison is especially virulent, and has a %d%% chance to ignore poison immunity.
  211 + return ([[A furious storm of blighted poison rages around the caster in a radius of %d for %d turns. Each creature hit by the storm takes %0.2f blight damage and is poisoned for %0.2f blight damage over 4 turns.
213 212 At talent level 2 you have a chance to inflict Insidious Blight, which reduces healing by %d%%.
214 213 At talent level 4 you have a chance to inflict Numbing Blight, which reduces all damage dealt by %d%%.
215 214 At talent level 6 you have a chance to inflict Crippling Blight, which causes talents to have a %d%% chance of failure.
216 215 Each possible effect is equally likely.
217 216 The poison damage dealt is capable of a critical strike.
218 217 The damage will increase with your Spellpower.]]):
219   - format(self:getTalentRadius(t), t.getDuration(self, t), dam/4, dam, t.getPoisonPenetration(self,t), heal_factor, power, fail)
  218 + format(self:getTalentRadius(t), t.getDuration(self, t), dam/4, dam, heal_factor, power, fail)
220 219 end,
221 220 }
\ No newline at end of file
... ...
... ... @@ -67,20 +67,23 @@ newTalent{
67 67 proj_speed = 20,
68 68 tactical = { ATTACK = {BLIGHT = 1.75}, HEAL = {BLIGHT = 1}}, -- damage to foe heals self
69 69 requires_target = true,
  70 + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 190) end,
70 71 target = function(self, t)
71   - return {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="bolt_blood"}}
  72 + return {type="bolt", range=self:getTalentRange(t), selffire=false, friendlyfire=false, talent=t, display={particle="bolt_blood"}}
72 73 end,
73 74 action = function(self, t)
74 75 local tg = self:getTalentTarget(t)
75 76 local x, y = self:getTarget(tg)
76 77 if not x or not y then return nil end
77   - self:projectile(tg, x, y, DamageType.DRAINLIFE, {dam=self:spellCrit(self:combatTalentSpellDamage(t, 10, 290)), healfactor=0.5}, {type="blood"})
  78 + local damage = self:spellCrit(t.getDamage(self, t))
  79 + self:projectile(tg, x, y, DamageType.SANGUINE, {dam=damage}, {type="blood"})
78 80 game:playSoundNear(self, "talents/slime")
79 81 return true
80 82 end,
81 83 info = function(self, t)
82   - return ([[Project a bolt of corrupted blood, doing %0.2f blight damage and healing you for half the damage done.
83   - The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 10, 290)))
  84 + return ([[Project a bolt of corrupted blood, doing %0.2f blight damage and healing you for 20%% the damage dealt.
  85 + 50%% of the damage dealt will be gained as maximum life for 7 turns (before the healing).
  86 + The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.BLIGHT, t.getDamage(self, t)))
84 87 end,
85 88 }
86 89
... ... @@ -89,25 +92,44 @@ newTalent{
89 92 type = {"corruption/blood", 3},
90 93 require = corrs_req3,
91 94 points = 5,
92   - cooldown = 12,
  95 + cooldown = 8,
93 96 vim = 30,
94   - tactical = { ATTACKAREA = {BLIGHT = 2}, DISABLE = 1 },
  97 + tactical = { ATTACKAREA = {BLIGHT = 0.5} }, -- Needs a better tactical table, setting to low priority for now so it gets used later in the rotation when diseases are up
95 98 range = 0,
96   - radius = function(self, t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
  99 + radius = function(self, t) return 10 end,
  100 + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 250) end,
  101 + getSlow = function(self, t) return self:combatTalentLimit(t, 100, 20, 70) end,
  102 + getHeal = function(self, t) return self:combatTalentSpellDamage(t, 10, 90) end,
97 103 requires_target = true,
98 104 target = function(self, t)
99   - return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
  105 + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, friendlyfire=false, talent=t}
100 106 end,
101 107 action = function(self, t)
102 108 local tg = self:getTalentTarget(t)
103   - self:project(tg, self.x, self.y, DamageType.BLOOD_BOIL, self:spellCrit(self:combatTalentSpellDamage(t, 28, 190)))
  109 + local x, y = self.x, self.y
  110 + local damage = self:spellCrit(t.getDamage(self, t))
  111 + local slow = t.getSlow(self, t) / 100
  112 + local heal = t.getHeal(self, t)
  113 + local amount = 0
  114 + self:project(tg, x, y, function(px, py)
  115 + local target = game.level.map(px, py, Map.ACTOR)
  116 + if not target then return end
  117 + local eff = target:removeEffectsFilter(function(e) return e.subtype.poison or e.subtype.disease or e.subtype.wound end, 1)
  118 + if eff and eff > 0 then
  119 + local dealt = DamageType:get(DamageType.BLIGHT).projector(self, target.x, target.y, DamageType.BLIGHT, damage)
  120 + target:setEffect(target.EFF_SLOW, 5, {src=self, power=slow})
  121 + amount = amount + 1
  122 + end
  123 + end)
  124 + if amount > 0 then self:heal(heal * amount, self) end
104 125 game.level.map:particleEmitter(self.x, self.y, tg.radius, "circle", {oversize=1, a=180, appear=8, limit_life=8, speed=-3, img="blood_circle", radius=tg.radius})
105 126 game:playSoundNear(self, "talents/slime")
106 127 return true
107 128 end,
108 129 info = function(self, t)
109   - return ([[Make the blood of all creatures around you in radius %d boil, doing %0.2f blight damage and slowing them by 20%%.
110   - The damage will increase with your Spellpower.]]):format(self:getTalentRadius(t), damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 28, 190)))
  130 + return ([[Make the impure blood of all creatures around you in radius %d boil.
  131 + Each enemy afflicted by a disease, poison, or wound will have one removed at random dealing %0.2f blight damage, healing you for %d, and slowing them by %d%% for 5 turns.
  132 + The damage will increase with your Spellpower.]]):format(self:getTalentRadius(t), damDesc(self, DamageType.BLIGHT, t.getDamage(self, t)), t.getHeal(self, t), t.getSlow(self, t))
111 133 end,
112 134 }
113 135
... ...
... ... @@ -23,13 +23,13 @@ newTalent{
23 23 require = corrs_req1,
24 24 points = 5,
25 25 vim = 13,
26   - cooldown = 4,
  26 + cooldown = 10,
27 27 range = 10,
28   - random_ego = "attack",
29 28 tactical = { ATTACK = {PHYSICAL = 2} },
30 29 direct_hit = true,
31 30 requires_target = true,
32   - getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 200) end,
  31 + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 250) end,
  32 + getBonus = function(self, t) return 0.3 end,
33 33 target = function(self, t)
34 34 return {type="beam", range=self:getTalentRange(t), talent=t}
35 35 end,
... ... @@ -37,15 +37,25 @@ newTalent{
37 37 local tg = self:getTalentTarget(t)
38 38 local x, y = self:getTarget(tg)
39 39 if not x or not y then return nil end
40   - self:project(tg, x, y, DamageType.PHYSICALBLEED, self:spellCrit(t.getDamage(self, t)))
  40 +
  41 + local dam = self:spellCrit(t.getDamage(self, t))
  42 +
  43 + self:project(tg, x, y, function(tx, ty)
  44 + local target = game.level.map(tx, ty, Map.ACTOR)
  45 + if not target then return end
  46 + local effs = #target:effectsFilter({status="detrimental", type="magical"})
  47 + local damage = dam * (1 + t.getBonus(self, t) * effs)
  48 + DamageType:get(DamageType.PHYSICAL).projector(self, tx, ty, DamageType.PHYSICAL, damage)
  49 + end)
41 50 local _ _, _, _, x, y = self:canProject(tg, x, y)
42 51 game.level.map:particleEmitter(self.x, self.y, tg.range, "bone_spear", {tx=x - self.x, ty=y - self.y})
43 52 game:playSoundNear(self, "talents/arcane")
  53 +
44 54 return true
45 55 end,
46 56 info = function(self, t)
47   - return ([[Conjures up a spear of bones, doing %0.2f physical damage to all targets in line, and inflicting bleeding for another %0.2f damage over 5 turns.
48   - The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)), damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)/2))
  57 + return ([[Conjures up a spear of bones, doing %0.2f physical damage to all targets in a line. Each target takes an additional %d%% damage for each magical debuff they are afflicted with.
  58 + The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)), damDesc(self, DamageType.PHYSICAL, t.getBonus(self, t)*100))
49 59 end,
50 60 }
51 61
... ... @@ -54,7 +64,7 @@ newTalent{
54 64 type = {"corruption/bone", 2},
55 65 require = corrs_req2,
56 66 points = 5,
57   - vim = 28,
  67 + vim = 15,
58 68 cooldown = 15,
59 69 range = function(self, t) return math.floor(self:combatTalentLimit(t, 10, 4, 9)) end,
60 70 tactical = { DISABLE = 1, CLOSEIN = 3 },
... ... @@ -67,56 +77,95 @@ newTalent{
67 77 if not x or not y then return nil end
68 78
69 79 local dam = self:spellCrit(t.getDamage(self, t))
70   -
71 80 self:project(tg, x, y, function(px, py)
72 81 local target = game.level.map(px, py, engine.Map.ACTOR)
73 82 if not target then return end
74 83
75   - target:pull(self.x, self.y, tg.range)
76   -
77   - DamageType:get(DamageType.PHYSICALBLEED).projector(self, target.x, target.y, DamageType.PHYSICALBLEED, dam)
78   - if target:canBe("pin") then
79   - target:setEffect(target.EFF_BONE_GRAB, t.getDuration(self, t), {apply_power=self:combatSpellpower()})
  84 + if core.fov.distance(self.x, self.y, target.x, target.y) > 1 then
  85 + target:pull(self.x, self.y, tg.range)
  86 + DamageType:get(DamageType.PHYSICAL).projector(self, target.x, target.y, DamageType.PHYSICAL, dam)
  87 + if target:canBe("pin") then
  88 + target:setEffect(target.EFF_BONE_GRAB, t.getDuration(self, t), {apply_power=self:combatSpellpower()})
  89 + else
  90 + game.logSeen(target, "%s resists the bone!", target.name:capitalize())
  91 + end
80 92 else
81   - game.logSeen(target, "%s resists the bone!", target.name:capitalize())
  93 + local tg = {type="cone", cone_angle=25, range=0, radius=8, friendlyfire=false}
  94 +
  95 + local grids = {}
  96 + self:project(tg, x, y, function(px, py)
  97 + if core.fov.distance(target.x, target.y, px, py) > 2 then grids[#grids+1] = {px, py} end
  98 + end)
  99 +
  100 + DamageType:get(DamageType.PHYSICAL).projector(self, target.x, target.y, DamageType.PHYSICAL, dam)
  101 + if target:canBe("pin") then
  102 + target:setEffect(target.EFF_BONE_GRAB, t.getDuration(self, t), {apply_power=self:combatSpellpower()})
  103 + else
  104 + game.logSeen(target, "%s resists the bone!", target.name:capitalize())
  105 + end
  106 +
  107 + local hit = self:checkHit(self:combatSpellpower(), target:combatSpellResist() + (target:attr("continuum_destabilization") or 0))
  108 + if not target:canBe("teleport") or not hit then
  109 + game.logSeen(target, "%s resists being teleported by Bone Grab!", target.name:capitalize())
  110 + return true
  111 + end
  112 + local spot = rng.table(grids)
  113 + if not spot then return end
  114 + target:teleportRandom(spot[1], spot[2], 0)
82 115 end
83 116 end)
84   - game:playSoundNear(self, "talents/arcane")
85   -
  117 + game:playSoundNear(self, "talents/arcane")
86 118 return true
87 119 end,
88 120 info = function(self, t)
89   - return ([[Grab a target and teleport it to your side, pinning it there with a bone rising from the ground for %d turns.
90   - The bone will also deal %0.2f physical damage, inflicting bleeding for another %0.2f damage over 5 turns.
  121 + return ([[Grab a target and teleport it to your side or if adjacent to a random location at least 3 spaces away from you, pinning it there with a bone rising from the ground for %d turns.
  122 + The bone will also deal %0.2f physical damage.
91 123 The damage will increase with your Spellpower.]]):
92   - format(t.getDuration(self, t), damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)), damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)/2))
  124 + format(t.getDuration(self, t), damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)))
93 125 end,
94 126 }
95 127
96 128 newTalent{
97   - name = "Bone Nova",
  129 + name = "Bone Spike",
98 130 type = {"corruption/bone", 3},
99 131 require = corrs_req3,
  132 + image = "talents/bone_nova.png",
100 133 points = 5,
101   - vim = 25,
102   - cooldown = 12,
103   - tactical = { ATTACKAREA = {PHYSICAL = 2} },
104   - random_ego = "attack",
105   - radius = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5)) end,
106   - getDamage = function(self, t) return self:combatTalentSpellDamage(t, 8, 180) end,
  134 + mode = "passive",
  135 + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 60) end,
  136 + radius = 10,
107 137 target = function(self, t)
108   - return {type="ball", radius=self:getTalentRadius(t), selffire=false, talent=t}
  138 + return {type="ball", radius=self:getTalentRadius(t), selffire=false, friendlyfire=false, talent=t}
109 139 end,
110   - action = function(self, t)
111   - local tg = self:getTalentTarget(t)
112   - self:project(tg, self.x, self.y, DamageType.PHYSICALBLEED, self:spellCrit(t.getDamage(self, t)))
113   - game.level.map:particleEmitter(self.x, self.y, tg.radius, "circle", {oversize=1.1, a=255, limit_life=8, grow=true, speed=0, img="bone_nova", radius=self:getTalentRadius(t)})
114   - game:playSoundNear(self, "talents/arcane")
115   - return true
  140 + callbackOnTalentPost = function(self, t, ab, ret, silent)
  141 + if ab.no_energy then return end
  142 + if self.turn_procs.bone_spike then return end
  143 + self.turn_procs.bone_spike = true
  144 + game:onTickEnd(function()
  145 + local tg = self:getTalentTarget(t)
  146 + local dam = t.getDamage(self, t)
  147 + local did_crit = false
  148 + self:project(tg, self.x, self.y, function(px, py)
  149 + local target = game.level.map(px, py, engine.Map.ACTOR)
  150 + if not target then return end
  151 + local nb = #target:effectsFilter({status="detrimental", type="magical"})
  152 + if nb and nb < 3 then return end
  153 +
  154 + -- Make sure crit is only calculated once, but do it here so we don't trigger a crit if there are no targets
  155 + if did_crit == false then
  156 + dam = self:spellCrit(dam)
  157 + did_crit = true
  158 + end
  159 +
  160 + self:project({type="beam", range=10, selffire=false, friendlyfire=false, talent=t}, target.x, target.y, DamageType.PHYSICAL, dam)
  161 + local _ _, _, _, x, y = self:canProject(tg, x, y)
  162 + game.level.map:particleEmitter(self.x, self.y, 10, "bone_spear", {speed=0.2, tx=target.x - self.x, ty=target.y - self.y})
  163 + end)
  164 + end)
116 165 end,
117 166 info = function(self, t)
118   - return ([[Fire bone spears in all directions, hitting all foes within radius %d for %0.2f physical damage, and inflicting bleeding for another %0.2f damage over 5 turns.
119   - The damage will increase with your Spellpower.]]):format(self:getTalentRadius(t), damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)), damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)/2))
  167 + return ([[Whenever you use a non-instant talent you launch a spear of bone at all enemies afflicted by 3 or more magical detrimental effects dealing %d physical damage to all enemies it passes through.
  168 + The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t)) )
120 169 end,
121 170 }
122 171
... ... @@ -126,12 +175,13 @@ newTalent{
126 175 points = 5,
127 176 mode = "sustained", no_sustain_autoreset = true,
128 177 require = corrs_req4,
129   - cooldown = 30,
  178 + cooldown = 15,
130 179 sustain_vim = 50,
131 180 tactical = { DEFEND = 4 },
132 181 direct_hit = true,
133   - getNb = function(self, t) return math.floor(self:combatTalentScale(t, 1, 5)) end,
134   - getRegen = function(self, t) return math.max(math.floor(30 / t.getNb(self, t)), 3) end,
  182 + getRegen = function(self, t) return self:combatTalentLimit(t, 3, 20, 3.3) end,
  183 + getNb = function(self, t) return math.floor(self:combatTalentScale(t, 1, 3.5)) end,
  184 + getThreshold = function(self, t) return math.floor(self:combatSpellpower()) end,
135 185 iconOverlay = function(self, t, p)
136 186 local p = self.sustain_talents[t.id]
137 187 if not p or not p.nb then return "" end
... ... @@ -143,15 +193,17 @@ newTalent{
143 193 if not p or p.nb < nb then return true end
144 194 end,
145 195 callbackOnActBase = function(self, t)
  196 + if not self:isTalentActive(t.id) then return end
146 197 local p = self.sustain_talents[t.id]
147 198 p.next_regen = (p.next_regen or 1) - 1
148 199 if p.next_regen <= 0 then
149   - p.next_regen = p.between_regens or 10
  200 + p.next_regen = t.getRegen(self, t) or 10
150 201
151 202 if p.nb < t.getNb(self, t) then
152 203 p.nb = p.nb + 1
153 204 if p.adv_gfx then
154 205 if p.particles[1] and p.particles[1]._shader and p.particles[1]._shader.shad then
  206 + if not p.particles[1].shader then p.particles[1] = self:addParticles(Particles.new("shader_ring_rotating", 1, {toback=true, a=0.5, rotation=0, radius=1.5, img="bone_shield"}, {type="boneshield"})) end
155 207 p.particles[1]._shader.shad:resetClean()
156 208 p.particles[1]._shader:setResetUniform("chargesCount", util.bound(p.nb, 0, 10))
157 209 p.particles[1].shader.chargesCount = util.bound(p.nb, 0, 10)
... ... @@ -159,16 +211,19 @@ newTalent{
159 211 else
160 212 p.particles[#p.particles+1] = self:addParticles(Particles.new("bone_shield", 1))
161 213 end
162   - game.logSeen(self, "A part of %s's bone shield regenerates.", self.name)
163 214 end
164 215 end
165 216 end,
166   - absorb = function(self, t, p)
  217 + callbackOnHit = function(self, t, cb, src, dt)
  218 + local p = self:isTalentActive(t.id)
  219 + if not p then return end
167 220 if not p.nb or p.nb <= 0 then return end
168   -
  221 + if not cb.value or cb.value < t.getThreshold(self, t) then return end
169 222 p.nb = p.nb - 1
170 223 if p.adv_gfx then
171 224 if p.particles[1] and p.particles[1]._shader and p.particles[1]._shader.shad then
  225 + -- Clones don't copy this so we need to recreate it sometimes
  226 + if not p.particles[1].shader then p.particles[1] = self:addParticles(Particles.new("shader_ring_rotating", 1, {toback=true, a=0.5, rotation=0, radius=1.5, img="bone_shield"}, {type="boneshield"})) end
172 227 p.particles[1]._shader.shad:resetClean()
173 228 p.particles[1]._shader:setResetUniform("chargesCount", util.bound(p.nb, 0, 10))
174 229 p.particles[1].shader.chargesCount = util.bound(p.nb, 0, 10)
... ... @@ -177,8 +232,8 @@ newTalent{
177 232 local pid = table.remove(p.particles)
178 233 self:removeParticles(pid)
179 234 end
180   -
181   - game.logPlayer(self, "Your bone shield absorbs the damage!")
  235 + game:delayedLogDamage(src, self, 0, ("#SLATE#(%d to bones)#LAST#"):format(cb.value), false)
  236 + cb.value = 0
182 237 return true
183 238 end,
184 239 activate = function(self, t)
... ... @@ -199,9 +254,9 @@ newTalent{
199 254 return {
200 255 adv_gfx = adv_gfx,
201 256 particles = ps,
  257 + clone_test = 1,
202 258 nb = nb,
203 259 next_regen = t.getRegen(self, t),
204   - between_regens = t.getRegen(self, t),
205 260 }
206 261 end,
207 262 deactivate = function(self, t, p)
... ... @@ -211,7 +266,8 @@ newTalent{
211 266 info = function(self, t)
212 267 return ([[Bone shields start circling around you. They will each fully absorb one attack.
213 268 %d shield(s) will be generated when first activated.
214   - Then every %d turns a new one will be created if not full.]]):
215   - format(t.getNb(self, t), t.getRegen(self, t))
  269 + Then every %d turns a new one will be created if not full.
  270 + This will only trigger on hits over %d damage based on Spellpower.]]):
  271 + format(t.getNb(self, t), t.getRegen(self, t), t.getThreshold(self, t))
216 272 end,
217 273 }
... ...
... ... @@ -22,7 +22,7 @@ newTalent{
22 22 type = {"corruption/curses", 1},
23 23 require = corrs_req1,
24 24 points = 5,
25   - cooldown = 20,
  25 + cooldown = 15,
26 26 vim = 20,
27 27 range = 10,
28 28 tactical = { DISABLE = 2 },
... ... @@ -35,14 +35,14 @@ newTalent{
35 35 self:project(tg, x, y, function(tx, ty)
36 36 local target = game.level.map(tx, ty, Map.ACTOR)
37 37 if not target then return end
38   - target:setEffect(target.EFF_CURSE_DEFENSELESSNESS, 10, {power=self:combatTalentSpellDamage(t, 30, 60), apply_power=self:combatSpellpower()})
  38 + target:setEffect(target.EFF_CURSE_DEFENSELESSNESS, 5, {power=self:combatTalentSpellDamage(t, 30, 60)})
39 39 game.level.map:particleEmitter(tx, ty, 1, "circle", {base_rot=0, oversize=0.7, a=130, limit_life=8, appear=8, speed=0, img="curse_gfx", radius=0})
40 40 end)
41 41 game:playSoundNear(self, "talents/slime")
42 42 return true
43 43 end,
44 44 info = function(self, t)
45   - return ([[Curses your target, decreasing its Defense and all saves by %d for 10 turns.
  45 + return ([[Curses your target, decreasing its Defense and all saves by %d for 5 turns. This cannot be saved against.
46 46 The effects will improve with your Spellpower.]]):format(self:combatTalentSpellDamage(t, 30, 60))
47 47 end,
48 48 }
... ... @@ -103,8 +103,8 @@ newTalent{
103 103 return true
104 104 end,
105 105 info = function(self, t)
106   - return ([[Curses your target, stopping any natural healing and dealing %0.2f darkness damage each turn for 10 turns.
107   - The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.DARKNESS, self:combatTalentSpellDamage(t, 10, 70)))
  106 + return ([[Curses your target, preventing normal life regeneration and dealing %0.2f darkness damage over 10 turns.
  107 + The damage will increase with your Spellpower.]]):format(damDesc(self, DamageType.DARKNESS, self:combatTalentSpellDamage(t, 10, 70)*10))
108 108 end,
109 109 }
110 110
... ...
... ... @@ -38,57 +38,61 @@ local getTargetDiseases = function(self, target)
38 38 return diseases
39 39 end
40 40
  41 +-- Fix dead priority
  42 +-- Add a clear display on where the disease went
41 43 newTalent{
42 44 name = "Virulent Disease",
43 45 type = {"corruption/plague", 1},
44 46 require = corrs_req1,
45 47 points = 5,
46   - vim = 8,
47 48 cooldown = 3,
48   - random_ego = "attack",
49   - tactical = { ATTACK = {BLIGHT = {disease=2}} },
50   - requires_target = true,
51   - no_energy = true,
52   - target = function(self, t) return {type="hit", range=self:getTalentRange(t), talent=t} end,
53   - range = function(self, t) return 5 end, -- Instant cast should not do thousands of damage at long range. This is still too powerful, though
54   - action = function(self, t)
55   - local tg = self:getTalentTarget(t)
56   - local x, y = self:getTarget(tg)
57   - if not x or not y then return nil end
  49 + mode = "passive",
  50 + do_disease = function(self, t, target, val)
  51 + if self:isTalentCoolingDown(t) then return end
58 52
59   - local diseases = {{self.EFF_WEAKNESS_DISEASE, "str"}, {self.EFF_ROTTING_DISEASE, "con"}, {self.EFF_DECREPITUDE_DISEASE, "dex"}}
60   - local disease = rng.table(diseases)
61   -
62   - -- Try to rot !
63   - self:project(tg, x, y, function(px, py)
  53 + -- Grab an enemy of radius 5 of the damaged target that has the most diseases else default to the actor damaged
  54 + local disease_target = {actor=target, count=0}
  55 + if dead then disease_target.actor = "none" end
  56 + self:project({type="ball", radius=5, friendlyfire=false, selffire=false, x=target.x, y=target.y}, target.x, target.y, function(px, py)
64 57 local target = game.level.map(px, py, engine.Map.ACTOR)
65 58 if not target then return end
66   - if target:canBe("disease") then
67   - local str, dex, con = not target:hasEffect(self.EFF_WEAKNESS_DISEASE) and target:getStr() or 0, not target:hasEffect(self.EFF_DECREPITUDE_DISEASE) and target:getDex() or 0, not target:hasEffect(self.EFF_ROTTING_DISEASE) and target:getCon() or 0
  59 + local count = #target:effectsFilter(function(e) return e.subtype.disease end, 9)
  60 + if (count > 0 and disease_target.count < count) or disease_target.actor == "none" then -- If the initial target was dead then we grab a semi-random one
  61 + disease_target.actor = target
  62 + disease_target.count = count
  63 + end
  64 + end)
68 65
69   - if str >= dex and str >= con then
70   - disease = {self.EFF_WEAKNESS_DISEASE, "str"}
71   - elseif dex >= str and dex >= con then
72   - disease = {self.EFF_DECREPITUDE_DISEASE, "dex"}
73   - elseif con > 0 then
74   - disease = {self.EFF_ROTTING_DISEASE, "con"}
75   - end
  66 + if disease_target.actor == "none" then return end
  67 + target = disease_target.actor
  68 + local diseases = {{self.EFF_WEAKNESS_DISEASE, "str"}, {self.EFF_ROTTING_DISEASE, "con"}, {self.EFF_DECREPITUDE_DISEASE, "dex"}}
  69 + local disease = rng.table(diseases)
76 70
77   - target:setEffect(disease[1], 6, {src=self, dam=self:spellCrit(7 + self:combatTalentSpellDamage(t, 6, 45)), [disease[2]]=self:combatTalentSpellDamage(t, 5, 35), apply_power=self:combatSpellpower()})
78   - else
79   - game.logSeen(target, "%s resists the disease!", target.name:capitalize())
  71 + if target:canBe("disease") then
  72 + local str, dex, con = not target:hasEffect(self.EFF_WEAKNESS_DISEASE) and target:getStr() or 0, not target:hasEffect(self.EFF_DECREPITUDE_DISEASE) and target:getDex() or 0, not target:hasEffect(self.EFF_ROTTING_DISEASE) and target:getCon() or 0
  73 +
  74 + if str >= dex and str >= con then
  75 + disease = {self.EFF_WEAKNESS_DISEASE, "str"}
  76 + elseif dex >= str and dex >= con then
  77 + disease = {self.EFF_DECREPITUDE_DISEASE, "dex"}
  78 + elseif con > 0 then
  79 + disease = {self.EFF_ROTTING_DISEASE, "con"}
80 80 end
81   - game.level.map:particleEmitter(px, py, 1, "circle", {oversize=0.7, a=200, limit_life=8, appear=8, speed=-2, img="disease_circle", radius=0})
82   - end)
83   - game:playSoundNear(self, "talents/slime")
84 81
85   - return true
  82 + target:setEffect(disease[1], 6, {src=self, dam=self:spellCrit(7 + self:combatTalentSpellDamage(t, 6, 45)), [disease[2]]=self:combatTalentSpellDamage(t, 5, 35), apply_power=self:combatSpellpower()})
  83 + else
  84 + game.logSeen(target, "%s resists the disease!", target.name:capitalize())
  85 + end
  86 + self:startTalentCooldown(t)
  87 + game.level.map:particleEmitter(target.x, target.y, 1, "circle", {oversize=0.7, a=200, limit_life=8, appear=8, speed=-2, img="disease_circle", radius=0})
  88 + game:playSoundNear(self, "talents/slime")
86 89 end,
87 90 info = function(self, t)
88   - return ([[Fires a bolt of pure filth, diseasing your target with a disease doing %0.2f blight damage per turn for 6 turns, and reducing one of its physical stats (strength, constitution, dexterity) by %d. The three diseases can stack.
  91 + return ([[Whenever you dealt non-disease blight damage you apply a disease dealing %0.2f blight damage per turn for 6 turns and reducing one of its physical stats (strength, constitution, dexterity) by %d. The three diseases can stack.
89 92 Virulent Disease will always try to apply a disease the target does not currently have, and also one that will have the most debilitating effect for the target.
  93 + This disease will try to prioritize being applied to an enemy with a high disease count near the target.
90 94 The effect will increase with your Spellpower.]]):
91   - format(damDesc(self, DamageType.BLIGHT, 7 + self:combatTalentSpellDamage(t, 6, 65)), self:combatTalentSpellDamage(t, 5, 35))
  95 + format(damDesc(self, DamageType.BLIGHT, 7 + self:combatTalentSpellDamage(t, 6, 45)), self:combatTalentSpellDamage(t, 5, 35))
92 96 end,
93 97 }
94 98
... ... @@ -98,8 +102,8 @@ newTalent{
98 102 require = corrs_req2,
99 103 points = 5,
100 104 vim = 18,
101   - cooldown = 9,
102   - range = 8,
  105 + cooldown = 4,
  106 + range = 10,
103 107 radius = function(self, t) return math.floor(self:combatTalentScale(t, 1.5, 3.5)) end,
104 108 getTargetDiseases = getTargetDiseases,
105 109 tactical = function(self, t, aitarget)
... ... @@ -130,7 +134,7 @@ newTalent{
130 134 local x, y = self:getTarget(tg)
131 135 if not x or not y then return nil end
132 136
133   - local dam = self:spellCrit(self:combatTalentSpellDamage(t, 15, 85))
  137 + local dam = self:spellCrit(self:combatTalentSpellDamage(t, 15, 90))
134 138 local diseases
135 139
136 140 -- Try to rot !
... ... @@ -148,7 +152,7 @@ newTalent{
148 152 end)
149 153
150 154 if diseases and #diseases > 0 then -- burst in a radius
151   - self:project({type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t)}, x, y, function(px, py)
  155 + self:project({type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t), talent=t}, x, y, function(px, py)
152 156 local target = game.level.map(px, py, engine.Map.ACTOR)
153 157 if not target or target == source or target == self or (self:reactionToward(target) >= 0) then return end
154 158
... ... @@ -157,7 +161,13 @@ newTalent{
157 161 parameters.src = self
158 162 parameters.apply_power = self:combatSpellpower()
159 163 parameters.__tmpvals = nil
160   - target:setEffect(disease.id, 6, parameters)
  164 +
  165 + local dur = math.max(6, parameters.dur)
  166 + if target:canBe("disease") then
  167 + target:setEffect(disease.id, dur, parameters)
  168 + else
  169 + game.logSeen(target, "%s resists the disease!", target.name:capitalize())
  170 + end
161 171 end
162 172 end)
163 173 game.level.map:particleEmitter(x, y,self:getTalentRadius(t), "circle", {oversize=0.7, a=200, limit_life=8, appear=8, speed=-2, img="disease_circle", radius=self:getTalentRadius(t)})
... ... @@ -168,9 +178,9 @@ newTalent{
168 178 end,
169 179 info = function(self, t)
170 180 return ([[Make your target's diseases burst, doing %0.2f blight damage for each disease it is infected with.
171   - This will also spread any diseases to any nearby foes in a radius of %d.
  181 + This will also spread any diseases to any nearby foes in a radius of %d with a minimum duration of 6.
172 182 The damage will increase with your Spellpower.]]):
173   - format(damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 15, 85)), self:getTalentRadius(t))
  183 + format(damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 15, 115)), self:getTalentRadius(t))
174 184 end,
175 185 }
176 186
... ... @@ -282,6 +292,7 @@ newTalent{
282 292 local params = table.clone(disease.params, true)
283 293 params.__tmpvals = nil
284 294 params.src = self
  295 + params.apply_power = self:combatSpellpower()
285 296 if target:canBe("disease") then
286 297 target:setEffect(disease.id, 6, params)
287 298 else
... ...
... ... @@ -38,10 +38,11 @@ newTalent{
38 38 info = function(self, t)
39 39 return ([[Allows you to dual wield any type of one handed weapons, and increases the damage of the off-hand weapon to %d%%.
40 40 Also, casting a spell (which uses a turn) will give a free melee attack at a random target in melee range for %d%% blight damage.]]):
41   - format(100*t.getoffmult(self,t), 100 * self:combatTalentWeaponDamage(t, 0.5, 1.1))
  41 + format(100*t.getoffmult(self,t), 100 * self:combatTalentWeaponDamage(t, 0.2, 0.7))
42 42 end,
43 43 }
44 44
  45 +-- Fix display
45 46 newTalent{
46 47 name = "Bloodlust",
47 48 type = {"corruption/reaving-combat", 2},
... ... @@ -52,13 +53,13 @@ newTalent{
52 53 -- Effect is refreshed in function _M:onTakeHit(value, src) in mod\class\Actor.lua
53 54 -- getParams called in definition of EFF_BLOODLUST in data\timed_effects\magical.lua
54 55 getParams = function(self, t) -- returns maxSP per turn, max duration
55   - return self:combatTalentScale(t, 1, 5, 0.75), math.floor(self:combatTalentScale(t, 2, 6))
  56 + return self:combatTalentScale(t, 1, 8, 0.75), math.floor(self:combatTalentScale(t, 2, 6))
56 57 end,
57 58 info = function(self, t)
58 59 local SPbonus, maxDur = t.getParams(self, t)
59 60 return ([[Each time you deal damage to one of your foes, you enter a bloodlust-infused frenzy, increasing your Spellpower by 1 (maximum %d Spellpower per turn, %d Spellpower overall), and extending any current frenzy for an additional turn.
60 61 The frenzy lasts up to %d turns, and the bonus decreases by %0.1f%% of its current value each turn you don't deal damage.]]):
61   - format(SPbonus, SPbonus*6, maxDur, 100/maxDur)
  62 + format(SPbonus / 5, SPbonus*8, maxDur, 100/maxDur)
62 63 end,
63 64 }
64 65
... ...
... ... @@ -99,8 +99,8 @@ carrionworm = function(self, target, duration, x, y)
99 99 m.unused_talents_types = 0
100 100 m.no_inventory_access = true
101 101 m.no_points_on_levelup = true
  102 + m.carrion_worm = true -- This keeps the on_death effect from spamming the damage log with 0s
102 103 m.save_hotkeys = true
103   - m.ai_state = m.ai_state or {}
104 104 m.ai_state.tactic_leash = 100
105 105 -- Try to use stored AI talents to preserve tweaking over multiple summons
106 106 m.ai_talents = self.stored_ai_talents and self.stored_ai_talents[m.name] or {}
... ... @@ -155,7 +155,7 @@ newTalent{
155 155 getDamageReduction = function(self, t)
156 156 return self:combatTalentLimit(t, 0.5, 0.1, 0.22)
157 157 end,
158   - tactical = { BUFF = 2 },
  158 + tactical = {BUFF = 3},
159 159 activate = function(self, t)
160 160 local resist = t.getResist(self,t)
161 161 local affinity = t.getAffinity(self,t)
... ... @@ -175,11 +175,10 @@ newTalent{
175 175 self:removeTemporaryValue("worm", p.worm)
176 176 return true
177 177 end,
178   - callbackPriorities={callbackOnHit = -5}, -- High priority since we do more than just reduce damage and want to make sure the worm spawn happens often
179   - callbackOnHit = function(self, t, cb)
180   - if ( cb.value > (0.15 * self.max_life) ) then
181   - local damageReduction = cb.value * t.getDamageReduction(self, t)
182   - cb.value = cb.value - damageReduction
  178 + callbackOnTakeDamage = function(self, t, src, x, y, type, dam, state)
  179 + if ( dam > (0.15 * self.max_life) ) then
  180 + local damageReduction = dam * t.getDamageReduction(self, t)
  181 + dam = dam - damageReduction
183 182
184 183 local nb = 0
185 184 if game.level then
... ... @@ -206,7 +205,7 @@ newTalent{
206 205 carrionworm(self, self, 5, gx, gy)
207 206 end
208 207 end
209   - return cb.value
  208 + return {dam = dam}
210 209 end
211 210 end,
212 211 info = function(self, t)
... ...
... ... @@ -23,19 +23,19 @@ newTalent{
23 23 require = corrs_req1,
24 24 points = 5,
25 25 vim = 0,
26   - cooldown = 9,
  26 + cooldown = 5,
27 27 reflectable = true,
28 28 proj_speed = 15,
29 29 tactical = { ATTACK = {BLIGHT = 1.75},
30 30 VIM = {BLIGHT = function(self, t, target) return 2*target:getRankVimAdjust()^.5 end}
31 31 },
32 32 requires_target = true,
33   - range = function(self, t) return math.floor(self:combatTalentScale(t, 5, 9)) end,
  33 + range = function(self, t) return math.min(10, math.floor(self:combatTalentScale(t, 6, 10))) end,
34 34 action = function(self, t)
35   - local tg = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="bolt_slime"}}
  35 + local tg = {type="bolt", friendlyblock=false, range=self:getTalentRange(t), talent=t, display={particle="bolt_slime"}}
36 36 local x, y = self:getTarget(tg)
37 37 if not x or not y then return nil end
38   - self:projectile(tg, x, y, DamageType.DRAIN_VIM, self:spellCrit(self:combatTalentSpellDamage(t, 25, 200)), {type="slime"})
  38 + self:project(tg, x, y, DamageType.DRAIN_VIM, self:spellCrit(self:combatTalentSpellDamage(t, 25, 200)), {type="slime"})
39 39 game:playSoundNear(self, "talents/slime")
40 40 return true
41 41 end,
... ... @@ -47,68 +47,22 @@ newTalent{
47 47 end,
48 48 }
49 49
50   ---[[
51   -newTalent{
52   - name = "Blood Sacrifice",
53   - type = {"corruption/sanguisuge", 2},
54   - require = corrs_req2,
55   - points = 5,
56   - vim = 0,
57   - cooldown = 30,
58   - range = 10,
59   - tactical = { VIM = 1 },
60   - action = function(self, t)
61   - local amount = self.life * 0.5
62   - if self.life <= amount + 1 then
63   - game.logPlayer(self, "Doing this would kill you.")
64   - return
65   - end
66   -
67   - local seen = false
68   - -- Check for visible monsters, only see LOS actors, so telepathy wont prevent resting
69   - core.fov.calc_circle(self.x, self.y, game.level.map.w, game.level.map.h, 20, function(_, x, y) return game.level.map:opaque(x, y) end, function(_, x, y)
70   - local actor = game.level.map(x, y, game.level.map.ACTOR)
71   - if actor and self:reactionToward(actor) < 0 and self:canSee(actor) and game.level.map.seens(x, y) then
72   - seen = {x=x,y=y,actor=actor}
73   - end
74   - end, nil)
75   - if not seen then
76   - game.logPlayer(self, "There are no foes in sight.")
77   - return
78   - end
79   -
80   - self:incVim(30 + self:combatTalentSpellDamage(t, 5, 150))
81   - self:takeHit(amount, self)
82   - game:playSoundNear(self, "talents/spell_generic2")
83   - return true
84   - end,
85   - info = function(self, t)
86   - return ([=[Sacrifices 50%% of your current life to restore %d vim.
87   - This only works if there is at least one foe in sight.
88   - The effect will increase with your Magic stat.]=]):
89   - format(30 + self:combatTalentSpellDamage(t, 5, 150))
90   - end,
91   -}
92   -]]
  50 +-- Sustain?
93 51 newTalent{
94 52 name = "Bloodcasting",
95 53 type = {"corruption/sanguisuge", 2},
96 54 require = corrs_req2,
97 55 points = 5,
98   - vim = 0,
99   - cooldown = 18,
100   - no_energy = true,
101   - range = 10,
  56 + mode = "passive",
102 57 no_npc_use = true,
103   - getDuration = function(self, t) return math.floor(self:combatTalentLimit(t, 18, 3, 7)) end, --Limit duration < 18
104   - action = function(self, t)
105   - self:setEffect(self.EFF_BLOODCASTING, t.getDuration(self,t), {})
106   - game:playSoundNear(self, "talents/spell_generic2")
107   - return true
  58 + getLifeCost = function(self, t) return math.floor(self:combatTalentScale(t, 250, 100)) end,
  59 + passives = function(self, t, p)
  60 + self:talentTemporaryValue(p, "bloodcasting", t.getLifeCost(self, t))
108 61 end,
109 62 info = function(self, t)
110   - return ([[For %d turns, your corruption spells will consume health instead of vim if their cost is higher than your vim.]]):
111   - format(t.getDuration(self,t))
  63 + return ([[Your corruption spells will consume health instead of vim if their cost is higher than your vim.
  64 + The health cost is equal to %d%% of the vim cost.]]):
  65 + format(t.getLifeCost(self,t))
112 66 end,
113 67 }
114 68
... ... @@ -121,6 +75,7 @@ newTalent{
121 75 sustain_vim = 5,
122 76 cooldown = 30,
123 77 range = 10,
  78 + no_energy = true,
124 79 tactical = { BUFF = 2 },
125 80 VimOnDeath = function(self, t) return self:combatTalentScale(t, 6, 16) end,
126 81 activate = function(self, t)
... ... @@ -155,15 +110,17 @@ newTalent{
155 110 cooldown = 20,
156 111 range = 10,
157 112 no_energy = true,
158   - tactical = { BUFF = 2 },
159   - getMult = function(self,t) return self:combatTalentScale(t, 8, 16) end,
  113 + tactical = { HEAL = 2 },
  114 + getMult = function(self,t) return self:combatTalentSpellDamage(t, 4, 30) end,
160 115 action = function(self, t)
161   - self:setEffect(self.EFF_LIFE_TAP, 7, {power=t.getMult(self,t)})
  116 + self:setEffect(self.EFF_LIFE_TAP, 2, {power=t.getMult(self,t)})
162 117 game:playSoundNear(self, "talents/spell_generic2")
163 118 return true
164 119 end,
165 120 info = function(self, t)
166   - return ([[Tap your life force to provide a furious boost, increasing all damage you deal by %0.1f%% for 7 turns.]]):
  121 + return ([[Feed on the pain you cause your foes.
  122 + For 2 turns you gain %d%% lifesteal on all damage dealt.
  123 + The lifesteal will increase with your Spellpower.]]):
167 124 format(t.getMult(self,t))
168 125 end,
169 126 }
... ...
... ... @@ -17,24 +17,29 @@
17 17 -- Nicolas Casalini "DarkGod"
18 18 -- darkgod@te4.org
19 19
  20 +-- Reaver gets an abnormally low number of melee strikes so its important that cooldowns and such reflect this, otherwise it encourages playing as a ranged caster
  21 +
20 22 local DamageType = require "engine.DamageType"
21 23
22 24 newTalent{
23   - name = "Rend",
  25 + name = "Virulent Strike",
  26 + short_name = "REND",
24 27 type = {"corruption/scourge", 1},
25 28 require = corrs_req1,
26 29 points = 5,
27   - vim = 9,
28   - cooldown = 6,
  30 + vim = 15,
  31 + cooldown = 4,
29 32 range = 1,
30 33 is_melee = true,
31 34 target = function(self, t) return {type="hit", range=self:getTalentRange(t)} end,
32 35 tactical = { ATTACK = {PHYSICAL = 2} },
33 36 requires_target = true,
  37 + getIncrease = function(self, t) return math.floor(self:combatTalentLimit(t, 4, 1, 3.5)) end,
  38 + getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.6) end,
34 39 action = function(self, t)
35 40 local weapon, offweapon = self:hasDualWeapon()
36 41 if not weapon then
37   - game.logPlayer(self, "You cannot use Rend without two weapons!")
  42 + game.logPlayer(self, "You cannot use Virulent Strike without two weapons!")
38 43 return nil
39 44 end
40 45
... ... @@ -43,32 +48,30 @@ newTalent{
43 48 if not target or not self:canProject(tg, x, y) then return nil end
44 49
45 50 DamageType:projectingFor(self, {project_type={talent=t}})
46   - local speed1, hit1 = self:attackTargetWith(target, weapon.combat, nil, self:combatTalentWeaponDamage(t, 0.8, 1.6))
47   - local speed2, hit2 = self:attackTargetWith(target, offweapon.combat, nil, self:getOffHandMult(offweapon.combat, self:combatTalentWeaponDamage(t, 0.8, 1.6)))
  51 + local speed1, hit1 = self:attackTargetWith(target, weapon.combat, nil, t.getDamage(self, t))
  52 + local speed2, hit2 = self:attackTargetWith(target, offweapon.combat, nil, self:getOffHandMult(offweapon.combat, t.getDamage(self, t)))
48 53 DamageType:projectingFor(self, nil)
49 54
50   - -- Try to bleed !
51 55 if hit1 then
52   - if target:canBe("cut") then
53   - target:setEffect(target.EFF_CUT, 5, {power=self:combatTalentSpellDamage(t, 5, 40), src=self, apply_power=self:combatPhysicalpower()})
54   - else
55   - game.logSeen(target, "%s resists the cut!", target.name:capitalize())
  56 + local effs = target:effectsFilter(function(e) return e.subtype.disease end, 1)
  57 + local eff2 = target:hasEffect(effs[1])
  58 + if eff2 then
  59 + eff2.dur = eff2.dur + t.getIncrease(self, t)
56 60 end
57 61 end
58 62 if hit2 then
59   - if target:canBe("cut") then
60   - target:setEffect(target.EFF_CUT, 5, {power=self:combatTalentSpellDamage(t, 5, 40), src=self, apply_power=self:combatPhysicalpower()})
61   - else
62   - game.logSeen(target, "%s resists the cut!", target.name:capitalize())
  63 + local effs = target:effectsFilter(function(e) return e.subtype.disease end, 1)
  64 + local eff2 = target:hasEffect(effs[1])
  65 + if eff2 then
  66 + eff2.dur = eff2.dur + t.getIncrease(self, t)
63 67 end
64 68 end
65 69
66 70 return true
67 71 end,
68 72 info = function(self, t)
69   - return ([[Hit the target with both weapons, doing %d%% damage with each hit. For each hit, the target will bleed for %0.2f damage each turn for 5 turns.
70   - The bleeding effect will increase with your Spellpower.]]):
71   - format(100 * self:combatTalentWeaponDamage(t, 0.8, 1.6), self:combatTalentSpellDamage(t, 5, 40))
  73 + return ([[Strike the target with both weapons dealing %d%% damage with each hit. Each strike that hits will increase the duration of a random disease effect by %d.]]):
  74 + format(100 * t.getDamage(self, t), t.getIncrease(self, t))
72 75 end,
73 76 }
74 77
... ... @@ -107,17 +110,19 @@ newTalent{
107 110 type = {"corruption/scourge", 3},
108 111 require = corrs_req3,
109 112 points = 5,
110   - vim = 18,
111   - cooldown = 12,
  113 + vim = 20,
  114 + cooldown = 8,
112 115 range = 1,
113   - radius = 1,
  116 + radius = function(self, t) return self:combatTalentLimit(t, 7, 1, 5) end,
114 117 requires_target = true,
115 118 is_melee = true,
116   - tactical = { ATTACK = {ACID = 2}, DISABLE = 1 },
  119 + tactical = { ATTACK = {ACID = 2}},
117 120 target = function(self, t)
118 121 -- Tries to simulate the acid splash
119   - return {type="ballbolt", range=1, radius=self:getTalentRadius(t), selffire=false, talent=t}
  122 + return {type="ballbolt", range=1, radius=self:getTalentRadius(t), selffire=false, friendlyfire=false, talent=t}
120 123 end,
  124 + getSplash = function(self, t) return self:combatTalentSpellDamage(t, 10, 200) end,
  125 + getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.6) end,
121 126 action = function(self, t)
122 127 local weapon, offweapon = self:hasDualWeapon()
123 128 if not weapon then
... ... @@ -130,8 +135,8 @@ newTalent{
130 135 if not target or not self:canProject(tg, x, y) then return nil end
131 136
132 137 DamageType:projectingFor(self, {project_type={talent=t}})
133   - local speed1, hit1 = self:attackTargetWith(target, weapon.combat, DamageType.ACID, self:combatTalentWeaponDamage(t, 0.8, 1.6))
134   - local speed2, hit2 = self:attackTargetWith(target, offweapon.combat, DamageType.ACID, self:getOffHandMult(offweapon.combat, self:combatTalentWeaponDamage(t, 0.8, 1.6)))
  138 + local speed1, hit1 = self:attackTargetWith(target, weapon.combat, DamageType.ACID, t.getDamage(self, t))
  139 + local speed2, hit2 = self:attackTargetWith(target, offweapon.combat, DamageType.ACID, self:getOffHandMult(offweapon.combat, t.getDamage(self, t)))
135 140 DamageType:projectingFor(self, nil)
136 141
137 142 -- Acid splash !
... ... @@ -139,35 +144,37 @@ newTalent{
139 144 local tg = self:getTalentTarget(t)
140 145 tg.x = target.x
141 146 tg.y = target.y
142   - self:project(tg, target.x, target.y, DamageType.ACID, self:spellCrit(self:combatTalentSpellDamage(t, 10, 130)))
  147 + self:project(tg, target.x, target.y, DamageType.ACID, self:spellCrit(t.getSplash(self, t)))
143 148 end
144 149
145 150 return true
146 151 end,
147 152 info = function(self, t)
148 153 return ([[Strike with each of your weapons, doing %d%% acid weapon damage with each hit.
149   - If at least one of the strikes hits, an acid splash is generated, doing %0.2f acid damage to all targets other than yourself adjacent to the foe you struck.
  154 + If at least one of the strikes hits, an acid splash is generated, doing %0.2f acid damage to all enemies in radius %d around the foe you struck.
150 155 The splash damage will increase with your Spellpower.]]):
151   - format(100 * self:combatTalentWeaponDamage(t, 0.8, 1.6), damDesc(self, DamageType.ACID, self:combatTalentSpellDamage(t, 10, 130)))
  156 + format(100 * t.getDamage(self, t), damDesc(self, DamageType.ACID, t.getSplash(self, t)), self:getTalentRadius(t))
152 157 end,
153 158 }
154 159
155 160 newTalent{
156   - name = "Dark Surprise",
  161 + name = "Corrupting Strike",
  162 + short_name = "DARK_SURPRISE",
157 163 type = {"corruption/scourge", 4},
158 164 require = corrs_req4,
159 165 points = 5,
160   - vim = 14,
  166 + vim = 30,
161 167 cooldown = 8,
162 168 range = 1,
163 169 is_melee = true,
164 170 requires_target = true,
165   - tactical = { ATTACK = {DARKNESS = 1, BLIGHT = 1}, DISABLE = 2 },
  171 + tactical = { ATTACK = {BLIGHT = 1},},
166 172 target = function(self, t) return {type="hit", range=self:getTalentRange(t)} end,
  173 + getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1, 2) end,
167 174