diff --git a/game/engines/default/engine/interface/ActorProject.lua b/game/engines/default/engine/interface/ActorProject.lua index 43d34781d191712480c4a5ea17493fd47bfc4eaf..72f8459cd6fffa2dd4a194a0b6b374e9ead889b1 100644 --- a/game/engines/default/engine/interface/ActorProject.lua +++ b/game/engines/default/engine/interface/ActorProject.lua @@ -201,7 +201,7 @@ function _M:project(t, x, y, damtype, dam, particles) self:check("on_project_grids", grids) -- Now project on each grid, one type - local tmp = {} + local state = {} local stop = false DamageType:projectingFor(self, {project_type=typ}) for px, ys in pairs(grids) do @@ -215,7 +215,7 @@ function _M:project(t, x, y, damtype, dam, particles) -- Otherwise hit else if type(damtype) == "function" then if damtype(px, py, t, self) then stop=true break end - else DamageType:get(damtype).projector(self, px, py, damtype, dam, tmp, nil) end + else DamageType:get(damtype).projector(self, px, py, damtype, dam, state, nil) end if particles then game.level.map:particleEmitter(px, py, 1, particles.type, particles.args) end diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua index a19087048420eee6439a032cc1722c82062e095b..0c7d0ecb8fd2a004bcdde9b833b22d52c6fe1dba 100644 --- a/game/modules/tome/data/damage_types.lua +++ b/game/modules/tome/data/damage_types.lua @@ -20,17 +20,35 @@ local print = print if not config.settings.cheat then print = function() end end +-- Loads the implicit crit if one has not been passed. +function DamageType.useImplicitCrit(src, state) + if state.crit_set then return end + state.crit_set = true + state.crit_type = src.turn_procs.is_crit + state.crit_power = src.turn_procs.crit_power or 1 + src.turn_procs.is_crit = nil + src.turn_procs.crit_power = nil +end + +local useImplicitCrit = DamageType.useImplicitCrit + -- The basic stuff used to damage a grid -setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) +setDefaultProjector(function(src, x, y, type, dam, state, no_martyr) if not game.level.map:isBound(x, y) then return 0 end + -- Manage crits. + state = state or {} + useImplicitCrit(src, state) + local crit_type = state.crit_type + local crit_power = state.crit_power + local add_dam = 0 if src:attr("all_damage_convert") and src.all_damage_convert ~= type then local ndam = dam * src.all_damage_convert_percent / 100 dam = dam - ndam local nt = src.all_damage_convert src.all_damage_convert = nil - add_dam = DamageType:get(nt).projector(src, x, y, nt, ndam, tmp, no_martyr) + add_dam = DamageType:get(nt).projector(src, x, y, nt, ndam, state, no_martyr) src.all_damage_convert = nt if dam <= 0 then return add_dam end end @@ -40,10 +58,10 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) local old = src.elemental_mastery src.elemental_mastery = nil dam = 0 - dam = dam + DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, ndam, tmp, no_martyr) - dam = dam + DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, ndam, tmp, no_martyr) - dam = dam + DamageType:get(DamageType.LIGHTNING).projector(src, x, y, DamageType.LIGHTNING, ndam, tmp, no_martyr) - dam = dam + DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, ndam, tmp, no_martyr) + dam = dam + DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, ndam, state, no_martyr) + dam = dam + DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, ndam, state, no_martyr) + dam = dam + DamageType:get(DamageType.LIGHTNING).projector(src, x, y, DamageType.LIGHTNING, ndam, state, no_martyr) + dam = dam + DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, ndam, state, no_martyr) src.elemental_mastery = old return dam end @@ -53,8 +71,8 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) local old = src.twilight_mastery src.twilight_mastery = nil dam = 0 - dam = dam + DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, ndam, tmp, no_martyr) - dam = dam + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, ndam, tmp, no_martyr) + dam = dam + DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, ndam, state, no_martyr) + dam = dam + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, ndam, state, no_martyr) src.twilight_mastery = old return dam end @@ -69,20 +87,23 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) print("[PROJECTOR] starting dam", dam) - if src.turn_procs and src.turn_procs.is_crit and target:attr("ignore_direct_crits") and rng.percent(target:attr("ignore_direct_crits")) then - dam = dam / src.turn_procs.crit_power + local ignore_direct_crits = target:attr 'ignore_direct_crits' + if crit_power > 1 and ignore_direct_crits and rng.percent(ignore_direct_crits) then + dam = dam / crit_power + crit_power = 1 print("[PROJECTOR] crit power reduce dam", dam) game.logSeen(target, "%s shrugs off the critical damage!", target.name:capitalize()) - elseif src.turn_procs and src.turn_procs.is_crit and src.turn_procs.shadowstrike_crit and src.x then + elseif src.turn_procs and crit_power > 1 and src.turn_procs.shadowstrike_crit and src.x then local d = core.fov.distance(src.x, src.y, x, y) if d > 3 then local reduc = math.scale(d, 3, 10, 0, 1) - dam = dam * (src.turn_procs.crit_power - reduc * src.turn_procs.shadowstrike_crit) / src.turn_procs.crit_power - print("[PROJECTOR] shadowstrike crit power reduce dam on range", dam, d, reduc, "::", src.turn_procs.crit_power, "=>", src.turn_procs.crit_power - reduc * src.turn_procs.shadowstrike_crit) + dam = dam * (crit_power - reduc * src.turn_procs.shadowstrike_crit) / crit_power + print("[PROJECTOR] shadowstrike crit power reduce dam on range", dam, d, reduc, "::", crit_power, "=>", crit_power - reduc * src.turn_procs.shadowstrike_crit) + crit_power = crit_power - reduc * src.turn_procs.shadowstrike_crit end end - local hd = {"DamageProjector:base", src=src, x=x, y=y, type=type, dam=dam, tmp=tmp, no_martyr=no_martyr} + local hd = {"DamageProjector:base", src=src, x=x, y=y, type=type, dam=dam, state=state, no_martyr=no_martyr} if src:triggerHook(hd) then dam = hd.dam if hd.stopped then return hd.stopped end end -- Difficulty settings @@ -335,7 +356,7 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) dam = dam * target:callTalent(target.T_ROLL_WITH_IT, "getMult") print("[PROJECTOR] after Roll With It dam", dam) end - + if src and src.hasEffect and src:hasEffect(src.EFF_SEAL_FATE) then src:callEffect(src.EFF_SEAL_FATE, "doDamage", target) end @@ -346,9 +367,9 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) -- Sanctuary: reduces damage if it comes from outside of Gloom if target.isTalentActive and target:isTalentActive(target.T_GLOOM) and target:knowTalent(target.T_SANCTUARY) then - if tmp and tmp.sanctuaryDamageChange then + if state and state.sanctuaryDamageChange then -- projectile was targeted outside of gloom - dam = dam * (100 + tmp.sanctuaryDamageChange) / 100 + dam = dam * (100 + state.sanctuaryDamageChange) / 100 print("[PROJECTOR] Sanctuary (projectile) dam", dam) elseif src and src.x and src.y then -- assume instantaneous projection and check range to source @@ -401,10 +422,10 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) print("[PROJECTOR] final dam after static checks", dam) - local hd = {"DamageProjector:final", src=src, x=x, y=y, type=type, dam=dam, tmp=tmp, no_martyr=no_martyr} + local hd = {"DamageProjector:final", src=src, x=x, y=y, type=type, dam=dam, state=state, no_martyr=no_martyr} if src:triggerHook(hd) then dam = hd.dam if hd.stopped then return hd.stopped end end if target.fireTalentCheck then - local ret = target:fireTalentCheck("callbackOnTakeDamage", src, x, y, type, dam, tmp, no_martyr) + local ret = target:fireTalentCheck("callbackOnTakeDamage", src, x, y, type, dam, state, no_martyr) if ret then if ret.dam then dam = ret.dam end if ret.stopped then return ret.stopped end @@ -423,7 +444,7 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) local visible, srcSeen, tgtSeen = game:logVisible(src, target) if visible then -- don't log damage that the player doesn't know about local source = src.__project_source or src - if src.turn_procs and src.turn_procs.is_crit then + if crit_power > 1 then game:delayedLogDamage(source, target, dam, ("#{bold}#%s%d %s#{normal}##LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam, DamageType:get(type).name), true) else game:delayedLogDamage(source, target, dam, ("%s%d %s#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam, DamageType:get(type).name), false) @@ -433,11 +454,11 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) if dam > 0 and src.attr and src:attr("martyrdom") and not no_martyr then game:delayedLogMessage(src, target, "martyrdom", "#CRIMSON##Source# damages %s through Martyrdom!", string.his_her_self(src)) - DamageType.defaultProjector(target, src.x, src.y, type, dam * src.martyrdom / 100, tmp, true) + DamageType.defaultProjector(target, src.x, src.y, type, dam * src.martyrdom / 100, state, true) end if target.attr and target:attr("reflect_damage") and not no_martyr and src.x and src.y then game:delayedLogMessage(target, src, "reflect_damage"..(src.uid or ""), "#CRIMSON##Source# reflects damage back to #Target#!") - DamageType.defaultProjector(target, src.x, src.y, type, dam * target.reflect_damage / 100, tmp, true) + DamageType.defaultProjector(target, src.x, src.y, type, dam * target.reflect_damage / 100, state, true) end -- Braided damage if dam > 0 and target:hasEffect(target.EFF_BRAIDED) then @@ -558,15 +579,16 @@ setDefaultProjector(function(src, x, y, type, dam, tmp, no_martyr) end end end - - if src.turn_procs and src.turn_procs.is_crit then + + -- Use state, because we don't care if it was shrugged off. + if state.crit_power > 1 and not state.crit_elemental_surge then if src.knowTalent and src:knowTalent(src.T_ELEMENTAL_SURGE) then src:triggerTalent(src.T_ELEMENTAL_SURGE, nil, target, type, dam) end - src.turn_procs.is_crit = nil + state.crit_elemental_surge = true end - + if src.turn_procs and not src.turn_procs.dazing_damage and src.hasEffect and src:hasEffect(src.EFF_DAZING_DAMAGE) then if target:canBe("stun") then local power = math.max(src:combatSpellpower(), src:combatMindpower(), src:combatPhysicalpower()) @@ -634,22 +656,24 @@ newDamageType{ newDamageType{ name = "fire", type = "FIRE", text_color = "#LIGHT_RED#", antimagic_resolve = true, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if src.fire_convert_to then if src.fire_convert_to[2] >= 100 then - return DamageType:get(src.fire_convert_to[1]).projector(src, x, y, src.fire_convert_to[1], dam * src.fire_convert_to[2] / 100) + return DamageType:get(src.fire_convert_to[1]).projector(src, x, y, src.fire_convert_to[1], dam * src.fire_convert_to[2] / 100, state, no_martyr) else local old = src.fire_convert_to src.fire_convert_to = nil - dam = DamageType:get(old[1]).projector(src, x, y, old[1], dam * old[2] / 100) + - DamageType:get(type).projector(src, x, y, type, dam * (100 - old[2]) / 100) + dam = DamageType:get(old[1]).projector(src, x, y, old[1], dam * old[2] / 100, state, no_martyr) + + DamageType:get(type).projector(src, x, y, type, dam * (100 - old[2]) / 100, state, no_martyr) src.fire_convert_to = old return dam end end local a = game.level.map(x, y, Map.ACTOR) local acheive = a and src.player and not a.training_dummy and a ~= src - local realdam = DamageType.defaultProjector(src, x, y, type, dam) + local realdam = DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) if realdam > 0 and acheive then world:gainAchievement("PYROMANCER", src, realdam) end @@ -660,10 +684,12 @@ newDamageType{ newDamageType{ name = "cold", type = "COLD", text_color = "#1133F3#", antimagic_resolve = true, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local a = game.level.map(x, y, Map.ACTOR) local acheive = a and src.player and not a.training_dummy and a ~= src - local realdam = DamageType.defaultProjector(src, x, y, type, dam) + local realdam = DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) if realdam > 0 and acheive then world:gainAchievement("CRYOMANCER", src, realdam) end @@ -677,8 +703,10 @@ newDamageType{ newDamageType{ name = "lightning", type = "LIGHTNING", text_color = "#ROYAL_BLUE#", antimagic_resolve = true, - projector = function(src, x, y, type, dam) - local realdam = DamageType.defaultProjector(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) return realdam end, death_message = {"electrocuted", "shocked", "bolted", "volted", "amped", "zapped"}, @@ -688,9 +716,11 @@ newDamageType{ newDamageType{ name = "acid", type = "ACID", text_color = "#GREEN#", antimagic_resolve = true, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) - local realdam = DamageType.defaultProjector(src, x, y, type, dam) + local realdam = DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) if realdam > 0 and target and src.knowTalent and src:knowTalent(src.T_NATURAL_ACID) then local t = src:getTalentFromId(src.T_NATURAL_ACID) src:setEffect(src.EFF_NATURAL_ACID, t.getDuration(src, t), {}) @@ -704,9 +734,11 @@ newDamageType{ newDamageType{ name = "nature", type = "NATURE", text_color = "#LIGHT_GREEN#", antimagic_resolve = true, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) - local realdam = DamageType.defaultProjector(src, x, y, type, dam) + local realdam = DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) if realdam > 0 and target and src.knowTalent and src:knowTalent(src.T_CORROSIVE_NATURE) then local t = src:getTalentFromId(src.T_CORROSIVE_NATURE) src:setEffect(src.EFF_CORROSIVE_NATURE, t.getDuration(src, t), {}) @@ -719,11 +751,13 @@ newDamageType{ newDamageType{ name = "blight", type = "BLIGHT", text_color = "#DARK_GREEN#", antimagic_resolve = true, - projector = function(src, x, y, type, dam, extra) - local realdam = DamageType.defaultProjector(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) -- Spread diseases if possible - if realdam > 0 and target and target:attr("diseases_spread_on_blight") and (not extra or not extra.from_disease) then + if realdam > 0 and target and target:attr("diseases_spread_on_blight") and (not state or not state.from_disease) then src:callTalent(src.T_EPIDEMIC, "do_spread", target, realdam) end return realdam @@ -743,8 +777,10 @@ newDamageType{ name = "darkness", type = "DARKNESS", text_color = "#GREY#", antimagic_resolve = true, death_message = {"shadowed", "darkened", "swallowed by the void"}, - projector = function(src, x, y, type, dam, extra) - local realdam = DamageType.defaultProjector(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) -- Darken if realdam > 0 and src:attr("darkness_darkens") then @@ -759,7 +795,9 @@ newDamageType{ -- Most uses of this have their damage effected by mental save and do not trigger cross tiers, ie, melee items newDamageType{ name = "mind", type = "MIND", text_color = "#YELLOW#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) local thought_form if target and src and target.summoner and target.summoner == src and target.type and target.type == "thought-form" then thought_form = true end @@ -771,10 +809,10 @@ newDamageType{ if crossTierChance and rng.percent(crossTierChance) then target:crossTierEffect(target.EFF_BRAINLOCKED, src:combatMindpower()) end - return DamageType.defaultProjector(src, x, y, type, dam) + return DamageType.defaultProjector(src, x, y, type, dam, state, no_martyr) else game.logSeen(target, "%s resists the mind attack!", target.name:capitalize()) - return DamageType.defaultProjector(src, x, y, type, dam / 2) + return DamageType.defaultProjector(src, x, y, type, dam / 2, state, no_martyr) end end return 0 @@ -786,14 +824,16 @@ newDamageType{ -- If you use this for something else make sure to note it has no power check or sanity check on how much turn energy is drained newDamageType{ name = "winter", type = "WINTER", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local srcx, srcy = dam.x, dam.y local base = dam dam = dam.dam if not base.st then - DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam) + DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam, state, no_martyr) else - DamageType:get(base.st).projector(src, x, y, base.st, dam) + DamageType:get(base.st).projector(src, x, y, base.st, dam, state, no_martyr) end local target = game.level.map(x, y, Map.ACTOR) if target then @@ -813,8 +853,10 @@ newDamageType{ -- Temporal + Stun newDamageType{ name = "temporal stun", type = "TEMPORALSTUN", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("stun") then @@ -829,7 +871,9 @@ newDamageType{ -- Lite up the room newDamageType{ name = "lite", type = "LITE", text_color = "#YELLOW#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) -- Dont lit magically unlit grids local g = game.level.map(x, y, Map.TERRAIN+1) if g and g.unlit then @@ -844,7 +888,9 @@ newDamageType{ -- Break stealth newDamageType{ name = "illumination", type = "BREAK_STEALTH", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) -- Dont lit magically unlit grids local a = game.level.map(x, y, Map.ACTOR) if a then @@ -856,7 +902,9 @@ newDamageType{ -- Silence newDamageType{ name = "silence", type = "SILENCE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("silence") then @@ -871,12 +919,14 @@ newDamageType{ -- Silence newDamageType{ name = "arcane silence", type = "ARCANE_SILENCE", text_color = "#PURPLE#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local chance = 100 if _G.type(dam) == "table" then dam, chance = dam.dam, dam.chance end local target = game.level.map(x, y, Map.ACTOR) - local realdam = DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam) + local realdam = DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam, state, no_martyr) if target then if rng.percent(chance) and target:canBe("silence") then target:setEffect(target.EFF_SILENCED, 3, {apply_power=src:combatSpellpower()}) @@ -891,7 +941,9 @@ newDamageType{ -- Silence newDamageType{ name = "silence", type = "RANDOM_SILENCE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(dam) then if target:canBe("silence") then @@ -906,7 +958,9 @@ newDamageType{ -- Blinds newDamageType{ name = "blindness", type = "BLIND", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("blind") then @@ -919,7 +973,9 @@ newDamageType{ } newDamageType{ name = "blindness", type = "BLINDPHYSICAL", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("blind") then @@ -932,7 +988,9 @@ newDamageType{ } newDamageType{ name = "blinding ink", type = "BLINDING_INK", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("blind") then @@ -945,7 +1003,9 @@ newDamageType{ } newDamageType{ name = "blindness", type = "BLINDCUSTOMMIND", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("blind") then @@ -960,21 +1020,25 @@ newDamageType{ -- Lite + Light damage newDamageType{ name = "bright light", type = "LITE_LIGHT", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.LITE).projector(src, x, y, DamageType.LITE, 1) - return DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.LITE).projector(src, x, y, DamageType.LITE, 1, state, no_martyr) + return DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam, state, no_martyr) end, } -- Fire damage + DOT newDamageType{ name = "fire burn", type = "FIREBURN", text_color = "#LIGHT_RED#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local dur = 3 local perc = 50 if _G.type(dam) == "table" then dam, dur, perc = dam.dam, dam.dur, (dam.initial or perc) end local init_dam = dam * perc / 100 - if init_dam > 0 then DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, init_dam) end + if init_dam > 0 then DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, init_dam, state ,no_martyr) end local target = game.level.map(x, y, Map.ACTOR) if target then -- Set on fire! @@ -988,19 +1052,21 @@ newDamageType{ -- Fire damage + DOT + 25% chance of Fireflash newDamageType{ name = "stunning fire", type = "FIRE_STUN", text_color = "#LIGHT_RED#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local chance = 25 local dur = 3 local perc = 50 if _G.type(dam) == "table" then dam, dur, perc = dam.dam, dam.dur, (dam.initial or perc) end local init_dam = dam * perc / 100 - if init_dam > 0 then DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, init_dam) end + if init_dam > 0 then DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, init_dam, state, no_martyr) end local target = game.level.map(x, y, Map.ACTOR) if target then dam = dam - init_dam target:setEffect(target.EFF_BURNING, dur, {src=src, power=dam / dur, no_ct_effect=true}) if rng.percent(chance) then - DamageType:get(DamageType.FLAMESHOCK).projector(src, x, y, DamageType.FLAMESHOCK, {dur=3, dam=15, apply_power=src:combatMindpower()}) + DamageType:get(DamageType.FLAMESHOCK).projector(src, x, y, DamageType.FLAMESHOCK, {dur=3, dam=15, apply_power=src:combatMindpower()}, state, no_martyr) end end return init_dam @@ -1009,11 +1075,13 @@ newDamageType{ newDamageType{ name = "fire burn", type = "GOLEM_FIREBURN", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local realdam = 0 local target = game.level.map(x, y, Map.ACTOR) if target and target ~= src and target ~= src.summoner then - realdam = DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam) + realdam = DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam, state, no_martyr) end return realdam end, @@ -1022,10 +1090,12 @@ newDamageType{ -- Drain Life... with fire! newDamageType{ name = "devouring flames", type = "FIRE_DRAIN", text_color = "#LIGHT_RED#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, healfactor=0.1} end local target = game.level.map(x, y, Map.ACTOR) -- Get the target first to make sure we heal even on kill - local realdam = DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam.dam) + local realdam = DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam.dam, state, no_martyr) if target and realdam > 0 then src:heal(realdam * dam.healfactor, target) src:logCombat(target, "#Source# drains life from #Target#!") @@ -1037,17 +1107,21 @@ newDamageType{ -- Darkness + Fire newDamageType{ name = "shadowflame", type = "SHADOWFLAME", text_color = "#BF7F73#", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam / 2) - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam / 2) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam / 2, state, no_martyr) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam / 2, state, no_martyr) end, } -- Darkness + Stun newDamageType{ name = "darkness", type = "DARKSTUN", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then -- try to stun @@ -1063,10 +1137,12 @@ newDamageType{ -- Darkness but not over minions newDamageType{ name = "darkness", type = "MINION_DARKNESS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and (not target.necrotic_minion or target.summoner ~= src) then - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam, state, no_martyr) end end, } @@ -1074,10 +1150,12 @@ newDamageType{ -- Fore but not over minions newDamageType{ name = "fire", type = "FIRE_FRIENDS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and target.summoner ~= src then - DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam) + DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam, state, no_martyr) end end, } @@ -1085,8 +1163,10 @@ newDamageType{ -- Cold + Stun newDamageType{ name = "cold", type = "COLDSTUN", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("stun") then @@ -1101,7 +1181,9 @@ newDamageType{ -- Fire DOT + Stun newDamageType{ name = "flameshock", type = "FLAMESHOCK", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, dur=4} end local target = game.level.map(x, y, Map.ACTOR) if target then @@ -1118,12 +1200,14 @@ newDamageType{ -- Cold damage + freeze chance newDamageType{ name = "ice", type = "ICE", text_color = "#1133F3#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local chance = 25 if _G.type(dam) == "table" then chance, dam = dam.chance, dam.dam end - local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam) + local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam, state, no_martyr) if rng.percent(chance) then - DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.5}) + DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.5}, state, no_martyr) end return realdam end, @@ -1132,15 +1216,17 @@ newDamageType{ -- Cold damage + freeze chance + 20% slow newDamageType{ name = "slowing ice", type = "ICE_SLOW", text_color = "#1133F3#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local chance = 25 local target = game.level.map(x, y, Map.ACTOR) if _G.type(dam) == "table" then chance, dam = dam.chance, dam.dam end - local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam) + local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam, state, no_martyr) if target then target:setEffect(target.EFF_SLOW, 3, {power=0.2, no_ct_effect=true}) if rng.percent(chance) then - DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.5}) + DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.5}, state, no_martyr) end end return realdam @@ -1150,15 +1236,17 @@ newDamageType{ -- Cold damage + freeze chance, increased if wet newDamageType{ name = "ice storm", type = "ICE_STORM", text_color = "#1133F3#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local chance = 25 local target = game.level.map(x, y, Map.ACTOR) if target and target:hasEffect(target.EFF_WET) then dam = dam * 1.3 chance = 50 end - local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam) + local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam, state, no_martyr) if rng.percent(chance) then - DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.5}) + DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.5}, state, no_martyr) end return realdam end, @@ -1167,13 +1255,15 @@ newDamageType{ -- Increased cold damage + freeze chance if wet newDamageType{ name = "glacial vapour", type = "GLACIAL_VAPOUR", text_color = "#1133F3#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local chance = 0 local target = game.level.map(x, y, Map.ACTOR) if target and target:hasEffect(target.EFF_WET) then dam = dam * 1.3 chance = 15 end - local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam) + local realdam = DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam, state, no_martyr) if rng.percent(chance) then - DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.2}) + DamageType:get(DamageType.FREEZE).projector(src, x, y, DamageType.FREEZE, {dur=2, hp=70+dam*1.2}, state, no_martyr) end return realdam end, @@ -1182,9 +1272,11 @@ newDamageType{ -- Cold damage + freeze ground newDamageType{ name = "cold ground", type = "COLDNEVERMOVE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, dur=4} end - DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam.dam) + DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("pin") and target:canBe("stun") and not target:attr("fly") and not target:attr("levitation") then @@ -1201,7 +1293,9 @@ newDamageType{ -- Freezes target, checks for spellresistance and stun resistance newDamageType{ name = "freeze", type = "FREEZE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then -- Freeze it, if we pass the test @@ -1220,7 +1314,9 @@ newDamageType{ -- Dim vision newDamageType{ name = "sticky smoke", type = "STICKY_SMOKE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("blind") then @@ -1235,8 +1331,10 @@ newDamageType{ -- Acid damage + blind chance newDamageType{ name = "acid blind", type = "ACID_BLIND", text_color = "#GREEN#", - projector = function(src, x, y, type, dam) - local realdam = DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(25) then if target:canBe("blind") then @@ -1252,8 +1350,10 @@ newDamageType{ -- Darkness damage + blind chance newDamageType{ name = "blinding darkness", type = "DARKNESS_BLIND", - projector = function(src, x, y, type, dam) - local realdam = DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(25) then if target:canBe("blind") then @@ -1269,8 +1369,10 @@ newDamageType{ -- Light damage + blind chance newDamageType{ name = "blinding light", type = "LIGHT_BLIND", text_color = "#YELLOW#", - projector = function(src, x, y, type, dam) - local realdam = DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(25) then if target:canBe("blind") then @@ -1286,10 +1388,12 @@ newDamageType{ -- Lightning damage + daze chance newDamageType{ name = "dazing lightning", type = "LIGHTNING_DAZE", text_color = "#ROYAL_BLUE#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, daze=25} end dam.daze = dam.daze or 25 - local realdam = DamageType:get(DamageType.LIGHTNING).projector(src, x, y, DamageType.LIGHTNING, dam.dam) + local realdam = DamageType:get(DamageType.LIGHTNING).projector(src, x, y, DamageType.LIGHTNING, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and dam.daze > 0 and rng.percent(dam.daze) then if target:canBe("stun") then @@ -1312,15 +1416,17 @@ newDamageType{ -- Cold/physical damage + repulsion; checks for spell power against physical resistance newDamageType{ name = "cold repulsion", type = "WAVE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local srcx, srcy = dam.x, dam.y local base = dam dam = dam.dam if not base.st then - DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam / 2) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2) + DamageType:get(DamageType.COLD).projector(src, x, y, DamageType.COLD, dam / 2, state, no_martyr) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2, state, no_martyr) else - DamageType:get(base.st).projector(src, x, y, base.st, dam) + DamageType:get(base.st).projector(src, x, y, base.st, dam, state, no_martyr) end local target = game.level.map(x, y, Map.ACTOR) if target then @@ -1342,11 +1448,13 @@ newDamageType{ -- Bloodspring damage + repulsion; checks for spell power against physical resistance newDamageType{ name = "bloodspring", type = "BLOODSPRING", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local srcx, srcy = dam.x, dam.y local base = dam dam = dam.dam - DamageType:get(base.st).projector(src, x, y, base.st, dam) + DamageType:get(base.st).projector(src, x, y, base.st, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:checkHit(base.power or src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then @@ -1363,13 +1471,15 @@ newDamageType{ -- Fireburn damage + repulsion; checks for spell power against physical resistance newDamageType{ name = "fire repulsion", type = "FIREKNOCKBACK", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if _G.type(dam) ~= "table" then dam = {dam=dam, dist=3} end - tmp = tmp or {} - if target and not tmp[target] then - tmp[target] = true - DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam.dam) + state = state or {} + if target and not state[target] then + state[target] = true + DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam.dam, state, no_martyr) if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(src.x, src.y, dam.dist) target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower()) @@ -1384,13 +1494,15 @@ newDamageType{ -- Fireburn damage + repulsion; checks for mind power against physical resistance newDamageType{ name = "burning repulsion", type = "FIREKNOCKBACK_MIND", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if _G.type(dam) ~= "table" then dam = {dam=dam, dist=3} end - tmp = tmp or {} - if target and not tmp[target] then - tmp[target] = true - DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam.dam) + state = state or {} + if target and not state[target] then + state[target] = true + DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam.dam, state, no_martyr) if target:checkHit(src:combatMindpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(src.x, src.y, dam.dist) target:crossTierEffect(target.EFF_OFFBALANCE, src:combatMindpower()) @@ -1405,13 +1517,15 @@ newDamageType{ -- Darkness damage + repulsion; checks for spell power against mental resistance newDamageType{ name = "darkness repulsion", type = "DARKKNOCKBACK", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if _G.type(dam) ~= "table" then dam = {dam=dam, dist=3} end - tmp = tmp or {} - if target and not tmp[target] then - tmp[target] = true - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam) + state = state or {} + if target and not state[target] then + state[target] = true + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam, state, no_martyr) if target:checkHit(src:combatSpellpower(), target:combatMentalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(src.x, src.y, dam.dist) target:crossTierEffect(target.EFF_BRAINLOCKED, src:combatSpellpower()) @@ -1426,14 +1540,16 @@ newDamageType{ -- Physical damage + repulsion; checks for spell power against physical resistance newDamageType{ name = "physical repulsion", type = "SPELLKNOCKBACK", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) local realdam = 0 if _G.type(dam) ~= "table" then dam = {dam=dam, dist=3} end - tmp = tmp or {} - if target and not tmp[target] then - tmp[target] = true - realdam = DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + state = state or {} + if target and not state[target] then + state[target] = true + realdam = DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(src.x, src.y, dam.dist) target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower()) @@ -1449,12 +1565,14 @@ newDamageType{ -- Physical damage + repulsion; checks for mind power against physical resistance newDamageType{ name = "physical repulsion", type = "MINDKNOCKBACK", - projector = function(src, x, y, type, dam, tmp) - local target = game.level.map(x, y, Map.ACTOR) - tmp = tmp or {} - if target and not tmp[target] then - tmp[target] = true - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) + local target = game.level.map(x, y, Map.ACTOR) + state = state or {} + if target and not state[target] then + state[target] = true + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam, state, no_martyr) if target:checkHit(src:combatMindpower() * 0.8, target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(src.x, src.y, 3) target:crossTierEffect(target.EFF_OFFBALANCE, src:combatMindpower()) @@ -1469,13 +1587,15 @@ newDamageType{ -- Physical damage + repulsion; checks for attack power against physical resistance newDamageType{ name = "physical repulsion", type = "PHYSKNOCKBACK", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) - tmp = tmp or {} + state = state or {} if _G.type(dam) ~= "table" then dam = {dam=dam, dist=3} end - if target and not tmp[target] then - tmp[target] = true - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + if target and not state[target] then + state[target] = true + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) if target:checkHit(src:combatPhysicalpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(dam.x or src.x, dam.y or src.y, dam.dist) target:crossTierEffect(target.EFF_OFFBALANCE, src:combatPhysicalpower()) @@ -1490,11 +1610,13 @@ newDamageType{ -- Fear check + repulsion; checks for mind power against physical resistance newDamageType{ name = "fear repulsion", type = "FEARKNOCKBACK", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) - tmp = tmp or {} - if target and not tmp[target] then - tmp[target] = true + state = state or {} + if target and not state[target] then + state[target] = true if target:checkHit(src:combatMindpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("fear") then target:knockback(dam.x, dam.y, dam.dist) target:crossTierEffect(target.EFF_BRAINLOCKED, src:combatMindpower()) @@ -1510,12 +1632,14 @@ newDamageType{ newDamageType{ name = "poison", type = "POISON", text_color = "#LIGHT_GREEN#", projector = function(src, x, y, t, dam) + state = state or {} + useImplicitCrit(src, state) local power if type(dam) == "table" then power = dam.apply_power dam = dam.dam end - local realdam = DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam / 6) + local realdam = DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam / 6, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and target:canBe("poison") then target:setEffect(target.EFF_POISONED, 5, {src=src, power=dam / 6, apply_power=power or (src.combatAttack and src:combatAttack()) or 0}) @@ -1527,8 +1651,10 @@ newDamageType{ -- Inferno: fire and maybe remove stuff newDamageType{ name = "cleansing fire", type = "INFERNO", - projector = function(src, x, y, type, dam) - local realdam = DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and src:attr("cleansing_flames") and rng.percent(src:attr("cleansing_flames")) then local effs = {} @@ -1552,9 +1678,11 @@ newDamageType{ -- Very special, does not have a power check newDamageType{ name = "spydric poison", type = "SPYDRIC_POISON", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, dur=3} end - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam / dam.dur) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam / dam.dur, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and target:canBe("poison") then target:setEffect(target.EFF_SPYDRIC_POISON, dam.dur, {src=src, power=dam.dam / dam.dur, no_ct_effect=true}) @@ -1565,9 +1693,11 @@ newDamageType{ -- Crippling poison: failure to act newDamageType{ name = "crippling poison", type = "CRIPPLING_POISON", text_color = "#LIGHT_GREEN#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, dur=3} end - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam / dam.dur) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam / dam.dur, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and target:canBe("poison") then target:setEffect(target.EFF_CRIPPLING_POISON, dam.dur, {src=src, power=dam.dam / dam.dur, no_ct_effect=true}) @@ -1578,9 +1708,11 @@ newDamageType{ -- Insidious poison: prevents healing newDamageType{ name = "insidious poison", type = "INSIDIOUS_POISON", text_color = "#LIGHT_GREEN#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, dur=7, heal_factor=dam} end - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam / dam.dur) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam / dam.dur, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and target:canBe("poison") then target:setEffect(target.EFF_INSIDIOUS_POISON, dam.dur, {src=src, power=dam.dam / dam.dur, heal_factor=dam.heal_factor, no_ct_effect=true}) @@ -1591,8 +1723,10 @@ newDamageType{ -- Bleeding damage newDamageType{ name = "bleed", type = "BLEED", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 6) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 6, state, no_martyr) dam = dam - dam / 6 local target = game.level.map(x, y, Map.ACTOR) if target and target:canBe("cut") then @@ -1605,8 +1739,10 @@ newDamageType{ -- Physical damage + bleeding % of it newDamageType{ name = "physical bleed", type = "PHYSICALBLEED", - projector = function(src, x, y, type, dam) - local realdam = DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if realdam > 0 and target and target:canBe("cut") then target:setEffect(target.EFF_CUT, 5, {src=src, power=dam * 0.1, no_ct_effect=true}) @@ -1617,9 +1753,11 @@ newDamageType{ -- Slime damage newDamageType{ name = "nature slow", type = "SLIME", text_color = "#LIGHT_GREEN#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, power=0.15} end - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then target:setEffect(target.EFF_SLOW, 3, {power=dam.power, no_ct_effect=true}) @@ -1631,6 +1769,8 @@ newDamageType{ newDamageType{ name = "dig", type = "DIG", projector = function(src, x, y, typ, dam) + state = state or {} + useImplicitCrit(src, state) local feat = game.level.map(x, y, Map.TERRAIN) if feat then if feat.dig then @@ -1653,7 +1793,9 @@ newDamageType{ -- Slowness newDamageType{ name = "slow", type = "SLOW", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then -- Freeze it, if we pass the test @@ -1665,7 +1807,9 @@ newDamageType{ newDamageType{ name = "congeal time", type = "CONGEAL_TIME", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then -- Freeze it, if we pass the test @@ -1678,7 +1822,9 @@ newDamageType{ -- Time prison, invulnerability and stun newDamageType{ name = "time prison", type = "TIME_PRISON", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then -- Freeze it, if we pass the test @@ -1699,7 +1845,9 @@ newDamageType{ -- Confusion newDamageType{ name = "confusion", type = "CONFUSION", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("confusion") then @@ -1714,7 +1862,9 @@ newDamageType{ -- Confusion newDamageType{ name = "% chance of confusion", type = "RANDOM_CONFUSION", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam} end local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(dam.dam) then @@ -1730,7 +1880,9 @@ newDamageType{ -- Confusion newDamageType{ name = "% chance of confusion", type = "RANDOM_CONFUSION_PHYS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam} end local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(dam.dam) then @@ -1745,7 +1897,9 @@ newDamageType{ newDamageType{ name = "% chance of gloom effects", type = "RANDOM_GLOOM", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(dam) then if not src:checkHit(src:combatMindpower(), target:combatMentalResist()) then return end @@ -1796,7 +1950,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to cause #YELLOW#random gloom#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s<%d%%%% gloom chance>#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -1842,7 +1998,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to inflict #GREY#damage reduction#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s<%d%%%% dark numbing chance>#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -1872,7 +2030,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to gain #LIGHT_STEEL_BLUE#10%% of a turn#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src and src.name and rng.percent(dam) then if src.turn_procs and src.turn_procs.item_temporal_energize and src.turn_procs.item_temporal_energize > 3 then @@ -1905,7 +2065,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to #GREEN#corrode armour#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s<%d%%%% corrode armour chance>#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -1935,7 +2097,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to #YELLOW#blind#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s<%d%%%% blind chance>#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -1968,7 +2132,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to #ROYAL_BLUE#daze#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s<%d%%%% daze chance>#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -1998,7 +2164,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to #DARK_GREEN#disease#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s<%d%%%% disease chance>#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -2027,11 +2195,13 @@ newDamageType{ return ("* #DARK_ORCHID#%d arcane resource#LAST# burn%s") :format(dam or 0, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then dam = target.burnArcaneResources and target:burnArcaneResources(dam) or 0 - return DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam) + return DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam, state, no_martyr) end return 0 end, @@ -2053,7 +2223,9 @@ newDamageType{ return ("* Slows global speed by #LIGHT_GREEN#%d%%#LAST#%s") :format(dam, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s(slow %d%%%%)#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -2080,7 +2252,9 @@ newDamageType{ return ("* #LIGHT_GREEN#%d%%#LAST# chance to #ORCHID#reduce powers#LAST# by %d%%%s") :format(dam, 20, parens) end, - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then game:delayedLogDamage(src, target, 0, ("%s<%d%%%% scour chance>#LAST#"):format(DamageType:get(type).text_color or "#aaaaaa#", dam), false) @@ -2097,7 +2271,9 @@ newDamageType{ -- gBlind newDamageType{ name = "blinding", type = "RANDOM_BLIND", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam} end local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(dam.dam) then @@ -2113,8 +2289,10 @@ newDamageType{ -- Physical + Blind newDamageType{ name = "blinding physical", type = "SAND", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("blind") then @@ -2129,8 +2307,10 @@ newDamageType{ -- Physical + Pinned newDamageType{ name = "physical pinning", type = "PINNING", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("pin") then @@ -2145,9 +2325,11 @@ newDamageType{ -- Drain Exp newDamageType{ name = "regressive blight", type = "DRAINEXP", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam} end - local realdam = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam) + local realdam = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:checkHit((dam.power_check or src.combatSpellpower)(src), (dam.resist_check or target.combatMentalResist)(target), 0, 95, 15) then @@ -2164,10 +2346,12 @@ newDamageType{ -- Drain Life newDamageType{ name = "draining blight", type = "DRAINLIFE", text_color = "#DARK_GREEN#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, healfactor=0.4} end local target = game.level.map(x, y, Map.ACTOR) -- Get the target first to make sure we heal even on kill - local realdam = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam) + local realdam = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam, state, no_martyr) if target and realdam > 0 then src:heal(realdam * dam.healfactor, target) src:logCombat(target, "#Source# drains life from #Target#!") @@ -2179,10 +2363,12 @@ newDamageType{ -- Drain Vim newDamageType{ name = "vim draining blight", type = "DRAIN_VIM", text_color = "#DARK_GREEN#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, vim=0.2} end local target = game.level.map(x, y, Map.ACTOR) - local realdam = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam) + local realdam = DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam, state, no_martyr) if target and target ~= src and target.summoner ~= src and realdam > 0 then src:incVim(realdam * dam.vim * target:getRankVimAdjust()) end @@ -2193,13 +2379,15 @@ newDamageType{ -- Demonfire: heal demon; damage others newDamageType{ name = "demonfire", type = "DEMONFIRE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and target:attr("demon") then target:heal(dam, src) return -dam elseif target then - DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam) + DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam, state, no_martyr) return dam end end, @@ -2208,7 +2396,9 @@ newDamageType{ -- Retch: heal undead; damage living newDamageType{ name = "purging blight", type = "RETCH", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and (target:attr("undead") or target:attr(retch_heal)) then target:heal(dam * 1.5, src) @@ -2230,7 +2420,7 @@ newDamageType{ end end elseif target then - DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam) + DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam, state, no_martyr) if src.callTalent then if rng.percent(src:callTalent(src.T_RETCH, "getPurgeChance")) then @@ -2255,12 +2445,14 @@ newDamageType{ -- Holy light, damage demon/undead; heal others newDamageType{ name = "holy light", type = "HOLY_LIGHT", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and not target:attr("undead") and not target:attr("demon") then target:heal(dam / 2, src) elseif target then - DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam) + DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam, state, no_martyr) end end, } @@ -2268,7 +2460,9 @@ newDamageType{ -- Heals newDamageType{ name = "healing", type = "HEAL", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then target:attr("allow_on_heal", 1) @@ -2282,7 +2476,9 @@ newDamageType{ -- Keep an eye on this and Weapon of Light for any infinite stack shield then engage combos newDamageType{ name = "healing light", type = "HEALING_POWER", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then target:setEffect(target.EFF_EMPOWERED_HEALING, 1, {power=(dam/200)}) @@ -2318,11 +2514,13 @@ newDamageType{ -- Light damage+heal source, used by Radiance newDamageType{ name = "judgement", type = "JUDGEMENT", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and target ~= src then --print("[JUDGEMENT] src ", src, "target", target, "src", src ) - DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam) + DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam, state, no_martyr) if dam >= 100 then src:attr("allow_on_heal", 1) end src:heal(dam / 2, src) if dam >= 100 then src:attr("allow_on_heal", -1) end @@ -2334,14 +2532,16 @@ newDamageType{ newDamageType{ name = "healing nature", type = "HEALING_NATURE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and not target:attr("undead") then if dam >= 100 then target:attr("allow_on_heal", 1) else target:attr("silent_heal", 1) end target:heal(dam, src) if dam >= 100 then target:attr("allow_on_heal", -1) else target:attr("silent_heal", -1) end elseif target then - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam, state, no_martyr) end end, } @@ -2350,9 +2550,11 @@ newDamageType{ -- Should no longer be used on items, use ITEM_BLIGHT_DISEASE newDamageType{ name = "infective blight", type = "CORRUPTED_BLOOD", text_color = "#DARK_GREEN#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam} end - DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam) + DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and target:canBe("disease") and rng.percent(dam.disease_chance or 20) then local eff = rng.table{{target.EFF_ROTTING_DISEASE, "con"}, {target.EFF_DECREPITUDE_DISEASE, "dex"}, {target.EFF_WEAKNESS_DISEASE, "str"}} @@ -2364,8 +2566,10 @@ newDamageType{ -- blood boiled, blight damage + slow newDamageType{ name = "hindering blight", type = "BLOOD_BOIL", text_color = "#DARK_GREEN#", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.BLIGHT).projector(src, x, y, DamageType.BLIGHT, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and not target:attr("undead") and not target:attr("construct") then target:setEffect(target.EFF_SLOW, 4, {power=0.2, no_ct_effect=true}) @@ -2385,8 +2589,10 @@ newDamageType{ -- Physical + Stun Chance newDamageType{ name = "physical stun", type = "PHYSICAL_STUN", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(25) then if target:canBe("stun") then @@ -2401,9 +2607,11 @@ newDamageType{ -- Physical Damage/Cut Split newDamageType{ name = "physical bleed", type = "SPLIT_BLEED", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 12) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2, state, no_martyr) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 12, state, no_martyr) dam = dam - dam / 12 local target = game.level.map(x, y, Map.ACTOR) if target and target:canBe("cut") then @@ -2415,25 +2623,31 @@ newDamageType{ -- Temporal/Physical damage newDamageType{ name = "temporal shear", type = "MATTER", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam / 2) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam / 2, state, no_martyr) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2, state, no_martyr) end, } -- Temporal/Darkness damage newDamageType{ name = "temporal darkness", type = "VOID", text_color = "#GREY#", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam / 2) - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam / 2) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam / 2, state, no_martyr) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam / 2, state, no_martyr) end, } -- Gravity damage types newDamageType{ name = "gravity", type = "GRAVITY", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam} end local target = game.level.map(x, y, Map.ACTOR) if not target then return end @@ -2446,13 +2660,15 @@ newDamageType{ target:setEffect(target.EFF_ANTI_GRAVITY, dam.dur, {apply_power=apply, no_ct_effect=true}) end end - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) end, } newDamageType{ name = "gravity pin", type = "GRAVITYPIN", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) local reapplied = false if target and not target:isTalentActive(target.T_GRAVITY_LOCUS) then @@ -2468,24 +2684,26 @@ newDamageType{ else game.logSeen(target, "%s resists the pin!", target.name:capitalize()) end - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam, state, no_martyr) end end, } newDamageType{ name = "physical repulsion", type = "REPULSION", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) - tmp = tmp or {} + state = state or {} -- extra damage on pinned targets if target and target:attr("never_move") then dam = dam * 1.5 end - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam) -- This damage type can deal damage multiple times, use with accordingly + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam, state, no_martyr) -- This damage type can deal damage multiple times, use with accordingly -- check knockback - if target and not target:attr("never_move") and not tmp[target] then - tmp[target] = true + if target and not target:attr("never_move") and not state[target] then + state[target] = true if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(src.x, src.y, 2) target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower()) @@ -2500,6 +2718,8 @@ newDamageType{ newDamageType{ name = "grow", type = "GROW", projector = function(src, x, y, typ, dam) + state = state or {} + useImplicitCrit(src, state) local feat = game.level.map(x, y, Map.TERRAIN) if feat then if feat.grow then @@ -2520,10 +2740,12 @@ newDamageType{ -- Mosses newDamageType{ name = "pinning nature", type = "GRASPING_MOSS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src:reactionToward(target) < 0 then - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam, state, no_martyr) target:setEffect(target.EFF_SLOW_MOVE, 4, {apply_power=src:combatMindpower(), power=dam.slow/100}, true) if target:canBe("pin") and rng.percent(dam.pin) then target:setEffect(target.EFF_PINNED, 4, {apply_power=src:combatMindpower()}, true) @@ -2536,10 +2758,12 @@ newDamageType{ newDamageType{ name = "healing nature", type = "NOURISHING_MOSS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src:reactionToward(target) < 0 then - local realdam = DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam) + local realdam = DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam, state, no_martyr) if realdam > 0 then src:heal(realdam * dam.factor, target) end end end, @@ -2547,10 +2771,12 @@ newDamageType{ newDamageType{ name = "impeding nature", type = "SLIPPERY_MOSS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src:reactionToward(target) < 0 then - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam, state, no_martyr) target:setEffect(target.EFF_SLIPPERY_MOSS, 2, {apply_power=src:combatMindpower(), fail=dam.fail}, true) end end, @@ -2558,10 +2784,12 @@ newDamageType{ newDamageType{ name = "confounding nature", type = "HALLUCINOGENIC_MOSS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src:reactionToward(target) < 0 then - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, dam.dam, state, no_martyr) if target:canBe("confusion") and rng.percent(dam.chance) then target:setEffect(target.EFF_CONFUSED, 2, {apply_power=src:combatMindpower(), power=dam.power}, true) else @@ -2574,7 +2802,9 @@ newDamageType{ -- Circles newDamageType{ name = "sanctity", type = "SANCTITY", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target == src then @@ -2590,13 +2820,15 @@ newDamageType{ newDamageType{ name = "defensive darkness", type = "SHIFTINGSHADOWS", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target == src then target:setEffect(target.EFF_SHIFTING_SHADOWS, 1, {power= dam, no_ct_effect=true}) else - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam, state, no_martyr) end end end, @@ -2604,14 +2836,16 @@ newDamageType{ newDamageType{ name = "blazing light", type = "BLAZINGLIGHT", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target == src then target:setEffect(target.EFF_BLAZING_LIGHT, 1, {power= 1 + (dam / 4), no_ct_effect=true}) else - DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam) - DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam) + DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam, state, no_martyr) + DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam, state, no_martyr) end end end, @@ -2619,14 +2853,16 @@ newDamageType{ newDamageType{ name = "prismatic repulsion", type = "WARDING", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target == src then target:setEffect(target.EFF_WARDING, 1, {power=dam*5, no_ct_effect=true}) elseif target ~= src then - DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam ) - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam) + DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam, state, no_martyr) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam, state, no_martyr) if target:checkHit(src:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 15) and target:canBe("knockback") then target:knockback(src.x, src.y, 1) target:crossTierEffect(target.EFF_OFFBALANCE, src:combatSpellpower()) @@ -2641,7 +2877,9 @@ newDamageType{ newDamageType{ name = "mind slow", type = "MINDSLOW", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then local sx, sy = game.level.map:getTileToScreen(x, y) @@ -2653,7 +2891,9 @@ newDamageType{ -- Freezes target, checks for physresistance newDamageType{ name = "mind freeze", type = "MINDFREEZE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then -- Freeze it, if we pass the test @@ -2669,12 +2909,14 @@ newDamageType{ newDamageType{ name = "implosion", type = "IMPLOSION", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local dur = 3 local perc = 50 if _G.type(dam) == "table" then dam, dur, perc = dam.dam, dam.dur, (dam.initial or perc) end local init_dam = dam - if init_dam > 0 then DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, init_dam) end + if init_dam > 0 then DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, init_dam, state, no_martyr) end local target = game.level.map(x, y, Map.ACTOR) if target then target:setEffect(target.EFF_IMPLODING, dur, {src=src, power=dam}) @@ -2685,27 +2927,31 @@ newDamageType{ -- Temporal + Stat damage newDamageType{ name = "regressive temporal", type = "CLOCK", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then local dam = 2 + math.ceil(dam / 15) target:setEffect(target.EFF_TURN_BACK_THE_CLOCK, 3, {power=dam, apply_power=src:combatSpellpower(), min_dur=1}) end -- Reduce Con then deal the damage - DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam) + DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam, state, no_martyr) end, } -- Temporal Over Time newDamageType{ name = "wasting temporal", type = "WASTING", text_color = "#LIGHT_STEEL_BLUE#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) local dur = 3 local perc = 30 if _G.type(dam) == "table" then dam, dur, perc = dam.dam, dam.dur, (dam.initial or perc) end local init_dam = dam * perc / 100 - if init_dam > 0 then DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, init_dam) end + if init_dam > 0 then DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, init_dam, state, no_martyr) end if target then -- Set wasting effect dam = dam - init_dam @@ -2717,7 +2963,9 @@ newDamageType{ newDamageType{ name = "stop", type = "STOP", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("stun") then @@ -2731,8 +2979,10 @@ newDamageType{ newDamageType{ name = "debilitating temporal", type = "RETHREAD", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam.dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) local chance = rng.range(1, 4) -- Pull random effect @@ -2768,11 +3018,13 @@ newDamageType{ newDamageType{ name = "draining physical", type = "DEVOUR_LIFE", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam} end local target = game.level.map(x, y, Map.ACTOR) -- Get the target first to make sure we heal even on kill if target then dam.dam = math.max(0, math.min(target.life, dam.dam)) end - local realdam = DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + local realdam = DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) if target and realdam > 0 then local heal = realdam * (dam.healfactor or 1) -- cannot be reduced @@ -2788,8 +3040,10 @@ newDamageType{ newDamageType{ name = "temporal slow", type = "CHRONOSLOW", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam.dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) local reapplied = false if target then @@ -2807,17 +3061,21 @@ newDamageType{ newDamageType{ name = "molten rock", type = "MOLTENROCK", - projector = function(src, x, y, type, dam) - return DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam / 2) + - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + return DamageType:get(DamageType.FIRE).projector(src, x, y, DamageType.FIRE, dam / 2, state, no_martyr) + + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam / 2, state, no_martyr) end, } newDamageType{ name = "entangle", type = "ENTANGLE", - projector = function(src, x, y, type, dam) - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam/3) - DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, 2*dam/3) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam/3, state, no_martyr) + DamageType:get(DamageType.NATURE).projector(src, x, y, DamageType.NATURE, 2*dam/3, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("pin") then @@ -2831,8 +3089,10 @@ newDamageType{ newDamageType{ name = "manaworm arcane", type = "MANAWORM", - projector = function(src, x, y, type, dam) - local realdam = DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target then if game.zone.void_blast_hits and game.party:hasMember(target) then game.zone.void_blast_hits = game.zone.void_blast_hits + 1 end @@ -2850,8 +3110,10 @@ newDamageType{ newDamageType{ name = "arcane blast", type = "VOID_BLAST", - projector = function(src, x, y, type, dam) - local realdam = DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) + local realdam = DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if game.zone.void_blast_hits and target and game.party:hasMember(target) then game.zone.void_blast_hits = game.zone.void_blast_hits + 1 @@ -2862,7 +3124,9 @@ newDamageType{ newDamageType{ name = "circle of death", type = "CIRCLE_DEATH", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and (src:reactionToward(target) < 0 or dam.ff) then for eff_id, p in pairs(target.tmp) do @@ -2883,10 +3147,12 @@ newDamageType{ -- Darkness damage + speed reduction + minion damage inc newDamageType{ name = "decaying darkness", type = "RIGOR_MORTIS", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam, state, no_martyr) target:setEffect(target.EFF_SLOW, dam.dur, {power=dam.speed, apply_power=src:combatSpellpower()}) target:setEffect(target.EFF_RIGOR_MORTIS, dam.dur, {power=dam.minion, apply_power=src:combatSpellpower()}) end @@ -2895,7 +3161,9 @@ newDamageType{ newDamageType{ name = "abyssal darkness", type = "ABYSSAL_SHROUD", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) --make it dark game.level.map.remembers(x, y, false) game.level.map.lites(x, y, false) @@ -2911,7 +3179,7 @@ newDamageType{ end end target:setEffect(target.EFF_ABYSSAL_SHROUD, 2, {power=dam.power, lite=dam.lite, apply_power=src:combatSpellpower(), min_dur=1}, reapplied) - DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam) + DamageType:get(DamageType.DARKNESS).projector(src, x, y, DamageType.DARKNESS, dam.dam, state, no_martyr) end end, } @@ -2919,7 +3187,9 @@ newDamageType{ newDamageType{ name = "% chance to summon an orc spirit", type = "GARKUL_INVOKE", text_color = "#SALMON#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, engine.Map.ACTOR) if not target then return end if game.party:hasMember(src) and game.party:findMember{type="garkul spirit"} then return end @@ -2984,7 +3254,9 @@ newDamageType{ -- speed reduction, hateful whisper newDamageType{ name = "nightmare", type = "NIGHTMARE", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src:reactionToward(target) < 0 then if rng.chance(10) and not target:hasEffect(target.EFF_HATEFUL_WHISPER) then @@ -3000,7 +3272,9 @@ newDamageType{ newDamageType{ name = "weakness", type = "WEAKNESS", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then local reapplied = target:hasEffect(target.EFF_WEAKENED) @@ -3012,7 +3286,9 @@ newDamageType{ -- Generic apply temporary effect newDamageType{ name = "special effect", type = "TEMP_EFFECT", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then local ok = false @@ -3027,11 +3303,13 @@ newDamageType{ newDamageType{ name = "manaburn arcane", type = "MANABURN", text_color = "#PURPLE#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then dam = target.burnArcaneResources and target:burnArcaneResources(dam) or 0 - return DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam) + return DamageType:get(DamageType.ARCANE).projector(src, x, y, DamageType.ARCANE, dam, state, no_martyr) end return 0 end, @@ -3039,7 +3317,9 @@ newDamageType{ newDamageType{ name = "leaves", type = "LEAVES", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if src:reactionToward(target) < 0 then @@ -3058,12 +3338,14 @@ newDamageType{ -- Distortion; Includes knockback, penetrate, stun, and explosion paramters newDamageType{ name = "distorting physical", type = "DISTORTION", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if not target then return end - tmp = tmp or {} - if target and not tmp[target] then - tmp[target] = true + state = state or {} + if target and not state[target] then + state[target] = true local old_pen = 0 game.level.map:particleEmitter(x, y, 1, "distortion") @@ -3089,7 +3371,7 @@ newDamageType{ -- Our damage target:setEffect(target.EFF_DISTORTION, 2, {power=dam.distort or 0}) if not dam.explosion_done then - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) end -- Do knockback if dam.knockback then @@ -3120,16 +3402,18 @@ newDamageType{ -- Mind/Fire damage with lots of parameter options newDamageType{ name = "dreamforge", type = "DREAMFORGE", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if not target then return end local power, dur, chance, dist, fail, do_particles - tmp = tmp or {} + state = state or {} if _G.type(dam) == "table" then dam, power, dur, chance, fail, dist, do_particles = dam.dam, dam.power, dam.dur, dam.chance, dam.fail, dam.dist, dam.do_particles end - if target and not tmp[target] then + if target and not state[target] then if src:checkHit(src:combatMindpower(), target:combatMentalResist(), 0, 95) then - DamageType:get(DamageType.MIND).projector(src, x, y, DamageType.MIND, {dam=dam/2, alwaysHit=true}) - DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam/2) + DamageType:get(DamageType.MIND).projector(src, x, y, DamageType.MIND, {dam=dam/2, alwaysHit=true}, state, no_martyr) + DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam/2, state, no_martyr) if power and power > 0 then local silent = true and target:hasEffect(target.EFF_BROKEN_DREAM) or false target:setEffect(target.EFF_BROKEN_DREAM, dur, {power=power, fail=fail}, silent) @@ -3155,8 +3439,8 @@ newDamageType{ end end else -- Save for half damage - DamageType:get(DamageType.MIND).projector(src, x, y, DamageType.MIND, {dam=dam/4, alwaysHit=true}) - DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam/4) + DamageType:get(DamageType.MIND).projector(src, x, y, DamageType.MIND, {dam=dam/4, alwaysHit=true}, state, no_martyr) + DamageType:get(DamageType.FIREBURN).projector(src, x, y, DamageType.FIREBURN, dam/4, state, no_martyr) game.logSeen(target, "%s resists the dream forge!", target.name:capitalize()) end end @@ -3165,7 +3449,9 @@ newDamageType{ newDamageType{ name = "natural mucus", type = "MUCUS", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and not target.turn_procs.mucus then target.turn_procs.mucus = true @@ -3191,9 +3477,11 @@ newDamageType{ newDamageType{ name = "disarming acid", type = "ACID_DISARM", text_color = "#GREEN#", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {chance=25, dam=dam} end - local realdam = DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam.dam) + local realdam = DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) if target and rng.percent(dam.chance) then if target:canBe("disarm") then @@ -3209,11 +3497,13 @@ newDamageType{ -- Acid damage + Accuracy/Defense/Armor Down Corrosion newDamageType{ name = "corrosive acid", type = "ACID_CORRODE", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dur = 4, armor = dam/2, defense = dam/2, dam = dam, atk=dam/2} end local target = game.level.map(x, y, Map.ACTOR) if target then - DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam.dam) + DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam.dam, state, no_martyr) target:setEffect(target.EFF_CORRODE, dam.dur, {atk=dam.atk, armor=dam.armor, defense=dam.defense, apply_power=src:combatMindpower()}) end end, @@ -3222,10 +3512,12 @@ newDamageType{ -- Bouncy slime! newDamageType{ name = "bouncing slime", type = "BOUNCE_SLIME", - projector = function(src, x, y, type, dam, tmp, _, tg) + projector = function(src, x, y, type, dam, state, _, tg) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then - local realdam = DamageType:get(DamageType.SLIME).projector(src, x, y, DamageType.SLIME, {dam=dam.dam, power=0.30}) + local realdam = DamageType:get(DamageType.SLIME).projector(src, x, y, DamageType.SLIME, {dam=dam.dam, power=0.30}, state, no_martyr) if dam.nb > 0 then dam.done = dam.done or {} @@ -3253,11 +3545,13 @@ newDamageType{ -- Acid damage + Slow newDamageType{ name = "caustic mire", type = "CAUSTIC_MIRE", - projector = function(src, x, y, type, dam, tmp) + projector = function(src, x, y, type, dam, state) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dur = 2, slow=20} end local target = game.level.map(x, y, Map.ACTOR) if target then - DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam.dam) + DamageType:get(DamageType.ACID).projector(src, x, y, DamageType.ACID, dam.dam, state, no_martyr) target:setEffect(target.EFF_SLOW, dam.dur, {power=dam.slow/100, apply_power=src:combatSpellpower()}) end end, @@ -3266,23 +3560,27 @@ newDamageType{ -- Sun Path damage newDamageType{ name = "sun path", type = "SUN_PATH", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src:reactionToward(target) < 0 then - return DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam) + return DamageType:get(DamageType.LIGHT).projector(src, x, y, DamageType.LIGHT, dam, state, no_martyr) end end, } newDamageType{ name = "telekinetic shove", type = "TK_PUSHPIN", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then if target:canBe("knockback") then target:knockback(src.x, src.y, dam.push, nil, function(g, x, y) if game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move", target) then - DamageType:get(DamageType.PHYSICAL).projector(src, target.x, target.y, DamageType.PHYSICAL, dam.dam) + DamageType:get(DamageType.PHYSICAL).projector(src, target.x, target.y, DamageType.PHYSICAL, dam.dam, state, no_martyr) if target:canBe("pin") then target:setEffect(target.EFF_PINNED, dam.dur, {apply_power=src:combatMindpower()}) else @@ -3292,7 +3590,7 @@ newDamageType{ end) return dam.dam else - DamageType:get(DamageType.PHYSICAL).projector(src, target.x, target.y, DamageType.PHYSICAL, dam.dam) + DamageType:get(DamageType.PHYSICAL).projector(src, target.x, target.y, DamageType.PHYSICAL, dam.dam, state, no_martyr) game.logSeen(src, "%s resists the shove!", target.name:capitalize()) return dam.dam end @@ -3303,7 +3601,9 @@ newDamageType{ -- Prevents Teleportation newDamageType{ name = "dimensional anchor", type = "DIMENSIONAL_ANCHOR", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, apply_power=apply_power or src:combatSpellpower()} end local target = game.level.map(x, y, Map.ACTOR) if target then @@ -3312,10 +3612,12 @@ newDamageType{ end, }newDamageType{ name = "brain storm", type = "BRAINSTORM", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target then - DamageType:get(DamageType.LIGHTNING).projector(src, target.x, target.y, DamageType.LIGHTNING, dam) + DamageType:get(DamageType.LIGHTNING).projector(src, target.x, target.y, DamageType.LIGHTNING, dam, state, no_martyr) if target:checkHit(src:combatMindpower(), target:combatMentalResist(), 0, 95, 15) then target:crossTierEffect(target.EFF_BRAINLOCKED, src:combatMindpower()) else @@ -3334,10 +3636,12 @@ newDamageType{ newDamageType{ name = "static net", type = "STATIC_NET", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if target and src:reactionToward(target) < 0 then - DamageType:get(DamageType.LIGHTNING).projector(src, x, y, DamageType.LIGHTNING, dam.dam) + DamageType:get(DamageType.LIGHTNING).projector(src, x, y, DamageType.LIGHTNING, dam.dam, state, no_martyr) target:setEffect(target.EFF_SLOW, 4, {apply_power=src:combatMindpower(), power=dam.slow/100}, true) elseif target == src then target:setEffect(target.EFF_STATIC_CHARGE, 4, {power=dam.weapon}, true) @@ -3348,9 +3652,11 @@ newDamageType{ -- Physical damage + daze chance newDamageType{ name = "impact", type = "IMPACT", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) if _G.type(dam) == "number" then dam = {dam=dam, daze=dam/2} end - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam, state, no_martyr) local target = game.level.map(x, y, Map.ACTOR) dam.daze = math.min(25, dam.daze) -- 25% daze chance cap if target and dam.daze > 0 and rng.percent(dam.daze) then @@ -3366,11 +3672,13 @@ newDamageType{ -- Temporal/Physical damage with possible chance to debalitate newDamageType{ name = "warp", type = "WARP", - projector = function(src, x, y, type, dam) + projector = function(src, x, y, type, dam, state, no_martyr) + state = state or {} + useImplicitCrit(src, state) local target = game.level.map(x, y, Map.ACTOR) if not target then return end if _G.type(dam) == "number" then dam = {dam=dam, chance=chance or 0, dur=dur or 3, apply_power=apply_power or src:combatSpellpower()} end - + -- Factor in fractured space bonuses local fracture = false if src.isTalentActive and src:isTalentActive(src.T_FRACTURED_SPACE) then @@ -3382,15 +3690,15 @@ newDamageType{ end -- Deal Damage - DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam / 2) - DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam.dam / 2) + DamageType:get(DamageType.PHYSICAL).projector(src, x, y, DamageType.PHYSICAL, dam.dam / 2, state, no_martyr) + DamageType:get(DamageType.TEMPORAL).projector(src, x, y, DamageType.TEMPORAL, dam.dam / 2, state, no_martyr) -- Increase fracture charges and refresh decay rate if fracture then fracture.charges = math.min(6, fracture.charges + 1) fracture.decay = 0 end - + -- Pull random effect if rng.percent(dam.chance) then local effect = rng.range(1, 4) @@ -3421,4 +3729,4 @@ newDamageType{ end end end, -} \ No newline at end of file +}