diff --git a/spec/System/MercenaryTestHelpers.lua b/spec/System/MercenaryTestHelpers.lua new file mode 100644 index 00000000000..f522440ed0d --- /dev/null +++ b/spec/System/MercenaryTestHelpers.lua @@ -0,0 +1,57 @@ +-- Mercenary-spec fixtures. Loaded by Mercenary suites via dofile; not a busted spec. +local MercenaryTest = { } + +function MercenaryTest.selectScionLuminary() + local scionId + for classId, class in pairs(build.spec.tree.classes) do + if class.name == "Scion" then scionId = classId break end + end + build.spec:SelectClass(assert(scionId)) + local luminaryId + for ascendClassId, ascendClass in pairs(build.spec.curClass.classes) do + if ascendClass.name == "Luminary" then luminaryId = ascendClassId break end + end + build.spec:SelectAscendClass(assert(luminaryId)) +end + +function MercenaryTest.allocate(name) + local node + for _, candidate in pairs(build.spec.nodes) do + if candidate.name == name and (not node or candidate.id < node.id) then node = candidate end + end + node = node or build.spec.tree.ascendancyMap[name] + node = node or build.spec.tree.ascendancyMap[name:lower()] + node = assert(node, name) + node = build.spec.nodes[node.id] or node + if node.path then + build.spec:AllocNode(node) + else + node.alloc = true + build.spec.allocNodes[node.id] = node + end + return node +end + +function MercenaryTest.allocatePermanentHire() + MercenaryTest.selectScionLuminary() + MercenaryTest.allocate("Noble Blood") +end + +function MercenaryTest.freshHire() + newBuild() + MercenaryTest.allocatePermanentHire() + build.characterLevel = 90 + build.characterLevelAutoMode = false +end + +function MercenaryTest.calculateBuild(enemyLevel) + build.configTab.input.enemyLevel = enemyLevel or 83 + build.configTab:BuildModList() + build.spec.modFlag = true + build.buildFlag = true + runCallback("OnFrame") + runCallback("OnFrame") + return build.calcsTab.mainEnv +end + +return MercenaryTest diff --git a/spec/System/TestActorConfig_spec.lua b/spec/System/TestActorConfig_spec.lua new file mode 100644 index 00000000000..a956be9e02f --- /dev/null +++ b/spec/System/TestActorConfig_spec.lua @@ -0,0 +1,651 @@ +describe("Player and mercenary configuration", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + local selectScionLuminary = MercenaryTest.selectScionLuminary + local allocate = MercenaryTest.allocate + local calculateBuild = MercenaryTest.calculateBuild + local function configureMercenary() + allocate("Noble Blood") + local profile = build.mercenaryTab.profile + profile.classId = "MeleeAOEMarauder" + profile.buildId = "MeleeAOEMarauderFireSlam" + profile.foundAreaLevel = 68 + profile.mainSkillId = "TectonicSlamFireMercenary" + profile.skills = { { id = "TectonicSlamFireMercenary", enabled = true, supports = { } } } + build.mercenaryTab:Changed() + build.mercenaryTab:GetItemSet(true) + end + + local function envMercenarySkillDist(env) + return assert(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")).mainSkill.skillCfg.skillDist + end + + local function envMercenaryDamageMore(env) + local skill = assert(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")).mainSkill + return skill.skillModList:More(skill.skillCfg, "Damage") + end + + local function actorConfig() + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + return configSet + end + + local function calculateWithoutConfigRebuild() + build.spec.modFlag = true + build.buildFlag = true + runCallback("OnFrame") + runCallback("OnFrame") + return build.calcsTab.mainEnv + end + + local function fresh() + newBuild() + selectScionLuminary() + configureMercenary() + end + + before_each(fresh) + + it("rebuilds actor configuration when a Mercenary is hired", function() + newBuild() + selectScionLuminary() + local configSet = actorConfig() + configSet.actors.mercenary.input.usePowerCharges = true + build.configTab:BuildModList() + + configureMercenary() + local env = calculateWithoutConfigRebuild() + local mercenary = assert(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(mercenary.modDB:Flag(nil, "UsePowerCharges")) + + fresh() + -- restores player source configuration when a Mercenary is removed + local configSet = actorConfig() + configSet.input.conditionEnemyChilledByYourHits = true + configSet.customModsList[1].text = "Enemies Chilled by your Hits are Shocked" + build.configTab:BuildModList() + local hired = calculateWithoutConfigRebuild() + assert.is_true(hired.enemyDB:GetCondition("Shocked") or hired.enemyDB:Flag(nil, "Condition:Shocked")) + + build.mercenaryTab.profile.buildId = nil + build.mercenaryTab.profile.classId = nil + build.mercenaryTab.profile.mainSkillId = nil + build.mercenaryTab.profile.skills = { } + build.mercenaryTab:Changed() + local unhired = calculateWithoutConfigRebuild() + assert.is_nil(unhired.mercenary) + assert.is_true(unhired.enemyDB:GetCondition("Shocked") or unhired.enemyDB:Flag(nil, "Condition:Shocked")) + end) + + it("scopes shared encounter config vs actor combat and custom mods", function() + build.configTab.input.PvpScaling = true + local env = calculateBuild() + assert.is_true(env.player.modDB:Flag(nil, "HasPvpScaling")) + assert.is_true(env.mercenary.modDB:Flag(nil, "HasPvpScaling")) + + local configSet = actorConfig() + configSet.customModsList[1].text = "100000% increased Accuracy Rating" + env = calculateBuild() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.player.modDB:Sum("INC", nil, "Accuracy") >= 100000) + assert.is_true(env.mercenary.modDB:Sum("INC", nil, "Accuracy") < 100000) + + configSet.customModsList[1].text = "" + configSet.actors.mercenary.customModsList[1].text = "100000% increased Accuracy Rating" + env = calculateBuild() + assert.is_true(env.mercenary.modDB:Sum("INC", nil, "Accuracy") >= 100000) + assert.is_true(env.player.modDB:Sum("INC", nil, "Accuracy") < 100000) + + configSet.actors.mercenary.customModsList[1].text = "" + build.configTab.input.usePowerCharges = true + env = calculateBuild() + assert.is_true(env.player.modDB:Flag(nil, "UsePowerCharges")) + assert.is_not_true(env.mercenary.modDB:Flag(nil, "UsePowerCharges")) + + build.configTab.input.usePowerCharges = nil + configSet.actors.mercenary.input.usePowerCharges = true + env = calculateBuild() + assert.is_true(env.mercenary.modDB:Flag(nil, "UsePowerCharges")) + assert.is_not_true(env.player.modDB:Flag(nil, "UsePowerCharges")) + end) + + it("Config UI writes and hides against the viewed actor without stealing Items comparison", function() + local configTab = build.configTab + local configSet = actorConfig() + configTab:SetViewActor("mercenary") + configTab:SetConfigValue("usePowerCharges", true) + assert.is_true(configSet.actors.mercenary.input.usePowerCharges) + assert.is_not_true(configSet.input.usePowerCharges) + assert.is_not_true(configTab.input.usePowerCharges) + configTab:SetViewActor("player") + configTab:SetConfigValue("usePowerCharges", true) + assert.is_true(configSet.input.usePowerCharges) + + configTab:SetViewActor("mercenary") + configTab:SetConfigValue("minionsConditionFullLife", true) + assert.is_true(configSet.actors.mercenary.input.minionsConditionFullLife) + assert.is_not_true(configSet.input.minionsConditionFullLife) + configTab:SetViewActor("player") + configTab:SetConfigValue("minionsConditionFullLife", true) + assert.is_true(configSet.input.minionsConditionFullLife) + assert.is_true(configSet.actors.mercenary.input.minionsConditionFullLife) + + configTab:SetConfigValue("pantheonMajorGod", "TheBrineKing") + configTab:SetConfigValue("pantheonMinorGod", "Gruthkul") + configTab:SetConfigValue("bandit", "Alira") + configTab:SetViewActor("player") + assert.is_true(configTab.varControls.pantheonMajorGod.shown()) + assert.is_true(configTab.varControls.bandit.shown()) + configTab:SetViewActor("mercenary") + assert.is_false(configTab.varControls.pantheonMajorGod.shown()) + assert.is_false(configTab.varControls.pantheonMinorGod.shown()) + assert.is_false(configTab.varControls.bandit.shown()) + assert.is_false(configTab.varControls.resistancePenalty.shown()) + end) + + it("switching Config Sets does not change actor equipment", function() + local itemsTab = build.itemsTab + local configTab = build.configTab + local originalPlayerId = itemsTab.activeItemSetId + local originalMercId = itemsTab:GetActorItemSetId("MERCENARY") + local altPlayer = itemsTab:NewItemSet() + altPlayer.title = "Bossing" + table.insert(itemsTab.itemSetOrderList, altPlayer.id) + local bossing = configTab:NewConfigSet() + table.insert(configTab.configSetOrderList, bossing.id) + configTab:SetActiveConfigSet(bossing.id) + assert.are.equal(originalPlayerId, itemsTab.activeItemSetId) + assert.are.equal(originalMercId, itemsTab:GetActorItemSetId("MERCENARY")) + assert.is_nil(configTab.configSets[bossing.id].actors.player.itemSetId) + assert.is_nil(configTab.configSets[bossing.id].actors.mercenary.itemSetId) + + fresh() + -- round-trips actor combat config XML without owning item sets + local configTab = build.configTab + local configSet = actorConfig() + configSet.customModsList[1].text = "10% increased Damage" + configSet.actors.mercenary.customModsList[1].text = "20% increased Damage" + configSet.actors.mercenary.input.usePowerCharges = true + configTab.input.enemyIsBoss = "Uber" + local xml = { elem = "Config" } + configTab:Save(xml) + -- Player and shared values keep the upstream ConfigSet layout; only the Mercenary gets an Actor node. + local actorIds, mercenaryMods, playerMods, sharedBoss = { }, nil, nil, nil + for _, child in ipairs(xml[1]) do + if child.elem == "Actor" then + actorIds[child.attrib.id] = child + if child.attrib.id == "mercenary" then + for _, grand in ipairs(child) do + if grand.elem == "CustomModifierBlock" then mercenaryMods = grand[1] end + end + end + elseif child.elem == "CustomModifierBlock" then + playerMods = child[1] + elseif child.elem == "Input" and child.attrib.name == "enemyIsBoss" then + sharedBoss = child.attrib.string + end + end + assert.is_nil(actorIds.player) + assert.is_not_nil(actorIds.mercenary) + assert.are.equal("10% increased Damage", playerMods) + assert.are.equal("20% increased Damage", mercenaryMods) + assert.are.equal("Uber", sharedBoss) + + fresh() + build.configTab:Load(xml, "actor-config.xml") + build.configTab:PostLoad() + local loaded = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(loaded) + assert.are.equal("Uber", loaded.input.enemyIsBoss) + assert.are.equal("10% increased Damage", loaded.customModsList[1].text) + assert.is_true(loaded.actors.mercenary.input.usePowerCharges) + assert.are.equal("20% increased Damage", loaded.actors.mercenary.customModsList[1].text) + + local itemsTab = build.itemsTab + local livePlayerId = itemsTab.activeItemSetId + local liveMercenaryId = itemsTab:GetActorItemSetId("MERCENARY") + build.configTab:Load({ + elem = "Config", + attrib = { activeConfigSet = "1" }, + { + elem = "ConfigSet", + attrib = { id = "1", title = "Mapping" }, + { elem = "Actor", attrib = { id = "player", itemSetId = "99" } }, + { elem = "Actor", attrib = { id = "mercenary", itemSetId = "99" } }, + }, + }, "legacy-config-itemset.xml") + build.configTab:PostLoad() + local mapping = build.configTab.configSets[1] + build.configTab:EnsureActorConfig(mapping) + assert.is_nil(mapping.actors.player.itemSetId) + assert.is_nil(mapping.actors.mercenary.itemSetId) + assert.are.equal(livePlayerId, itemsTab.activeItemSetId) + assert.are.equal(liveMercenaryId, itemsTab:GetActorItemSetId("MERCENARY")) + end) + + it("keeps Mercenary melee distance independent of the player", function() + local configTab = build.configTab + local configSet = actorConfig() + assert.are.equal(15, configSet.actors.mercenary.placeholder.meleeDistance) + assert.are.equal(40, configSet.actors.mercenary.placeholder.projectileDistance) + assert.are.equal(15, envMercenarySkillDist(calculateBuild())) + + configSet.input.meleeDistance = 1 + configSet.actors.mercenary.input.meleeDistance = 40 + assert.are.equal(40, envMercenarySkillDist(calculateBuild())) + configSet.input.meleeDistance = 40 + configSet.actors.mercenary.input.meleeDistance = 1 + assert.are.equal(1, envMercenarySkillDist(calculateBuild())) + + configSet.placeholder.meleeDistance = 15 + configSet.actors.mercenary.placeholder.meleeDistance = 7 + configTab:SetViewActor("player") + assert.are.equal(15, configTab:GetDefaultState("meleeDistance")) + configTab:SetViewActor("mercenary") + assert.are.equal(7, configTab:GetDefaultState("meleeDistance")) + configTab:SetViewActor("player") + assert.are.equal(15, configTab:GetDefaultState("meleeDistance")) + assert.are.equal(7, configSet.actors.mercenary.placeholder.meleeDistance) + + configSet.actors.mercenary.input.meleeDistance = nil + configSet.actors.mercenary.customModsList[1].text = "Deal up to 15% more Melee Damage to Enemies, based on proximity" + configSet.input.meleeDistance = 40 + local atDefault = envMercenaryDamageMore(calculateBuild()) + configSet.actors.mercenary.input.meleeDistance = 40 + local atForty = envMercenaryDamageMore(calculateBuild()) + assert.is_true(atDefault > atForty) + configSet.actors.mercenary.input.meleeDistance = 15 + configSet.input.meleeDistance = 1 + assert.are.near(atDefault, envMercenaryDamageMore(calculateBuild()), 10 ^ -9) + + configSet.actors.mercenary.placeholder.meleeDistance = 15 + configSet.actors.mercenary.input.meleeDistance = 15 + local xml = { elem = "Config" } + configTab:Save(xml) + local saved + for _, child in ipairs(xml[1]) do + if child.elem == "Actor" and child.attrib.id == "mercenary" then + for _, grand in ipairs(child) do + if grand.elem == "Input" and grand.attrib.name == "meleeDistance" then + saved = tonumber(grand.attrib.number) + end + end + end + end + assert.is_nil(saved) + end) + + it("shows source-owned enemy configuration only for the actor that uses it", function() + local configTab = build.configTab + local configSet = actorConfig() + local control = assert(configTab.varControls.conditionEnemyChilledByYourHits) + local chilledByHitsMod = "Enemies Chilled by your Hits are Shocked" + local function assertShownForActor(playerShown, mercenaryShown) + configTab:SetViewActor("player") + assert.are.equal(playerShown, control.shown()) + configTab:SetViewActor("mercenary") + assert.are.equal(mercenaryShown, control.shown()) + end + + configSet.customModsList[1].text = chilledByHitsMod + local env = calculateBuild() + assert.is_not_nil(env.actorUsage.player.enemyConditions.ChilledByYourHits) + assert.is_nil(env.actorUsage.mercenary.enemyConditions.ChilledByYourHits) + assertShownForActor(true, false) + + configSet.customModsList[1].text = "" + configSet.actors.mercenary.customModsList[1].text = chilledByHitsMod + env = calculateBuild() + assert.is_nil(env.actorUsage.player.enemyConditions.ChilledByYourHits) + assert.is_not_nil(env.actorUsage.mercenary.enemyConditions.ChilledByYourHits) + assertShownForActor(false, true) + + -- keeps by-you ailment conditions source-owned + local frozenByYouMod = "Enemies permanently take 5% increased Damage for each second they've ever been Frozen by you, up to a maximum of 50%" + local ignitedByYouMod = "Enemies Ignited by you take 20% increased Damage" + local curseByYouMod = "Enemies you Curse take 20% increased Damage" + local chilledByYouBurningMod = "Enemies Chilled by you take 20% increased Burning Damage" + local againstChilledMod = "20% increased Damage against Chilled Enemies" + local function enemyShocked(env) + return env.enemyDB:GetCondition("Shocked") or env.enemyDB:Flag(nil, "Condition:Shocked") + end + local function enemyDamageTaken(env) + return env.enemyDB:Sum("INC", nil, "DamageTaken") + end + local function enemyFireDotTaken(env) + return env.enemyDB:Sum("INC", nil, "FireDamageTakenOverTime") + end + local function actorDamageInc(env, owner) + return (owner == "PLAYER" and env.player or env.mercenary).modDB:Sum("INC", nil, "Damage") + end + local function overlayFlag(db, name) + return db:GetCondition(name) or db:Flag(nil, "Condition:"..name) + end + local function setActorMod(owner, text) + local configSet = actorConfig() + if owner == "PLAYER" then + configSet.customModsList[1].text = text + else + configSet.actors.mercenary.customModsList[1].text = text + end + end + local function setActorInput(owner, key, value) + local configSet = actorConfig() + if owner == "PLAYER" then + configSet.input[key] = value + else + configSet.actors.mercenary.input[key] = value + end + end + local ownerMatrix = { + { source = "PLAYER", target = "MERCENARY", match = false }, + { source = "MERCENARY", target = "MERCENARY", match = true }, + { source = "MERCENARY", target = "PLAYER", match = false }, + { source = "PLAYER", target = "PLAYER", match = true }, + } + local function runOwnerMatrix(spec) + for _, case in ipairs(ownerMatrix) do + fresh() + local baseline = spec.measure and spec.measure(calculateBuild(), case) or 0 + setActorInput(case.source, spec.input, spec.value) + setActorMod(case.target, spec.mod) + local env = calculateBuild() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local actual = spec.actual(env, case) + local expect = spec.expect and spec.expect(case) or (case.match and spec.effect or 0) + assert.are.equal(expect, actual - (spec.subtractBaseline and baseline or 0), spec.name.." "..case.source.." -> "..case.target) + if spec.overlay then + local sourceDB = case.source == "PLAYER" and env.player.enemySourceDB or env.mercenary.enemySourceDB + local otherDB = case.source == "PLAYER" and env.mercenary.enemySourceDB or env.player.enemySourceDB + assert.is_true(overlayFlag(env.enemyDB, spec.overlay), spec.name.." shared") + assert.is_true(overlayFlag(sourceDB, spec.overlay), spec.name.." overlay") + assert.is_not_true(overlayFlag(otherDB, spec.overlay), spec.name.." other") + end + end + end + runOwnerMatrix({ + name = "shock", + input = "conditionEnemyChilledByYourHits", + value = true, + mod = chilledByHitsMod, + actual = function(env) return enemyShocked(env) and 1 or 0 end, + effect = 1, + overlay = "Chilled", + }) + runOwnerMatrix({ + name = "frozen", + input = "multiplierFrozenByYouSeconds", + value = 10, + mod = frozenByYouMod, + measure = enemyDamageTaken, + actual = enemyDamageTaken, + subtractBaseline = true, + effect = 50, + overlay = "Frozen", + }) + runOwnerMatrix({ + name = "chilled-burning", + input = "multiplierChilledByYouSeconds", + value = 10, + mod = chilledByYouBurningMod, + measure = enemyFireDotTaken, + actual = enemyFireDotTaken, + subtractBaseline = true, + effect = 20, + }) + runOwnerMatrix({ + name = "chilled-by-hits-burning", + input = "conditionEnemyChilledByYourHits", + value = true, + mod = chilledByYouBurningMod, + measure = enemyFireDotTaken, + actual = enemyFireDotTaken, + subtractBaseline = true, + effect = 20, + }) + runOwnerMatrix({ + name = "against-chilled", + input = "conditionEnemyChilledByYourHits", + value = true, + mod = againstChilledMod, + measure = function(env, case) return actorDamageInc(env, case.target) end, + actual = function(env, case) return actorDamageInc(env, case.target) end, + subtractBaseline = true, + expect = function() return 20 end, + }) + + for _, case in ipairs({ + { key = "conditionEnemyIgnited", mod = ignitedByYouMod, owner = "MERCENARY", delta = 0 }, + { key = "conditionEnemyShocked", mod = "Enemies Shocked by you take 20% increased Damage", owner = "MERCENARY", delta = 0 }, + { key = "conditionEnemyIgnited", mod = ignitedByYouMod, owner = "PLAYER", delta = 20 }, + }) do + fresh() + local configSet = actorConfig() + configSet.input[case.key] = true + local baseline = enemyDamageTaken(calculateBuild()) + setActorMod(case.owner, case.mod) + local env = calculateBuild() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal(case.delta, enemyDamageTaken(env) - baseline, case.mod) + end + + fresh() + local configSet = actorConfig() + configSet.customModsList[1].text = curseByYouMod + local baseline = enemyDamageTaken(calculateBuild()) + assert.is_not_true(configSet.input.conditionEnemyCursed) + build.skillsTab:PasteSocketGroup("Despair 20/0 1") + local env = calculateBuild() + assert.is_true(env.enemy.modDB.conditions.Cursed) + assert.are.equal(20, enemyDamageTaken(env) - baseline) + + local function configureCurseMerc() + local profile = build.mercenaryTab.profile + profile.classId = "ChaosMinionWitch" + profile.buildId = "ChaosMinionWitchDot" + profile.mainSkillId = "BaneMercenary" + profile.skills = { + { id = "BaneMercenary", enabled = true, supports = { } }, + { id = "TemporalChainsMercenary", enabled = true, count = 1, supports = { } }, + } + build.mercenaryTab:Changed() + build.mercenaryTab:GetItemSet(true) + end + fresh() + configSet = actorConfig() + configSet.customModsList[1].text = curseByYouMod + baseline = enemyDamageTaken(calculateBuild()) + configureCurseMerc() + env = calculateBuild() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.enemy.modDB.conditions.Cursed) + assert.are.equal(baseline, enemyDamageTaken(env)) + + fresh() + configureCurseMerc() + configSet = actorConfig() + baseline = enemyDamageTaken(calculateBuild()) + configSet.actors.mercenary.customModsList[1].text = curseByYouMod + env = calculateBuild() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.enemy.modDB.conditions.Cursed) + assert.are.equal(20, enemyDamageTaken(env) - baseline) + end) + + it("drives Elemental Equilibrium hit elements from each actor's own overlay", function() + local configSet = actorConfig() + configSet.input.enemyConditionHitByFireDamage = true + local env = calculateBuild() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.player.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_not_true(env.mercenary.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_not_true(env.enemyDB:GetCondition("HitByFireDamage") or env.enemyDB:Flag(nil, "Condition:HitByFireDamage")) + + configSet.input.enemyConditionHitByFireDamage = nil + configSet.actors.mercenary.input.enemyConditionHitByFireDamage = true + env = calculateBuild() + assert.is_true(env.mercenary.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_not_true(env.player.enemySourceDB:GetCondition("HitByFireDamage")) + + fresh() + allocate("Elemental Equilibrium") + build.skillsTab:PasteSocketGroup("Fireball 20/0 1") + env = calculateBuild() + assert.is_true(env.player.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_not_true(env.player.enemySourceDB:GetCondition("HitByColdDamage")) + assert.is_not_true(env.mercenary.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_true(env.enemyDB:Flag(nil, "Condition:HasColdExposure") or env.enemy.modDB.conditions.HasColdExposure) + assert.is_true(env.enemyDB:Flag(nil, "Condition:HasLightningExposure") or env.enemy.modDB.conditions.HasLightningExposure) + assert.is_not_true(env.enemyDB:Flag(nil, "Condition:HasFireExposure") or env.enemy.modDB.conditions.HasFireExposure) + + fresh() + allocate("Elemental Equilibrium") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + configSet = actorConfig() + configSet.actors.mercenary.customModsList[1].text = "Hits that deal Elemental Damage remove Exposure to those Elements and inflict Exposure to other Elements Exposure inflicted this way applies -25% to Resistances" + env = calculateBuild() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.player.enemySourceDB:GetCondition("HitByLightningDamage")) + assert.is_not_true(env.player.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_true(env.mercenary.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_not_true(env.mercenary.enemySourceDB:GetCondition("HitByLightningDamage")) + assert.is_not_true(env.enemyDB:Flag(nil, "Condition:HasLightningExposure") or env.enemy.modDB.conditions.HasLightningExposure) + assert.is_true(env.enemyDB:Flag(nil, "Condition:HasColdExposure") or env.enemy.modDB.conditions.HasColdExposure) + assert.is_not_true(env.enemyDB:Flag(nil, "Condition:HasFireExposure") or env.enemy.modDB.conditions.HasFireExposure) + + fresh() + -- keeps Mercenary EE hit history on an overlay when config source mods are empty + local calcs = require("Modules.CalcBase") + local configSet = actorConfig() + assert.is_nil(configSet.actors.mercenary.input.enemyConditionHitByFireDamage) + assert.is_nil(configSet.actors.mercenary.input.enemyConditionHitByColdDamage) + assert.is_nil(configSet.actors.mercenary.input.enemyConditionHitByLightningDamage) + configSet.actors.mercenary.customModsList[1].text = "Hits that deal Elemental Damage remove Exposure to those Elements and inflict Exposure to other Elements Exposure inflicted this way applies -25% to Resistances" + calculateBuild() + wipeTable(build.configTab.mercenaryEnemyModList) + assert.is_nil(build.configTab.mercenaryEnemyModList[1]) + local env = calcs.initEnv(build, "MAIN") + calcs.perform(env) + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_not_nil(env.mercenary.enemySourceDB) + assert.is_true(env.mercenary.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_not_true(env.mercenary.enemySourceDB:GetCondition("HitByColdDamage")) + assert.is_not_true(env.mercenary.enemySourceDB:GetCondition("HitByLightningDamage")) + assert.is_not_true(env.enemyDB:GetCondition("HitByFireDamage") or env.enemyDB:Flag(nil, "Condition:HitByFireDamage")) + assert.is_true(env.enemyDB:Flag(nil, "Condition:HasColdExposure") or env.enemy.modDB.conditions.HasColdExposure) + assert.is_true(env.enemyDB:Flag(nil, "Condition:HasLightningExposure") or env.enemy.modDB.conditions.HasLightningExposure) + assert.is_not_true(env.enemyDB:Flag(nil, "Condition:HasFireExposure") or env.enemy.modDB.conditions.HasFireExposure) + + fresh() + -- scales each exposure with its inflictor before choosing the strongest + local configSet = actorConfig() + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + local exposure = "Nearby Enemies have Fire Exposure" + local bonus = "Exposure you inflict applies an extra -25% to the affected Resistance" + local function fireResistance() + return calculateBuild().enemyDB:Sum("BASE", nil, "FireResist") + end + local baseline = fireResistance() + for _, owner in ipairs({ "player", "mercenary" }) do + local source = owner == "player" and configSet or configSet.actors.mercenary + local other = owner == "player" and configSet.actors.mercenary or configSet + source.customModsList[1].text = exposure + other.customModsList[1].text = bonus + local env = calculateBuild() + assert.are.equal(baseline - 10, env.enemyDB:Sum("BASE", nil, "FireResist")) + assert.is_true(env[owner].modDB:Flag(nil, "Condition:AppliedExposureRecently")) + assert.is_not_true(env[owner == "player" and "mercenary" or "player"].modDB:Flag(nil, "Condition:AppliedExposureRecently")) + source.customModsList[1].text = exposure.."\n"..bonus + other.customModsList[1].text = exposure + assert.are.equal(baseline - 35, fireResistance()) + end + configSet.customModsList[1].text = "" + configSet.actors.mercenary.customModsList[1].text = "100% chance to inflict Cold Exposure on Hit with Cold Damage\n"..bonus + configSet.input.conditionEnemyColdExposure = true + local env = calculateBuild() + assert.are.equal(-35, env.enemyDB:Sum("BASE", nil, "ColdResist") - baseline) + assert.is_not_true(env.player.modDB:Flag(nil, "Condition:AppliedExposureRecently")) + end) + + it("keeps minion curses separate from both owners' by-you conditions", function() + local configSet = actorConfig() + build.skillsTab:PasteSocketGroup("Summon Skitterbots 20/0 1") + local profile = build.mercenaryTab.profile + for _, buildId in ipairs(build.data.mercenaries.buildOrder) do + local mercBuild = build.data.mercenaries.builds[buildId] + if isValueInArray(mercBuild.skillIds, "SummonSkitterbotsMercenary") then + profile.buildId, profile.classId = buildId, mercBuild.classId + break + end + end + profile.mainSkillId = "SummonSkitterbotsMercenary" + profile.skills = { { id = profile.mainSkillId, enabled = true, supports = { } } } + build.mercenaryTab:Changed() + configSet.customModsList[1].text = "Enemies you Curse take 20% increased Damage" + configSet.actors.mercenary.customModsList[1].text = "Enemies you Curse take 30% increased Damage" + build.configTab:BuildModList() + local calcs = require("Modules.CalcBase") + for _, owner in ipairs({ "player", "mercenary" }) do + local env = calcs.initEnv(build, "MAIN") + env[owner].modDB:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("ExtraCurse", "LIST", { skillId = "Enfeeble", level = 1 }, "Test") }, "Test") + calcs.perform(env) + assert.is_true(env.enemyDB:GetCondition("Cursed")) + assert.is_true(env[owner].mainSkill.minion.enemySourceDB:GetCondition("Cursed")) + assert.is_not_true(env.player.enemySourceDB:GetCondition("Cursed")) + assert.is_not_true(env.mercenary.enemySourceDB:GetCondition("Cursed")) + end + + fresh() + -- preserves competing skill exposures through debuff merging + local configSet = actorConfig() + local profile = build.mercenaryTab.profile + for _, buildId in ipairs(build.data.mercenaries.buildOrder) do + local mercBuild = build.data.mercenaries.builds[buildId] + if isValueInArray(mercBuild.skillIds, "FrostBombMercenary") then + profile.buildId, profile.classId = buildId, mercBuild.classId + break + end + end + profile.mainSkillId = "FrostBombMercenary" + profile.skills = { { id = profile.mainSkillId, enabled = true, includeInFullDPS = true, supports = { } } } + build.mercenaryTab:Changed() + build.skillsTab:PasteSocketGroup("Frost Bomb 20/0 1") + build.skillsTab.socketGroupList[1].includeInFullDPS = true + local baseline = calculateBuild().enemyDB:Sum("BASE", nil, "ColdResist") + for _, config in ipairs({ configSet, configSet.actors.mercenary }) do + config.customModsList[1].text = "Exposure you inflict applies an extra -25% to the affected Resistance" + local env = calculateBuild() + assert.are.equal(baseline - 25, env.enemyDB:Sum("BASE", nil, "ColdResist")) + local firstDPS = env.player.output.FullDPS + assert.are.equal(firstDPS, calculateBuild().player.output.FullDPS) + config.customModsList[1].text = "" + end + + fresh() + -- hover comparisons use the viewed actor's output + calculateBuild() + local configTab = build.configTab + local captured + local function captureRun() + configTab.calcFunc = nil + captured = "unset" + configTab.RunComparisonCalc = function(self, calcFunc, comparisonActor) + captured = comparisonActor + return calcFunc(comparisonActor and { comparisonActor = comparisonActor } or nil) + end + local tooltip = new("Tooltip"):Tooltip() + assert.has_no.errors(function() + configTab.varControls.usePowerCharges.tooltipFunc(tooltip) + end) + configTab.RunComparisonCalc = nil + end + + configTab:SetViewActor("mercenary") + captureRun() + assert.are.equal("MERCENARY", captured) + + configTab:SetViewActor("player") + captureRun() + assert.is_nil(captured) + end) +end) diff --git a/spec/System/TestBuildDisplayStats_spec.lua b/spec/System/TestBuildDisplayStats_spec.lua index c198aaf2455..206a9f69b91 100644 --- a/spec/System/TestBuildDisplayStats_spec.lua +++ b/spec/System/TestBuildDisplayStats_spec.lua @@ -31,6 +31,46 @@ describe("Build display stats", function() assert.are.equals("^7123", build:FormatStat({ fmt = ".1f", compactValue = true }, 123)) end) + it("shows Mercenary sidebar stats", function() + local mercenaryDisplayStats = LoadModule("Modules/BuildDisplayStats").mercenaryDisplayStats + build.controls.statBox.list = { } + build:AddDisplayStatList(mercenaryDisplayStats, { + mainSkill = { skillFlags = { attack = true, hit = true } }, + output = { + Speed = 1.5, + PreEffectiveCritChance = 12.34, + CritChance = 10, + CritMultiplier = 2, + HitChance = 95, + FireResist = 75, + FireResistOverCap = 15, + ColdResist = 75, + ColdResistOverCap = 20, + LightningResist = 75, + LightningResistOverCap = 25, + ChaosResist = 20, + ChaosResistOverCap = 5, + CrabBarriersMax = 0, + CrabBarriers = 0, + }, + modDB = { Flag = function() return false end }, + }) + + for _, label in ipairs({ "Attack Rate", "Crit Chance", "Effective Crit Chance", "Crit Multiplier", "Hit Chance" }) do + assert.is_truthy(getSidebarStat(label), label) + end + for _, stat in ipairs({ + { label = "Fire Resistance", overCap = 15 }, + { label = "Cold Resistance", overCap = 20 }, + { label = "Lightning Resistance", overCap = 25 }, + { label = "Chaos Resistance", overCap = 5 }, + }) do + local value = getSidebarStat(stat.label) + assert.is_truthy(value, stat.label) + assert.is_truthy(value:find("(+" .. stat.overCap .. "%)", 1, true), stat.label) + end + end) + it("shows guard suffixes for EHP and max hit values", function() build.skillsTab:PasteSocketGroup("Steelskin 20/0 1") runCallback("OnFrame") diff --git a/spec/System/TestCalcsSourceSkillFlags_spec.lua b/spec/System/TestCalcsSourceSkillFlags_spec.lua new file mode 100644 index 00000000000..13f15bce569 --- /dev/null +++ b/spec/System/TestCalcsSourceSkillFlags_spec.lua @@ -0,0 +1,101 @@ +describe("Calcs source-skill flag visibility", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + local allocatePermanentHire = MercenaryTest.allocatePermanentHire + local function skillSelectRow(label) + for _, section in ipairs(build.calcsTab.sectionList) do + if section.id == "SkillSelect" then + for _, row in ipairs(section.subSection[1].data) do + if row.label == label then return row end + end + end + end + end + + before_each(function() + newBuild() + end) + + it("keeps the calculation actor dropdown populated after refresh", function() + assert.are.equal(4, #calcLib.calculationActorList) + build.calcsTab:SyncActorList() + build.calcsTab:SyncActorList() + local actor = build.calcsTab.skillSelectSection.controls.actor + assert.is_true(#actor.list >= 2) + assert.are.equal("PLAYER", actor.list[1].actorId) + assert.are.equal(4, #calcLib.calculationActorList) + end) + + it("follows source-skill flags for player, minion, and Mercenary actors", function() + for _, case in ipairs({ + { label = "Skill Part", flag = "multiPart" }, + { label = "Skill Stages", flag = "multiStage" }, + { label = "Active Mines", flag = "mine" }, + }) do + local row = assert(skillSelectRow(case.label), case.label) + assert.are.equal(case.flag, row.playerFlag, case.label) + assert.is_nil(row.flag, case.label) + end + + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + runCallback("OnFrame") + build.calcsTab.input.actor = "PLAYER" + assert.is_true(not build.calcsTab:CheckFlag(skillSelectRow("Skill Part"))) + build.calcsTab.calcsEnv.player.mainSkill.skillFlags.multiPart = true + assert.is_true(build.calcsTab:CheckFlag(skillSelectRow("Skill Part"))) + + newBuild() + build.skillsTab:PasteSocketGroup("Summon Raging Spirit 20/0 1") + runCallback("OnFrame") + local env = assert(build.calcsTab.calcsEnv) + local playerFlags = env.player.mainSkill.skillFlags + local minionFlags = env.minion.mainSkill.skillFlags + playerFlags.multiPart, playerFlags.multiStage, playerFlags.mine = true, true, true + minionFlags.multiPart, minionFlags.multiStage, minionFlags.mine = nil, nil, nil + build.calcsTab.input.actor = "PLAYER_MINION" + assert.is_true(build.calcsTab:CheckFlag(skillSelectRow("Skill Part"))) + assert.is_true(build.calcsTab:CheckFlag(skillSelectRow("Skill Stages"))) + assert.is_true(build.calcsTab:CheckFlag(skillSelectRow("Active Mines"))) + + newBuild() + allocatePermanentHire() + local profile = build.mercenaryTab.profile + profile.classId = "AurasMinionsTemplar" + profile.buildId = "AurasMinionsTemplarSmite" + profile.foundAreaLevel = 68 + profile.mainSkillId = "SSMHolySpectresMercenary" + profile.lifeComparison = "AUTO" + profile.skills = { { id = "SSMHolySpectresMercenary", enabled = true, includeInFullDPS = false, count = 1, supports = { } } } + local itemSet = build.mercenaryTab:GetItemSet(true) + local mace = new("Item"):Item("Rarity: Normal\nDriftwood Club") + local shield = new("Item"):Item("Rarity: Normal\nTwig Spirit Shield") + build.itemsTab:AddItem(mace, true) + build.itemsTab:AddItem(shield, true) + itemSet["Weapon 1"].selItemId = mace.id + itemSet["Weapon 2"].selItemId = shield.id + build.mercenaryTab:Changed() + build.configTab.input.enemyLevel = 83 + build.configTab:BuildModList() + build.spec.modFlag = true + build.buildFlag = true + runCallback("OnFrame") + runCallback("OnFrame") + env = assert(build.calcsTab.calcsEnv) + assert.is_table(env.mercenary) + assert.is_table(env.mercenaryMinion) + playerFlags = env.player.mainSkill.skillFlags + local mercenaryFlags = env.mercenary.mainSkill.skillFlags + minionFlags = env.mercenaryMinion.mainSkill.skillFlags + playerFlags.multiPart, playerFlags.multiStage, playerFlags.mine = nil, nil, nil + mercenaryFlags.multiPart, mercenaryFlags.multiStage, mercenaryFlags.mine = true, true, true + minionFlags.multiPart, minionFlags.multiStage, minionFlags.mine = nil, nil, nil + for _, actor in ipairs({ "MERCENARY", "MERCENARY_MINION" }) do + build.calcsTab.input.actor = actor + assert.is_true(build.calcsTab:CheckFlag(skillSelectRow("Skill Part")), actor) + assert.is_true(build.calcsTab:CheckFlag(skillSelectRow("Skill Stages")), actor) + assert.is_true(build.calcsTab:CheckFlag(skillSelectRow("Active Mines")), actor) + end + mercenaryFlags.multiPart, mercenaryFlags.multiStage, mercenaryFlags.mine = nil, nil, nil + build.calcsTab.input.actor = "MERCENARY_MINION" + assert.is_true(not build.calcsTab:CheckFlag(skillSelectRow("Skill Part"))) + end) +end) diff --git a/spec/System/TestCompareTab_spec.lua b/spec/System/TestCompareTab_spec.lua index 1eeb3313ed9..142f6f5dcbd 100644 --- a/spec/System/TestCompareTab_spec.lua +++ b/spec/System/TestCompareTab_spec.lua @@ -1,4 +1,50 @@ describe("CompareTab", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + local allocatePermanentHire = MercenaryTest.allocatePermanentHire + it("imports Mercenary builds and preserves their Calcs skill selection", function() + newBuild() + allocatePermanentHire() + build.mercenaryTab.profile = { + classId = "EleBowRanger", + buildId = "EleBowRangerClones", + foundAreaLevel = 68, + mainSkillId = "MirrorArrowMercenary", + lifeComparison = "AUTO", + skills = { + { id = "MirrorArrowMercenary", enabled = true, includeInFullDPS = true, supports = { } }, + { id = "IceShotMercenary", enabled = true, includeInFullDPS = false, supports = { } }, + }, + } + build.mercenaryTab:Changed() + local mercenaryItemSet = build.mercenaryTab:GetItemSet(true) + local item = new("Item"):Item("Rarity: Normal\nCrude Bow") + item.id = 999903 + build.itemsTab.items[item.id] = item + mercenaryItemSet["Weapon 1"].selItemId = item.id + build.calcsTab.input.actor = "MERCENARY" + build.configTab.input.enemyLevel = 83 + build.configTab:BuildModList() + build.calcsTab:BuildOutput() + + local compareTab = build.compareTab + assert.is_true(compareTab:ImportBuild(assert(build:SaveDB("mercenary-compare")), "Mercenary")) + local entry = assert(compareTab:GetActiveCompare()) + compareTab:UpdateSetSelectors(entry) + assert.is_true(compareTab.controls.cmpMainSkill:IsShown()) + assert.are.equal(2, #compareTab.controls.cmpMainSkill.list) + compareTab.controls.cmpMainSkill:SetSel(2) + assert.are.equal("IceShotMercenary", entry.mercenaryTab.profile.mainSkillId) + entry.mercenaryTab.profile.mainSkillId = "MirrorArrowMercenary" + entry.mercenaryTab:Changed() + compareTab.compareViewMode = "CALCS" + compareTab:RefreshCalcsSkillControls(entry) + assert.is_true(entry.calcsTab:IsMercenaryActor()) + assert.is_true(compareTab.controls.cmpCalcsMainSkill:IsShown()) + assert.are.equal(2, #compareTab.controls.cmpCalcsMainSkill.list) + compareTab.controls.cmpCalcsMainSkill:SetSel(2) + assert.are.equal("IceShotMercenary", entry.mercenaryTab.profile.mainSkillId) + end) + it("hides skill detail controls after removing the final comparison", function() newBuild() local compareTab = build.compareTab @@ -38,4 +84,137 @@ describe("CompareTab", function() assert.are.equals(build.calcsTab.mainOutput.GemQuality, entry.calcsTab.mainOutput.GemQuality) assert.are.equals(build.calcsTab.mainOutput.CombinedDPS, entry.calcsTab.mainOutput.CombinedDPS) end) + + it("copies an item from the visible Mercenary set into the primary Mercenary set", function() + newBuild() + allocatePermanentHire() + build.mercenaryTab.profile = { + classId = "EleBowRanger", + buildId = "EleBowRangerClones", + foundAreaLevel = 68, + mainSkillId = "MirrorArrowMercenary", + lifeComparison = "AUTO", + skills = { { id = "MirrorArrowMercenary", enabled = true, supports = { } } }, + } + build.mercenaryTab:Changed() + local primaryMercenarySet = assert(build.mercenaryTab:GetItemSet(true)) + local item = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + build.itemsTab:AddItem(item, true) + build.itemsTab:AddItem(quiver, true) + primaryMercenarySet["Weapon 1"].selItemId = item.id + primaryMercenarySet["Weapon 2"].selItemId = quiver.id + + build.configTab.input.enemyLevel = 83 + build.configTab:BuildModList() + build.calcsTab:BuildOutput() + local compareTab = build.compareTab + assert.is_true(compareTab:ImportBuild(assert(build:SaveDB("mercenary-copy")), "Mercenary")) + local entry = assert(compareTab:GetActiveCompare()) + entry.itemsTab:SetViewItemSet(assert(entry.itemsTab:GetActorItemSetId("MERCENARY"))) + build.itemsTab:SetViewItemSet(primaryMercenarySet.id) + build.calcsTab:BuildOutput() + local _, baseOutput, actorOutputs = build.calcsTab:GetMiscCalculator() + assert.are.equal(actorOutputs.PLAYER, baseOutput) + assert.is_truthy(actorOutputs.MERCENARY) + + local playerWeapon = build.itemsTab.activeItemSet["Weapon 1"] + playerWeapon.selItemId = 0 + compareTab:CopyCompareItemToPrimary("Weapon 1", entry, true) + + local copiedItemId = primaryMercenarySet["Weapon 1"].selItemId + assert.is_true(copiedItemId > 0) + assert.are.equal("Crude Bow", build.itemsTab.items[copiedItemId].name) + assert.are.equal(0, playerWeapon.selItemId) + end) + + it("views an item set from Compare without equipping the player", function() + newBuild() + allocatePermanentHire() + build.mercenaryTab.profile = { + classId = "TrapsMinesShadow", + buildId = "TrapsMinesShadowLightning", + foundAreaLevel = 68, + mainSkillId = "LightningTrapMercenary", + lifeComparison = "AUTO", + skills = { { id = "LightningTrapMercenary", enabled = true, supports = { } } }, + } + build.mercenaryTab:Changed() + local itemsTab = build.itemsTab + local playerSetId = itemsTab.activeItemSetId + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + assert.are_not.equal(playerSetId, mercSet.id) + itemsTab:SetViewItemSet(mercSet.id, "MERCENARY") + local playerIndex, mercIndex + for index, itemSetId in ipairs(itemsTab.itemSetOrderList) do + if itemSetId == playerSetId then playerIndex = index end + if itemSetId == mercSet.id then mercIndex = index end + end + build.compareTab.controls.primaryItemSetSelect.selFunc(playerIndex, itemsTab.itemSets[playerSetId].title or "Default") + assert.are.equal(playerSetId, itemsTab.activeItemSetId) + assert.are.equal(playerSetId, itemsTab.viewItemSetId) + assert.are.equal("MERCENARY", itemsTab.viewComparisonActor) + build.compareTab.controls.primaryItemSetSelect.selFunc(mercIndex, mercSet.title or "Default") + assert.are.equal(playerSetId, itemsTab.activeItemSetId) + assert.are.equal(mercSet.id, itemsTab.viewItemSetId) + assert.are.equal("MERCENARY", itemsTab.viewComparisonActor) + + assert(build.itemsTab:SetActorItemSet("MERCENARY", playerSetId)) + itemsTab:SetViewItemSet(playerSetId, "MERCENARY") + build.compareTab.controls.primaryItemSetSelect.selFunc(playerIndex, itemsTab.itemSets[playerSetId].title or "Default") + assert.are.equal("MERCENARY", itemsTab.viewComparisonActor) + assert.are.equal(playerSetId, itemsTab.activeItemSetId) + end) + + it("Compare Config copies and edits mercenary actor overlays", function() + newBuild() + allocatePermanentHire() + build.mercenaryTab.profile = { + classId = "EleBowRanger", + buildId = "EleBowRangerClones", + foundAreaLevel = 68, + mainSkillId = "MirrorArrowMercenary", + lifeComparison = "AUTO", + skills = { { id = "MirrorArrowMercenary", enabled = true, includeInFullDPS = true, supports = { } } }, + } + build.mercenaryTab:Changed() + build.mercenaryTab:GetItemSet(true) + local configTab = build.configTab + local configSet = configTab.configSets[configTab.activeConfigSetId] + configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.input.usePowerCharges = true + configTab:BuildModList() + build.calcsTab:BuildOutput() + + local compareTab = build.compareTab + assert.is_true(compareTab:ImportBuild(assert(build:SaveDB("mercenary-config")), "Mercenary")) + local entry = assert(compareTab:GetActiveCompare()) + configSet.actors.mercenary.input.usePowerCharges = false + compareTab.configViewActor = "mercenary" + compareTab:RebuildConfigControls(entry) + local ctrl = assert(compareTab.configControls.usePowerCharges) + assert.is_false(ctrl.primaryControl.state) + assert.is_true(ctrl.compareControl.state) + + compareTab:CopyCompareConfig() + assert.is_true(configSet.actors.mercenary.input.usePowerCharges) + assert.is_not_true(configTab.input.usePowerCharges) + + configTab:SetViewActor("player") + compareTab.configViewActor = "mercenary" + compareTab:RebuildConfigControls(entry) + ctrl = assert(compareTab.configControls.usePowerCharges) + local captured + configTab.RunComparisonCalc = function(self, calcFunc, comparisonActor) + captured = comparisonActor + return calcFunc(comparisonActor and { comparisonActor = comparisonActor } or nil) + end + local tooltip = new("Tooltip"):Tooltip() + assert.has_no.errors(function() + ctrl.primaryControl.tooltipFunc(tooltip) + end) + configTab.RunComparisonCalc = nil + assert.are.equal("player", configTab:GetViewActor()) + assert.are.equal("MERCENARY", captured) + end) end) diff --git a/spec/System/TestConfigScope_spec.lua b/spec/System/TestConfigScope_spec.lua new file mode 100644 index 00000000000..6070871c57d --- /dev/null +++ b/spec/System/TestConfigScope_spec.lua @@ -0,0 +1,64 @@ +describe("ConfigScope source-owned enemy semantics", function() + local ConfigScope = require("Modules.ConfigScope") + local configOptions = LoadModule("Modules/ConfigOptions") + + local function reindex() + ConfigScope.index(configOptions) + end + + it("does not treat ByYou names as source-owned without explicit metadata", function() + assert.is_true(ConfigScope.isSourceOwnedEnemyVar("FrozenByYou")) + assert.is_false(ConfigScope.isSourceOwnedEnemyVar("InventedByYou")) + assert.is_false(ConfigScope.isSourceOwnedEnemyMod({ name = "Condition:InventedByYou" })) + assert.is_true(ConfigScope.isSourceOwnedEnemyMod({ name = "Condition:FrozenByYou" })) + assert.is_false(ConfigScope.isSourceOwnedEnemyMod({ name = "Condition:Chilled" })) + assert.is_true(ConfigScope.isSourceOwnedEnemyMod({ name = "Condition:Chilled", sourceOwned = true })) + end) + + it("requires explicit enemyState for ByYou option names", function() + local ok, err = pcall(ConfigScope.index, { + { section = "Skill Options", scope = "actor" }, + { var = "conditionEnemyInventedByYou", type = "check", ifEnemyCond = "InventedByYou" }, + }) + reindex() + assert.is_false(ok) + assert.matches("needs explicit enemyState", tostring(err)) + end) + + it("stamps sourceOwned on FrozenByYou tags from parse, including ModCache hits", function() + local mods = modLib.parseMod("Enemies permanently take 5% increased Damage for each second they've ever been Frozen by you, up to a maximum of 50%") + assert.is_table(mods) + local inner = mods[1] and mods[1].value and mods[1].value.mod + assert.is_table(inner) + local seen = { FrozenByYou = false, FrozenByYouSeconds = false } + for _, tag in ipairs(inner) do + if tag.var == "FrozenByYou" then + assert.is_true(tag.sourceOwned) + seen.FrozenByYou = true + elseif tag.var == "FrozenByYouSeconds" then + assert.is_true(tag.sourceOwned) + seen.FrozenByYouSeconds = true + end + end + assert.is_true(seen.FrozenByYou) + assert.is_true(seen.FrozenByYouSeconds) + end) + + it("does not copy source-option encounter facts onto the player overlay", function() + local shared = { name = "Condition:Chilled", skipEncounterOverlayCopy = true } + local encounter = { name = "Condition:Chilled" } + assert.is_false(ConfigScope.shouldCopyEncounterOntoPlayerOverlay(shared)) + assert.is_true(ConfigScope.shouldCopyEncounterOntoPlayerOverlay(encounter)) + local mods = { } + function mods:AddMod(mod) + table.insert(self, mod) + end + ConfigScope.addSourceEncounterFact(mods, "Chilled") + assert.are.equal(2, #mods) + assert.is_true(mods[1].skipEncounterOverlayCopy) + assert.is_not_true(mods[1].sourceOwned) + assert.is_true(mods[2].sourceOwned) + assert.is_false(ConfigScope.shouldCopyEncounterOntoPlayerOverlay(mods[1])) + assert.is_true(ConfigScope.isSourceOwnedEnemyMod(mods[2])) + end) +end) diff --git a/spec/System/TestGenericItemSets_spec.lua b/spec/System/TestGenericItemSets_spec.lua new file mode 100644 index 00000000000..c200467e6af --- /dev/null +++ b/spec/System/TestGenericItemSets_spec.lua @@ -0,0 +1,524 @@ +describe("Generic item sets for player, Animate Guardian, and Mercenary", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + local selectScionLuminary = MercenaryTest.selectScionLuminary + local MercenaryTools = require("Modules.MercenaryTools") + local calcs = require("Modules.CalcBase") + + local function findGuardianGem() + for _, socketGroup in ipairs(build.skillsTab.socketGroupList) do + for _, gem in ipairs(socketGroup.gemList) do + local name = gem.nameSpec or (gem.gemData and gem.gemData.name) or (gem.grantedEffect and gem.grantedEffect.name) + if name == "Animate Guardian" then + return gem + end + end + end + end + + local function findCanonicalGuardianItemSet() + local itemsTab = build.itemsTab + for _, itemSetId in ipairs(itemsTab.itemSetOrderList) do + local itemSet = itemsTab.itemSets[itemSetId] + if itemSet.title == "Animate Guardian" and itemSet.id ~= itemsTab.activeItemSetId then + return itemSet + end + end + end + + local function makeImportItem(typeLine, inventoryId, itemId) + return { + id = itemId or "guardian-helm-1", + frameType = 0, + name = "", + typeLine = typeLine, + inventoryId = inventoryId, + ilvl = 10, + properties = {}, + sockets = {}, + socketedItems = {}, + } + end + + before_each(function() + newBuild() + end) + + it("Items dropdown views a set without wearing it", function() + local itemsTab = build.itemsTab + local secondSet = itemsTab:NewItemSet() + secondSet.title = "Alternate" + table.insert(itemsTab.itemSetOrderList, secondSet.id) + local playerHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + local otherHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(playerHelmet, true) + itemsTab:AddItem(otherHelmet, true) + local playerSetId = itemsTab.activeItemSetId + itemsTab.activeItemSet.Helmet.selItemId = playerHelmet.id + secondSet.Helmet.selItemId = otherHelmet.id + itemsTab:PopulateSlots() + + itemsTab.controls.setSelect.selIndex = 2 + itemsTab.controls.setSelect.selFunc(2, secondSet.title) + assert.are.equal(playerSetId, itemsTab.activeItemSetId) + assert.are.equal(secondSet.id, itemsTab.viewItemSetId) + assert.are.equal(otherHelmet.id, itemsTab.slots.Helmet.selItemId) + + secondSet.title = "Inspected" + assert(itemsTab:SetViewItemSet(secondSet.id)) + itemsTab:Draw({ x = 0, y = 0, width = 1920, height = 1080 }, { }) + assert.are.equal(2, itemsTab.controls.setSelect.selIndex) + assert.are.equal(secondSet.id, itemsTab.viewItemSetId) + assert.are.equal(playerSetId, itemsTab.activeItemSetId) + + selectScionLuminary() + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + local shield = new("Item"):Item("Rarity: Normal\nGoathide Buckler") + itemsTab:AddItem(staff, true) + itemsTab:AddItem(shield, true) + mercSet["Weapon 1"].selItemId = staff.id + mercSet["Weapon 2"].selItemId = shield.id + assert(itemsTab:SetViewItemSet(mercSet.id)) + itemsTab:PopulateSlots() + assert.are.equal(staff.id, mercSet["Weapon 1"].selItemId) + assert.are.equal(shield.id, mercSet["Weapon 2"].selItemId) + local listed + for index, itemId in ipairs(itemsTab.slots["Weapon 2"].items) do + if itemId == shield.id then listed = itemsTab.slots["Weapon 2"].list[index] break end + end + assert.is_not_nil(listed) + assert.matches(colorCodes.NEGATIVE, listed, nil, true) + + newBuild() + itemsTab = build.itemsTab + local wand = new("Item"):Item("Rarity: Normal\nDriftwood Wand") + shield = new("Item"):Item("Rarity: Normal\nGoathide Buckler") + staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + itemsTab:AddItem(wand, true) + itemsTab:AddItem(shield, true) + itemsTab:AddItem(staff, true) + itemsTab.activeItemSet["Weapon 1"].selItemId = wand.id + itemsTab.activeItemSet["Weapon 2"].selItemId = shield.id + itemsTab:PopulateSlots() + itemsTab.slots["Weapon 1"]:SetSelItemId(staff.id, itemsTab:GetVisibleItemSet()) + itemsTab:PopulateSlots() + assert.are.equal(0, itemsTab.activeItemSet["Weapon 2"].selItemId) + assert.are.equal(0, itemsTab.slots["Weapon 2"].selItemId) + + newBuild() + itemsTab = build.itemsTab + build.skillsTab:PasteSocketGroup("Slot: Weapon 1\nHeavy Strike 20/0 1\n") + build.skillsTab:PasteSocketGroup("Slot: Weapon 1 Swap\nCleave 20/0 1\n") + build.mainSocketGroup = 1 + local inactiveSet = itemsTab:NewItemSet() + inactiveSet.title = "Inactive" + table.insert(itemsTab.itemSetOrderList, inactiveSet.id) + assert(itemsTab:SetViewItemSet(inactiveSet.id)) + itemsTab.controls.weaponSwap2.onClick() + assert.is_true(inactiveSet.useSecondWeaponSet) + assert.is_not_true(itemsTab.activeItemSet.useSecondWeaponSet) + assert.are.equal(1, build.mainSocketGroup) + + assert(itemsTab:SetViewItemSet(itemsTab.activeItemSetId)) + itemsTab.controls.weaponSwap2.onClick() + assert.is_true(itemsTab.activeItemSet.useSecondWeaponSet) + assert.are.equal(2, build.mainSocketGroup) + end) + + it("lets any actor wear any generic item set", function() + selectScionLuminary() + local itemsTab = build.itemsTab + local playerSet = itemsTab.activeItemSet + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local mercSet = build.mercenaryTab:GetItemSet(true) + assert.are_not.equal(playerSet.id, mercSet.id) + assert(build.itemsTab:SetActorItemSet("MERCENARY", playerSet.id)) + assert.are.equal(playerSet.id, itemsTab:GetActorItemSetId("MERCENARY")) + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + local gem = assert(findGuardianGem()) + gem.skillMinionItemSet = playerSet.id + gem.skillMinionItemSetCalcs = playerSet.id + + local helmet = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(helmet, true) + itemsTab.activeItemSet.Helmet.selItemId = helmet.id + local valid, reason = MercenaryTools.validateEquippedItem(helmet, "Helmet", { + profile = build.mercenaryTab.profile, + mercenaryData = build.mercenaryTab.data, + itemSet = itemsTab.activeItemSet, + playerItemSet = itemsTab.activeItemSet, + items = itemsTab.items, + playerHasFlag = function() return true end, + }) + assert.is_true(valid, reason) + + local function contains(list, wanted) + for _, itemSetId in ipairs(list) do + if itemSetId == wanted then return true end + end + return false + end + assert.is_true(contains(itemsTab.itemSetOrderList, playerSet.id)) + assert.is_true(contains(itemsTab.itemSetOrderList, mercSet.id)) + + local bossingSet = itemsTab:NewItemSet() + bossingSet.title = "Bossing" + table.insert(itemsTab.itemSetOrderList, bossingSet.id) + assert(build.itemsTab:SetActorItemSet("MERCENARY", bossingSet.id)) + assert.is_true(contains(itemsTab.itemSetOrderList, playerSet.id)) + assert.is_true(contains(itemsTab.itemSetOrderList, bossingSet.id)) + assert.is_true(contains(itemsTab.itemSetOrderList, mercSet.id)) + + local xml = { } + build.itemsTab:Save(xml) + for _, node in ipairs(xml) do + if node.elem == "ItemSet" then + assert.is_nil(node.attrib.owner) + end + end + end) + + it("imports Animate Guardian gear into the canonical AG set, not worn or custom gem refs", function() + local itemsTab = build.itemsTab + local guardianSet = itemsTab:NewItemSet() + guardianSet.title = "Animate Guardian" + table.insert(itemsTab.itemSetOrderList, guardianSet.id) + local oldHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(oldHelmet, true) + guardianSet.Helmet.selItemId = oldHelmet.id + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + runCallback("OnFrame") + local gem = assert(findGuardianGem()) + gem.skillMinionItemSet = guardianSet.id + gem.skillMinionItemSetCalcs = guardianSet.id + local setCountBefore = #itemsTab.itemSetOrderList + build.importTab:ImportItemsAndSkills({ + level = 12, + equipment = { makeImportItem("Driftwood Wand", "Weapon", "player-weapon-1") }, + guardian = { makeImportItem("Leather Cap", "Helm", "fresh-guardian-helm") }, + }, false, true, true) + assert.are.equal(setCountBefore, #itemsTab.itemSetOrderList) + assert.are.equal("fresh-guardian-helm", itemsTab.items[guardianSet.Helmet.selItemId].uniqueID) + + newBuild() + itemsTab = build.itemsTab + local playerHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(playerHelmet, true) + itemsTab.activeItemSet.Helmet.selItemId = playerHelmet.id + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + runCallback("OnFrame") + gem = assert(findGuardianGem()) + gem.skillMinionItemSet = itemsTab.activeItemSetId + gem.skillMinionItemSetCalcs = itemsTab.activeItemSetId + setCountBefore = #itemsTab.itemSetOrderList + build.importTab:ImportItemsAndSkills({ + level = 12, + equipment = { makeImportItem("Driftwood Wand", "Weapon", "player-weapon-1") }, + guardian = { makeImportItem("Leather Cap", "Helm", "fresh-guardian-helm") }, + }, false, false, true) + assert.are.equal(playerHelmet.id, itemsTab.activeItemSet.Helmet.selItemId) + gem = assert(findGuardianGem()) + assert.are.equal(itemsTab.activeItemSetId, gem.skillMinionItemSet) + local canonical = assert(findCanonicalGuardianItemSet()) + assert.are.equal("fresh-guardian-helm", itemsTab.items[canonical.Helmet.selItemId].uniqueID) + assert.is_true(#itemsTab.itemSetOrderList > setCountBefore) + + newBuild() + itemsTab = build.itemsTab + local bossSet = itemsTab:NewItemSet() + bossSet.title = "Boss AG" + table.insert(itemsTab.itemSetOrderList, bossSet.id) + local calcsSet = itemsTab:NewItemSet() + calcsSet.title = "Calcs AG" + table.insert(itemsTab.itemSetOrderList, calcsSet.id) + local bossHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + local calcsHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(bossHelmet, true) + itemsTab:AddItem(calcsHelmet, true) + bossSet.Helmet.selItemId = bossHelmet.id + calcsSet.Helmet.selItemId = calcsHelmet.id + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + runCallback("OnFrame") + gem = assert(findGuardianGem()) + gem.skillMinionItemSet = bossSet.id + gem.skillMinionItemSetCalcs = calcsSet.id + build.importTab:ImportItemsAndSkills({ + level = 12, + equipment = { makeImportItem("Driftwood Wand", "Weapon", "player-weapon-1") }, + guardian = { makeImportItem("Leather Cap", "Helm", "fresh-guardian-helm") }, + }, false, false, true) + gem = assert(findGuardianGem()) + assert.are.equal(bossSet.id, gem.skillMinionItemSet) + assert.are.equal(calcsSet.id, gem.skillMinionItemSetCalcs) + assert.are.equal(bossHelmet.id, bossSet.Helmet.selItemId) + assert.are.equal(calcsHelmet.id, calcsSet.Helmet.selItemId) + assert.are.equal("fresh-guardian-helm", itemsTab.items[findCanonicalGuardianItemSet().Helmet.selItemId].uniqueID) + end) + + it("character import returns the Items tab to player equipment", function() + selectScionLuminary() + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local itemsTab = build.itemsTab + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local mercHat = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(mercHat, true) + mercSet.Helmet.selItemId = mercHat.id + assert(itemsTab:SetViewItemSet(mercSet.id, "MERCENARY")) + assert.are.equal(mercSet.id, itemsTab.viewItemSetId) + build.importTab:ImportItemsAndSkills({ + level = 12, + equipment = { makeImportItem("Iron Hat", "Helm", "imported-helm") }, + }, false, false, true) + assert.are.equal(itemsTab.activeItemSetId, itemsTab.viewItemSetId) + assert.are.equal("PLAYER", itemsTab.viewComparisonActor) + assert.are.equal(mercSet.id, itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(mercHat.id, itemsTab:GetActorItemSet("MERCENARY").Helmet.selItemId) + assert.are.equal("Iron Hat", itemsTab.items[itemsTab.activeItemSet.Helmet.selItemId].name) + end) + + it("tooltips and equipped detection follow the visible actor except tree jewels stay player", function() + selectScionLuminary() + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local itemsTab = build.itemsTab + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local hoverHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(hoverHelmet, true) + assert(itemsTab:SetViewItemSet(mercSet.id)) + local calcsTab = build.calcsTab + local originalGetMiscCalculator = calcsTab.GetMiscCalculator + local captured + calcsTab.GetMiscCalculator = function(self) + local calcFunc, calcBase, actorOutputs = originalGetMiscCalculator(self) + return function(override, useFullDPS) + captured = override + return calcFunc(override, useFullDPS) + end, calcBase, actorOutputs + end + local ok, err = pcall(function() + itemsTab:AddItemTooltip(new("Tooltip"):Tooltip(), hoverHelmet) + assert.are.equal(mercSet.id, captured.itemSetId) + assert.are.equal("MERCENARY", captured.comparisonActor) + assert.are.equal("Helmet", captured.repSlotName) + end) + calcsTab.GetMiscCalculator = originalGetMiscCalculator + assert(ok, err) + + newBuild() + itemsTab = build.itemsTab + local spec = build.spec + local socketNode + for _, node in pairs(spec.nodes) do + if node.type == "Socket" then socketNode = node break end + end + socketNode = assert(socketNode) + socketNode.alloc = true + spec.allocNodes[socketNode.id] = socketNode + itemsTab:UpdateSockets() + local jewel = new("Item"):Item("Rarity: RARE\nPlain Spark\nCrimson Jewel\nImplicits: 0\n+100 to maximum Life\n") + itemsTab:AddItem(jewel, true) + itemsTab.sockets[socketNode.id]:SetSelItemId(jewel.id) + itemsTab:PopulateSlots() + local equippedSlot, equippedSet = itemsTab:GetEquippedSlotForItem(jewel) + assert.are.equal(itemsTab.sockets[socketNode.id], equippedSlot) + assert.is_nil(equippedSet) + assert.are.equal("Jewel "..socketNode.id, itemsTab:GetComparisonSlotNameForItem(jewel)) + + selectScionLuminary() + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + mercSet = assert(build.mercenaryTab:GetItemSet(true)) + assert(itemsTab:SetViewItemSet(mercSet.id)) + build.configTab:BuildModList() + build.buildFlag = true + runCallback("OnFrame") + local capturedActor, compared + local originalCompare = build.AddStatComparesToTooltip + build.AddStatComparesToTooltip = function(self, tooltip, baseOutput, compareOutput, header, nodeCount, actor) + compared = true + capturedActor = actor + return originalCompare(self, tooltip, baseOutput, compareOutput, header, nodeCount, actor) + end + ok, err = pcall(function() + itemsTab:AddItemTooltip(new("Tooltip"):Tooltip(), jewel, itemsTab.sockets[socketNode.id]) + end) + build.AddStatComparesToTooltip = originalCompare + assert(ok, err) + assert.is_true(compared) + assert.is_nil(capturedActor) + + newBuild() + itemsTab = build.itemsTab + local equipped = new("Item"):Item("Rarity: Normal\nIron Hat") + local other = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(equipped, true) + itemsTab:AddItem(other, true) + itemsTab.activeItemSet.Helmet.selItemId = equipped.id + local mapping = itemsTab:NewItemSet() + mapping.title = "Mapping" + table.insert(itemsTab.itemSetOrderList, mapping.id) + mapping.Helmet.selItemId = other.id + itemsTab:PopulateSlots() + local slot, set = itemsTab:GetEquippedSlotForItem(equipped) + assert.are.equal("Helmet", slot.slotName) + assert.is_nil(set) + local otherSlot, otherSet = itemsTab:GetEquippedSlotForItem(other) + assert.are.equal(mapping, otherSet) + assert.does_not_match("Used in", itemsTab.controls.itemList:GetRowValue(1, 1, equipped.id)) + assert.matches("Used in 'Mapping'", itemsTab.controls.itemList:GetRowValue(1, 1, other.id)) + end) + + it("does not substitute an unrelated viewed item set for Animate Guardian", function() + local itemsTab = build.itemsTab + local guardianSet = itemsTab:NewItemSet() + guardianSet.title = "Guardian" + table.insert(itemsTab.itemSetOrderList, guardianSet.id) + local unrelated = itemsTab:NewItemSet() + unrelated.title = "Unassigned" + table.insert(itemsTab.itemSetOrderList, unrelated.id) + local helm = new("Item"):Item("Rarity: Rare\nGuardian helm\nIron Hat\n+100 to maximum Life") + itemsTab:AddItem(helm, true) + guardianSet.Helmet.selItemId = helm.id + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + local gem = assert(findGuardianGem()) + gem.skillMinionItemSet = guardianSet.id + gem.skillMinionItemSetCalcs = guardianSet.id + build.buildFlag = true + runCallback("OnFrame") + local base = calcs.initEnv(build, "CALCULATOR") + calcs.perform(base) + itemsTab:SetViewItemSet(unrelated.id) + local preview = calcs.initEnv(build, "CALCULATOR", itemsTab:ItemCalculationOverride("Helmet", new("Item"):Item("Rarity: Normal\nLeather Cap"))) + calcs.perform(preview) + assert.are.equal(guardianSet.id, preview.player.mainSkill.minion.itemSet.id) + assert.are.equal(base.minion.output.Life, preview.minion.output.Life) + end) + + it("matches actual weapon replacement for Animate Guardian Full DPS", function() + local items = build.itemsTab + local set = items:NewItemSet() + table.insert(items.itemSetOrderList, set.id) + local sword = new("Item"):Item("Rarity: Normal\nRusted Sword") + local better = new("Item"):Item("Rarity: Rare\nReview Sword\nRusted Sword\nAdds 100 to 100 Physical Damage") + items:AddItem(sword, true) + items:AddItem(better, true) + set["Weapon 1"].selItemId = sword.id + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + local group = build.skillsTab.socketGroupList[1] + group.includeInFullDPS = true + local gem = assert(findGuardianGem()) + gem.skillMinionItemSet = set.id + gem.skillMinionItemSetCalcs = set.id + build.configTab:BuildModList() + local calc, base = calcs.getMiscCalculator(build) + items:SetViewItemSet(set.id) + local preview = calc(items:ItemCalculationOverride("Weapon 1", better)) + set["Weapon 1"].selItemId = better.id + local actual = calcs.calcFullDPS(build, "CALCULATOR", {}).combinedDPS + assert.are.near(actual, preview.FullDPS, 1e-8) + assert.is_true(preview.FullDPS > base.FullDPS) + end) + + it("edits and undoes actor item-set assignments without a discarded-state argument", function() + MercenaryTest.allocatePermanentHire() + local itemsTab = build.itemsTab + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local mercSet = itemsTab:EnsureActorItemSet("MERCENARY") + local helm = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(helm, true) + assert(itemsTab:SetViewItemSet(mercSet.id, "MERCENARY")) + itemsTab.slots.Helmet:SetSelItemId(helm.id) + itemsTab:AddUndoState() + assert.are.equal(helm.id, itemsTab:GetActorItemSet("MERCENARY").Helmet.selItemId) + assert.are.equal(0, itemsTab.activeItemSet.Helmet.selItemId) + local playerSetId = itemsTab.activeItemSetId + assert(itemsTab:SetActorItemSet("MERCENARY", playerSetId, false)) + itemsTab:AddUndoState() + itemsTab:Undo() + assert.are.equal(mercSet.id, itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(helm.id, itemsTab.itemSets[mercSet.id].Helmet.selItemId) + local seen + function itemsTab:RestoreUndoState(state, extra) + seen = extra + self.activeItemSetId = state.activeItemSetId + self.activeItemSet = self.itemSets[self.activeItemSetId] + end + itemsTab:ResetUndo() + itemsTab:AddUndoState() + itemsTab:Undo() + assert.is_nil(seen) + end) + + it("persists actor assignments, blocks deleting referenced sets, and assigns from the manager", function() + MercenaryTest.allocatePermanentHire() + local itemsTab = build.itemsTab + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local mercSet = itemsTab:EnsureActorItemSet("MERCENARY") + local helm = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(helm, true) + mercSet.Helmet.selItemId = helm.id + local extra = itemsTab:NewItemSet() + extra.title = "Merc Gear" + table.insert(itemsTab.itemSetOrderList, extra.id) + itemsTab.actorItemSetIds.ZED = extra.id + local xml = { elem = "Items" } + itemsTab:Save(xml) + local actors, found = { } + for _, node in ipairs(xml) do + if node.elem == "ActorItemSet" then + table.insert(actors, node.attrib.actor) + if node.attrib.actor == "MERCENARY" then found = tonumber(node.attrib.itemSetId) end + end + end + assert.are.same({ "MERCENARY", "ZED" }, actors) + assert.are.equal(mercSet.id, found) + local control = new("ItemSetListControl"):ItemSetListControl(nil, {0,0,350,200}, itemsTab) + assert.is_false(control:CanDeleteItemSet(mercSet.id)) + control.selValue = extra.id + control.controls.equipActor:SelByValue("MERCENARY", "id") + control.controls.equip.onClick() + assert.are.equal(extra.id, itemsTab:GetActorItemSetId("MERCENARY")) + newBuild() + build.itemsTab:Load(xml, "items.xml") + build.mercenaryTab:Load({ elem = "Mercenary", attrib = { } }) + build.mercenaryTab:PostLoad() + newBuild() + MercenaryTest.allocatePermanentHire() + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local migrated = build.itemsTab:NewItemSet() + table.insert(build.itemsTab.itemSetOrderList, migrated.id) + build.mercenaryTab:Load({ + elem = "Mercenary", + attrib = { activeMercenarySet = "1" }, + { elem = "MercenarySet", attrib = { id = "1", itemSetId = tostring(migrated.id), buildId = "MeleeAOEMarauderFireSlam" } }, + }) + build.mercenaryTab:PostLoad() + assert.are.equal(migrated.id, build.itemsTab:GetActorItemSetId("MERCENARY")) + end) + + it("routes comparison to the viewing actor and does not create a set when selecting a build", function() + MercenaryTest.allocatePermanentHire() + local itemsTab = build.itemsTab + build.mercenaryTab.profile.classId = "MeleeAOEMarauder" + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab.profile.mainSkillId = "TectonicSlamFireMercenary" + build.mercenaryTab.profile.skills = { { id = "TectonicSlamFireMercenary", enabled = true, supports = { } } } + build.mercenaryTab:Changed() + assert.is_nil(itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(1, #itemsTab.itemSetOrderList) + local mercSet = itemsTab:EnsureActorItemSet("MERCENARY") + assert(itemsTab:SetViewItemSet(mercSet.id, "MERCENARY")) + assert.is_false(itemsTab.controls.weaponSwap2:IsShown()) + assert.are.equal("MERCENARY", itemsTab:ComparisonActorForItemSet(mercSet.id)) + assert.are.equal("PLAYER", itemsTab:ComparisonActorForItemSet(itemsTab.activeItemSetId)) + assert.are.equal("MERCENARY", itemsTab:ComparisonActorForSlot("Mercenary Helmet", itemsTab.activeItemSetId)) + assert.are.equal("PLAYER", itemsTab:ComparisonActorForSlot("Jewel 12345", mercSet.id)) + end) +end) diff --git a/spec/System/TestImportReimport_spec.lua b/spec/System/TestImportReimport_spec.lua index 9ae82d037c0..c56186d5c39 100644 --- a/spec/System/TestImportReimport_spec.lua +++ b/spec/System/TestImportReimport_spec.lua @@ -253,4 +253,63 @@ Blight 20/0 1 table.insert(build.itemsTab.itemSetOrderList, itemSet.id) assertReimportPreservesSkillSubstate("Weapon 1", "Driftwood Wand", "Weapon", "Animate Weapon", "skillMinionItemSet", itemSet.id) end) + + it("preserves Mercenary equipment and skills when importing a character", function() + local itemsTab = build.itemsTab + local mercenaryHelmetSlotName = "Helmet" + build.mercenaryTab.profile.buildId = "MeleeAOEMarauderFireSlam" + build.mercenaryTab:Changed() + local mercenaryItemSet = build.mercenaryTab:GetItemSet(true) + itemsTab:SetViewItemSet(mercenaryItemSet.id) + local equippedMercenaryHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(equippedMercenaryHelmet, true) + itemsTab.slots[mercenaryHelmetSlotName]:SetSelItemId(equippedMercenaryHelmet.id, itemsTab:GetVisibleItemSet()) + + local sharedMercenaryHelmet = new("Item"):Item("Rarity: Normal\nCone Helmet") + itemsTab:AddItem(sharedMercenaryHelmet, true) + local secondItemSet = itemsTab:NewItemSet() + table.insert(itemsTab.itemSetOrderList, secondItemSet.id) + secondItemSet.Helmet.selItemId = sharedMercenaryHelmet.id + + local mercenarySkills = { { + id = "InfernalBlowMercenary", + enabled = true, + count = 2, + supports = { { id = "IncreasedAreaOfEffectHigh", tier = 3 } }, + } } + build.mercenaryTab.profile.skills = mercenarySkills + + build.importTab:ImportItemsAndSkills(buildImportPayload({ + makeImportItem("Iron Hat", "Helm", { }, "test-import-player-helmet"), + }), true, true, true) + local importedPlayerHelmetId + for itemId, item in pairs(itemsTab.items) do + if item.uniqueID == "test-import-player-helmet" then importedPlayerHelmetId = itemId break end + end + + assert.are.equal(equippedMercenaryHelmet.id, mercenaryItemSet[mercenaryHelmetSlotName].selItemId) + assert.are.equal(itemsTab.activeItemSetId, itemsTab.viewItemSetId) + assert.are.equal("PLAYER", itemsTab.viewComparisonActor) + assert.are.equal(importedPlayerHelmetId, itemsTab.slots[mercenaryHelmetSlotName].selItemId) + assert.are.equal(sharedMercenaryHelmet.id, secondItemSet.Helmet.selItemId) + assert.is_not_nil(itemsTab.items[equippedMercenaryHelmet.id]) + assert.is_not_nil(itemsTab.items[sharedMercenaryHelmet.id]) + assert.are.equal(importedPlayerHelmetId, itemsTab.activeItemSet.Helmet.selItemId) + assert.are_not.equal(equippedMercenaryHelmet.id, itemsTab.activeItemSet.Helmet.selItemId) + assert.same(mercenarySkills, build.mercenaryTab.profile.skills) + + newBuild() + itemsTab = build.itemsTab + mercenaryItemSet = build.mercenaryTab:GetItemSet(true) + build.itemsTab:SetActorItemSet("MERCENARY", nil, false) + local orphanHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(orphanHelmet, true) + mercenaryItemSet["Helmet"].selItemId = orphanHelmet.id + build.importTab:ImportItemsAndSkills(buildImportPayload({ + makeImportItem("Iron Hat", "Helm", { }, "test-import-player-helmet-before-mercenary-profile"), + }), true, true, true) + assert.is_not_nil(itemsTab.items[orphanHelmet.id]) + assert.are.equal(orphanHelmet.id, mercenaryItemSet["Helmet"].selItemId) + assert.is_nil(build.itemsTab:GetActorItemSetId("MERCENARY")) + end) end) diff --git a/spec/System/TestItemDBControl_spec.lua b/spec/System/TestItemDBControl_spec.lua index 98d4605c4a2..bcee4cdc934 100644 --- a/spec/System/TestItemDBControl_spec.lua +++ b/spec/System/TestItemDBControl_spec.lua @@ -29,7 +29,13 @@ describe("ItemDBControl", function() } local itemsTab = { activeItemSet = { useSecondWeaponSet = false }, - slots = { ["Body Armour"] = {} }, + activeItemSetId = 1, + actorItemSetIds = { }, + GetActorItemSetId = function(self, actor) + if actor == "PLAYER" then return self.activeItemSetId end + return self.actorItemSetIds[actor] + end, + slots = { ["Body Armour"] = { slotName = "Body Armour", IsShown = function() return true end } }, build = { calcsTab = { GetMiscCalculator = function() @@ -43,6 +49,11 @@ describe("ItemDBControl", function() return item ~= invalidItem end, } + itemsTab.GetVisibleItemSet = function() return itemsTab.activeItemSet end + itemsTab.ItemCalculationOverride = function(_, slotName, item) + return { repSlotName = slotName, repItem = item } + end + itemsTab.orderedSlots = { itemsTab.slots["Body Armour"] } local control = new("ItemDBControl"):ItemDBControl(nil, { 0, 0, 100, 100 }, itemsTab, { list = { invalidItem, betterItem, worseItem }, }, "RARE") diff --git a/spec/System/TestItemListControl_spec.lua b/spec/System/TestItemListControl_spec.lua index 2d690a6eb86..a8be3c0f3d8 100644 --- a/spec/System/TestItemListControl_spec.lua +++ b/spec/System/TestItemListControl_spec.lua @@ -52,6 +52,7 @@ describe("ItemListControl", function() PopulateSlots = function() end, AddUndoState = function() end, } + itemsTab.GetVisibleItemSet = function() return itemsTab.visibleItemSet or itemsTab.activeItemSet end local control = new("ItemListControl"):ItemListControl(nil, { 0, 0, 360, 308 }, itemsTab, true) return control, itemsTab, treeTab end @@ -76,6 +77,23 @@ describe("ItemListControl", function() assert.are.same({ 1, 3 }, control.list) end) + it("uses the visible item set for the current loadout", function() + local control, itemsTab = newItemListControl() + local visibleItemSet = { + id = 3, + title = "Visible", + ["Body Armour"] = { selItemId = 2 }, + } + itemsTab.visibleItemSet = visibleItemSet + itemsTab.build.treeTab.specList[1].jewels = { } + control:UpdateLoadoutList() + control.controls.loadoutFilter.selIndex = 2 + + control:UpdateList() + + assert.are.same({ 2 }, control.list) + end) + it("uses the selected item set and passive tree for named loadouts", function() local control = newItemListControl() control:UpdateLoadoutList() diff --git a/spec/System/TestItemParse_spec.lua b/spec/System/TestItemParse_spec.lua index 66bc1cdb394..dfb881af02b 100644 --- a/spec/System/TestItemParse_spec.lua +++ b/spec/System/TestItemParse_spec.lua @@ -4,6 +4,24 @@ describe("TestItemParse", function() return "Rarity: Rare\nName\n"..base.."\n"..s end + it("round-trips Socketed Gem occupancy", function() + local item = new("Item"):Item([[Rarity: UNIQUE +Malachai's Artifice +Unset Ring +Sockets: W +Socketed Gem: 1 Heavy Strike 20/0 +Implicits: 1 +Has 1 Socket +-20% to all Elemental Resistances ++100% to Fire Resistance when Socketed with a Red Gem +All Sockets are White]]) + assert.are.equal("Heavy Strike", item.socketedGems[1].nameSpec) + assert.are.equal(20, item.socketedGems[1].level) + item:BuildAndParseRaw() + assert.are.equal("Heavy Strike", item.socketedGems[1].nameSpec) + assert.matches("Socketed Gem: 1 Heavy Strike 20/0", item.raw) + end) + it("Rarity", function() local item = new("Item"):Item("Rarity: Normal\nCoral Ring") assert.are.equals("NORMAL", item.rarity) diff --git a/spec/System/TestItemTools_spec.lua b/spec/System/TestItemTools_spec.lua index 58b8aa818e9..afc10bed60a 100644 --- a/spec/System/TestItemTools_spec.lua +++ b/spec/System/TestItemTools_spec.lua @@ -75,6 +75,7 @@ Can be Anointed local overrides = { } local fakeItemsTab = setmetatable({ displayItem = item, + actorItemSetIds = { }, build = { spec = { allocNodes = { } }, calcsTab = { diff --git a/spec/System/TestMercenaryAPI_spec.lua b/spec/System/TestMercenaryAPI_spec.lua new file mode 100644 index 00000000000..e6382adb75e --- /dev/null +++ b/spec/System/TestMercenaryAPI_spec.lua @@ -0,0 +1,156 @@ +describe("Mercenary API requests", function() + local json = require("dkjson") + local originalDownload, originalAPI + before_each(function() + newBuild() + originalDownload = launch.DownloadPage + originalAPI = main.api + end) + after_each(function() + launch.DownloadPage = originalDownload + main.api = originalAPI + while main.popups[1] do main:ClosePopup() end + end) + + local function api(scopes) + local instance = new("PoEAPI"):PoEAPI("fixture-token", "fixture-refresh", os.time() + 3600, scopes or "account:characters account:league_accounts") + instance.UpdateMain = function() end + return instance + end + + it("encodes the documented PC, Xbox and Sony league paths", function() + local instance = api() + local paths = { } + instance.DownloadWithRateLimit = function(_, _, path, callback) paths[#paths + 1] = path callback({ }) end + for _, realm in ipairs({"pc", "xbox", "sony"}) do instance:DownloadLeagueAccount(realm, "Test / League", function() end) end + assert.same({"/league-account/Test%20%2F%20League", "/league-account/xbox/Test%20%2F%20League", "/league-account/sony/Test%20%2F%20League"}, paths) + end) + + it("requires the granted scope while retaining character access", function() + local instance = api("account:characters") + local errorText + instance:DownloadLeagueAccount("pc", "Test", function(_, err) errorText = err end) + assert.equals("Authorize Mercenary access", errorText) + assert.equals("fixture-token", instance.authToken) + instance.grantedScopes = nil + assert.is_false(instance:HasScope("account:league_accounts")) + end) + + it("refreshes expired tokens and preserves scopes omitted by the refresh response", function() + local instance = api() + instance.tokenExpiry = 0 + launch.DownloadPage = function(_, url, callback, params) + assert.matches("User%-Agent: OAuth pob/", params.header) + if url:match("oauth/token$") then callback({body = json.encode({access_token = "refreshed", refresh_token = "next", expires_in = 3600})}) + else callback({body = '{"league_account":{"mercenaries":[]}}', header = "HTTP/1.1 200 OK\r\n"}) end + end + local result + instance:DownloadLeagueAccount("pc", "Test", function(body) result = body end) + assert.is_table(result.league_account) + assert.is_true(instance:HasScope("account:league_accounts")) + assert.equals("refreshed", instance.authToken) + end) + + it("uses server policy names and Retry-After for 429 responses", function() + local instance, requests = api(), 0 + launch.DownloadPage = function(_, _, callback) + requests = requests + 1 + callback({body = '{}', header = "HTTP/1.1 429 Too Many Requests\r\nX-Rate-Limit-Policy: league-account-dynamic\r\nRetry-After: 30\r\n"}, "Response code: 429") + end + local retry + instance:DownloadLeagueAccount("pc", "Test", function(_, err, timeNext) assert.equals("Response code: 429", err) retry = timeNext end) + assert.is_true(retry >= os.time() + 29) + instance:DownloadLeagueAccount("pc", "Test", function(_, err) assert.equals("Response code: 429", err) end) + assert.equals(1, requests) + end) + + it("retries unauthorized responses once and stops after a second 401", function() + local instance, requests, refreshes = api(), 0, 0 + launch.DownloadPage = function(_, url, callback) + if url:match("oauth/token$") then + refreshes = refreshes + 1 + assert.is_true(refreshes <= 1) + callback({body = json.encode({access_token = "refreshed", refresh_token = "next", expires_in = 3600})}) + else requests = requests + 1 callback({header = "HTTP/1.1 401 Unauthorized\r\n"}, "Response code: 401") end + end + local err + instance:DownloadLeagueAccount("pc", "Test", function(_, errorText) err = errorText end) + assert.equals("Response code: 401", err) + assert.equals(2, requests) + assert.equals(1, refreshes) + end) + + it("does not restore a logged-out session from a late token refresh", function() + local instance = api() + instance.tokenExpiry = 0 + local pending + launch.DownloadPage = function(_, _, callback) pending = callback end + instance:DownloadLeagueAccount("pc", "Test", function() end) + instance:ResetDetails() + pending({body = json.encode({access_token = "late", refresh_token = "next", expires_in = 3600})}) + assert.is_nil(instance.authToken) + end) + + it("requests league-account scope and labels the action until access is granted", function() + local originalLaunch = _G.LaunchSubScript + local authUrl + _G.LaunchSubScript = function(_, _, _, url) + authUrl = url + return nil + end + api():FetchAuthToken(function() end) + _G.LaunchSubScript = originalLaunch + assert.matches("account:profile", authUrl) + assert.matches("account:characters", authUrl) + assert.matches("account:league_accounts", authUrl) + main.api = api("account:characters") + assert.equals("Authorize Mercenary access", build.importTab.controls.charImportMercenaries.label()) + main.api.grantedScopes = "account:characters account:league_accounts" + assert.equals("Mercenaries...", build.importTab.controls.charImportMercenaries.label()) + end) + + local function prepareImport() + local instance = api() + main.api = instance + local tab = build.importTab + tab.controls.charSelect:SetList({{label = "Selected Character", char = { league = "Actual League" }}}) + tab.controls.charSelect:SetSel(1) + local pending + instance.DownloadCharacter = function(_, realm, name, callback) + assert.equals("Selected Character", name) + pending = callback + end + return instance, tab, function(body, err, timeNext) pending(body, err, timeNext) end + end + + it("uses the fetched character league and active index in the new action", function() + local instance, tab, complete = prepareImport() + local captured + instance.DownloadProfile = function(_, callback) callback({uuid = "fixture-account"}) end + instance.DownloadLeagueAccount = function(_, realm, league, callback) + assert.equals("Actual League", league) + callback({league_account = {mercenaries = {{ name = "Hire" }}}}) + end + tab.OpenMercenaryImportPopup = function(_, account, source) captured = {account, source} end + tab.controls.charImportMercenaries.onClick() + complete({character = {league = "Actual League", active_mercenary_index = 2}}) + assert.equals(2, captured[1].active_mercenary_index) + assert.equals("fixture-account", captured[2].account) + assert.is_false(tab.oauthLoading) + end) + + for _, change in ipairs({"cancel", "realm", "character", "account", "build", "loadout"}) do + it("rejects late responses after changing "..change, function() + local instance, tab, complete = prepareImport() + instance.DownloadProfile = function() error("Stale response requested account data") end + tab:DownloadMercenaries() + if change == "cancel" then tab:CancelMercenaryImport() + elseif change == "realm" then tab.controls.accountRealm:SetSel(2) + elseif change == "character" then tab.controls.charSelect:SetList({{label = "Other Character"}}) + elseif change == "account" then instance:ResetDetails() + elseif change == "build" then newBuild() + else build.mercenaryTab.profile = {skills = { }} end + complete({character = {league = "Actual League"}}) + end) + end +end) diff --git a/spec/System/TestMercenaryCalculations_spec.lua b/spec/System/TestMercenaryCalculations_spec.lua new file mode 100644 index 00000000000..cb528395907 --- /dev/null +++ b/spec/System/TestMercenaryCalculations_spec.lua @@ -0,0 +1,3949 @@ +describe("Permanent Mercenary calculations", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + local allocate = MercenaryTest.allocate + local MercenaryTools = require("Modules.MercenaryTools") + local calcs = require("Modules.CalcBase") + local configOptions = LoadModule("Modules/ConfigOptions") + local configVisibility = LoadModule("Modules/ConfigVisibility") + local elementalEquilibriumMod = "Hits that deal Elemental Damage remove Exposure to those Elements and inflict Exposure to other Elements Exposure inflicted this way applies -25% to Resistances" + local function equipmentSlot(slotName) + return assert(build.mercenaryTab:GetItemSet(true))[slotName] + end + + local function configure(classId, buildId, skillId, fields) + fields = fields or { } + local profile = build.mercenaryTab.profile + profile.classId = classId + profile.buildId = buildId + profile.foundAreaLevel = fields.foundAreaLevel or 68 + profile.mainSkillId = skillId + profile.lifeComparison = fields.lifeComparison or "AUTO" + profile.skills = { { + id = skillId, + enabled = true, + includeInFullDPS = fields.includeInFullDPS == true, + count = fields.count or 1, + skillPart = fields.skillPart, + skillMinionSkill = fields.skillMinionSkill, + supports = fields.supports or { }, + } } + build.mercenaryTab:Changed() + if buildId then + build.mercenaryTab:GetItemSet(true) + end + end + + local function configureSkill(skillId, fields) + build.data.ensureMercenaries() + for buildId, mercBuild in pairs(build.data.mercenaries.builds) do + for _, id in ipairs(mercBuild.skillIds or { }) do + if id == skillId then + configure(mercBuild.classId, buildId, skillId, fields) + return + end + end + end + error("no Mercenary build exports "..skillId) + end + + local calculate = MercenaryTest.calculateBuild + local fresh = MercenaryTest.freshHire + + local function rallyingWeaponFlat(actor, stat) + local total = 0 + for _, value in ipairs(actor.modDB:Tabulate("BASE", { keywordFlags = KeywordFlag.Attack }, stat)) do + if value.mod.source == "Rallying Cry" then + total = total + value.value + end + end + return total + end + + local function mercMainHandCrit(env) + local output = env.mercenary.output + local hand = output.MainHand or output + return hand.PreEffectiveCritChance or output.PreEffectiveCritChance, hand.CritMultiplier or output.CritMultiplier + end + + local function namedDps(skills, name) + for _, row in ipairs(skills or { }) do + if row.name == name then return row.dps end + end + return 0 + end + + local function assertStaticMercenaryError(env, pattern) + assert.is_nil(env.mercenary) + assert.is_nil(env.mercenaryCalculationErrors) + local errors = build.mercenaryTab:GetErrors() + assert.matches(pattern, table.concat(errors, "\n")) + local seen = { } + for _, errorText in ipairs(errors) do + assert.is_nil(seen[errorText], errorText) + seen[errorText] = true + end + end + + local function decayItem(baseName, id) + local item = new("Item"):Item("Rarity: RARE\nDecay Test\n"..baseName.."\nImplicits: 0\nYour Hits inflict Decay, dealing 700 Chaos Damage per second for 8 seconds\n") + item.id = id + build.itemsTab.items[id] = item + return item + end + + local function setMercenaryFullDPS(skillIds) + local profile = build.mercenaryTab.profile + local skills = { } + for _, skillId in ipairs(skillIds) do + table.insert(skills, { id = skillId, enabled = true, includeInFullDPS = true, count = 1, supports = { } }) + end + profile.skills = skills + profile.mainSkillId = skillIds[1] + build.mercenaryTab:Changed() + end + + local function selectMinionSkill(skillId) + local group = build.skillsTab.socketGroupList[build.mainSocketGroup] + local activeSkill = group.displaySkillList[group.mainActiveSkill] + local found + for index, minionSkill in ipairs(activeSkill.minion.activeSkillList) do + if minionSkill.activeEffect.grantedEffect.id == skillId then + activeSkill.activeEffect.srcInstance.skillMinionSkill = index + activeSkill.activeEffect.srcInstance.skillMinionSkillCalcs = index + found = true + break + end + end + assert.is_true(found, skillId) + end + + local function addMercItem(slotName, raw, id) + local item = new("Item"):Item(raw) + item.id = id + build.itemsTab.items[id] = item + equipmentSlot(slotName).selItemId = id + return item + end + + local function mercActor() + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + return configSet, configSet.actors.mercenary.input + end + + local function shownFor(var, actor) + build.configTab:SetViewActor(actor) + return build.configTab.varControls[var].shown() + end + + before_each(fresh) + + it("does not pin recycled Mercenary databases after unhire", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local env = calculate() + assert.is_not_nil(env.mercenary) + build.mercenaryTab.profile.buildId = nil + build.mercenaryTab.profile.classId = nil + build.mercenaryTab:Changed() + env = calculate() + assert.is_nil(env.mercenary) + assert.is_nil(env.recycledMercenaryModDB) + assert.is_nil(env.recycledMercenaryItemModDB) + assert.is_nil(env.recycledMercenaryEnemySourceDB) + assert.is_nil(env.cachedMercenaryModDB) + assert.is_nil(env.player.enemySourceDB) + end) + + it("keeps Infamous Mercenary mods and support stat maps off player tables", function() + build.data.ensureMercenaries() + assert.is_not_nil(build.data.itemMods.Mercenary.MercenaryModTravelSkillCrit) + assert.is_nil(build.data.itemMods.Item.MercenaryModTravelSkillCrit) + assert.are_not.equal(build.data.skillStatMap, build.data.mercenarySupportStatMap) + local nested + for statId, playerMap in pairs(build.data.skillStatMap) do + local mercMap = build.data.mercenarySupportStatMap[statId] + if mercMap then + assert.are_not.equal(playerMap, mercMap, statId) + local playerMod, mercMod = playerMap[1], mercMap[1] + if playerMod and mercMod and type(playerMod.value) == "table" and playerMod.value.mod then + assert.are_not.equal(playerMod.value.mod, mercMod.value.mod, statId) + nested = true + break + end + end + end + assert.is_true(nested) + end) + + it("caches Mercenary skill output separately from the player", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local env = calculate() + assert.is_not_nil(env.mercenary) + local playerUUID = cacheSkillUUID(env.player.mainSkill, env) + local mercUUID = cacheSkillUUID(env.mercenary.mainSkill, env) + local playerCache = GlobalCache.cachedData.MAIN[playerUUID] + local mercCache = GlobalCache.cachedData.MAIN[mercUUID] + assert.are_not.equal(playerUUID, mercUUID) + assert.are_not.equal(playerCache, mercCache) + assert.are.equal(env.player.mainSkill, playerCache.ActiveSkill) + assert.are.equal(env.mercenary.mainSkill, mercCache.ActiveSkill) + assert.are.equal(env.mercenary.output.TotalDPS, mercCache.TotalDPS) + end) + + it("fails closed on invalid Mercenary loadouts", function() + local trap = { "TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary" } + local marauder = { "MeleeAOEMarauder", "MeleeAOEMarauderFireSlam" } + local function stubItem(fields) + local item = { + rarity = "RARE", requirements = { str = 1 }, grantedSkills = { }, modList = { }, + } + for key, value in pairs(fields) do item[key] = value end + build.itemsTab.items[item.id] = item + equipmentSlot(item.slot).selItemId = item.id + end + for _, case in ipairs({ + { err = "Enable at least one Mercenary skill", apply = function() + configure(trap[1], trap[2], trap[3]) + build.mercenaryTab.profile.skills[1].enabled = false + end }, + { err = "Select a Mercenary class and build", apply = function() + configure(trap[1], trap[2], trap[3]) + build.mercenaryTab.profile.buildId = "NotARealBuild" + end }, + { err = "cannot have more than 6", apply = function() + configure(marauder[1], marauder[2], "InfernalBlowMercenary") + local profile = build.mercenaryTab.profile + profile.skills = { } + for _, skillId in ipairs(build.data.mercenaries.builds.MeleeAOEMarauderFireSlam.skillIds) do + table.insert(profile.skills, { id = skillId, enabled = true, supports = { } }) + if #profile.skills == 7 then break end + end + profile.mainSkillId = profile.skills[1].id + end }, + { err = "Duplicate skill", apply = function() + configure(trap[1], trap[2], trap[3]) + table.insert(build.mercenaryTab.profile.skills, { id = trap[3], enabled = true, supports = { } }) + end }, + { err = "disabled", apply = function() + configure(trap[1], trap[2], trap[3]) + local profile = build.mercenaryTab.profile + profile.skills = { + { id = trap[3], enabled = false, supports = { } }, + { id = "ZealotryMercenary", enabled = true, supports = { } }, + } + profile.mainSkillId = trap[3] + end }, + { err = "Skill pool", apply = function() + configure(marauder[1], marauder[2], "FissureSlamMercenary") + table.insert(build.mercenaryTab.profile.skills, { id = "TectonicSlamFireMercenary", enabled = true, supports = { } }) + end }, + { err = "Duplicate support family", apply = function() + configure(trap[1], trap[2], trap[3], { + supports = { { id = "AddedLightningHigh", tier = 3 }, { id = "AddedLightningMid", tier = 2 } }, + }) + end }, + { err = "Selected Calcs skill is not configured", apply = function() + configure(trap[1], trap[2], trap[3]) + build.mercenaryTab.profile.mainSkillId = "ZealotryMercenary" + end }, + { err = "Body Armour", apply = function() + configure(marauder[1], marauder[2], "InfernalCryMercenary") + stubItem({ id = 9040, name = "Illegal Unique Body", type = "Body Armour", base = { type = "Body Armour" }, rarity = "UNIQUE", slot = "Body Armour" }) + end }, + { err = "Helmet", apply = function() + configure(marauder[1], marauder[2], "InfernalCryMercenary") + stubItem({ id = 9043, name = "Dex Helmet", type = "Helmet", base = { type = "Helmet" }, requirements = { dex = 1 }, slot = "Helmet" }) + end }, + { err = "Weapon 2", apply = function() + configure("EleBowRanger", "EleBowRangerFire", "BurningArrowMercenary") + addMercItem("Weapon 1", "Rarity: Normal\nCrude Bow", 9044) + end }, + { err = "Mercenary level must be an integer between 1 and 100", enemyLevel = 85, apply = function() + configure(trap[1], trap[2], trap[3], { foundAreaLevel = 101 }) + end }, + }) do + fresh() + case.apply() + assertStaticMercenaryError(calculate(case.enemyLevel), case.err) + end + + fresh() + local env = calculate() + assert.is_nil(env.mercenary) + assert.is_nil(env.mercenaryCalculationErrors) + configure(trap[1], trap[2], trap[3]) + assert.is_table(build.mercenaryTab:GetItemSet(false)) + assert.is_false(build.itemsTab:SetActorItemSet("MERCENARY", 99999, false)) + assert.is_table(build.mercenaryTab:GetItemSet(false)) + assert.is_true(build.itemsTab:SetActorItemSet("MERCENARY", nil, false)) + env = calculate() + assert.is_not_nil(env.mercenary) + assert.is_nil(env.mercenaryCalculationErrors) + + fresh() + configure("ChaosMinionWitch", "ChaosMinionWitchInstability", "SSMMercenaryRelic") + addMercItem("Weapon 1", "Rarity: Normal\nGlass Shank", 9052) + addMercItem("Weapon 2", "Rarity: Normal\nTwig Spirit Shield", 9053) + env = calculate(83) + assert.is_nil(env.mercenary) + assert.matches("Unholy Relic has no exported skills", table.concat(env.mercenaryCalculationErrors or { }, "\n")) + end) + + + it("hires only with Noble Blood on Luminary", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "ZealotryMercenary") + local hired = calculate() + assert.is_true(hired.player.modDB.conditions.AffectedByZealotry) + + local nobleBlood + for _, node in pairs(build.spec.allocNodes) do + if node.name == "Noble Blood" then nobleBlood = node break end + end + nobleBlood = assert(nobleBlood, "Noble Blood") + build.spec.allocNodes[nobleBlood.id] = nil + nobleBlood.alloc = false + local unhired = calculate() + assert.is_nil(unhired.mercenary) + assert.is_nil(unhired.player.enemySourceDB) + assert.is_not_true(unhired.player.modDB.conditions.AffectedByZealotry) + assert.matches("Noble Blood", table.concat(build.mercenaryTab:GetErrors(), "\n")) + assert.are.equal("TrapsMinesShadowLightning", build.mercenaryTab.profile.buildId) + assert.matches("Noble Blood", table.concat(build.controls.warnings.lines, "\n")) + assert.is_true(build.controls.modeMercenary:IsShown()) + + for classId, class in pairs(build.spec.tree.classes) do + if class.name == "Marauder" then build.spec:SelectClass(classId) break end + end + assert.is_nil(calculate().mercenary) + assert.matches("Scion's Luminary", table.concat(build.mercenaryTab:GetErrors(), "\n")) + assert.are.equal("TrapsMinesShadowLightning", build.mercenaryTab.profile.buildId) + assert.not_matches("Mercenary:", table.concat(build.controls.warnings.lines, "\n")) + assert.is_true(not build.controls.modeMercenary:IsShown()) + build.viewMode = "MERCENARY" + build.calcsTab.input.actor = "MERCENARY" + build:SyncMercenaryUi() + assert.are.equal("TREE", build.viewMode) + assert.are.equal("PLAYER", build.calcsTab.input.actor) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + assert.is_true(build.itemsTab:SetActorItemSet("MERCENARY", nil, false)) + build.calcsTab.input.actor = "MERCENARY" + local env = calculate() + assert.is_not_nil(env.mercenary) + assert.is_nil(env.mercenaryCalculationErrors) + assert.is_not_nil(build.calcsTab:GetDisplayActor(build.calcsTab.calcsEnv)) + + fresh() + -- does not warn an unused Scion Mercenary loadout until the tab is open + assert.is_true(build.controls.modeMercenary:IsShown()) + assert.is_nil(calculate().mercenary) + assert.not_matches("Mercenary:", table.concat(build.controls.warnings.lines, "\n")) + build.viewMode = "MERCENARY" + build:RefreshStatList() + assert.matches("Select a Mercenary class", table.concat(build.controls.warnings.lines, "\n")) + end) + + it("keeps independent loadouts and persists XML", function() + build.mercenaryTab:EnsureData() + build.mercenaryTab:Changed() + assert.are.equal(7, #build.mercenaryTab.controls.class.list) + assert.are.equal("Templar (Str / Int)", build.mercenaryTab.controls.class.list[1].label) + + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local firstId = build.mercenaryTab.activeMercenarySetId + local firstEnv = calculate() + assert.are.equal("LightningTrapMercenary", firstEnv.mercenary.mainSkill.activeEffect.grantedEffect.id) + + local second = build.mercenaryTab:NewMercenarySet() + table.insert(build.mercenaryTab.mercenarySetOrderList, second.id) + build.mercenaryTab:SetActiveMercenarySet(second.id) + build.mercenaryTab.profile.classId = "TrapsMinesShadow" + build.mercenaryTab.profile.buildId = "TrapsMinesShadowLightning" + build.mercenaryTab.profile.mainSkillId = "ZealotryMercenary" + build.mercenaryTab.profile.skills = { { id = "ZealotryMercenary", enabled = true, supports = { } } } + build.mercenaryTab:GetItemSet(true) + local secondEnv = calculate() + assert.are.equal("ZealotryMercenary", secondEnv.mercenary.mainSkill.activeEffect.grantedEffect.id) + + build.mercenaryTab:SetActiveMercenarySet(firstId) + local firstAgainEnv = calculate() + assert.are.equal("LightningTrapMercenary", firstAgainEnv.mercenary.mainSkill.activeEffect.grantedEffect.id) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { + includeInFullDPS = true, + count = 2, + skillPart = 1, + skillMinionSkill = 2, + supports = { { id = "AddedLightningHigh", tier = 3 } }, + }) + assert(build.mercenaryTab:GetItemSet(true)) + local function savedState() + local saved = { elem = "Mercenary", attrib = { } } + build.mercenaryTab:Save(saved) + return saved + end + local saved = savedState() + build.mercenaryTab:Reset() + build.mercenaryTab:Load(saved) + assert.are.same(saved, savedState()) + + build.calcsTab:Load({ { elem = "Input", attrib = { name = "showMinion", boolean = "true" } } }) + assert.are.equal("PLAYER_MINION", build.calcsTab.input.actor) + assert.is_true(build.calcsTab.input.legacyShowMinion) + env = calculate() + assert.is_nil(env.minion) + assert.are.equal(env.player, build.calcsTab:GetDisplayActor(env)) + local savedCalcs = { } + build.calcsTab:Save(savedCalcs) + build.calcsTab:ResetUndo() + build.calcsTab:SetCalculationActor("PLAYER_MINION") + build.calcsTab:AddUndoState() + assert.is_nil(build.calcsTab.input.legacyShowMinion) + build.calcsTab:Undo() + assert.is_true(build.calcsTab.input.legacyShowMinion) + assert.are.equal(env.player, build.calcsTab:GetDisplayActor(env)) + build.calcsTab:Load(savedCalcs) + assert.is_true(build.calcsTab.input.legacyShowMinion) + assert.are.equal("PLAYER_MINION", build.calcsTab.input.actor) + assert.are.equal(env.player, build.calcsTab:GetDisplayActor(env)) + build.calcsTab:SetCalculationActor("PLAYER_MINION") + assert.is_nil(build.calcsTab.input.legacyShowMinion) + assert.is_nil(build.calcsTab:GetDisplayActor(env)) + env = calculate() + assert.is_nil(env.minion) + assert.is_nil(build.calcsTab:GetDisplayActor(env)) + assert.is_truthy(build.calcsTab.calcsOutput.ActorUnavailableMessage) + end) + + it("calculates the selected actor and explicitly selected Full DPS", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { + includeInFullDPS = true, + count = 2, + skillPart = 1, + supports = { { id = "AddedLightningHigh", tier = 3 } }, + }) + local env = calculate() + assert.is_table(env.mercenary) + assert.are.equal("Mercenary", env.mercenary.type) + assert.are.equal(68, env.mercenary.level) + assert.are.equal(2160, env.mercenary.output.Life) + assert.is_true(env.mercenary.output.CombinedDPS > 0) + assert.are.equal(1, env.mercenary.output.TrapThrowCount) + assert.are.equal(-90, env.mercenary.modDB:Sum("INC", nil, "DamageTaken")) + assert.are.near(0.2, env.mercenary.modDB:More({ flags = ModFlag.Dot }, "DamageTaken"), 10 ^ -9) + -- The permanent-hire Damage penalty belongs to the constructed Mercenary + -- actor, not to the Noble Blood node that allows hiring one. + local penalty = MercenaryTools.permanentDamageMore(env.mercenary.level, build.data.mercenaries.permanentMercenaryDamageMore) + assert.are.near(1 + penalty / 100, env.mercenary.modDB:More(nil, "Damage"), 10 ^ -9) + assert.are.near(env.mercenary.output.CombinedDPS * 2, env.mercenary.output.FullDPS, 10 ^ -6) + assert.are.near(env.mercenary.output.FullDPS, build.calcsTab.mainOutput.FullDPS, 10 ^ -6) + assert.is_table(env.mercenary.output.SkillDPS) + assert.is_number(env.mercenary.output.FullDotDPS) + assert.is_true(#env.mercenary.output.SkillDPS > 0) + assert.is_nil(env.minion) + local fullDPSWithoutPlayerAura = env.mercenary.output.FullDPS + build.skillsTab:PasteSocketGroup("Zealotry 20/0 1") + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.AffectedByZealotry) + assert.is_true(env.mercenary.output.FullDPS > fullDPSWithoutPlayerAura) + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + env = calculate() + assert.is_true(build.calcsTab.mainOutput.FullDPS > env.mercenary.output.FullDPS) + + build.calcsTab.input.actor = "MERCENARY" + build.buildFlag = true + runCallback("OnFrame") + assert.are.near(env.mercenary.output.CombinedDPS, build.calcsTab.calcsOutput.CombinedDPS, 10 ^ -6) + build.calcsTab.input.actor = "MERCENARY_MINION" + build.buildFlag = true + runCallback("OnFrame") + assert.matches("unavailable", build.calcsTab.calcsOutput.ActorUnavailableMessage) + end) + + it("scales found-area level, gem levels, and exclusive extracted skills", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { foundAreaLevel = 40 }) + assert.are.equal(40, calculate(30).mercenary.level) + assert.are.equal(60, calculate(60).mercenary.level) + build.mercenaryTab.profile.foundAreaLevel = 68 + assert.are.equal(68, calculate(68).mercenary.level) + build.mercenaryTab.profile.foundAreaLevel = 80 + assert.are.equal(80, calculate(90).mercenary.level) + + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { foundAreaLevel = 100 }) + local env = calculate(85) + assert.are.equal(100, env.mercenary.level) + assert.is_number(env.mercenary.averageDamage) + assert.is_true(env.mercenary.averageDamage > 0) + + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { foundAreaLevel = 82 }) + local level82Skill = assert(calculate(90).mercenary.mainSkill) + assert.are.equal(26, level82Skill.activeEffect.level) + assert.is_true(level82Skill.skillFlags.trap) + assert.is_nil(level82Skill.skillFlags.selfCast) + assert.are.equal(1260, level82Skill.skillData.LightningMin) + assert.are.equal(3780, level82Skill.skillData.LightningMax) + + build.mercenaryTab.profile.foundAreaLevel = 83 + local level83Skill = assert(calculate(90).mercenary.mainSkill) + assert.are.equal(26, level83Skill.activeEffect.level) + assert.are.equal(1329, level83Skill.skillData.LightningMin) + assert.are.equal(3986, level83Skill.skillData.LightningMax) + + build.mercenaryTab.profile.foundAreaLevel = 84 + assert.are.equal(27, assert(calculate(90).mercenary.mainSkill).activeEffect.level) + + configure("Crit1HShadow", "Crit1HShadowPhysSpell", "DonutCircleMercenary", { foundAreaLevel = 83, skillPart = 1 }) + local outer = calculate(83).mercenary + assert.is_true(outer.mainSkill.skillFlags.hit) + assert.is_true(outer.mainSkill.skillFlags.area) + assert.are.equal(3167, outer.mainSkill.skillData.PhysicalMin) + assert.are.equal(3500, outer.mainSkill.skillData.PhysicalMax) + local outerDamageMore = outer.mainSkill.skillModList:More(outer.mainSkill.skillCfg, "Damage") + build.mercenaryTab.profile.skills[1].skillPart = 2 + local centre = calculate(83).mercenary + assert.are.equal("Centre", centre.mainSkill.skillPartName) + assert.are.near(outerDamageMore * 1.5, centre.mainSkill.skillModList:More(centre.mainSkill.skillCfg, "Damage"), 10 ^ -9) + + configure("PhysConvertTemplar", "PhysConvertTemplarFire", "HolyFireMortarMercenary", { foundAreaLevel = 83, skillPart = 1 }) + local first = calculate(83).mercenary + local firstHitDamageMore = first.mainSkill.skillModList:More(first.mainSkill.skillCfg, "Damage") + build.mercenaryTab.profile.skills[1].skillPart = 2 + local secondHit = calculate(83).mercenary + assert.are.equal("Second Hit", secondHit.mainSkill.skillPartName) + assert.are.near(firstHitDamageMore * 0.4, secondHit.mainSkill.skillModList:More(secondHit.mainSkill.skillCfg, "Damage"), 10 ^ -9) + + configure("MeleeAOEMarauder", "MeleeAOEMarauderNonSlam", "WindSlashMercenary", { foundAreaLevel = 83 }) + local baseline = calculate(83).mercenary + local baseDamage = baseline.modDB:Sum("INC", nil, "Damage") + local baseSpeed = baseline.modDB:Sum("INC", nil, "Speed") + local baseMovementSpeed = baseline.modDB:Sum("INC", nil, "MovementSpeed") + table.insert(build.mercenaryTab.profile.skills, { id = "EnrageMercenary", enabled = true, count = 1, supports = { } }) + local enraged = calculate(83).mercenary + assert.is_true(enraged.modDB.conditions.AffectedByEnrage) + assert.are.equal(baseDamage + 35, enraged.modDB:Sum("INC", nil, "Damage")) + assert.are.equal(baseSpeed + 40, enraged.modDB:Sum("INC", nil, "Speed")) + assert.are.equal(baseMovementSpeed + 60, enraged.modDB:Sum("INC", nil, "MovementSpeed")) + + configure("Crit1HShadow", "Crit1HShadowPhysSpell", "TemporalAnomalyMercenary", { foundAreaLevel = 83 }) + assert.are.equal(-25, calculate(83).enemy.modDB:Sum("INC", nil, "ActionSpeed")) + + configure("MeleeAOEMarauder", "MeleeAOEMarauderPhysSlam", "VaalVitalityMercenary", { foundAreaLevel = 83 }) + local vitality = calculate(83) + assert.are.equal(26, vitality.mercenary.mainSkill.activeEffect.level) + assert.is_true(vitality.player.modDB.conditions.AffectedByVaalVitality) + assert.are.near(580 / 60, vitality.player.modDB:Sum("BASE", nil, "LifeRegenPercent"), 10 ^ -9) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarSmite", "SSMHolySpectresMercenary", { + foundAreaLevel = 83, + includeInFullDPS = true, + count = 4, + skillMinionSkill = 2, + }) + local mace = new("Item"):Item("Rarity: Normal\nDriftwood Club") + local shield = new("Item"):Item("Rarity: Normal\nTwig Spirit Shield") + mace.id, shield.id = 9050, 9051 + build.itemsTab.items[mace.id], build.itemsTab.items[shield.id] = mace, shield + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = mace.id, shield.id + env = calculate(83) + local summon = env.mercenary.mainSkill + local fireball = env.mercenaryMinion.mainSkill + assert.are.equal(83, env.mercenaryMinion.level) + assert.are.equal("HolyFireElementalFireball", fireball.activeEffect.grantedEffect.id) + assert.are.equal(2, fireball.activeEffect.level) + assert.are.equal(1654, fireball.skillData.FireMin) + assert.are.equal(2561, fireball.skillData.FireMax) + assert.are.equal(2, summon.activeEffect.srcInstance.skillMinionSkill) + assert.is_true(env.mercenaryMinion.output.TotalDPS > 0) + assert.are.near(env.mercenaryMinion.output.TotalDPS * 4 + env.mercenary.output.FullDotDPS, env.mercenary.output.FullDPS, 10 ^ -6) + + equipmentSlot("Weapon 1").selItemId = 0 + equipmentSlot("Weapon 2").selItemId = 0 + configure("ChaosMinionWitch", "ChaosMinionWitchChaosHit", "SSMMercenarySoulrendOrb", { + foundAreaLevel = 83, + skillMinionSkill = 2, + }) + env = calculate(83) + assert.are.equal("GSRitualChaosPulse", env.mercenaryMinion.mainSkill.activeEffect.grantedEffect.id) + assert.is_true(env.mercenaryMinion.modDB:Flag(nil, "Condition:CannotBeDamaged")) + assert.is_true(env.mercenaryMinion.modDB:Flag(nil, "AlliesAurasCannotAffectSelf")) + end) + + it("calculates Mercenary Blight maximum sustainable stacks from the Mercenary skill cache", function() + configureSkill("BlightMercenary", { skillPart = 2 }) + local blight = calculate(83) + assert.is_table(blight.mercenary, table.concat(blight.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal(2, blight.mercenary.mainSkill.skillPart) + assert.are.equal("Maximum Sustainable Stacks", blight.mercenary.mainSkill.skillPartName) + assert.is_true(blight.mercenary.mainSkill.skillModList:Sum("BASE", blight.mercenary.mainSkill.skillCfg, "Multiplier:BlightMaxStages") > 0) + + build.skillsTab:PasteSocketGroup("Blight 20/0 1") + build.skillsTab.socketGroupList[1].gemList[1].skillPart = 2 + local blightWithPlayer = calculate(83) + assert.is_table(blightWithPlayer.mercenary, table.concat(blightWithPlayer.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(blightWithPlayer.mercenary.mainSkill.skillModList:Sum("BASE", blightWithPlayer.mercenary.mainSkill.skillCfg, "Multiplier:BlightMaxStages") > 0) + assert.is_true(blightWithPlayer.player.mainSkill.skillModList:Sum("BASE", blightWithPlayer.player.mainSkill.skillCfg, "Multiplier:BlightMaxStages") > 0) + + fresh() + -- errors when a mercenary skill cache UUID has no grantedEffect id + local ok, err = pcall(cacheSkillUUID, { + actor = { isMercenary = true }, + activeEffect = { grantedEffect = { name = "Blight" } }, + }, { build = { skillsTab = { socketGroupList = { } } } }) + assert.is_false(ok) + assert.matches("grantedEffect.id", tostring(err)) + end) + + it("applies permanent bases, taper, charges, and small passives", function() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + local env = calculate(83) + local mercenary = assert(env.mercenary) + assert.are.equal(build.data.monsterConstants["base_critical_strike_multiplier"] - 100, mercenary.modDB:Sum("BASE", nil, "CritMultiplier")) + assert.are.equal(build.data.monsterConstants["critical_ailment_dot_multiplier_+"], mercenary.modDB:Sum("BASE", { skillCond = { CriticalStrike = true } }, "DotMultiplier")) + assert.are.near(298.29000854492, mercenary.averageDamage, 10 ^ -9) + assert.are.equal(3320, mercenary.output.Life) + assert.are.near(713.8, mercenary.output.LifeRegen, 10 ^ -9) + assert.are.equal(150, mercenary.modDB:Sum("INC", nil, "Life")) + assert.are.equal(100, mercenary.modDB:Sum("INC", nil, "Armour")) + assert.are.equal(295, mercenary.modDB:Sum("INC", nil, "Damage")) + assert.are.equal(208, mercenary.modDB:Sum("BASE", nil, "Str")) + assert.are.equal(21, mercenary.modDB:Sum("BASE", nil, "Dex")) + assert.are.equal(21, mercenary.modDB:Sum("BASE", nil, "Int")) + local penalty = MercenaryTools.permanentDamageMore(mercenary.level, build.data.mercenaries.permanentMercenaryDamageMore) + assert.are.near(1 + penalty / 100, mercenary.modDB:More(nil, "Damage"), 10 ^ -9) + + local function sourceMore(modDB) + for _, value in ipairs(modDB:Tabulate("MORE", nil, "Damage")) do + if value.mod.source == "Permanent Mercenary" then + return value.mod.value + end + end + return 0 + end + local expected = { [44] = 0, [45] = 0, [46] = -1, [82] = -29, [83] = -30 } + for _, level in ipairs({ 44, 45, 46, 82, 83 }) do + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { + foundAreaLevel = level, + }) + env = calculate(level) + assert.are.equal(level, env.mercenary.level) + assert.are.equal(expected[level], sourceMore(env.mercenary.modDB), "skill penalty at "..level) + assert.is_true(env.mercenary.output.CombinedDPS > 0) + end + for _, level in ipairs({ 44, 45, 46, 82, 83 }) do + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary", { + foundAreaLevel = level, + }) + env = calculate(level) + assert.is_table(env.mercenaryMinion) + assert.are.equal(expected[level], sourceMore(env.mercenaryMinion.modDB), "minion penalty at "..level) + assert.is_true(env.mercenaryMinion.output.TotalDPS > 0) + end + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + env = calculate() + local modDB = env.mercenary.modDB + local cfg = env.mercenary.mainSkill.skillCfg + local constants = build.data.characterConstants + local function chargeMod(modType, name, multiplier) + local charges = modDB.multipliers[multiplier] or 0 + modDB.multipliers[multiplier] = charges + 1 + for _, value in ipairs(modDB:Tabulate(modType, cfg, name)) do + for _, tag in ipairs(value.mod) do + if tag.type == "Multiplier" and tag.var == multiplier then + local oneMoreCharge = modDB:EvalMod(value.mod, cfg) + modDB.multipliers[multiplier] = charges + 2 + local delta = modDB:EvalMod(value.mod, cfg) - oneMoreCharge + modDB.multipliers[multiplier] = charges + return delta + end + end + end + modDB.multipliers[multiplier] = charges + error("Missing "..multiplier.." bonus for "..name) + end + + assert.are.near(constants["critical_strike_chance_+%_per_power_charge"], chargeMod("INC", "CritChance", "PowerCharge"), 10 ^ -9) + assert.are.near(constants["object_inherent_damage_+%_final_per_frenzy_charge"], chargeMod("MORE", "Damage", "FrenzyCharge"), 10 ^ -9) + assert.are.near(constants["physical_damage_reduction_%_per_endurance_charge"], chargeMod("BASE", "PhysicalDamageReduction", "EnduranceCharge"), 10 ^ -9) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + local baseline = calculate() + local mercenaryLife = baseline.mercenary.modDB:Sum("INC", nil, "Life") + local minionLife = baseline.mercenaryMinion.modDB:Sum("INC", nil, "Life") + local function hasDamageSmallPassive(modDB) + for _, value in ipairs(modDB:Tabulate("INC", nil, "Damage")) do + if value.mod.value == 15 then return true end + end + return false + end + assert.is_true(hasDamageSmallPassive(baseline.mercenary.modDB)) + assert.is_true(hasDamageSmallPassive(baseline.mercenaryMinion.modDB)) + + allocate("Mercenary Life, Light Radius") + env = calculate() + assert.are.equal(mercenaryLife + 15, env.mercenary.modDB:Sum("INC", nil, "Life")) + assert.are.equal(minionLife + 15, env.mercenaryMinion.modDB:Sum("INC", nil, "Life")) + end) + + it("applies and shows actor-local Configuration", function() + local function configOption(var) + for _, varData in ipairs(configOptions) do + if varData.var == var then return varData end + end + end + local function mercHelmet(id, name, condType, condVar) + local mod = { + name = "Damage", type = "INC", value = 20, source = name, flags = 0, keywordFlags = 0, + { type = condType, var = condVar }, + } + build.itemsTab.items[id] = { + id = id, name = name, type = "Helmet", base = { type = "Helmet" }, rarity = "RARE", + requirements = { str = 1 }, grantedSkills = { }, modList = { mod }, + } + equipmentSlot("Helmet").selItemId = id + return mod + end + + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + local focusedDamage = mercHelmet(9036, "Mercenary Config Test", "Condition", "Focused") + local env = calculate() + local baseDamage = env.mercenary.modDB:Sum("INC", nil, "Damage") + local focusedConditionSource + for _, mod in ipairs(env.conditionsUsed.Focused or { }) do + if mod.source == focusedDamage.source then focusedConditionSource = mod.source end + end + assert.are.equal(focusedDamage.source, focusedConditionSource) + assert.is_false(shownFor("conditionFocused", "player")) + assert.is_false(shownFor("detonateDeadCorpseLife", "player")) + assert.is_true(shownFor("conditionFocused", "mercenary")) + assert.is_true(shownFor("detonateDeadCorpseLife", "mercenary")) + assert.is_false(configVisibility.isRelevantForBuild(assert(configOption("detonateDeadCorpseLife")), build, "player")) + assert.is_true(configVisibility.isRelevantForBuild(configOption("detonateDeadCorpseLife"), build, "mercenary")) + local _, input = mercActor() + input.conditionFocused = true + input.detonateDeadCorpseLife = 12345 + env = calculate() + assert.is_true(env.mercenary.modDB:GetCondition("Focused")) + assert.are.equal(baseDamage + focusedDamage.value, env.mercenary.modDB:Sum("INC", nil, "Damage")) + assert.are.equal(12345, env.mercenary.mainSkill.skillData.corpseLife) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + mercHelmet(9051, "Mercenary Stationary Test", "ActorCondition", "Stationary") + calculate() + assert.is_false(shownFor("conditionStationary", "player")) + assert.is_true(shownFor("conditionStationary", "mercenary")) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + mercHelmet(9050, "Mercenary Leech Test", "Condition", "Leeching") + local configSet = select(1, mercActor()) + configSet.input.conditionLeechingLife = true + calculate() + local leechingLifeConfig, leechingConfig = configOption("conditionLeechingLife"), configOption("conditionLeeching") + assert.is_false(configVisibility.isRelevantForBuild(assert(leechingLifeConfig), build, "player")) + assert.is_false(configVisibility.isRelevantForBuild(assert(leechingConfig), build, "player")) + assert.is_true(configVisibility.isRelevantForBuild(leechingConfig, build, "mercenary")) + configSet.actors.mercenary.input.conditionLeechingLife = true + assert.is_false(configVisibility.isRelevantForBuild(leechingLifeConfig, build, "player")) + assert.is_true(configVisibility.isRelevantForBuild(leechingLifeConfig, build, "mercenary")) + assert.is_true(shownFor("conditionLeechingLife", "player")) + local label = build.configTab.varControls.conditionLeechingLife.label + if type(label) == "function" then label = label() end + assert.matches("%^xDD0022", assert(label)) + + fresh() + configureSkill("VigilantStrikeMercenary") + addMercItem("Weapon 1", "Rarity: Normal\nDriftwood Club", 9041) + configSet = select(1, mercActor()) + local bypassed = assert(calculate().mercenary) + configSet.actors.mercenary.input.VigilantStrikeBypassCD = false + local onCooldown = assert(calculate().mercenary) + assert.is_true(bypassed.output.Speed > onCooldown.output.Speed) + assert.is_true(shownFor("VigilantStrikeBypassCD", "mercenary")) + assert.is_false(shownFor("VigilantStrikeBypassCD", "player")) + + fresh() + configureSkill("ToxicRainMercenary") + addMercItem("Weapon 1", "Rarity: Normal\nCrude Bow", 9042) + addMercItem("Weapon 2", "Rarity: Normal\nSerrated Arrow Quiver", 9043) + local baseline = assert(calculate().mercenary) + configSet = select(1, mercActor()) + configSet.actors.mercenary.input.toxicRainPodOverlap = 5 + local overlapped = assert(calculate().mercenary) + assert.are.equal(5, overlapped.mainSkill.skillData.podOverlapMultiplier) + assert.is_true(overlapped.output.CombinedDPS > baseline.output.CombinedDPS) + assert.is_true(shownFor("toxicRainPodOverlap", "mercenary")) + + fresh() + configureSkill("KineticBlastAltMercenary") + addMercItem("Weapon 1", "Rarity: Normal\nDriftwood Wand", 9060) + addMercItem("Weapon 2", "Rarity: Normal\nTwig Spirit Shield", 9061) + local profile = build.mercenaryTab.profile + table.insert(profile.skills, { id = "FlameWallMercenary", enabled = true, count = 1, supports = { } }) + build.mercenaryTab:Changed() + baseline = assert(calculate().mercenary) + configSet = select(1, mercActor()) + configSet.actors.mercenary.input.flameWallAddedDamage = true + local flamed = assert(calculate()) + local fireCfg = { flags = ModFlag.Projectile } + assert.is_true(flamed.mercenary.modDB:GetCondition("FlameWallAddedDamage")) + assert.is_true(flamed.mercenary.modDB:Sum("BASE", fireCfg, "FireMin") > baseline.modDB:Sum("BASE", fireCfg, "FireMin")) + assert.is_true(flamed.mercenary.output.CombinedDPS > baseline.output.CombinedDPS) + assert.is_true(shownFor("flameWallAddedDamage", "mercenary")) + + fresh() + configure("EleBowRanger", "EleBowRangerFire", "BurningArrowMercenary") + addMercItem("Weapon 1", "Rarity: Normal\nCrude Bow", 9038) + addMercItem("Weapon 2", "Rarity: Normal\nSerrated Arrow Quiver", 9039) + + baseline = assert(calculate().mercenary.output) + configSet = select(1, mercActor()) + configSet.actors.mercenary.input.buffOnslaught = true + local configured = assert(calculate().mercenary) + + assert.is_true(configured.modDB:GetCondition("Onslaught")) + assert.is_true(configured.output.Speed > baseline.Speed) + assert.is_true(configured.output.CombinedDPS > baseline.CombinedDPS) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { foundAreaLevel = 68 }) + local forbiddenFlask = new("Item"):Item("Rarity: Normal\nSmall Life Flask") + forbiddenFlask.id = 9020 + build.itemsTab.items[forbiddenFlask.id] = forbiddenFlask + build.itemsTab.activeItemSet["Flask 1"].selItemId = forbiddenFlask.id + assert.is_table(calculate(83).mercenary) + assert.not_matches("Flask 1", table.concat(build.mercenaryTab:GetErrors(), "\n")) + build.itemsTab.activeItemSet["Flask 1"].selItemId = 0 + + build.characterLevel = 48 + assert.is_table(calculate(83).mercenary) + assert.matches("20 below", table.concat(build.mercenaryTab:GetErrors(), "\n")) + build.characterLevel = 49 + assert.is_table(calculate(83).mercenary) + build.characterLevel = 90 + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + build.skillsTab:PasteSocketGroup("Summon Raging Spirit 20/0 1") + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + local fullLifeMod = "Minions have 100% chance to deal double damage while they are on full life" + configSet.customModsList[1].text = fullLifeMod + configSet.actors.mercenary.customModsList[1].text = fullLifeMod + configSet.actors.mercenary.input.minionsConditionFullLife = true + env = calculate() + assert.is_table(env.mercenaryMinion) + assert.is_table(env.minion) + assert.is_true(env.mercenaryMinion.modDB:Flag(nil, "Condition:FullLife")) + assert.is_not_true(env.minion.modDB:Flag(nil, "Condition:FullLife")) + assert.are.equal(100, env.mercenaryMinion.modDB:Sum("BASE", nil, "DoubleDamageChance")) + assert.are.equal(0, env.minion.modDB:Sum("BASE", nil, "DoubleDamageChance")) + + configSet.actors.mercenary.input.minionsConditionFullLife = nil + configSet.input.minionsConditionFullLife = true + env = calculate() + assert.is_not_true(env.mercenaryMinion.modDB:Flag(nil, "Condition:FullLife")) + assert.is_true(env.minion.modDB:Flag(nil, "Condition:FullLife")) + assert.are.equal(0, env.mercenaryMinion.modDB:Sum("BASE", nil, "DoubleDamageChance")) + assert.are.equal(100, env.minion.modDB:Sum("BASE", nil, "DoubleDamageChance")) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + fullLifeMod = "Minions have 100% chance to deal double damage while they are on full life" + configSet.actors.mercenary.customModsList[1].text = fullLifeMod + env = calculate() + assert.is_table(env.mercenaryMinion) + assert.is_nil(env.minion) + + local fullLifeConfig + for _, varData in ipairs(configOptions) do + if varData.var == "minionsConditionFullLife" then fullLifeConfig = varData break end + end + assert.is_false(configVisibility.isRelevantForBuild(assert(fullLifeConfig), build, "player")) + assert.is_true(configVisibility.isRelevantForBuild(fullLifeConfig, build, "mercenary")) + build.configTab:SetViewActor("player") + assert.is_false(build.configTab.varControls.minionsConditionFullLife.shown()) + build.configTab:SetViewActor("mercenary") + assert.is_true(build.configTab.varControls.minionsConditionFullLife.shown()) + + configSet.actors.mercenary.customModsList[1].text = "" + configSet.customModsList[1].text = fullLifeMod + build.skillsTab:PasteSocketGroup("Summon Raging Spirit 20/0 1") + env = calculate() + assert.is_table(env.minion) + assert.is_true(configVisibility.isRelevantForBuild(fullLifeConfig, build, "player")) + assert.is_false(configVisibility.isRelevantForBuild(fullLifeConfig, build, "mercenary")) + build.configTab:SetViewActor("player") + assert.is_true(build.configTab.varControls.minionsConditionFullLife.shown()) + build.configTab:SetViewActor("mercenary") + assert.is_false(build.configTab.varControls.minionsConditionFullLife.shown()) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.input.minionsConditionCreatedRecently = true + env = calculate() + assert.is_true(env.mercenary.modDB:Flag(nil, "Condition:MinionsCreatedRecently")) + assert.is_not_true(env.player.modDB:Flag(nil, "Condition:MinionsCreatedRecently")) + + fresh() + configure("EleBowRanger", "EleBowRangerFire", "BurningArrowMercenary") + addMercItem("Weapon 1", "Rarity: Normal\nCrude Bow", 9060) + addMercItem("Weapon 2", "Rarity: Normal\nSerrated Arrow Quiver", 9061) + configSet = select(1, mercActor()) + assert.are.equal(40, configSet.actors.mercenary.placeholder.projectileDistance) + env = calculate() + assert.are.equal(40, env.mercenary.mainSkill.skillCfg.skillDist) + + configSet.actors.mercenary.customModsList[1].text = "Projectiles gain Damage as they travel farther, dealing up to 30% more Damage with Hits and Ailments" + configSet.input.projectileDistance = 70 + local function damageMore() + local rampEnv = calculate() + local skill = assert(rampEnv.mercenary, table.concat(rampEnv.mercenaryCalculationErrors or { }, "\n")).mainSkill + return skill.skillModList:More(skill.skillCfg, "Damage") + end + local atDefault = damageMore() + configSet.actors.mercenary.input.projectileDistance = 70 + local atSeventy = damageMore() + assert.is_true(atSeventy > atDefault) + configSet.actors.mercenary.input.projectileDistance = 40 + configSet.input.projectileDistance = 10 + assert.are.near(atDefault, damageMore(), 10 ^ -9) + + fresh() + configureSkill("HolyFlameTotemMercenary") + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.input.TotemsSummoned = 5 + local mercenary = assert(calculate().mercenary, table.concat(build.calcsTab.mainEnv.mercenaryCalculationErrors or { }, "\n")) + local defaultCount = mercenary.output.ActiveTotemLimit + assert.is_true(defaultCount >= 1) + assert.are.equal(defaultCount, mercenary.output.TotemsSummoned) + configSet.actors.mercenary.input.TotemsSummoned = 3 + mercenary = assert(calculate().mercenary) + assert.are.equal(3, mercenary.output.TotemsSummoned) + configSet.input.TotemsSummoned = 1 + mercenary = assert(calculate().mercenary) + assert.are.equal(3, mercenary.output.TotemsSummoned) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.input.warcryMode = "AVERAGE" + configSet.actors.mercenary.input.warcryMode = "AVERAGE" + local average = assert(calculate().mercenary).output.WarcryEffectMod + assert.is_true(average > 0) + configSet.actors.mercenary.input.warcryMode = "MAX" + local maxHit = assert(calculate().mercenary).output.WarcryEffectMod + assert.is_true(maxHit > average) + configSet.input.warcryMode = "MAX" + configSet.actors.mercenary.input.warcryMode = "AVERAGE" + assert.are.near(average, assert(calculate().mercenary).output.WarcryEffectMod, 10 ^ -9) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.input.physMode = "FIRE" + configSet.actors.mercenary.input.physMode = "COLD" + local origBuildModList = build.configTab.BuildModList + function build.configTab:BuildModList(...) + origBuildModList(self, ...) + self.mercenaryModList:NewMod("MinionModifier", "LIST", { + mod = modLib.createMod("PhysicalDamageGainAsRandom", "BASE", 35) + }, "Test") + end + local function gainAs(physEnv) + local minion = assert(physEnv.mercenaryMinion, table.concat(physEnv.mercenaryCalculationErrors or { }, "\n")) + local skill = minion.mainSkill + return skill.skillModList:Sum("BASE", skill.skillCfg, "PhysicalDamageGainAsFire"), + skill.skillModList:Sum("BASE", skill.skillCfg, "PhysicalDamageGainAsCold"), + skill.skillModList:Sum("BASE", skill.skillCfg, "PhysicalDamageGainAsLightning") + end + local fire, cold, lightning = gainAs(calculate()) + assert.are.equal(0, fire) + assert.are.equal(35, cold) + assert.are.equal(0, lightning) + configSet.input.physMode = "LIGHTNING" + fire, cold, lightning = gainAs(calculate()) + assert.are.equal(0, fire) + assert.are.equal(35, cold) + assert.are.equal(0, lightning) + configSet.actors.mercenary.input.physMode = "FIRE" + fire, cold, lightning = gainAs(calculate()) + assert.are.equal(35, fire) + assert.are.equal(0, cold) + assert.are.equal(0, lightning) + end) + + it("shares enemy Wither once and isolates actor-local keystones, Exposure, Cruelty, and flask recovery", function() + configureSkill("WitherTotemMercenary") + local staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + staff.id = 9044 + build.itemsTab.items[staff.id] = staff + equipmentSlot("Weapon 1").selItemId = staff.id + local profile = build.mercenaryTab.profile + table.insert(profile.skills, { id = "EssenceDrainAltMercenary", enabled = true, includeInFullDPS = true, count = 1, supports = { } }) + build.mercenaryTab:Changed() + assert(calculate()) + assert.is_true(build.configTab.varControls.multiplierWitheredStackCount.shown()) + profile.mainSkillId = "EssenceDrainAltMercenary" + build.mercenaryTab:Changed() + local baseline = assert(calculate()) + local baselineDot = baseline.mercenary.output.TotalDot or 0 + build.configTab.input.multiplierWitheredStackCount = 15 + local withered = assert(calculate()) + local witherMods = 0 + for _, mod in ipairs(build.configTab.enemyModList) do + if mod.name == "Multiplier:WitheredStack" then + witherMods = witherMods + 1 + assert.are.equal(15, mod.value) + end + end + assert.are.equal(1, witherMods) + assert.is_not_nil(withered.enemy.modDB.mods["Multiplier:WitheredStack"]) + assert.is_true(withered.enemy.modDB:Sum("INC", nil, "ChaosDamageTaken") > 0) + assert.is_true((withered.mercenary.output.TotalDot or 0) > baselineDot) + + fresh() + configureSkill("WitherTotemMercenary") + staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + staff.id = 9045 + build.itemsTab.items[staff.id] = staff + equipmentSlot("Weapon 1").selItemId = staff.id + build.skillsTab:PasteSocketGroup("Wither 20/0 1") + build.configTab.input.multiplierWitheredStackCount = 15 + local env = assert(calculate()) + local witheredSources = 0 + for _, mod in ipairs(env.enemy.modDB.mods["ChaosDamageTaken"] or { }) do + if mod.source == "Withered" then + witheredSources = witheredSources + 1 + end + end + assert.are.equal(1, witheredSources) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.skillsTab:PasteSocketGroup("Fireball 20/0 1\nCruelty 20/0 1\n") + env = calculate() + assert.are.equal(40, env.player.modDB.multipliers.Cruelty) + assert.is_nil(env.mercenary.modDB.multipliers.Cruelty) + + fresh() + build.skillsTab:PasteSocketGroup("Spark 20/0 1\nAwakened Fire Penetration 20/0 1\n") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + env = calculate() + assert.is_true(env.player.modDB.conditions.CanApplyFireExposure) + assert.is_not_true(env.mercenary.modDB.conditions.CanApplyFireExposure) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "MoltenStrikeHolyMercenary", { + supports = { { id = "HolyMoltenStrikeSpecificLightningExposureHigh", tier = 3 } }, + }) + staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + staff.id = 9101 + build.itemsTab.items[staff.id] = staff + equipmentSlot("Weapon 1").selItemId = staff.id + build.skillsTab:PasteSocketGroup("Spark 20/0 1") + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.CanApplyLightningExposure) + assert.is_not_true(env.player.modDB.conditions.CanApplyLightningExposure) + + fresh() + allocate("Precise Technique") + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary") + env = calculate() + assert.is_true(env.keystonesAdded["Precise Technique"]) + assert.is_true(env.player.output.PreciseTechnique) + assert.is_not_true(env.mercenary.calcEnv.keystonesAdded["Precise Technique"]) + assert.is_not_true(env.mercenary.output.PreciseTechnique) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary") + local helmet = new("Item"):Item([[Rarity: Rare +Precise Technique Test Helm +Iron Hat +-------- +Precise Technique +]]) + build.itemsTab:AddItem(helmet, true) + equipmentSlot("Helmet").selItemId = helmet.id + env = calculate() + assert.is_nil(env.mercenaryCalculationErrors and env.mercenaryCalculationErrors[1], table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_not_true(env.keystonesAdded["Precise Technique"]) + assert.is_not_true(env.player.output.PreciseTechnique) + assert.is_true(env.mercenary.calcEnv.keystonesAdded["Precise Technique"]) + assert.is_true(env.mercenary.output.PreciseTechnique) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local lifeFlask = new("Item"):Item("Rarity: Normal\nEternal Life Flask") + build.itemsTab:AddItem(lifeFlask, true) + build.itemsTab.slots["Flask 1"].selItemId = lifeFlask.id + build.itemsTab.activeItemSet["Flask 1"].selItemId = lifeFlask.id + env = calculate() + assert.is_true((env.player.output.LifeFlaskRecovery or 0) > 0) + assert.are.equal(0, env.mercenary.output.LifeFlaskRecovery or 0) + assert.are.equal(0, env.mercenary.output.LifeFlaskCharges or 0) + assert.are_not.equal(env.itemModDB, env.mercenary.calcEnv.itemModDB) + end) + + it("calculates extracted skill DPS, parts, exerts, and on-hit curses", function() + configure("MiscScion", "MiscScionPhysDot", "BladeVortexAltMercenary", { includeInFullDPS = true }) + local env = calculate() + local activeSkill = env.mercenary.mainSkill + assert.are.near(env.mercenary.averageDamage * 366 / 6000, activeSkill.skillData.PhysicalDot, 10 ^ -9) + assert.are.equal(5, activeSkill.skillData.corruptedBloodStacks) + assert.is_true(env.mercenary.output.CorruptingBloodDPS > 0) + assert.are.near(env.mercenary.output.CombinedDPS, env.mercenary.output.FullDPS, 10 ^ -6) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + local mercenary = assert(calculate(83).mercenary) + assert.is_true(mercenary.mainSkill.skillData.explodeCorpse) + assert.are.equal("Fire", mercenary.mainSkill.skillData.corpseExplosionDamageType) + assert.are.near(0.08, mercenary.mainSkill.skillData.corpseExplosionLifeMultiplier, 10 ^ -9) + -- Found-area 68 is inside the 3.29.1 taper, so this hit includes -18% more Damage + -- rather than the -30% endgame cap. + assert.are.near(1984.5, mercenary.output.AverageHit, 10 ^ -9) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary") + local profile = build.mercenaryTab.profile + profile.skills = { + { id = "TectonicSlamFireMercenary", enabled = true, includeInFullDPS = false, count = 1, supports = { } }, + { id = "InfernalCryMercenary", enabled = true, includeInFullDPS = false, count = 1, supports = { } }, + } + profile.mainSkillId = "TectonicSlamFireMercenary" + build.mercenaryTab:Changed() + local mace = new("Item"):Item("Rarity: Normal\nDriftwood Maul") + mace.id = 9060 + build.itemsTab.items[mace.id] = mace + equipmentSlot("Weapon 1").selItemId = mace.id + env = calculate() + assert.is_true(env.mercenary.modDB:Sum("BASE", nil, "NumInfernalExerts") > 0) + assert.is_true(env.mercenary.modDB:Sum("BASE", nil, "Multiplier:ExertingWarcryCount") > 0) + + fresh() + configure("NonEleBowRanger", "NonEleBowRangerPhys", "BarrageAltMercenary", { skillPart = 2 }) + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9018, 9017 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + + local skill = assert(calculate(83).mercenary.mainSkill) + assert.are.equal("All Projectiles", skill.skillPartName) + assert.are.equal(6, skill.skillData.barrageFinalVolleyAdditionalProjectiles) + assert.are.equal(16, skill.skillData.dpsMultiplier) + + fresh() + configure("MeleeAOEStrikeDuelist", "MeleeAOEStrikeDuelistCyclone", "VaalDoubleStrikeMercenary") + local sword = new("Item"):Item("Rarity: Normal\nCorroded Blade") + sword.id = 9019 + build.itemsTab.items[sword.id] = sword + equipmentSlot("Weapon 1").selItemId = sword.id + skill = assert(calculate(83).mercenary.mainSkill) + assert.are.equal(2, skill.skillData.dpsMultiplier) + + fresh() + configure("EleBowRanger", "EleBowRangerClones", "VaalIceShotMercenary", { + supports = { { id = "MultipleProjectilesHigh", tier = 3 } }, + }) + bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9020, 9021 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + env = calculate(83) + skill = assert(env.mercenary.mainSkill) + assert.are.equal(6, skill.skillData.vaalIceShotMirageCount) + assert.is_true(env.mercenary.output.ProjectileCount > 1) + assert.are.equal(7, skill.skillData.dpsMultiplier) + + fresh() + configure("EleBowRanger", "EleBowRangerClones", "IceShotMercenary") + bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9420, 9421 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + env = calculate(83) + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal(build.data.nonDamagingAilment.Chill.max, env.mercenary.output.MaximumChill) + assert.are.equal(build.data.nonDamagingAilment.Shock.max, env.mercenary.output.MaximumShock) + + allocate("Legendary Rings") + local taming = new("Item"):Item([[Rarity: UNIQUE +The Taming +Prismatic Ring +Implicits: 1 ++10% to all Elemental Resistances ++30% to all Elemental Resistances +10% chance to Freeze, Shock and Ignite +35% increased Elemental Damage with Hits and Ailments for each type of Elemental Ailment on Enemy]]) + build.itemsTab:AddItem(taming, true) + equipmentSlot("Ring 1").selItemId = taming.id + env = calculate(83) + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal(build.data.nonDamagingAilment.Chill.max, env.mercenary.output.MaximumChill) + assert.are.equal(build.data.nonDamagingAilment.Shock.max, env.mercenary.output.MaximumShock) + + local shockCapRing = new("Item"):Item("Rarity: RARE\nShock Cap\nIron Ring\nImplicits: 0\n+40% to Maximum Effect of Shock") + build.itemsTab:AddItem(shockCapRing, true) + equipmentSlot("Ring 1").selItemId = shockCapRing.id + env = calculate(83) + assert.are.equal(build.data.nonDamagingAilment.Shock.max + 40, env.mercenary.output.MaximumShock) + assert.are.equal(build.data.nonDamagingAilment.Chill.max, env.mercenary.output.MaximumChill) + + fresh() + configure("MeleeStrikesMarauder", "MeleeStrikesMaraduerPhys", "HeavyStrikeMercenary") + mace = new("Item"):Item("Rarity: Normal\nDriftwood Club") + mace.id = 9012 + build.itemsTab.items[mace.id] = mace + equipmentSlot("Weapon 1").selItemId = mace.id + env = calculate() + local foundVulnerability + for _, activeSkill in ipairs(env.mercenary.activeSkillList) do + if activeSkill.activeEffect.grantedEffect.id == "Vulnerability" then foundVulnerability = true break end + end + assert.is_true(foundVulnerability) + assert.is_true(env.enemy.modDB.conditions.Cursed) + + fresh() + configure("MeleeAOEStrikeDuelist", "DivingDuelist", "ElementalHitColdOnlyMercenary") + sword = new("Item"):Item("Rarity: Normal\nRusted Sword") + sword.id = 9013 + build.itemsTab.items[sword.id] = sword + equipmentSlot("Weapon 1").selItemId = sword.id + env = calculate() + assert.are.equal(3, env.mercenary.mainSkill.skillPart) + assert.are.equal("Cold Attack", env.mercenary.mainSkill.skillPartName) + assert.is_true(env.mercenary.output.CombinedDPS > 0) + build.mercenaryTab.profile.skills[1].skillPart = 4 + build.mercenaryTab:Changed() + env = calculate() + assert.are.equal(4, env.mercenary.mainSkill.skillPart) + end) + + it("applies Mercenary supports, including to minions", function() + configure("EleBowRanger", "EleBowRangerFire", "BurningArrowMercenary", { + supports = { { id = "ArrowNovaHigh", tier = 3 } }, + }) + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9010, 9011 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + local mercenary = assert(calculate().mercenary) + assert.is_truthy(mercenary.mainSkill.skillData.projectilesNova) + assert.is_true(mercenary.output.CombinedDPS > 0) + assert.are.equal("ArrowNovaHigh", build.mercenaryTab.profile.skills[1].supports[1].id) + + fresh() + configure("EleBowRanger", "EleBowRangerClones", "MirrorArrowMercenary", { + includeInFullDPS = true, + }) + bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9016, 9017 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + + local baseline = assert(calculate()) + local baselineMinionDPS = assert(baseline.mercenaryMinion.output.TotalDPS) + local baselineFullDPS = assert(baseline.mercenary.output.FullDPS) + local support = assert(build.data.mercenaries.supports.AddedColdHigh) + build.mercenaryTab.profile.skills[1].supports = { { id = support.id, tier = support.variant } } + build.mercenaryTab:Changed() + + local supported = assert(calculate()) + local minionSkill = assert(supported.mercenaryMinion.mainSkill) + local hasSupport = false + for _, effect in ipairs(minionSkill.effectList) do + if effect.grantedEffect.mercenarySupportId == support.id then hasSupport = true break end + end + assert.is_true(hasSupport) + assert.is_true(supported.mercenaryMinion.output.TotalDPS > baselineMinionDPS) + assert.is_true(supported.mercenary.output.FullDPS > baselineFullDPS) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "FissureSlamMercenary", { + supports = { { id = "FistOfWarHigh", tier = 3 } }, + }) + mercenary = assert(calculate(83).mercenary) + assert.is_nil(mercenary.mainSkill.skillTypes[SkillType.Slam]) + local hasFistOfWar = false + for _, effect in ipairs(mercenary.mainSkill.effectList) do + if effect.grantedEffect.mercenarySupportId == "FistOfWarHigh" then hasFistOfWar = true break end + end + assert.is_true(hasFistOfWar) + assert.are.equal(0, mercenary.output.FistOfWarUptimeRatio or 0) + end) + + it("routes auras, warcries, curses, and party import/export", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "ZealotryMercenary") + local auraEnv = calculate() + assert.is_true(auraEnv.player.modDB.conditions.AffectedByZealotry) + build.skillsTab:PasteSocketGroup("Summon Raging Spirit 20/0 1") + auraEnv = calculate() + assert.is_true(auraEnv.minion.modDB.conditions.AffectedByZealotry) + + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + build.mercenaryTab.profile.skills[1].enabled = false + build.mercenaryTab:Changed() + local playerFullDPSWithoutMercenaryAura = calculate().player.output.FullDPS + build.mercenaryTab.profile.skills[1].enabled = true + build.mercenaryTab:Changed() + auraEnv = calculate() + assert.is_true(auraEnv.player.modDB.conditions.AffectedByZealotry) + assert.is_true(auraEnv.player.output.FullDPS > playerFullDPSWithoutMercenaryAura) + + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + local minionEnv = calculate() + assert.is_table(minionEnv.mercenaryMinion) + assert.is_table(minionEnv.mercenary.mainSkill.minion) + assert.are.equal(minionEnv.mercenary, minionEnv.mercenaryMinion.parent) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarSpectres", "AbsolutionMercenary") + table.insert(build.mercenaryTab.profile.skills, { + id = "BattlemagesCryMercenary", + enabled = true, + count = 1, + supports = { }, + }) + local env = calculate() + assert.is_table(env.mercenaryMinion) + local affectedByBattlemagesCry = false + for condition in pairs(env.mercenaryMinion.modDB.conditions) do + if condition:find("Battlemage", 1, true) then affectedByBattlemagesCry = true break end + end + assert.is_true(affectedByBattlemagesCry) + + fresh() + configure("MeleeStrikesMarauder", "MeleeStrikesMaraduerPhys", "EnduringCryMercenary") + env = calculate() + assert.is_true(env.player.modDB:Flag(nil, "UseEnduranceCharges")) + assert.are.equal(3, env.player.modDB:Override(nil, "EnduranceCharges")) + assert.are.near(10, env.player.modDB:Sum("BASE", nil, "LifeRegenPercent"), 10 ^ -9) + + fresh() + local weapon = new("Item"):Item([[Rarity: Rare +Rallying Test Sword +Rusted Sword +-------- +Adds 500 to 500 Physical Damage]]) + build.itemsTab:AddItem(weapon, true) + build.itemsTab.activeItemSet["Weapon 1"].selItemId = weapon.id + build.skillsTab:PasteSocketGroup("Rallying Cry 20/0 1") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + env = calculate() + assert.is_true(rallyingWeaponFlat(env.mercenary, "PhysicalMin") > 0) + assert.is_true(rallyingWeaponFlat(env.mercenary, "PhysicalMax") > 0) + + fresh() + configure("MeleeAOEStrikeDuelist", "MeleeAOEStrikeDuelistCyclone", "RallyingCryMercenary") + weapon = new("Item"):Item([[Rarity: Rare +Rallying Test Greatsword +Corroded Blade +-------- +Adds 500 to 500 Physical Damage]]) + build.itemsTab:AddItem(weapon, true) + equipmentSlot("Weapon 1").selItemId = weapon.id + env = calculate() + assert.is_true(rallyingWeaponFlat(env.player, "PhysicalMin") > 0) + assert.is_true(rallyingWeaponFlat(env.player, "PhysicalMax") > 0) + assert.are.equal(0, rallyingWeaponFlat(env.mercenary, "PhysicalMin")) + + fresh() + weapon = new("Item"):Item([[Rarity: Rare +Rallying Test Sword +Rusted Sword +-------- +Adds 500 to 500 Physical Damage]]) + build.itemsTab:AddItem(weapon, true) + build.itemsTab.activeItemSet["Weapon 1"].selItemId = weapon.id + build.skillsTab:PasteSocketGroup("Rallying Cry 20/0 1") + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + env = calculate() + local mercenaryFlat = rallyingWeaponFlat(env.mercenary, "PhysicalMin") + local minionFlat = rallyingWeaponFlat(env.mercenaryMinion, "PhysicalMin") + assert.is_true(mercenaryFlat > 0) + assert.is_true(minionFlat > mercenaryFlat) + assert.are.near(2, minionFlat / mercenaryFlat, 0.05) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + local average = calculate().player.modDB:Sum("BASE", nil, "PhysicalDamageGainAsFire") + assert.is_true(average > 0) + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.input.warcryMode = "MAX" + local maxHit = calculate().player.modDB:Sum("BASE", nil, "PhysicalDamageGainAsFire") + assert.is_true(maxHit > average) + + fresh() + build.skillsTab:PasteSocketGroup("Zealotry 20/0 1") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.AffectedByZealotry) + local spellCfg = { flags = ModFlag.Spell } + local strongestEffect = env.mercenary.modDB:More(spellCfg, "Damage") + + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "ZealotryMercenary") + env = calculate() + assert.are.near(strongestEffect, env.mercenary.modDB:More(spellCfg, "Damage"), 10 ^ -9) + + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + env = calculate() + assert.is_true(env.mercenaryMinion.modDB.conditions.AffectedByZealotry) + + fresh() + configure("ChaosMinionWitch", "ChaosMinionWitchDot", "BaneMercenary") + table.insert(build.mercenaryTab.profile.skills, { + id = "TemporalChainsMercenary", + enabled = true, + count = 1, + supports = { }, + }) + env = calculate() + assert.are.equal(1, env.mercenary.modDB.multipliers.CurseOnEnemy) + assert.is_true(env.enemy.modDB.conditions.Cursed) + + fresh() + build.skillsTab:PasteSocketGroup("Vulnerability 20/0 1") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + env = calculate() + assert.is_true(env.enemy.modDB.conditions.Cursed) + assert.are.equal(1, env.player.modDB.multipliers.CurseOnEnemy) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local baselineDamage = calculate().mercenary.modDB:Sum("INC", nil, "Damage") + local auraMods = new("ModList"):ModList() + auraMods:NewMod("Damage", "INC", 20, "Imported Party Aura") + build.partyTab.actor.Aura = { Aura = { ImportedAura = { effectMult = 100, modList = auraMods } } } + build.partyTab.actor.modDB:NewMod("PartyMemberMaximumEnduranceChargesEqualToYours", "FLAG", true, "Imported Party Member") + build.partyTab.actor.output.EnduranceChargesMax = 9 + env = calculate() + assert.are.equal(baselineDamage + 20, env.mercenary.modDB:Sum("INC", nil, "Damage")) + assert.is_true(env.mercenary.modDB.conditions.AffectedByImportedAura) + assert.are.equal(9, env.player.output.EnduranceChargesMax) + assert.are_not.equals(9, env.mercenary.output.EnduranceChargesMax) + + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + env = calculate() + assert.is_true(env.mercenaryMinion.modDB.conditions.AffectedByImportedAura) + + fresh() + build.partyTab.enableExportBuffs = true + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "ZealotryMercenary") + calculate() + assert.is_table(build.partyTab.buffExports.Aura.Zealotry) + assert.is_true(#build.partyTab.buffExports.Aura.Zealotry.modList > 0) + + fresh() + build.partyTab.enableExportBuffs = true + local function exportedEffect() + calculate() + return assert(build.partyTab.buffExports.Aura.Zealotry).effectMult + end + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab:PasteSocketGroup("Zealotry 20/0 1") + local playerGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + build.mainSocketGroup = 1 + build.configTab.input.customMods = "Zealotry has 200% increased Aura Effect" + build.configTab:BuildModList() + local playerStrong = exportedEffect() + assert.are.near(3, playerStrong, 10 ^ -9) + + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "ZealotryMercenary") + playerGroup.enabled = false + local mercDefault = exportedEffect() + assert.is_true(playerStrong > mercDefault) + + playerGroup.enabled = true + assert.are.near(playerStrong, exportedEffect(), 10 ^ -9) + + build.configTab.input.customMods = "Zealotry has 50% reduced Aura Effect" + build.configTab:BuildModList() + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList = { { title = "Default", enabled = true, text = "Zealotry has 200% increased Aura Effect" } } + playerGroup.enabled = false + local mercStrong = exportedEffect() + build.mercenaryTab.profile.skills[1].enabled = false + build.mercenaryTab:Changed() + playerGroup.enabled = true + local playerWeak = exportedEffect() + assert.is_true(mercStrong > playerWeak) + + build.mercenaryTab.profile.skills[1].enabled = true + build.mercenaryTab:Changed() + assert.are.near(mercStrong, exportedEffect(), 10 ^ -9) + + fresh() + -- honours incoming ally aura restrictions and stronger imported auras on a Mercenary + allocate("Legendary Arms") + configure("Crit1HShadow", "Crit1HShadowPoison", "PestilentStrikeMercenary") + local sword = new("Item"):Item("Rarity: Unique\nIchimonji\nCorsair Sword\nAllies' Aura Buffs do not affect you\nYour Aura Buffs do not affect allies") + build.itemsTab:AddItem(sword, true) + equipmentSlot("Weapon 1").selItemId = sword.id + local baseline = assert(calculate().mercenary).output.Evasion + build.skillsTab:PasteSocketGroup("Grace 20/0 1") + local env = calculate() + assert.is_true(env.mercenary.modDB:Flag(nil, "AlliesAurasCannotAffectSelf")) + assert.are.equal(baseline, env.mercenary.output.Evasion) + assert.is_not_true(env.mercenary.modDB.conditions.AffectedByGrace) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.partyTab.enableExportBuffs = true + build.skillsTab:PasteSocketGroup("Grace 20/0 1") + calculate() + local exported = assert(build.partyTab.buffExports.Aura.Grace) + local localOnly = calculate().mercenary.output.Evasion + build.partyTab.actor.Aura = { Aura = { Grace = { effectMult = 200, modList = exported.modList } } } + local withLocal = calculate().mercenary.output.Evasion + for _, group in ipairs(build.skillsTab.socketGroupList) do + for _, gem in ipairs(group.gemList) do gem.enabled = false end + end + local importedOnly = calculate().mercenary.output.Evasion + assert.is_true(importedOnly > localOnly) + assert.are.equal(importedOnly, withLocal) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.partyTab.enableExportBuffs = true + build.skillsTab:PasteSocketGroup("Grace 20/0 1") + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList[1].text = "100% increased Effect of Buffs on you" + calculate() + exported = assert(build.partyTab.buffExports.Aura.Grace) + local scaled = calculate() + assert.are.equal(100, scaled.mercenary.modDB:Sum("INC", nil, "BuffEffectOnSelf")) + localOnly = scaled.mercenary.output.Evasion + -- 150% imported is weaker than local if recipient self-effect is ignored + -- (1.5 vs 2.0), but stronger once both sides include it (2.5 vs 2.0). + build.partyTab.actor.Aura = { Aura = { Grace = { effectMult = 150, modList = exported.modList } } } + withLocal = calculate().mercenary.output.Evasion + for _, group in ipairs(build.skillsTab.socketGroupList) do + for _, gem in ipairs(group.gemList) do gem.enabled = false end + end + importedOnly = calculate().mercenary.output.Evasion + assert.is_true(importedOnly > localOnly) + assert.are.equal(importedOnly, withLocal) + + fresh() + -- uses a stronger imported aura instead of a Mercenary's own weaker aura + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + table.insert(build.mercenaryTab.profile.skills, { id = "ZealotryMercenary", enabled = true, supports = { } }) + build.mercenaryTab:Changed() + build.partyTab.enableExportBuffs = true + build.skillsTab:PasteSocketGroup("Zealotry 20/0 1") + calculate() + local exported = assert(build.partyTab.buffExports.Aura.Zealotry) + for _, group in ipairs(build.skillsTab.socketGroupList) do + for _, gem in ipairs(group.gemList) do gem.enabled = false end + end + local spellCfg = { flags = ModFlag.Spell } + local localOnly = calculate().mercenary.modDB:More(spellCfg, "Damage") + build.partyTab.actor.Aura = { Aura = { Zealotry = { effectMult = 200, modList = exported.modList } } } + local withLocal = calculate().mercenary.modDB:More(spellCfg, "Damage") + build.mercenaryTab.profile.skills[2].enabled = false + build.mercenaryTab:Changed() + local importedOnly = calculate().mercenary.modDB:More(spellCfg, "Damage") + assert.is_true(importedOnly > localOnly) + assert.are.near(importedOnly, withLocal, 10 ^ -9) + assert.is_true(calculate().mercenary.modDB.conditions.AffectedByZealotry) + + fresh() + -- applies recipient self-effect when a stronger imported aura replaces a Mercenary aura on the player + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "ZealotryMercenary") + build.partyTab.enableExportBuffs = true + calculate() + local exported = assert(build.partyTab.buffExports.Aura.Zealotry) + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "100% increased Effect of Buffs on you" + local spellCfg = { flags = ModFlag.Spell } + local localOnly = calculate().player.modDB:More(spellCfg, "Damage") + assert.are.equal(100, calculate().player.modDB:Sum("INC", nil, "BuffEffectOnSelf")) + -- 150% imported is weaker than local if recipient self-effect is ignored + -- (1.5 vs 2.0), but stronger once both sides include it (2.5 vs 2.0). + build.partyTab.actor.Aura = { Aura = { Zealotry = { effectMult = 150, modList = exported.modList } } } + local withLocal = calculate().player.modDB:More(spellCfg, "Damage") + build.mercenaryTab.profile.skills[1].enabled = false + build.mercenaryTab:Changed() + local importedOnly = calculate().player.modDB:More(spellCfg, "Damage") + assert.is_true(importedOnly > localOnly) + assert.are.near(importedOnly, withLocal, 10 ^ -9) + + fresh() + -- applies recipient self-effect when a stronger imported aura replaces the player's own weaker aura + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.partyTab.enableExportBuffs = true + build.skillsTab:PasteSocketGroup("Grace 20/0 1") + calculate() + local exported = assert(build.partyTab.buffExports.Aura.Grace) + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "100% increased Effect of Buffs on you" + local localOnly = calculate().player.output.Evasion + assert.are.equal(100, calculate().player.modDB:Sum("INC", nil, "BuffEffectOnSelf")) + -- 150% imported is weaker than local if recipient self-effect is ignored + -- (1.5 vs 2.0), but stronger once both sides include it (2.5 vs 2.0). + build.partyTab.actor.Aura = { Aura = { Grace = { effectMult = 150, modList = exported.modList } } } + local withLocal = calculate().player.output.Evasion + for _, group in ipairs(build.skillsTab.socketGroupList) do + for _, gem in ipairs(group.gemList) do gem.enabled = false end + end + local importedOnly = calculate().player.output.Evasion + assert.is_true(importedOnly > localOnly) + assert.are.equal(importedOnly, withLocal) + + fresh() + -- arbitrates imported Vaal auras and marks the underlying aura condition + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.partyTab.enableExportBuffs = true + build.skillsTab:PasteSocketGroup("Vaal Grace 20/0 1") + calculate() + local exported = assert(build.partyTab.buffExports.Aura["Vaal Grace"]) + local env = calculate() + local localOnly = env.mercenary.modDB:Sum("BASE", nil, "EvadeChance") + assert.is_true(env.mercenary.modDB.conditions.AffectedByVaalGrace) + assert.is_true(env.mercenary.modDB.conditions.AffectedByGrace) + build.partyTab.actor.Aura = { Aura = { Vaal = { ["Vaal Grace"] = { effectMult = 200, modList = exported.modList } } } } + local withLocal = calculate().mercenary.modDB:Sum("BASE", nil, "EvadeChance") + for _, group in ipairs(build.skillsTab.socketGroupList) do + for _, gem in ipairs(group.gemList) do gem.enabled = false end + end + env = calculate() + local importedOnly = env.mercenary.modDB:Sum("BASE", nil, "EvadeChance") + assert.is_true(importedOnly > localOnly) + assert.are.equal(importedOnly, withLocal) + assert.is_true(env.mercenary.modDB.conditions.AffectedByVaalGrace) + assert.is_true(env.mercenary.modDB.conditions.AffectedByGrace) + end) + + it("applies player Quicksilver flasks to a Mercenary with QuickSilverAppliesToAllies", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local silver = new("Item"):Item("Rarity: Normal\nQuicksilver Flask") + build.itemsTab:AddItem(silver, true) + build.itemsTab.slots["Flask 1"].selItemId = silver.id + build.itemsTab.slots["Flask 1"].active = true + build.itemsTab.activeItemSet["Flask 1"].selItemId = silver.id + build.itemsTab.activeItemSet["Flask 1"].active = true + local baseline = calculate() + assert.is_true(baseline.player.modDB.conditions.UsingQuicksilverFlask) + assert.is_nil(baseline.mercenary.modDB.conditions.UsingQuicksilverFlask) + local baseMove = baseline.mercenary.modDB:Sum("INC", nil, "MovementSpeed") + build.configTab.input.customMods = "Quicksilver Flasks you Use also apply to nearby Allies" + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "Quicksilver Flasks you Use also apply to nearby Allies" + build.configTab:BuildModList() + local env = calculate() + assert.is_true(env.mercenary.modDB.conditions.UsingQuicksilverFlask) + assert.is_true(env.mercenary.modDB.conditions.UsingFlask) + assert.is_true((env.mercenary.appliedFlasks or { })[silver]) + assert.is_true(env.mercenary.modDB:Sum("INC", nil, "MovementSpeed") > baseMove) + + configure("AurasMinionsTemplar", "AurasMinionsTemplarStaff", "HeraldOfPurityMercenary") + env = calculate() + assert.is_table(env.mercenaryMinion) + assert.is_true(env.mercenaryMinion.modDB.conditions.UsingQuicksilverFlask) + assert.is_true(env.mercenaryMinion.modDB.conditions.UsingFlask) + assert.is_true((env.mercenaryMinion.appliedFlasks or { })[silver]) + assert.is_true(env.mercenaryMinion.modDB:Sum("INC", nil, "MovementSpeed") > 0) + + fresh() + -- applies Bestowed Knighthood taunt and Mercenary aura effect + local mods = assert(modLib.parseMod("Your Mercenary has 50% increased effect of Non-Curse Auras from Skills")) + assert.are.equal("AuraEffect", mods[1].value.mod.name) + + allocate("Bestowed Knighthood") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local env = calculate() + local auraCfg = { skillTypes = { [SkillType.Aura] = true } } + assert.are.equal(50, env.mercenary.modDB:Sum("INC", auraCfg, "AuraEffect")) + assert.are.equal(0, env.mercenary.modDB:Sum("INC", nil, "AuraEffectOnSelf")) + assert.is_true(env.enemy.modDB.conditions.TauntedByMercenary) + assert.are.near(0.9, env.player.modDB:More(nil, "DamageTaken"), 10 ^ -9) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "ZealotryMercenary") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + env = calculate() + local baseAuraMore = env.player.modDB:More({ flags = ModFlag.Spell }, "Damage") + local baseFullDPS = env.player.output.FullDPS + assert.is_true(env.player.modDB.conditions.AffectedByZealotry) + assert.is_true(baseFullDPS > 0) + + allocate("Bestowed Knighthood") + env = calculate() + -- Aura stats are floored after effect, so 15% more * 1.5 becomes 22% more. + assert.are.near(1 + math.floor((baseAuraMore - 1) * 100 * 1.5) / 100, env.player.modDB:More({ flags = ModFlag.Spell }, "Damage"), 10 ^ -9) + assert.is_true(env.player.output.FullDPS > baseFullDPS) + end) + + it("weights support-aura weapon mods against player Full DPS", function() + configure("AurasMinionsTemplar", "AurasMinionsTemplarSpectres", "WrathMercenary") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + local itemsTab = build.itemsTab + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local blankWand = new("Item"):Item("Rarity: Normal\nDriftwood Wand") + local wrathWand = new("Item"):Item([[Rarity: Rare +Eagle Gnarl +Driftwood Wand +-------- +Wrath has 40% increased Aura Effect]]) + itemsTab:AddItem(blankWand, true) + itemsTab:AddItem(wrathWand, true) + mercSet["Weapon 1"].selItemId = blankWand.id + local env = calculate() + assert.is_true(env.player.modDB.conditions.AffectedByWrath) + local playerFullDPSWithout = env.player.output.FullDPS + local mercenaryFullDPSWithout = env.mercenary.output.FullDPS or 0 + assert.is_true(playerFullDPSWithout > 0) + + mercSet["Weapon 1"].selItemId = wrathWand.id + env = calculate() + assert.is_true(env.player.output.FullDPS > playerFullDPSWithout) + assert.are.equal(mercenaryFullDPSWithout, env.mercenary.output.FullDPS or 0) + + assert(itemsTab:SetViewItemSet(mercSet.id)) + local calcFunc, _, actorOutputs = build.calcsTab:GetMiscCalculator() + local blankOutput = calcFunc(itemsTab:ItemCalculationOverride("Weapon 1", blankWand)) + local unequipped = calcFunc(itemsTab:ItemCalculationOverride("Weapon 1", nil)) + assert.are.near(env.player.output.FullDPS, actorOutputs.MERCENARY.FullDPS, 10 ^ -6) + assert.is_true(blankOutput.FullDPS < actorOutputs.MERCENARY.FullDPS) + assert.is_true(unequipped.FullDPS < actorOutputs.MERCENARY.FullDPS) + + local tooltip = new("Tooltip"):Tooltip() + itemsTab:AddItemTooltip(tooltip, wrathWand, itemsTab.slots["Weapon 1"]) + local tooltipLines = { } + local sawRemoveHeader, sawFullDPS + for _, line in ipairs(tooltip.lines) do + local text = line.text or "" + table.insert(tooltipLines, text) + if text:find("Removing this item", 1, true) then + sawRemoveHeader = true + end + if sawRemoveHeader and text:find("Full DPS", 1, true) then + sawFullDPS = true + end + end + assert.is_true(sawRemoveHeader, table.concat(tooltipLines, "\n")) + assert.is_true(sawFullDPS, table.concat(tooltipLines, "\n")) + + local queryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator(itemsTab.tradeQuery) + queryGenerator:StartQuery(itemsTab.slots["Weapon 1"], { + itemSetId = mercSet.id, + influence1 = 1, + influence2 = 1, + includeTalisman = false, + includeCorrupted = false, + includeScourge = false, + includeEldritch = false, + includeMirrored = false, + statWeights = { { stat = "FullDPS", weightMult = 1 } }, + requiredMods = { }, + }) + queryGenerator.calcContext.co = nil + local wrathMod + for _, mod in pairs(queryGenerator.modData.Explicit) do + if mod.tradeMod and mod.tradeMod.id == "explicit.stat_2181791238" and mod.Wand then + wrathMod = mod + break + end + end + wrathMod = assert(wrathMod, "Wrath aura effect wand trade modifier is missing") + queryGenerator.modWeights = { } + queryGenerator.alreadyWeightedMods = { } + queryGenerator:GenerateModWeights({ WrathAuraEffect = wrathMod }) + assert.are.equal(1, #queryGenerator.modWeights) + assert.are.equal("explicit.stat_2181791238", queryGenerator.modWeights[1].tradeModId) + assert.is_true(queryGenerator.modWeights[1].meanStatDiff > 0.01) + if queryGenerator.calcContext.popup then + main:ClosePopup() + end + end) + + it("shows player Full DPS when removing a Mercenary abyss jewel", function() + configure("AurasMinionsTemplar", "AurasMinionsTemplarSpectres", "WrathMercenary") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + local itemsTab = build.itemsTab + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local helmet = new("Item"):Item([[Rarity: Rare +Socketed Crown +Crusader Helmet +-------- +Has 1 Abyssal Socket]]) + local jewel = new("Item"):Item([[Rarity: Rare +Support Eye +Hypnotic Eye Jewel +-------- +40% increased Effect of Non-Curse Auras from your Skills]]) + itemsTab:AddItem(helmet, true) + itemsTab:AddItem(jewel, true) + mercSet.Helmet.selItemId = helmet.id + mercSet["Helmet Abyssal Socket 1"].selItemId = jewel.id + local env = calculate() + assert.is_true(env.player.modDB.conditions.AffectedByWrath) + local playerFullDPS = env.player.output.FullDPS + assert.is_true(playerFullDPS > 0) + + assert(itemsTab:SetViewItemSet(mercSet.id)) + local calcFunc, _, actorOutputs = build.calcsTab:GetMiscCalculator() + local unequipped = calcFunc(itemsTab:ItemCalculationOverride("Helmet Abyssal Socket 1", nil)) + assert.are.near(playerFullDPS, actorOutputs.MERCENARY.FullDPS, 10 ^ -6) + assert.is_true(unequipped.FullDPS < actorOutputs.MERCENARY.FullDPS) + local removedEnv = build.calcsTab.calcs.initEnv(build, "CALCULATOR", itemsTab:ItemCalculationOverride("Helmet Abyssal Socket 1", nil)) + assert.is_nil(removedEnv.mercenary.itemList["Helmet Abyssal Socket 1"]) + + local tooltip = new("Tooltip"):Tooltip() + itemsTab:AddItemTooltip(tooltip, jewel, itemsTab.slots["Helmet Abyssal Socket 1"]) + local tooltipLines = { } + local sawRemoveHeader, sawFullDPS + for _, line in ipairs(tooltip.lines) do + local text = line.text or "" + table.insert(tooltipLines, text) + if text:find("Removing this item", 1, true) then + sawRemoveHeader = true + end + if sawRemoveHeader and text:find("Full DPS", 1, true) then + sawFullDPS = true + end + end + assert.is_true(sawRemoveHeader, table.concat(tooltipLines, "\n")) + assert.is_true(sawFullDPS, table.concat(tooltipLines, "\n")) + end) + + it("applies Links and Loyal Bodyguard", function() + assert.is_nil(build.skillsTab.controls.linkTarget) + allocate("Oath of Fealty") + allocate("Golden Glory") + build.skillsTab:PasteSocketGroup("Flame Link 20/0 1") + local linkGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { includeInFullDPS = true }) + local env = calculate() + local baseDPS = env.mercenary.output.CombinedDPS + local baseFullDPS = env.mercenary.output.FullDPS + assert.is_true(env.mercenary.modDB.conditions.AffectedByLink) + -- Neither Link node modifier changes a number PoB calculates, so both are + -- recognised as unsupported rather than parsed into an unread flag. + for _, modLine in ipairs({ "Link Skills have infinite Attachment Duration", "If your Linked Mercenary dies, the Link owner does not also die" }) do + local mods, unsupported = modLib.parseMod(modLine) + assert.are.equal(0, #mods, modLine) + assert.are.equal(modLine, unsupported) + end + assert.are.near(0.5, env.player.mainSkill.skillModList:More(env.player.mainSkill.skillCfg, "Cost"), 10 ^ -9) + + linkGroup.enabled = false + env = calculate() + assert.is_nil(env.mercenary.modDB.conditions.AffectedByLink) + + linkGroup.enabled = true + build.configTab.input.customMods = "100% increased Light Radius" + build.configTab:BuildModList() + env = calculate() + assert.is_true(env.mercenary.output.CombinedDPS > baseDPS) + assert.is_true(env.mercenary.output.FullDPS > baseFullDPS) + assert.is_true(env.mercenary.modDB.conditions.AffectedByLink) + + fresh() + build.skillsTab:PasteSocketGroup("Vampiric Link 20/0 1") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + env = calculate() + assert.are.equal(env.player, env.mercenary.parent) + assert.are.equal(env.player.output.MaxLifeLeechRatePercent, env.mercenary.output.MaxLifeLeechRatePercent) + + fresh() + allocate("Loyal Bodyguard") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { lifeComparison = "MERCENARY" }) + env = calculate() + assert.are.equal(20, env.player.modDB:Sum("BASE", nil, "takenFromMercenaryBeforeYou")) + assert.are.equal(0, env.mercenary.modDB:Sum("BASE", nil, "LifeRecoup")) + + build.mercenaryTab.profile.lifeComparison = "PLAYER" + env = calculate() + assert.are.equal(0, env.player.modDB:Sum("BASE", nil, "takenFromMercenaryBeforeYou")) + assert.are.equal(40, env.mercenary.modDB:Sum("BASE", nil, "LifeRecoup")) + + build.mercenaryTab.profile.lifeComparison = "AUTO" + local equalizer = { + id = 9037, name = "Player Life Equalizer", type = "Helmet", base = { type = "Helmet" }, rarity = "RARE", + requirements = { }, grantedSkills = { }, sockets = { }, modList = { { + name = "Life", type = "BASE", value = env.mercenary.output.Life - env.player.output.Life, + source = "Test", flags = 0, keywordFlags = 0, + } }, + } + build.itemsTab.items[equalizer.id] = equalizer + build.itemsTab.slots.Helmet:SetSelItemId(equalizer.id) + env = calculate() + assert.are.equal(env.player.output.Life, env.mercenary.output.Life) + assert.are.equal(0, env.player.modDB:Sum("BASE", nil, "takenFromMercenaryBeforeYou")) + assert.are.equal(0, env.mercenary.modDB:Sum("BASE", nil, "LifeRecoup")) + + fresh() + -- applies Destructive Link and Ceinture flasks + local sceptre = new("Item"):Item("Rarity: Normal\nVoid Sceptre") + build.itemsTab:AddItem(sceptre, true) + build.itemsTab.slots["Weapon 1"].selItemId = sceptre.id + build.itemsTab.activeItemSet["Weapon 1"].selItemId = sceptre.id + local sword = new("Item"):Item("Rarity: Normal\nRusted Sword") + build.itemsTab:AddItem(sword, true) + + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "400% increased Critical Strike Chance" + build.configTab:BuildModList() + + build.skillsTab:PasteSocketGroup("Heavy Strike 20/0 1") + build.mainSocketGroup = #build.skillsTab.socketGroupList + build.skillsTab:PasteSocketGroup("Destructive Link 21/0 1") + local linkGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + configure("MeleeAOEStrikeDuelist", "MeleeAOEStrikeDuelistRangeStrikes", "FrostBladesMercenary", { includeInFullDPS = true }) + equipmentSlot("Weapon 1").selItemId = sword.id + + linkGroup.enabled = false + local env = calculate() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local unlinkedCrit, unlinkedMulti = mercMainHandCrit(env) + assert.is_not_nil(unlinkedCrit) + assert.is_nil(env.mercenary.modDB.conditions.AffectedByDestructiveLink) + + linkGroup.enabled = true + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.AffectedByLink) + assert.is_true(env.mercenary.modDB.conditions.AffectedByDestructiveLink) + local playerSheetCrit = env.player.output.MainHand.PreEffectiveCritChance + local linkedCrit, linkedMulti = mercMainHandCrit(env) + assert.is_true(playerSheetCrit > env.player.weaponData1.CritChance) + assert.are.near(playerSheetCrit, linkedCrit, 0.01) + assert.is_true(linkedMulti > unlinkedMulti) + + build.skillsTab:PasteSocketGroup("Clarity 20/0 1") + build.mainSocketGroup = #build.skillsTab.socketGroupList + env = calculate() + local auraLinkedCrit, auraLinkedMulti = mercMainHandCrit(env) + assert.is_true(env.mercenary.modDB.conditions.AffectedByDestructiveLink) + assert.is_nil(env.player.output.MainHand) + assert.are.near(playerSheetCrit, auraLinkedCrit, 0.01) + assert.is_true(auraLinkedCrit > env.player.weaponData1.CritChance) + assert.is_true(auraLinkedMulti > unlinkedMulti) + + configSet.customModsList[1].text = "400% increased Critical Strike Chance\nNever deal Critical Strikes" + build.configTab:BuildModList() + env = calculate() + local neverCrit, neverCritMulti = mercMainHandCrit(env) + assert.is_true(env.player.modDB:Flag({ flags = ModFlag.Attack }, "NeverCrit")) + assert.are.near(playerSheetCrit, neverCrit, 0.01) + assert.is_true(neverCritMulti > unlinkedMulti) + + fresh() + build.skillsTab:PasteSocketGroup("Flame Link 20/0 1") + linkGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local recipientBelt = new("Item"):Item("Rarity: Rare\nRecipient Effect\nCloth Belt\nFlasks applied to you have 25% increased Effect") + recipientBelt.id = 9029 + build.itemsTab.items[recipientBelt.id] = recipientBelt + equipmentSlot("Belt").selItemId = recipientBelt.id + + local granite = new("Item"):Item("Rarity: Magic\nChemist's Granite Flask of the Opossum\n12% increased Movement Speed during Effect") + granite.id = 9030 + granite.flaskData.effectInc = 10 + build.itemsTab.items[granite.id] = granite + build.itemsTab.slots["Flask 1"].selItemId = granite.id + build.itemsTab.slots["Flask 1"].active = true + build.itemsTab.activeItemSet["Flask 1"].selItemId = granite.id + build.itemsTab.activeItemSet["Flask 1"].active = true + build.configTab.input.customMods = "Flasks applied to you have 30% increased Effect" + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "Flasks applied to you have 30% increased Effect" + configSet.actors.mercenary.customModsList[1].text = "Flasks applied to you have 30% increased Effect" + build.configTab:BuildModList() + env = calculate() + local baseArmour = env.mercenary.modDB:Sum("BASE", nil, "Armour") + local baseMovementSpeed = env.mercenary.modDB:Sum("INC", nil, "MovementSpeed") + assert.is_true(env.player.modDB.conditions.UsingGraniteFlask) + assert.is_nil(env.mercenary.modDB.conditions.UsingGraniteFlask) + + local ceinture = new("Item"):Item("Rarity: Unique\nCeinture of Benevolence\nCloth Belt\nNon-Unique Utility Flasks you Use apply to Linked Targets") + ceinture.id = 9031 + build.itemsTab.items[ceinture.id] = ceinture + build.itemsTab.slots.Belt.selItemId = ceinture.id + build.itemsTab.activeItemSet.Belt.selItemId = ceinture.id + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.UsingFlask) + assert.is_true(env.mercenary.modDB.conditions.UsingGraniteFlask) + assert.are.equal(baseArmour + 2475, env.mercenary.modDB:Sum("BASE", nil, "Armour")) + assert.are.equal(baseMovementSpeed + 19, env.mercenary.modDB:Sum("INC", nil, "MovementSpeed")) + + linkGroup.enabled = false + env = calculate() + assert.is_nil(env.mercenary.modDB.conditions.UsingFlask) + assert.is_nil(env.mercenary.modDB.conditions.UsingGraniteFlask) + assert.are.equal(baseArmour, env.mercenary.modDB:Sum("BASE", nil, "Armour")) + + linkGroup.enabled = true + granite.rarity = "UNIQUE" + granite.title = "Unique Granite Flask" + env = calculate() + assert.is_nil(env.mercenary.modDB.conditions.UsingFlask) + assert.is_nil(env.mercenary.modDB.conditions.UsingGraniteFlask) + assert.are.equal(baseArmour, env.mercenary.modDB:Sum("BASE", nil, "Armour")) + + local lifeFlask = new("Item"):Item("Rarity: Normal\nEternal Life Flask") + lifeFlask.id = 9032 + build.itemsTab.items[lifeFlask.id] = lifeFlask + build.itemsTab.slots["Flask 1"].selItemId = lifeFlask.id + build.itemsTab.activeItemSet["Flask 1"].selItemId = lifeFlask.id + env = calculate() + assert.is_nil(env.mercenary.modDB.conditions.UsingFlask) + assert.is_nil(env.mercenary.modDB.conditions.UsingEternalLifeFlask) + + fresh() + local function onslaughtMovementSpeed(actor) + local total = 0 + for _, mod in ipairs(actor.modDB.mods["MovementSpeed"] or { }) do + if mod.source == "Onslaught" then + total = total + mod.value + end + end + return total + end + local function equipFlask(slotName, item) + build.itemsTab.items[item.id] = item + build.itemsTab.slots[slotName].selItemId = item.id + build.itemsTab.slots[slotName].active = true + build.itemsTab.activeItemSet[slotName].selItemId = item.id + build.itemsTab.activeItemSet[slotName].active = true + end + local function clearFlask(slotName) + build.itemsTab.slots[slotName].selItemId = 0 + build.itemsTab.activeItemSet[slotName].selItemId = 0 + end + + build.skillsTab:PasteSocketGroup("Flame Link 20/0 1") + linkGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + configure("EleBowRanger", "EleBowRangerFire", "ArtilleryBallistaMercenary", { + supports = { { id = "ArtilleryBallistaSpecificOnslaughtHigh", tier = 3 } }, + }) + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9120, 9121 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList[1].text = "Flasks applied to you have 30% increased Effect" + build.configTab:BuildModList() + + env = calculate() + assert.is_true(env.mercenary.modDB:Flag(nil, "Onslaught")) + assert.are.equal(20, onslaughtMovementSpeed(env.mercenary)) + + local silver = new("Item"):Item("Rarity: Magic\nChemist's Silver Flask of Curing") + silver.id = 9122 + silver.flaskData.effectInc = 20 + equipFlask("Flask 1", silver) + env = calculate() + assert.is_true(env.player.modDB.conditions.UsingSilverFlask) + assert.is_nil(env.mercenary.modDB.conditions.UsingSilverFlask) + assert.is_nil((env.mercenary.appliedFlasks or { })[silver]) + assert.are.equal(24, onslaughtMovementSpeed(env.player)) + assert.are.equal(20, onslaughtMovementSpeed(env.mercenary)) + + ceinture = new("Item"):Item("Rarity: Unique\nCeinture of Benevolence\nCloth Belt\nNon-Unique Utility Flasks you Use apply to Linked Targets") + ceinture.id = 9124 + build.itemsTab.items[ceinture.id] = ceinture + build.itemsTab.slots.Belt.selItemId = ceinture.id + build.itemsTab.activeItemSet.Belt.selItemId = ceinture.id + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.UsingSilverFlask) + assert.is_true(env.mercenary.appliedFlasks[silver]) + assert.are.equal(24, onslaughtMovementSpeed(env.player)) + assert.are.equal(30, onslaughtMovementSpeed(env.mercenary)) + + local cinderswallow = new("Item"):Item("Rarity: Unique\nCinderswallow Urn\nSilver Flask") + cinderswallow.id = 9123 + assert.are.equal("UNIQUE", cinderswallow.rarity) + assert.are.equal("Silver Flask", cinderswallow.baseName) + cinderswallow.flaskData.effectInc = 80 + clearFlask("Flask 1") + equipFlask("Flask 2", cinderswallow) + env = calculate() + assert.is_true(env.player.modDB.conditions.UsingSilverFlask) + assert.is_nil(env.mercenary.modDB.conditions.UsingSilverFlask) + assert.is_nil((env.mercenary.appliedFlasks or { })[cinderswallow]) + assert.are.equal(36, onslaughtMovementSpeed(env.player)) + assert.are.equal(20, onslaughtMovementSpeed(env.mercenary)) + + equipFlask("Flask 1", silver) + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.UsingSilverFlask) + assert.is_true(env.mercenary.appliedFlasks[silver]) + assert.is_nil(env.mercenary.appliedFlasks[cinderswallow]) + assert.are.equal(36, onslaughtMovementSpeed(env.player)) + assert.are.equal(30, onslaughtMovementSpeed(env.mercenary)) + + linkGroup.enabled = false + env = calculate() + assert.is_nil(env.mercenary.modDB.conditions.UsingSilverFlask) + assert.is_nil((env.mercenary.appliedFlasks or { })[silver]) + assert.is_nil((env.mercenary.appliedFlasks or { })[cinderswallow]) + assert.are.equal(36, onslaughtMovementSpeed(env.player)) + assert.are.equal(20, onslaughtMovementSpeed(env.mercenary)) + end) + + it("uses separate equipment sets for calculation, comparison, and trade", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local env = calculate() + local compare, playerBase, actorBases = build.calcsTab.calcs.getMiscCalculator(build) + assert.are.equal(env.player.output.Life, playerBase.Life) + assert.are.equal(env.mercenary.output.Life, actorBases.MERCENARY.Life) + assert.are.equal(env.player.output.Life, compare({ }).Life) + assert.are.equal(env.mercenary.output.Life, compare({ comparisonActor = "MERCENARY" }).Life) + + compare = build.calcsTab.calcs.getMiscCalculator(build) + local ok, err = pcall(compare, { itemSetId = 99999 }) + assert.is_true(not ok) + assert.matches("Unknown item set id", tostring(err)) + assert.is_number(compare({ }).Life) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local itemsTab = build.itemsTab + local guardianSet = itemsTab:NewItemSet() + guardianSet.title = "Animate Guardian" + table.insert(itemsTab.itemSetOrderList, guardianSet.id) + local mercenarySet = assert(build.mercenaryTab:GetItemSet(true)) + + local playerHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + local guardianHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + local mercenaryHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(playerHelmet, true) + itemsTab:AddItem(guardianHelmet, true) + itemsTab:AddItem(mercenaryHelmet, true) + itemsTab.activeItemSet.Helmet.selItemId = playerHelmet.id + guardianSet.Helmet.selItemId = guardianHelmet.id + mercenarySet["Helmet"].selItemId = mercenaryHelmet.id + + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + local guardianGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + build.mainSocketGroup = #build.skillsTab.socketGroupList + local guardianGem + for _, gem in ipairs(guardianGroup.gemList) do + if gem.nameSpec == "Animate Guardian" or gem.gemData and gem.gemData.name == "Animate Guardian" or gem.grantedEffect and gem.grantedEffect.name == "Animate Guardian" then + guardianGem = gem + break + end + end + guardianGem = assert(guardianGem) + guardianGem.skillMinionItemSet = guardianSet.id + guardianGem.skillMinionItemSetCalcs = guardianSet.id + + env = calculate() + assert.are.equal(playerHelmet, env.player.itemList.Helmet) + assert.are.equal(guardianHelmet, env.minion.itemList.Helmet) + assert.are.equal(mercenaryHelmet, env.mercenary.itemList.Helmet) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + itemsTab = build.itemsTab + local firstSet = assert(build.mercenaryTab:GetItemSet(true)) + local secondSet = itemsTab:NewItemSet() + secondSet.title = "Alternate Equipment" + table.insert(itemsTab.itemSetOrderList, secondSet.id) + local firstHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + local secondHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(firstHelmet, true) + itemsTab:AddItem(secondHelmet, true) + firstSet["Helmet"].selItemId = firstHelmet.id + secondSet["Helmet"].selItemId = secondHelmet.id + + build.itemsTab:SetActorItemSet("MERCENARY", secondSet.id) + env = calculate() + assert.are.equal(secondSet.id, build.itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(secondHelmet, env.mercenary.itemList.Helmet) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + itemsTab = build.itemsTab + mercenarySet = assert(build.mercenaryTab:GetItemSet(true)) + local currentHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(currentHelmet, true) + mercenarySet["Helmet"].selItemId = currentHelmet.id + + local tradeQuery = itemsTab.tradeQuery + tradeQuery.tradeQueryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator(itemsTab) + tradeQuery.slotTables[1] = { slotName = "Helmet", itemSetId = mercenarySet.id } + tradeQuery.resultTbl[1] = { { item_string = [[Rarity: Rare +Mercenary's Test +Leather Cap +-------- ++100 to maximum Life]] } } + tradeQuery.statSortSelectionList = { { stat = "Life", weightMult = 1 } } + + calculate() + local _, _, actorOutputs = build.calcsTab:GetMiscCalculator() + local evaluation = tradeQuery:GetResultEvaluation(1, 1) + assert.is_number(evaluation[1].output.Life) + assert.is_true(evaluation[1].output.Life > actorOutputs.MERCENARY.Life) + assert.is_true(evaluation[1].weight > 0) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + calculate() + assert(build.itemsTab:SetViewItemSet(mercSet.id)) + build.calcsTab:BuildOutput() + local calcFunc, calcBase + calcFunc, calcBase, actorOutputs = build.calcsTab:GetMiscCalculator() + assert.are.equal(actorOutputs.PLAYER, calcBase) + assert.are.equal(calcFunc().Life, calcBase.Life) + assert.is_truthy(actorOutputs.MERCENARY) + assert.are.equal(calcFunc({ comparisonActor = "MERCENARY" }).Life, actorOutputs.MERCENARY.Life) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + itemsTab = build.itemsTab + mercSet = assert(build.mercenaryTab:GetItemSet(true)) + playerHelmet = new("Item"):Item([[Rarity: Rare +Player Helmet +Iron Hat +-------- ++1000 to maximum Life]]) + local mercHelmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + local replacementHelmet = new("Item"):Item([[Rarity: Rare +Replacement Helmet +Leather Cap +-------- ++100 to maximum Life]]) + itemsTab:AddItem(playerHelmet, true) + itemsTab:AddItem(mercHelmet, true) + itemsTab:AddItem(replacementHelmet, true) + itemsTab.activeItemSet.Helmet.selItemId = playerHelmet.id + mercSet.Helmet.selItemId = mercHelmet.id + calculate() + assert(itemsTab:SetViewItemSet(mercSet.id)) + calcFunc, _, actorOutputs = build.calcsTab:GetMiscCalculator() + local playerReplacement = calcFunc({ + repSlotName = "Helmet", + repItem = replacementHelmet, + }) + local mercReplacement = calcFunc(itemsTab:ItemCalculationOverride("Helmet", replacementHelmet)) + assert.is_true(playerReplacement.Life < actorOutputs.PLAYER.Life) + assert.is_true(mercReplacement.Life > actorOutputs.MERCENARY.Life) + assert.are_not.equal(playerReplacement.Life, mercReplacement.Life) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + itemsTab = build.itemsTab + mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local unique = new("Item"):Item("Rarity: Unique\nGoldrim\nLeather Cap\n+30% to all Elemental Resistances") + itemsTab:AddItem(unique, true) + calculate() + assert(itemsTab:SetViewItemSet(mercSet.id, "MERCENARY")) + local calc = build.calcsTab:GetMiscCalculator() + local uniqueError = "Helmet: requires a modifier allowing your Mercenary to equip Unique Helmets" + local preview = calc(itemsTab:ItemCalculationOverride("Helmet", unique)) + mercSet.Helmet.selItemId = unique.id + local equipped = calc({ comparisonActor = "MERCENARY" }) + local removed = calc(itemsTab:ItemCalculationOverride("Helmet", nil)) + mercSet.Helmet.selItemId = 0 + local cleared = calc({ comparisonActor = "MERCENARY" }) + assert.are.equal(uniqueError, equipped.ActorUnavailableMessage) + assert.is_nil(cleared.ActorUnavailableMessage) + assert.are.equal(equipped.ActorUnavailableMessage, preview.ActorUnavailableMessage) + assert.is_nil(removed.ActorUnavailableMessage) + assert.is_truthy(cleared.Life) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + itemsTab = build.itemsTab + mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local mainDagger = new("Item"):Item("Rarity: Normal\nGlass Shank") + local offDagger = new("Item"):Item("Rarity: Normal\nGlass Shank") + local previewWand = new("Item"):Item("Rarity: Normal\nDriftwood Wand") + itemsTab:AddItem(mainDagger, true) + itemsTab:AddItem(offDagger, true) + itemsTab:AddItem(previewWand, true) + mercSet["Weapon 1"].selItemId = mainDagger.id + mercSet["Weapon 2"].selItemId = offDagger.id + calculate() + assert(itemsTab:SetViewItemSet(mercSet.id, "MERCENARY")) + calc = build.calcsTab:GetMiscCalculator() + local dualWield = calc({ comparisonActor = "MERCENARY" }) + local wandPreview = calc(itemsTab:ItemCalculationOverride("Weapon 1", previewWand)) + assert.is_nil(dualWield.ActorUnavailableMessage) + assert.matches("Weapon 2: invalid base slot or weapon configuration", wandPreview.ActorUnavailableMessage) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + itemsTab = build.itemsTab + local playerSetId = itemsTab.activeItemSetId + assert(build.itemsTab:SetActorItemSet("MERCENARY", playerSetId, false)) + playerHelmet = new("Item"):Item([[Rarity: Rare +Player Helmet +Iron Hat +-------- ++100 to maximum Life]]) + replacementHelmet = new("Item"):Item([[Rarity: Rare +Replacement Helmet +Iron Hat +-------- ++1000 to maximum Life]]) + itemsTab:AddItem(playerHelmet, true) + itemsTab:AddItem(replacementHelmet, true) + itemsTab.activeItemSet.Helmet.selItemId = playerHelmet.id + calculate() + assert(itemsTab:SetViewItemSet(playerSetId, "MERCENARY")) + _, _, actorOutputs = build.calcsTab:GetMiscCalculator() + env = build.calcsTab.calcs.initEnv(build, "CALCULATOR", itemsTab:ItemCalculationOverride("Helmet", replacementHelmet)) + build.calcsTab.calcs.perform(env) + assert.are.equal(actorOutputs.PLAYER.Life, env.player.output.Life) + assert.is_true(env.mercenary.output.Life > actorOutputs.MERCENARY.Life) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + itemsTab = build.itemsTab + playerSetId = itemsTab.activeItemSetId + assert(build.itemsTab:SetActorItemSet("MERCENARY", playerSetId, false)) + playerHelmet = new("Item"):Item([[Rarity: Rare +Player Helmet +Iron Hat +-------- ++100 to maximum Life]]) + replacementHelmet = new("Item"):Item([[Rarity: Rare +Replacement Helmet +Iron Hat +-------- ++1000 to maximum Life]]) + itemsTab:AddItem(playerHelmet, true) + itemsTab:AddItem(replacementHelmet, true) + itemsTab.activeItemSet.Helmet.selItemId = playerHelmet.id + calculate() + assert(itemsTab:SetViewItemSet(playerSetId, "PLAYER")) + _, _, actorOutputs = build.calcsTab:GetMiscCalculator() + env = build.calcsTab.calcs.initEnv(build, "CALCULATOR", itemsTab:ItemCalculationOverride("Helmet", replacementHelmet)) + build.calcsTab.calcs.perform(env) + assert.is_true(env.player.output.Life > actorOutputs.PLAYER.Life) + assert.are.equal(actorOutputs.MERCENARY.Life, env.mercenary.output.Life) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + itemsTab = build.itemsTab + local configuredGuardianSet = itemsTab:NewItemSet() + configuredGuardianSet.title = "Configured Guardian" + table.insert(itemsTab.itemSetOrderList, configuredGuardianSet.id) + local selectedGuardianSet = itemsTab:NewItemSet() + selectedGuardianSet.title = "Trader Guardian" + table.insert(itemsTab.itemSetOrderList, selectedGuardianSet.id) + + local configuredHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + local selectedHelmet = new("Item"):Item([[Rarity: Rare +Selected Guardian Helmet +Iron Hat +-------- ++10 to maximum Life]]) + replacementHelmet = new("Item"):Item([[Rarity: Rare +Replacement Guardian Helmet +Iron Hat +-------- ++100 to maximum Life]]) + itemsTab:AddItem(configuredHelmet, true) + itemsTab:AddItem(selectedHelmet, true) + itemsTab:AddItem(replacementHelmet, true) + configuredGuardianSet.Helmet.selItemId = configuredHelmet.id + selectedGuardianSet.Helmet.selItemId = selectedHelmet.id + + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + guardianGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + build.mainSocketGroup = #build.skillsTab.socketGroupList + guardianGem = nil + for _, gem in ipairs(guardianGroup.gemList) do + if gem.nameSpec == "Animate Guardian" or gem.gemData and gem.gemData.name == "Animate Guardian" or gem.grantedEffect and gem.grantedEffect.name == "Animate Guardian" then + guardianGem = gem + break + end + end + guardianGem = assert(guardianGem) + guardianGem.skillMinionItemSet = selectedGuardianSet.id + guardianGem.skillMinionItemSetCalcs = selectedGuardianSet.id + + calculate() + itemsTab:SetViewItemSet(selectedGuardianSet.id) + local tradeQueryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator(itemsTab.tradeQuery) + tradeQueryGenerator:StartQuery(itemsTab.slots.Helmet, { + itemSetId = selectedGuardianSet.id, + influence1 = 1, + influence2 = 1, + statWeights = { { stat = "Life", weightMult = 1 } }, + requiredMods = { }, + }) + tradeQueryGenerator.calcContext.co = nil + local baseOutput = tradeQueryGenerator.calcContext.baseOutput + local replacementOutput = tradeQueryGenerator.calcContext.calcFunc({ + itemSetId = selectedGuardianSet.id, + comparisonActor = "PLAYER", + repSlotName = "Helmet", + repItem = replacementHelmet, + }) + + assert.are.equal(baseOutput.Life, replacementOutput.Life) + assert.is_true(replacementOutput.Minion.Life > baseOutput.Minion.Life) + end) + + it("applies Animate Guardian extra auras to the player and Mercenary when AG is not the main skill", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local itemsTab = build.itemsTab + local guardianSet = itemsTab:NewItemSet() + guardianSet.title = "Animate Guardian" + table.insert(itemsTab.itemSetOrderList, guardianSet.id) + + local leerCast = new("Item"):Item([[Rarity: Rare +Leer Cast +Festival Mask +You and nearby allies gain 50% increased Damage]]) + local kingmaker = new("Item"):Item([[Rarity: Rare +Kingmaker +Despot Axe +Nearby Allies have Culling Strike +Nearby Allies have +50% to Critical Strike Multiplier +Nearby Allies have +10 Fortification]]) + itemsTab:AddItem(leerCast, true) + itemsTab:AddItem(kingmaker, true) + guardianSet.Helmet.selItemId = leerCast.id + guardianSet["Weapon 1"].selItemId = kingmaker.id + + build.skillsTab:PasteSocketGroup("Precision 20/0 1") + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + build.mainSocketGroup = 1 + local guardianGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + local guardianGem + for _, gem in ipairs(guardianGroup.gemList) do + if gem.nameSpec == "Animate Guardian" or gem.gemData and gem.gemData.name == "Animate Guardian" or gem.grantedEffect and gem.grantedEffect.name == "Animate Guardian" then + guardianGem = gem + break + end + end + guardianGem = assert(guardianGem) + guardianGem.skillMinionItemSet = guardianSet.id + guardianGem.skillMinionItemSetCalcs = guardianSet.id + + local env = calculate() + assert.is_nil(env.minion) + local guardian + for _, skill in ipairs(env.player.activeSkillList) do + if skill.minion and skill.minion.itemSet == guardianSet then + guardian = skill.minion + break + end + end + assert.is_not_nil(guardian) + assert.are.equal(leerCast, guardian.itemList.Helmet) + assert.are.equal(kingmaker, guardian.itemList["Weapon 1"]) + + local playerFort = env.player.modDB:Sum("BASE", nil, "MinimumFortification") + local mercFort = env.mercenary.modDB:Sum("BASE", nil, "MinimumFortification") + local playerCull = env.player.modDB:Max(nil, "CullPercent") or 0 + local mercCull = env.mercenary.modDB:Max(nil, "CullPercent") or 0 + local playerDamage = env.player.modDB:Sum("INC", nil, "Damage") + local mercDamage = env.mercenary.modDB:Sum("INC", nil, "Damage") + local playerCritMulti = env.player.modDB:Sum("BASE", nil, "CritMultiplier") + local mercCritMulti = env.mercenary.modDB:Sum("BASE", nil, "CritMultiplier") + assert.is_true(playerFort >= 10, "player should receive Kingmaker fortification") + assert.is_true(mercFort >= 10, "Mercenary should receive Kingmaker fortification") + assert.is_true(playerCull >= 10, "player should receive Kingmaker culling strike") + assert.is_true(mercCull >= 10, "Mercenary should receive Kingmaker culling strike") + assert.is_true(playerDamage >= 50, "player should receive Leer Cast extra aura") + assert.is_true(mercDamage >= 50, "Mercenary should receive Leer Cast extra aura") + assert.is_true(playerCritMulti >= 50, "player should receive Kingmaker crit multiplier") + assert.is_true(mercCritMulti >= 50, "Mercenary should receive Kingmaker crit multiplier") + + guardianGem.enabled = false + env = calculate() + assert.is_true(env.player.modDB:Sum("BASE", nil, "MinimumFortification") < playerFort) + assert.is_true(env.mercenary.modDB:Sum("BASE", nil, "MinimumFortification") < mercFort) + assert.is_true((env.player.modDB:Max(nil, "CullPercent") or 0) < playerCull) + assert.is_true((env.mercenary.modDB:Max(nil, "CullPercent") or 0) < mercCull) + assert.is_true(env.player.modDB:Sum("INC", nil, "Damage") < playerDamage) + assert.is_true(env.mercenary.modDB:Sum("INC", nil, "Damage") < mercDamage) + assert.is_true(env.player.modDB:Sum("BASE", nil, "CritMultiplier") < playerCritMulti) + assert.is_true(env.mercenary.modDB:Sum("BASE", nil, "CritMultiplier") < mercCritMulti) + end) + + it("expands anoints, sockets, presence implicits, and strips granted skills", function() + allocate("Legendary Arms") + allocate("Legendary Helmets") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local baseline = calculate().mercenary + local baselineFireResist = baseline.output.FireResist + local baselineDamage = baseline.modDB:Sum("INC", nil, "Damage") + local baselineMoreDamage = baseline.modDB:More(nil, "Damage") + local presenceDamage = { + name = "Damage", type = "INC", value = 20, source = "Presence Test", flags = 0, keywordFlags = 0, + { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" }, + } + local item = { + id = 9003, + name = "Mercenary Test Helmet", + type = "Helmet", + base = { type = "Helmet" }, + rarity = "UNIQUE", + requirements = { level = 1, dex = 1 }, + grantedSkills = { }, + modList = { + { name = "GrantedPassive", type = "LIST", value = "diamond skin", source = "Test", flags = 0, keywordFlags = 0 }, + { name = "Keystone", type = "LIST", value = "resolute technique", source = "Test", flags = 0, keywordFlags = 0 }, + presenceDamage, + }, + implicitModLines = { { line = "While a Unique Enemy is in your Presence, 20% increased Damage", modList = { presenceDamage } } }, + } + build.itemsTab.items[item.id] = item + equipmentSlot("Helmet").selItemId = item.id + build.configTab.input.enemyIsBoss = "None" + local mercenary = calculate().mercenary + assert.are.equal(baselineFireResist + 15, mercenary.output.FireResist) + -- Presence implicits are always active on hired Mercenaries, even with no Unique enemy. + assert.are.equal(baselineDamage + 20, mercenary.modDB:Sum("INC", nil, "Damage")) + assert.are.equal(round(baselineMoreDamage * 1.08, 2), mercenary.modDB:More(nil, "Damage")) + assert.is_true(mercenary.modDB:Flag(nil, "CannotBeEvaded")) + assert.is_true(mercenary.modDB:Flag(nil, "NeverCrit")) + local _, _, actorBases = build.calcsTab:GetMiscCalculator() + assert.are.near(mercenary.output.CombinedDPS, actorBases.MERCENARY.CombinedDPS, 10 ^ -6) + + fresh() + allocate("Legendary Helmets") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + baselineDamage = calculate().mercenary.modDB:Sum("INC", nil, "Damage") + local againstUnique = { + name = "Damage", type = "INC", value = 15, source = "Against Unique Test", flags = 0, keywordFlags = 0, + { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" }, + } + item = { + id = 9005, + name = "Mercenary Against Unique Helmet", + type = "Helmet", + base = { type = "Helmet" }, + rarity = "UNIQUE", + requirements = { level = 1, dex = 1 }, + grantedSkills = { }, + modList = { againstUnique }, + explicitModLines = { { line = "15% increased Damage against Unique Enemies", modList = { againstUnique } } }, + } + build.itemsTab.items[item.id] = item + equipmentSlot("Helmet").selItemId = item.id + build.configTab.input.enemyIsBoss = "None" + assert.are.equal(baselineDamage, calculate().mercenary.modDB:Sum("INC", nil, "Damage")) + build.configTab.input.enemyIsBoss = "Pinnacle" + assert.are.equal(baselineDamage + 15, calculate().mercenary.modDB:Sum("INC", nil, "Damage")) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + baseline = calculate().mercenary + local baselineLife = baseline.output.Life + local baselineBaseLife = baseline.modDB:Sum("BASE", nil, "Life") + item = { + id = 9004, + name = "Mercenary Socket Test", + type = "Helmet", + base = { type = "Helmet" }, + rarity = "RARE", + requirements = { dex = 1 }, + grantedSkills = { }, + sockets = { { color = "R", group = 1 }, { color = "G", group = 1 } }, + modList = { + { name = "Life", type = "BASE", value = 40, source = "Test", flags = 0, keywordFlags = 0, + { type = "Multiplier", var = "EmptyRedSocketsInAnySlot" } }, + }, + } + build.itemsTab.items[item.id] = item + equipmentSlot("Helmet").selItemId = item.id + mercenary = calculate().mercenary + assert.are.equal(1, mercenary.modDB.multipliers.EmptyRedSocketsInAnySlot) + assert.are.equal(1, mercenary.modDB.multipliers.EmptyGreenSocketsInAnySlot) + assert.are.equal(baselineBaseLife + 40, mercenary.modDB:Sum("BASE", nil, "Life")) + assert.is_true(mercenary.output.Life > baselineLife) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + baseline = calculate().mercenary + local helmet = { + id = 9005, name = "Mercenary Abyss Helmet", type = "Helmet", base = { type = "Helmet" }, rarity = "RARE", + requirements = { dex = 1 }, grantedSkills = { }, sockets = { { color = "A", group = 1 } }, abyssalSocketCount = 1, modList = { }, + } + local jewel = { + id = 9006, name = "Mercenary Abyss Jewel", type = "Jewel", base = { type = "Jewel", subType = "Abyss" }, rarity = "RARE", + requirements = { level = 1 }, grantedSkills = { }, modList = { + { name = "Life", type = "BASE", value = 40, source = "Test", flags = 0, keywordFlags = 0 }, + }, + } + build.itemsTab.items[helmet.id], build.itemsTab.items[jewel.id] = helmet, jewel + equipmentSlot("Helmet").selItemId = helmet.id + equipmentSlot("Helmet Abyssal Socket 1").selItemId = jewel.id + mercenary = calculate().mercenary + assert.are.equal(baseline.modDB:Sum("BASE", nil, "Life") + 40, mercenary.modDB:Sum("BASE", nil, "Life")) + assert.are.equal(jewel, mercenary.itemList["Helmet Abyssal Socket 1"]) + + local itemsTab = build.itemsTab + assert(itemsTab:SetViewItemSet(assert(build.mercenaryTab:GetItemSet(true)).id)) + local calcFunc, _, actorOutputs = build.calcsTab:GetMiscCalculator() + local removed = calcFunc(itemsTab:ItemCalculationOverride("Helmet Abyssal Socket 1", nil)) + assert.is_true(removed.Life < actorOutputs.MERCENARY.Life) + local withJewelEnv = build.calcsTab.calcs.initEnv(build, "CALCULATOR") + local removedEnv = build.calcsTab.calcs.initEnv(build, "CALCULATOR", itemsTab:ItemCalculationOverride("Helmet Abyssal Socket 1", nil)) + assert.are.equal(jewel, withJewelEnv.mercenary.itemList["Helmet Abyssal Socket 1"]) + assert.is_nil(removedEnv.mercenary.itemList["Helmet Abyssal Socket 1"]) + assert.are.equal(withJewelEnv.mercenary.modDB:Sum("BASE", nil, "Life") - 40, removedEnv.mercenary.modDB:Sum("BASE", nil, "Life")) + + fresh() + configure("ChaosMinionWitch", "ChaosMinionWitchChaosHitNoble", "DarkPactMercenary") + allocate("Legendary Helmets") + local baselineMana = calculate().mercenary.modDB:Sum("BASE", nil, "Mana") + local ebers = new("Item"):Item([[Rarity: Unique +Eber's Unification +Hubris Circlet +Trigger Level 10 Void Gaze when you use a Skill +150% increased Energy Shield ++80 to maximum Mana +50% increased Stun and Block Recovery +Gain 8% of Elemental Damage as Extra Chaos Damage +]]) + assert.are.equal("VoidGaze", ebers.grantedSkills[1].skillId) + build.itemsTab:AddItem(ebers, true) + equipmentSlot("Helmet").selItemId = ebers.id + local env = calculate() + assert.is_nil(env.mercenaryCalculationErrors and env.mercenaryCalculationErrors[1], table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_table(env.mercenary) + assert.are.equal(ebers, env.mercenary.itemList.Helmet) + assert.are.equal(baselineMana + 80, env.mercenary.modDB:Sum("BASE", nil, "Mana")) + assert.are.equal(8, env.mercenary.modDB:Sum("BASE", nil, "ElementalDamageGainAsChaos")) + assert.are.equal(50, env.mercenary.modDB:Sum("INC", nil, "StunRecovery")) + assert.are.equal(0, #env.mercenary.modDB:List(nil, "ExtraSkill")) + for _, skill in ipairs(env.mercenary.activeSkillList) do + assert.are_not.equal("VoidGaze", skill.activeEffect.grantedEffect.id) + end + end) + + it("includes Mercenary Mirage in Full DPS and uses actor-local count-once", function() + configure("NonEleBowRanger", "NonEleBowRangerChaos", "CausticArrowMercenary", { + includeInFullDPS = true, + supports = { { id = "MirageArcherHigh", tier = 3 } }, + }) + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9014, 9015 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + local mercenary = assert(calculate().mercenary) + assert.is_table(mercenary.mainSkill.mirage) + assert.is_true(mercenary.mainSkill.mirage.output.TotalDPS > 0) + local mirageBreakdown + for _, skillDPS in ipairs(mercenary.output.SkillDPS) do + if skillDPS.source == "Mercenary Mirage" then mirageBreakdown = skillDPS break end + end + assert.is_table(mirageBreakdown) + assert.are.near(mercenary.mainSkill.mirage.output.TotalDPS, mirageBreakdown.dps, 10 ^ -6) + assert.are.near(mercenary.output.CombinedDPS, mercenary.output.FullDPS, 10 ^ -6) + assert.is_true(not mercenary.mainSkill.skillCfg.skillCond.usedByMirage) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { includeInFullDPS = true }) + local withoutMirage = assert(calculate().mercenary.output.CombinedDPS) + build.itemsTab:CreateDisplayItemFromRaw([[Rarity: NORMAL +Crude Bow +Sockets: G-G-G-G-G-G]]) + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Mirage Archer 20/0 1\nRain of Arrows 20/0 1\n") + local env = calculate() + assert.is_table(env.mercenary) + assert.is_true(not env.mercenary.mainSkill.skillCfg.skillCond.usedByMirage) + assert.are.near(withoutMirage, env.mercenary.output.CombinedDPS, 10 ^ -6) + local again = calculate() + assert.is_true(not again.mercenary.mainSkill.skillCfg.skillCond.usedByMirage) + assert.are.near(withoutMirage, again.mercenary.output.CombinedDPS, 10 ^ -6) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarSpectres", "AbsolutionMercenary", { + includeInFullDPS = true, + count = 3, + }) + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.input.absolutionSkillDamageCountedOnce = true + build.configTab:BuildModList() + env = calculate() + assert.is_true(env.skillsUsed.Absolution) + assert.are.near(env.mercenary.output.TotalDPS + env.mercenaryMinion.output.TotalDPS * 3, env.mercenary.output.FullDPS, 10 ^ -6) + + fresh() + configure("AurasMinionsTemplar", "AurasMinionsTemplarSpectres", "AbsolutionMercenary", { + includeInFullDPS = true, + count = 3, + }) + build.configTab.input.absolutionSkillDamageCountedOnce = true + build.configTab:BuildModList() + env = calculate() + assert.are.near(env.mercenary.output.TotalDPS * 3 + env.mercenaryMinion.output.TotalDPS * 3, env.mercenary.output.FullDPS, 10 ^ -6) + + fresh() + -- counts only the strongest Decay in Full DPS + local wand = new("Item"):Item("Rarity: RARE\nDecay Test\nGoat's Horn\nImplicits: 0\nYour Hits inflict Decay, dealing 700 Chaos Damage per second for 8 seconds\n") + build.itemsTab:AddItem(wand, true) + build.itemsTab.slots["Weapon 1"].selItemId = wand.id + build.itemsTab.activeItemSet["Weapon 1"].selItemId = wand.id + build.skillsTab:PasteSocketGroup("Lightning Trap 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + runCallback("OnFrame") + local trapDecay = calcs.calcFullDPS(build, "CALCULATOR", { }).decayDPS + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].enabled = false + build.skillsTab:PasteSocketGroup("Lightning Spire Trap 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + runCallback("OnFrame") + local spireDecay = calcs.calcFullDPS(build, "CALCULATOR", { }).decayDPS + build.skillsTab.socketGroupList[1].enabled = true + runCallback("OnFrame") + local both = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.is_true(trapDecay > 0) + assert.is_true(spireDecay > 0) + assert.are.near(math.max(trapDecay, spireDecay), both.decayDPS, 10 ^ -6) + assert.is_true(both.decayDPS < trapDecay + spireDecay - 1) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { includeInFullDPS = true }) + wand = decayItem("Goat's Horn", 9101) + equipmentSlot("Weapon 1").selItemId = wand.id + setMercenaryFullDPS({ "LightningTrapMercenary" }) + trapDecay = calcs.calcFullDPS(build, "CALCULATOR", { }).decayDPS + setMercenaryFullDPS({ "LightningSpireTrapMercenary" }) + spireDecay = calcs.calcFullDPS(build, "CALCULATOR", { }).decayDPS + setMercenaryFullDPS({ "LightningTrapMercenary", "LightningSpireTrapMercenary" }) + both = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.is_true(trapDecay > 0) + assert.is_true(spireDecay > 0) + assert.are.near(math.max(trapDecay, spireDecay), both.decayDPS, 10 ^ -6) + assert.are.near(both.decayDPS, namedDps(both.mercenarySkills, "Best Decay DPS"), 10 ^ -6) + assert.is_true(both.decayDPS < trapDecay + spireDecay - 1) + + fresh() + configure("NonEleBowRanger", "NonEleBowRangerChaos", "CausticArrowMercenary", { + includeInFullDPS = true, + supports = { { id = "MirageArcherHigh", tier = 3 } }, + }) + local bow = decayItem("Crude Bow", 9102) + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + quiver.id = 9103 + build.itemsTab.items[quiver.id] = quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + local env = calculate() + assert.is_table(env.mercenary.mainSkill.mirage) + local sourceDecay = env.mercenary.output.DecayDPS or 0 + local mirageDecay = env.mercenary.mainSkill.mirage.output.DecayDPS or 0 + assert.is_true(sourceDecay > 0) + assert.is_true(mirageDecay > 0) + local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.are.near(math.max(sourceDecay, mirageDecay), fullDPS.decayDPS, 10 ^ -6) + assert.are.near(fullDPS.decayDPS, namedDps(fullDPS.mercenarySkills, "Best Decay DPS"), 10 ^ -6) + + fresh() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { includeInFullDPS = true }) + local mercWand = decayItem("Goat's Horn", 9104) + equipmentSlot("Weapon 1").selItemId = mercWand.id + local playerWand = new("Item"):Item("Rarity: RARE\nDecay Test\nGoat's Horn\nImplicits: 0\nYour Hits inflict Decay, dealing 700 Chaos Damage per second for 8 seconds\n") + build.itemsTab:AddItem(playerWand, true) + build.itemsTab.slots["Weapon 1"].selItemId = playerWand.id + build.itemsTab.activeItemSet["Weapon 1"].selItemId = playerWand.id + build.skillsTab:PasteSocketGroup("Lightning Trap 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + build.mainSocketGroup = #build.skillsTab.socketGroupList + env = calculate() + local playerDecay = env.player.output.DecayDPS or 0 + local mercDecay = env.mercenary.output.DecayDPS or 0 + assert.is_true(playerDecay > 0) + assert.is_true(mercDecay > 0) + fullDPS = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.are.near(math.max(playerDecay, mercDecay), fullDPS.decayDPS, 10 ^ -6) + assert.are.near(mercDecay, namedDps(fullDPS.mercenarySkills, "Best Decay DPS"), 10 ^ -6) + end) + + local function mercenaryFullDPS() + local full = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.is_true(full.mercenaryDPS > 0) + return full.mercenaryDPS + end + + it("keeps equipped Mercenary keystones when a player Full DPS skill is also calculated", function() + allocate("Legendary Amulets") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { includeInFullDPS = true }) + local amulet = new("Item"):Item([[Rarity: UNIQUE +Xoph's Blood +Amber Amulet +Requires Level 64 +Implicits: 1 ++25 to Strength +10% increased Strength +10% increased maximum Life ++30% to Fire Resistance +Damage Penetrates 10% Fire Resistance +Cover Enemies in Ash when they Hit you +Avatar of Fire +]]) + build.itemsTab:AddItem(amulet, true) + equipmentSlot("Amulet").selItemId = amulet.id + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + local playerGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + playerGroup.includeInFullDPS = false + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "; ")) + assert.is_true(env.mercenary.calcEnv.keystonesAdded["Avatar of Fire"]) + local alone = mercenaryFullDPS() + playerGroup.includeInFullDPS = true + assert.are.near(alone, mercenaryFullDPS(), 1e-4) + + fresh() + -- keeps inherent Mercenary keystones when a player Full DPS skill is also calculated + configureSkill("BoneshatterMercenary", { includeInFullDPS = true }) + local mace = new("Item"):Item("Rarity: Normal\nDriftwood Club") + build.itemsTab:AddItem(mace, true) + equipmentSlot("Weapon 1").selItemId = mace.id + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + local playerGroup = build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList] + playerGroup.includeInFullDPS = false + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "; ")) + assert.is_true(env.mercenary.calcEnv.keystonesAdded["Resolute Technique"]) + local alone = mercenaryFullDPS() + playerGroup.includeInFullDPS = true + assert.are.near(alone, mercenaryFullDPS(), 1e-4) + + fresh() + -- does not grow Mercenary Full DPS merely because extra Full DPS passes ran + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { includeInFullDPS = true }) + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.input.buffOnslaught = true + setMercenaryFullDPS({ "LightningTrapMercenary" }) + local trapOnly = namedDps(calcs.calcFullDPS(build, "CALCULATOR", { }).mercenarySkills, "Lightning Trap") + setMercenaryFullDPS({ "LightningSpireTrapMercenary" }) + local spireOnly = namedDps(calcs.calcFullDPS(build, "CALCULATOR", { }).mercenarySkills, "Lightning Spire Trap") + assert.is_true(trapOnly > 0) + assert.is_true(spireOnly > 0) + setMercenaryFullDPS({ "LightningTrapMercenary", "LightningSpireTrapMercenary" }) + local both = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.are.near(trapOnly, namedDps(both.mercenarySkills, "Lightning Trap"), 10 ^ -4) + assert.are.near(spireOnly, namedDps(both.mercenarySkills, "Lightning Spire Trap"), 10 ^ -4) + + fresh() + -- does not rebuild after the final player Full DPS skill when the Mercenary is excluded + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + build.mainSocketGroup = #build.skillsTab.socketGroupList + calculate() + + local originalInitEnv = calcs.initEnv + local initEnvCalls = 0 + calcs.initEnv = function(...) + initEnvCalls = initEnvCalls + 1 + return originalInitEnv(...) + end + local ok, fullDPS = pcall(calcs.calcFullDPS, build, "CALCULATOR", { }) + calcs.initEnv = originalInitEnv + + assert.is_true(ok, fullDPS) + assert.is_true(fullDPS.combinedDPS > 0) + assert.are.equal(0, #fullDPS.mercenarySkills) + assert.are.equal(1, initEnvCalls) + end) + + it("uniques named generic DoTs across actors and still stacks count", function() + local function grantedSkill(grantedEffect, flags) + return { + activeEffect = { grantedEffect = grantedEffect }, + skillFlags = flags or { }, + } + end + for _, case in ipairs({ + function() + local totals = { } + local identity = calcs.genericDotIdentity({ inheritedFrom = "EssenceDrainAltY", id = "EssenceDrainAltMercenary" }) + calcs.contributeGenericDot(totals, identity, { TotalDot = 100 }, { }, 1) + calcs.contributeGenericDot(totals, identity, { TotalDot = 80 }, { }, 1) + assert.are.equal(100, calcs.sumDotTotals(totals)) + calcs.contributeGenericDot(totals, identity, { TotalDot = 180 }, { }, 1) + assert.are.equal(180, calcs.sumDotTotals(totals)) + end, + function() + local totals = { } + calcs.contributeGenericDot(totals, calcs.genericDotIdentity({ id = "EssenceDrainAltY" }), { TotalDot = 80 }, { }, 1) + calcs.contributeGenericDot(totals, calcs.genericDotIdentity({ inheritedFrom = "EssenceDrainAltY", id = "EssenceDrainAltMercenary" }), { TotalDot = 150 }, { }, 1) + calcs.contributeGenericDot(totals, calcs.genericDotIdentity({ inheritedFrom = "EssenceDrainAltY", id = "EssenceDrainAltMercenaryEncounter" }), { TotalDot = 100 }, { }, 1) + assert.are.equal(150, calcs.sumDotTotals(totals)) + end, + function() + local totals = { } + calcs.contributeGenericDot(totals, calcs.genericDotIdentity({ inheritedFrom = "EssenceDrainAltY", id = "EssenceDrainAltMercenary" }), { TotalDot = 100 }, { }, 1) + calcs.contributeGenericDot(totals, calcs.genericDotIdentity({ inheritedFrom = "Bane", id = "BaneMercenary" }), { TotalDot = 40 }, { }, 1) + assert.are.equal(140, calcs.sumDotTotals(totals)) + end, + function() + local totals = { } + local identity = calcs.genericDotIdentity({ inheritedFrom = "ToxicRain", id = "ToxicRainMercenary" }) + calcs.contributeGenericDot(totals, identity, { TotalDot = 50 }, { DotCanStack = true }, 2) + calcs.contributeGenericDot(totals, identity, { TotalDot = 30 }, { DotCanStack = true }, 1) + assert.are.equal(130, calcs.sumDotTotals(totals)) + end, + function() + local totals = { } + calcs.contributeSkillGenericDot(totals, grantedSkill({ inheritedFrom = "SandstormChaosElementalSummoned", id = "SandstormChaosMercenary" }), { TotalDot = 100 }, 1) + calcs.contributeSkillGenericDot(totals, grantedSkill({ id = "SandstormChaosElementalSummoned" }), { TotalDot = 80 }, 1) + assert.are.equal(100, calcs.sumDotTotals(totals)) + end, + function() + local totals = { } + calcs.contributeSkillGenericDot(totals, grantedSkill({ id = "SandstormChaosElementalSummoned" }), { TotalDot = 90 }, 1) + calcs.contributeSkillGenericDot(totals, grantedSkill({ inheritedFrom = "SandstormChaosElementalSummoned", id = "SandstormChaosMercenary" }), { TotalDot = 70 }, 1) + assert.are.equal(90, calcs.sumDotTotals(totals)) + end, + function() + local totals = { } + calcs.contributeSkillGenericDot(totals, grantedSkill({ id = "SandstormChaosElementalSummoned" }), { TotalDot = 80 }, 1) + calcs.contributeSkillGenericDot(totals, grantedSkill({ id = "InfernalLegion" }), { TotalDot = 40 }, 1) + assert.are.equal(120, calcs.sumDotTotals(totals)) + end, + function() + local totals = { } + local summon = grantedSkill({ id = "SSMHolySpectresMercenary" }) + local minion = grantedSkill({ id = "ToxicRain" }, { DotCanStack = true }) + calcs.contributeSkillGenericDot(totals, minion, { TotalDot = 50 }, 2) + assert.are.equal(100, calcs.sumDotTotals(totals)) + calcs.contributeSkillGenericDot(totals, summon, { TotalDot = 50 }, 2) + assert.are.equal(150, calcs.sumDotTotals(totals)) + end, + }) do + case() + end + + configure("ChaosMinionWitch", "ChaosMinionWitchDot", "EssenceDrainAltMercenary", { includeInFullDPS = true }) + local staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + staff.id = 9106 + build.itemsTab.items[staff.id] = staff + equipmentSlot("Weapon 1").selItemId = staff.id + build.skillsTab:PasteSocketGroup("Essence Drain of Wickedness 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + build.mainSocketGroup = #build.skillsTab.socketGroupList + local env = calculate() + local playerDot = env.player.output.TotalDot or 0 + local mercDot = env.mercenary.output.TotalDot or 0 + assert.is_true(playerDot > 0) + assert.is_true(mercDot > 0) + local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.are.near(math.max(playerDot, mercDot), fullDPS.dotDPS, 10 ^ -6) + assert.are.near(mercDot, namedDps(fullDPS.mercenarySkills, "Full DoT DPS"), 10 ^ -6) + + fresh() + configure("ChaosMinionWitch", "ChaosMinionWitchDot", "EssenceDrainAltMercenary", { includeInFullDPS = true }) + staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + staff.id = 9107 + build.itemsTab.items[staff.id] = staff + equipmentSlot("Weapon 1").selItemId = staff.id + setMercenaryFullDPS({ "EssenceDrainAltMercenary" }) + local drain = calcs.calcFullDPS(build, "CALCULATOR", { }).dotDPS + setMercenaryFullDPS({ "BaneMercenary" }) + local bane = calcs.calcFullDPS(build, "CALCULATOR", { }).dotDPS + setMercenaryFullDPS({ "EssenceDrainAltMercenary", "BaneMercenary" }) + local both = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.is_true(drain > 0) + assert.is_true(bane > 0) + assert.are.near(drain + bane, both.dotDPS, 10 ^ -4) + assert.are.near(both.dotDPS, namedDps(both.mercenarySkills, "Full DoT DPS"), 10 ^ -6) + + fresh() + configure("NonEleBowRanger", "NonEleBowRangerChaos", "ToxicRainMercenary", { includeInFullDPS = true, count = 2 }) + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + bow.id, quiver.id = 9108, 9109 + build.itemsTab.items[bow.id], build.itemsTab.items[quiver.id] = bow, quiver + equipmentSlot("Weapon 1").selItemId, equipmentSlot("Weapon 2").selItemId = bow.id, quiver.id + env = calculate() + local onePod = env.mercenary.output.TotalDot or 0 + assert.is_true(onePod > 0) + fullDPS = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.are.near(onePod * 2, fullDPS.dotDPS, 10 ^ -4) + + fresh() + configure("ChaosMinionWitch", "ChaosMinionWitchDot", "SandstormChaosMercenary", { includeInFullDPS = true }) + staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + staff.id = 9110 + build.itemsTab.items[staff.id] = staff + equipmentSlot("Weapon 1").selItemId = staff.id + build.skillsTab:PasteSocketGroup("Summon Chaos Golem 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + build.mainSocketGroup = #build.skillsTab.socketGroupList + runCallback("OnFrame") + selectMinionSkill("SandstormChaosElementalSummoned") + env = calculate() + playerDot = env.minion.output.TotalDot or 0 + mercDot = env.mercenary.output.TotalDot or 0 + assert.is_true(playerDot > 0) + assert.is_true(mercDot > 0) + assert.are.not_equal(playerDot, mercDot) + fullDPS = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.are.near(math.max(playerDot, mercDot), fullDPS.dotDPS, 10 ^ -4) + assert.is_true(fullDPS.dotDPS < playerDot + mercDot - 1) + + fresh() + configure("ChaosMinionWitch", "ChaosMinionWitchDot", "EssenceDrainAltMercenary", { includeInFullDPS = true }) + staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + staff.id = 9111 + build.itemsTab.items[staff.id] = staff + equipmentSlot("Weapon 1").selItemId = staff.id + build.skillsTab:PasteSocketGroup("Summon Chaos Golem 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + build.mainSocketGroup = #build.skillsTab.socketGroupList + runCallback("OnFrame") + selectMinionSkill("SandstormChaosElementalSummoned") + env = calculate() + playerDot = env.minion.output.TotalDot or 0 + mercDot = env.mercenary.output.TotalDot or 0 + assert.is_true(playerDot > 0) + assert.is_true(mercDot > 0) + fullDPS = calcs.calcFullDPS(build, "CALCULATOR", { }) + assert.are.near(playerDot + mercDot, fullDPS.dotDPS, 10 ^ -4) + end) + + it("does not cap totem attack rate by mercenary recast cooldown", function() + configureSkill("VaalAncestralWarchiefMercenary") + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.mercenary.mainSkill.skillModList:Flag(env.mercenary.mainSkill.skillCfg, "TotemIgnoresCooldown")) + assert.is_true((env.mercenary.output.Cooldown or 0) > 0) + assert.is_true(env.mercenary.output.Speed > 1 / env.mercenary.output.Cooldown + 0.05) + end) + + it("keeps player flask activation while viewing another item set", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local granite = new("Item"):Item("Rarity: Magic\nChemist's Granite Flask of the Opossum\n12% increased Movement Speed during Effect") + build.itemsTab:AddItem(granite, true) + build.itemsTab.activeItemSet["Flask 1"].selItemId = granite.id + build.itemsTab.activeItemSet["Flask 1"].active = true + build.itemsTab.slots["Flask 1"].selItemId = granite.id + build.itemsTab.slots["Flask 1"].active = true + local env = calculate() + assert.is_true(env.player.modDB.conditions.UsingGraniteFlask) + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + assert(build.itemsTab:SetViewItemSet(mercSet.id)) + assert.is_not_true(build.itemsTab.slots["Flask 1"].active) + assert.is_true(build.itemsTab.activeItemSet["Flask 1"].active) + env = calculate() + assert.is_true(env.player.modDB.conditions.UsingGraniteFlask) + end) + + it("applies mercenary Elemental Equilibrium before player damage", function() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local withoutEE = env.player.output.TotalDPS + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList[1].text = elementalEquilibriumMod + env = calculate() + assert.is_true(env.mercenary.enemySourceDB:GetCondition("HitByFireDamage")) + assert.is_true(env.enemyDB:Flag(nil, "Condition:HasLightningExposure") or env.enemy.modDB.conditions.HasLightningExposure) + assert.is_true(env.player.output.TotalDPS > withoutEE) + + fresh() + -- applies player Elemental Equilibrium before mercenary damage + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary", { includeInFullDPS = true }) + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local withoutEE = env.mercenary.output.TotalDPS + local fullWithoutEE = env.player.output.FullDPS + allocate("Elemental Equilibrium") + env = calculate() + assert.is_true(env.player.enemySourceDB:GetCondition("HitByLightningDamage")) + assert.is_true(env.enemyDB:Flag(nil, "Condition:HasFireExposure") or env.enemy.modDB.conditions.HasFireExposure) + local automaticDPS = env.mercenary.output.TotalDPS + local automaticFull = env.player.output.FullDPS + local automaticFireResist = env.enemyDB:Sum("BASE", nil, "FireResist") + assert.is_true(automaticDPS > withoutEE) + assert.is_true(automaticFull > fullWithoutEE) + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.input.enemyConditionHitByLightningDamage = true + env = calculate() + assert.are.near(automaticDPS, env.mercenary.output.TotalDPS, 10 ^ -4) + assert.are.near(automaticFull, env.player.output.FullDPS, 10 ^ -4) + assert.are.equal(automaticFireResist, env.enemyDB:Sum("BASE", nil, "FireResist")) + + fresh() + -- keeps minion skills when both actors have Elemental Equilibrium + configureSkill("SSMSkeletalBossMercenary", { includeInFullDPS = true }) + table.insert(build.mercenaryTab.profile.skills, { id = "SSMPaganBishopMercenary", enabled = true, includeInFullDPS = true, count = 1, supports = { } }) + build.mercenaryTab:Changed() + build.skillsTab:PasteSocketGroup("Summon Raging Spirit 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + allocate("Elemental Equilibrium") + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList[1].text = elementalEquilibriumMod + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_table(env.player.mainSkill.minion) + assert.are.equal(env.minion, env.player.mainSkill.minion) + assert.is_true(#env.player.mainSkill.minion.activeSkillList > 0) + assert.is_table(env.mercenary.mainSkill.minion) + assert.are.equal(env.mercenaryMinion, env.mercenary.mainSkill.minion) + assert.is_true(#env.mercenary.mainSkill.minion.activeSkillList > 0) + calcs.buildOutput(build, "MAIN") + + fresh() + -- does not accumulate Ball Lightning hits when both actors have Elemental Equilibrium + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.skillsTab:PasteSocketGroup("Ball Lightning 20/0 1") + build.skillsTab.socketGroupList[1].gemList[1].skillPart = 2 + allocate("Elemental Equilibrium") + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local single = env.player.output.TotalDPS + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList[1].text = elementalEquilibriumMod + env = calculate() + assert.are.near(single, env.player.output.TotalDPS, 10 ^ -4) + + fresh() + -- uses stronger Mercenary EE exposure over an existing weaker exposure + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList[1].text = elementalEquilibriumMod + local before = calculate() + assert.is_true(before.mercenary.enemySourceDB:GetCondition("HitByLightningDamage")) + local beforeCold = before.enemyDB:Sum("BASE", nil, "ColdResist") + build.skillsTab:PasteSocketGroup("Frost Bomb 20/0 1") + local after = calculate() + assert.is_true(after.mercenary.enemySourceDB:GetCondition("HitByLightningDamage")) + assert.are.equal(beforeCold, after.enemyDB:Sum("BASE", nil, "ColdResist")) + + fresh() + -- clears HasLightningExposure when EE later hides that exposure + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "Nearby Enemies have Lightning Exposure" + local before = calculate() + assert.is_table(before.mercenary, table.concat(before.mercenaryCalculationErrors or { }, "\n")) + local beforeLightning = before.enemyDB:Sum("BASE", nil, "LightningResist") + assert.is_true(before.enemyDB:GetCondition("HasLightningExposure")) + configSet.actors.mercenary.customModsList[1].text = elementalEquilibriumMod + local after = calculate() + assert.is_true(after.mercenary.enemySourceDB:GetCondition("HitByLightningDamage")) + assert.are.equal(beforeLightning + 10, after.enemyDB:Sum("BASE", nil, "LightningResist")) + assert.is_not_true(after.enemyDB:GetCondition("HasLightningExposure")) + assert.is_not_true(after.enemyDB:Flag(nil, "Condition:HasLightningExposure") or after.enemy.modDB.conditions.HasLightningExposure) + assert.is_true(after.enemyDB:GetCondition("HasFireExposure") or after.enemyDB:Flag(nil, "Condition:HasFireExposure")) + assert.is_true(after.enemyDB:GetCondition("HasColdExposure") or after.enemyDB:Flag(nil, "Condition:HasColdExposure")) + end) + + it("previews supports for the selected non-main skill", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local tab = build.mercenaryTab + tab.profile.skills[2] = { id = "ZealotryMercenary", enabled = true, supports = { } } + tab.profile.mainSkillId = "ZealotryMercenary" + tab.selectedSkillIndex = 1 + tab:Changed() + calculate() + local base, modified + local original = build.AddStatComparesToTooltip + build.AddStatComparesToTooltip = function(_, _, before, after) + base, modified = before, after + end + local support = assert(build.data.mercenaries.supports.AddedLightningHigh) + local ok, err = pcall(tab.AddSupportTooltip, tab, new("Tooltip"):Tooltip(), support, 1, true) + build.AddStatComparesToTooltip = original + assert.is_true(ok, err) + assert.is_truthy(base and modified) + local hoveredDelta = (modified.CombinedDPS or 0) - (base.CombinedDPS or 0) + tab.profile.mainSkillId = "LightningTrapMercenary" + local expectedBefore = calculate().mercenary.output.CombinedDPS + tab.profile.skills[1].supports = { { id = "AddedLightningHigh", tier = 3 } } + local expectedAfter = calculate().mercenary.output.CombinedDPS + assert.are.near(expectedAfter - expectedBefore, hoveredDelta, 1e-8) + assert.is_true(hoveredDelta > 0) + end) + + it("applies mercenary Skitterbot shock and chill to the shared enemy", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "SummonSkitterbotsMercenary") + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.enemyDB:GetCondition("Shocked") or env.enemyDB:Flag(nil, "Condition:Shocked") or env.enemy.modDB.conditions.Shocked) + assert.is_true(env.enemyDB:GetCondition("Chilled") or env.enemyDB:Flag(nil, "Condition:Chilled") or env.enemy.modDB.conditions.Chilled) + assert.is_true((env.player.output.CurrentShock or 0) > 0) + assert.is_true((env.player.output.CurrentChill or 0) > 0) + end) + + it("scales mercenary abyss jewels by the parent item's socketed effect", function() + allocate("Legendary Belts") + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local mercSet = assert(build.mercenaryTab:GetItemSet(true)) + local belt = new("Item"):Item([[Rarity: UNIQUE +Darkness Enthroned +Stygian Vise +Has 1 Abyssal Socket +Has 1 Abyssal Socket +{range:1}(50-100)% increased Effect of Socketed Abyss Jewels]]) + local jewel = new("Item"):Item([[Rarity: Rare +Life Eye +Ghastly Eye Jewel ++40 to maximum Life]]) + build.itemsTab:AddItem(belt, true) + build.itemsTab:AddItem(jewel, true) + assert.are.equal(2, belt.socketedJewelEffectModifier) + mercSet.Belt.selItemId = belt.id + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local lifeWithoutJewel = env.mercenary.modDB:Sum("BASE", nil, "Life") + mercSet["Belt Abyssal Socket 1"].selItemId = jewel.id + env = calculate() + assert.are.equal(lifeWithoutJewel + 80, env.mercenary.modDB:Sum("BASE", nil, "Life")) + assert.is_not_nil(env.mercenary.itemList["Belt Abyssal Socket 1"]) + end) + + it("keeps spectre skill-id configuration visible for the owning actor", function() + local spectreId = "Metadata/Monsters/DemonModular/DemonModularBladeVortex" + assert.is_truthy(isValueInArray(build.data.minions[spectreId].skillList, "DemonModularBladeVortexSpectre")) + build.spectreList = { spectreId } + build.skillsTab:PasteSocketGroup("Raise Spectre 20/0 1") + local env = calculate() + assert.is_true(env.skillsUsed.DemonModularBladeVortexSpectre) + local option + for _, candidate in ipairs(configOptions) do + if candidate.var == "raiseSpectreBladeVortexBladeCount" then option = candidate break end + end + assert.is_true(configVisibility.isRelevantForBuild(assert(option), build, "player")) + + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "FissureSlamMercenary") + env = calculate() + assert.is_true(configVisibility.isRelevantForBuild(option, build, "player")) + assert.is_false(configVisibility.isRelevantForBuild(option, build, "mercenary")) + + fresh() + -- applies player spectre AllyModifier buffs to Mercenaries + local spectreId = "Metadata/Monsters/LeagueAzmeri/SpecialCorpses/VikingHigh" + assert.are.equal("Perfect Forest Warrior", build.data.minions[spectreId].name) + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "FissureSlamMercenary") + local env = calculate() + assert.is_not_true(env.player.modDB:Flag(nil, "Condition:Onslaught")) + assert.is_not_true(env.mercenary.modDB:Flag(nil, "Condition:Onslaught")) + + build.spectreList = { spectreId } + build.skillsTab:PasteSocketGroup("Raise Spectre 20/0 1") + env = calculate() + assert.is_not_nil(env.minion) + assert.are.equal(spectreId, env.minion.type) + assert.is_true(env.player.modDB:HasMod("FLAG", nil, "Condition:Onslaught")) + assert.is_true(env.mercenary.modDB:HasMod("FLAG", nil, "Condition:Onslaught")) + assert.is_true(env.player.modDB:Flag(nil, "Condition:Onslaught")) + assert.is_true(env.mercenary.modDB:Flag(nil, "Condition:Onslaught")) + if env.mercenaryMinion then + assert.is_true(env.mercenaryMinion.modDB:HasMod("FLAG", nil, "Condition:Onslaught")) + end + end) + + it("applies monster Soul Eater damage reduction to Mercenaries", function() + allocate("Legendary Gloves") + configure("ElementalWitch", "ElementalWitchLightning", "ArcMercenary") + local gloves = new("Item"):Item([[Rarity: UNIQUE +Soul Ascension +Carnal Mitts +Implicits: 0 +120% increased Evasion and Energy Shield +17% to Chaos Resistance +Eat a Soul when you Hit a Rare or Unique Enemy, no more than once every 0.5 seconds]]) + build.itemsTab:AddItem(gloves, true) + equipmentSlot("Gloves").selItemId = gloves.id + local config = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(config) + config.actors.mercenary.input.multiplierSoulEater = 0 + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local before = env.mercenary.output.FireMaximumHitTaken + local speed = env.mercenary.output.Speed + local playerBefore = env.player.output.FireMaximumHitTaken + config.actors.mercenary.input.multiplierSoulEater = 20 + env = calculate() + assert.is_true(env.mercenary.output.Speed > speed) + assert.is_true(env.mercenary.output.FireMaximumHitTaken > before) + assert.are.equal(playerBefore, env.player.output.FireMaximumHitTaken) + end) + + it("scales Mercenary quiver bonuses from Widowhail", function() + allocate("Legendary Arms") + configure("EleBowRanger", "EleBowRangerClones", "MirrorArrowMercenary") + local function add(raw) + local value = new("Item"):Item(raw) + build.itemsTab:AddItem(value, true) + return value + end + equipmentSlot("Weapon 1").selItemId = add("Rarity: Normal\nCrude Bow").id + equipmentSlot("Weapon 2").selItemId = add("Rarity: Rare\nReview Quiver\nTwo-Point Arrow Quiver\n+100 to maximum Life").id + local before = assert(calculate().mercenary).output.Life + equipmentSlot("Weapon 1").selItemId = add("Rarity: Unique\nWidowhail\nCrude Bow\n250% increased bonuses gained from Equipped Quiver").id + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal(250, env.mercenary.modDB:Sum("INC", nil, "EffectOfBonusesFromQuiver")) + assert.are.near(3.5, env.mercenary.modDB:Sum("BASE", nil, "WidowHailMultiplier"), 1e-9) + assert.is_true(env.mercenary.output.Life > before) + end) + + it("keeps the Mercenary in calculations when disabling the displayed skill", function() + configure("ElementalWitch", "ElementalWitchLightning", "ArcMercenary") + local tab = build.mercenaryTab + assert(tab:SetSkill(2, "SparkMercenary")) + assert.is_table(calculate().mercenary) + tab.selectedSkillIndex = 1 + tab.controls.skillEnabled.changeFunc(false) + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal("SparkMercenary", tab.profile.mainSkillId) + assert.are.equal("SparkMercenary", env.mercenary.mainSkill.mercenarySkill.id) + end) + + it("applies Mercenary socket occupancy to socket-property bonuses and empty-socket counts", function() + allocate("Legendary Rings") + allocate("Legendary Amulets") + configure("ElementalWitch", "ElementalWitchLightning", "ArcMercenary") + local emptyRing = new("Item"):Item([[Rarity: UNIQUE +Malachai's Artifice +Unset Ring +Sockets: W +Implicits: 1 +Has 1 Socket +-20% to all Elemental Resistances ++100% to Fire Resistance when Socketed with a Red Gem +All Sockets are White]]) + build.itemsTab:AddItem(emptyRing, true) + equipmentSlot("Ring 1").selItemId = emptyRing.id + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local before = env.mercenary.output.FireResistTotal + local occupiedRing = new("Item"):Item([[Rarity: UNIQUE +Malachai's Artifice +Unset Ring +Sockets: W +Socketed Gem: 1 Heavy Strike 20/0 +Implicits: 1 +Has 1 Socket +-20% to all Elemental Resistances ++100% to Fire Resistance when Socketed with a Red Gem +All Sockets are White]]) + build.itemsTab:AddItem(occupiedRing, true) + equipmentSlot("Ring 1").selItemId = occupiedRing.id + env = calculate() + assert.are.equal(before + 100, env.mercenary.output.FireResistTotal) + assert.are.equal(0, env.mercenary.modDB.multipliers.EmptyWhiteSocketsInAnySlot or 0) + + local amulet = new("Item"):Item([[Rarity: UNIQUE +The Untouched Soul +Gold Amulet +Variant: Pre 3.29.0 +Variant: Current +Selected Variant: 2 +Implicits: 1 +{range:1}(12-20)% increased Rarity of Items found ++40 to maximum Life for each Empty Red Socket on any Equipped Item ++225 to Accuracy Rating for each Empty Green Socket on any Equipped Item ++40 to maximum Mana for each Empty Blue Socket on any Equipped Item +{variant:1}+18% to all Elemental Resistances for each Empty White Socket on any Equipped Item +{variant:2}+12% to all Elemental Resistances for each Empty White Socket on any Equipped Item]]) + build.itemsTab:AddItem(amulet, true) + equipmentSlot("Amulet").selItemId = amulet.id + env = calculate() + local occupiedWithAmulet = env.mercenary.output.FireResistTotal + assert.are.equal(0, env.mercenary.modDB.multipliers.EmptyWhiteSocketsInAnySlot or 0) + equipmentSlot("Ring 1").selItemId = emptyRing.id + env = calculate() + assert.are.equal(1, env.mercenary.modDB.multipliers.EmptyWhiteSocketsInAnySlot) + assert.are.equal(occupiedWithAmulet - 100 + 12, env.mercenary.output.FireResistTotal) + end) + + it("scores support sort previews with the same dense list as SetSupport", function() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "FissureSlamMercenary") + local weapon = new("Item"):Item("Rarity: Normal\nStone Axe") + build.itemsTab:AddItem(weapon, true) + equipmentSlot("Weapon 1").selItemId = weapon.id + local tab = build.mercenaryTab + tab:EnsureData() + local skill = tab.profile.skills[1] + for _, id in ipairs({ "FistOfWarHigh", "AddedFireHigh" }) do + table.insert(skill.supports, { id = id, tier = assert(tab.data.supports[id]).variant }) + end + tab:Changed() + tab:RefreshControls() + tab.sortGemsByDPS = true + tab.sortGemsByDPSField = "CombinedDPS" + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local calc = build.calcsTab:GetMiscCalculator() + local first = table.remove(skill.supports, 1) + local removed = calc({ comparisonActor = "MERCENARY" }) + assert(not removed.ActorUnavailableMessage, removed.ActorUnavailableMessage) + table.insert(skill.supports, 1, first) + tab:QueueSupportSort(1) + while tab.supportSortCoroutine do tab:ProcessSupportSort() end + local removeEntry + for _, entry in ipairs(assert(tab.supportSortCache[1]).list) do + if not entry.id then removeEntry = entry end + end + assert.are.near(removed.CombinedDPS, assert(removeEntry).dps, 1e-8) + + skill.supports = { } + tab:Changed() + tab:RefreshControls() + tab:QueueSupportSort(3) + while tab.supportSortCoroutine do tab:ProcessSupportSort() end + local addEntry + for _, entry in ipairs(assert(tab.supportSortCache[3]).list) do + if entry.id == "AddedFireHigh" then addEntry = entry end + end + assert(addEntry) + assert(tab:SetSupport(3, addEntry.id)) + local added = calc({ comparisonActor = "MERCENARY" }) + assert(not added.ActorUnavailableMessage, added.ActorUnavailableMessage) + assert.are.near(added.CombinedDPS, addEntry.dps, 1e-8) + end) + + it("uses configured Flameblast stages in both MAIN and CALCS", function() + configureSkill("FlameblastMercenary") + build.mercenaryTab.profile.skills[1].skillStageCount = 1 + build.mercenaryTab:Changed() + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local function stageAfterFirst(actorEnv) + return actorEnv.mercenary.mainSkill.skillModList:Sum("BASE", nil, "Multiplier:FlameblastStageAfterFirst") + end + assert.are.equal(0, stageAfterFirst(env)) + assert.are.equal(0, stageAfterFirst(build.calcsTab.calcsEnv)) + end) + + it("applies Mercenary custom MORE mods in Full DPS without double-counting", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary", { includeInFullDPS = true }) + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.actors.mercenary.customModsList[1].text = "8% more Damage\n8% more Damage" + build.configTab:BuildModList() + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[#build.skillsTab.socketGroupList].includeInFullDPS = true + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local first = mercenaryFullDPS() + assert.are.near(first, mercenaryFullDPS(), 1e-4) + end) + + it("preserves imported party Destructive Link crit chance", function() + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.skillsTab.socketGroupList[1].includeInFullDPS = true + local party = build.partyTab.actor + build.partyTab:ParseBuffs(party.modDB, "MainHand.CritChance=25", "PartyMemberStats", party.output) + local link = modLib.createMod("MainHandCritIsEqualToParent", "FLAG", true, "Skill:DestructiveLink", 0, 0, { type = "GlobalEffect", effectType = "Link" }) + build.partyTab:ParseBuffs(party.Link, "Destructive Link\n100\n"..modLib.formatSourceMod(link), "Link") + build.configTab:BuildModList() + local env = calcs.initEnv(build, "CALCULATOR") + calcs.perform(env, true) + assert.are.equal(25, party.output.MainHand.CritChance) + assert.are.equal(25, calcs.actorMainHandSheetCritChance(party)) + assert.are.near(25, env.player.output.PreEffectiveCritChance, 1e-8) + end) + + it("rejects Mercenary item auras when the player equips Ichimonji", function() + configureSkill("FireballMercenary") + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "Your Mercenary can equip Unique Helmets" + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + local sword = new("Item"):Item("Rarity: Unique\nIchimonji\nCorsair Sword\nAllies' Aura Buffs do not affect you\nYour Aura Buffs do not affect allies") + build.itemsTab:AddItem(sword, true) + build.itemsTab.activeItemSet["Weapon 1"].selItemId = sword.id + local hat = new("Item"):Item("Rarity: Unique\nLeer Cast\nFestival Mask\nYou and nearby allies gain 50% increased Damage\n30% reduced Damage") + build.itemsTab:AddItem(hat, true) + local without = calculate() + assert.is_table(without.mercenary, table.concat(without.mercenaryCalculationErrors or { }, "\n")) + equipmentSlot("Helmet").selItemId = hat.id + local with = calculate() + assert.is_table(with.mercenary, table.concat(with.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal(hat, with.mercenary.itemList.Helmet) + assert.is_true(with.modDB:Flag(nil, "AlliesAurasCannotAffectSelf")) + assert.are.near(without.player.output.CombinedDPS, with.player.output.CombinedDPS, 1e-8) + end) + + it("applies Mercenary Vortex's guaranteed chill", function() + configureSkill("VortexMercenary") + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "100% increased Damage against Chilled Enemies" + build.skillsTab:PasteSocketGroup("Arc 20/0 1") + build.configTab:BuildModList() + local env = calcs.initEnv(build, "CALCULATOR") + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + calcs.perform(env, true) + assert.is_true(env.mercenary.mainSkill.skillTypes[SkillType.ChillingArea]) + assert.is_true(env.enemyDB:GetCondition("Chilled") or env.enemyDB:Flag(nil, "Condition:Chilled") or env.enemy.modDB.conditions.Chilled) + assert.is_true((env.player.output.CurrentChill or 0) > 0) + + fresh() + -- applies mercenary shock above the player's ailment cap + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local shockCapRing = new("Item"):Item("Rarity: RARE\nShock Cap\nIron Ring\nImplicits: 0\n+40% to Maximum Effect of Shock") + build.itemsTab:AddItem(shockCapRing, true) + equipmentSlot("Ring 1").selItemId = shockCapRing.id + build.configTab.input.conditionEnemyShocked = true + build.configTab.input.conditionShockEffect = 70 + local env = calculate(83) + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.are.equal(build.data.nonDamagingAilment.Shock.max, env.player.output.MaximumShock) + assert.are.equal(build.data.nonDamagingAilment.Shock.max + 40, env.mercenary.output.MaximumShock) + assert.are.equal(70, env.player.output.CurrentShock) + assert.are.equal(70, env.mercenary.output.CurrentShock) + assert.are.equal(70, env.enemyDB:Sum("BASE", nil, "Multiplier:ShockEffect")) + + fresh() + -- keeps Mercenary Assassin's Mark on a Hexproof enemy + configureSkill("AssassinsMarkMercenary") + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + build.itemsTab:AddItem(bow, true) + build.itemsTab:AddItem(quiver, true) + equipmentSlot("Weapon 1").selItemId = bow.id + equipmentSlot("Weapon 2").selItemId = quiver.id + build.configTab:BuildModList() + local env = calcs.initEnv(build, "CALCULATOR") + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + env.enemyDB:NewMod("Hexproof", "FLAG", true, "Review") + calcs.perform(env, true) + assert.is_true(env.enemyDB:GetCondition("Marked")) + assert.is_true(#env.curseSlots > 0) + end) + + it("sorts supports for the selected Mercenary skill when another skill is main", function() + configure("TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + local tab = build.mercenaryTab + tab.profile.skills[2] = { id = "ZealotryMercenary", enabled = true, supports = { } } + tab.profile.mainSkillId = "ZealotryMercenary" + tab.selectedSkillIndex = 1 + tab:Changed() + tab:RefreshControls() + tab.sortGemsByDPS, tab.sortGemsByDPSField = true, "CombinedDPS" + tab:QueueSupportSort(1) + while tab.supportSortCoroutine do tab:ProcessSupportSort() end + local scored + for _, row in ipairs(assert(tab.supportSortCache[1]).list) do + if row.id == "AddedLightningHigh" then scored = row.dps end + end + assert(scored) + assert.is_true(scored > 0) + tab.profile.mainSkillId = "LightningTrapMercenary" + tab.profile.skills[1].supports = { { id = "AddedLightningHigh", tier = assert(tab.data.supports.AddedLightningHigh).variant } } + local expected = calculate().mercenary.output.CombinedDPS + assert.are.near(expected, scored, 1e-8) + + fresh() + -- uses Average Hit when sorting Mercenary minion supports + configure("EleBowRanger", "EleBowRangerClones", "MirrorArrowMercenary") + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + build.itemsTab:AddItem(bow, true) + build.itemsTab:AddItem(quiver, true) + equipmentSlot("Weapon 1").selItemId = bow.id + equipmentSlot("Weapon 2").selItemId = quiver.id + local tab = build.mercenaryTab + tab.selectedSkillIndex = 1 + tab:Changed() + tab:RefreshControls() + tab.sortGemsByDPS, tab.sortGemsByDPSField = true, "AverageDamage" + tab:QueueSupportSort(1) + while tab.supportSortCoroutine do tab:ProcessSupportSort() end + local selectedRow + for _, row in ipairs(assert(tab.supportSortCache[1]).list) do + if row.id == "AddedColdHigh" then selectedRow = row break end + end + assert(selectedRow) + tab.profile.skills[1].supports = { { id = selectedRow.id, tier = selectedRow.tier } } + tab:Changed() + local env = calculate() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local output = assert(env.mercenary.output.Minion) + assert.are.near(output.AverageDamage, selectedRow.dps, 1e-8) + assert.are_not.equal(output.CombinedDPS, selectedRow.dps) + end) + + it("gives mercenaries player combat inherent mods, curse slots, skill setup, and aura accounting", function() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary") + local env = calculate() + local constants = build.data.characterConstants + assert.are.equal(1, env.mercenary.modDB:Sum("BASE", nil, "EnemyCurseLimit")) + assert.are.equal(constants["base_presence_radius"], env.mercenary.modDB:Sum("BASE", nil, "PresenceRadius")) + local bleedMore + for _, mod in ipairs(env.mercenary.modDB.mods.Damage or { }) do + if mod.type == "MORE" and mod.source == "Base" and mod.value == 200 and mod.keywordFlags == KeywordFlag.Bleed then + bleedMore = mod + end + end + assert.is_not_nil(bleedMore) + + local curseHelmet = new("Item"):Item("Rarity: Rare\nCurse Limit\nIron Hat\nYou can apply an additional Curse") + build.itemsTab:AddItem(curseHelmet, true) + equipmentSlot("Helmet").selItemId = curseHelmet.id + env = calculate() + assert.are.equal(2, env.mercenary.modDB:Sum("BASE", nil, "EnemyCurseLimit")) + + fresh() + configure("ChaosMinionWitch", "ChaosMinionWitchDot", "TemporalChainsMercenary") + local staff = new("Item"):Item("Rarity: Normal\nGnarled Branch") + build.itemsTab:AddItem(staff, true) + equipmentSlot("Weapon 1").selItemId = staff.id + local configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "You can apply an additional Curse" + build.skillsTab:PasteSocketGroup("Despair 20/0 1") + env = calculate() + local slotted, names = { }, { } + for _, slot in ipairs(env.curseSlots) do + slotted[slot.name] = true + table.insert(names, slot.name) + end + assert.is_true(slotted.Despair, table.concat(names, ", ")) + assert.is_true(slotted["Temporal Chains"], table.concat(names, ", ")) + assert.are.equal(2, #env.curseSlots) + + fresh() + configure("EleBowRanger", "EleBowRangerFire", "AlchemistsMarkMercenary") + build.mercenaryTab.profile.skills = { + { id = "AlchemistsMarkMercenary", enabled = true, supports = { } }, + { id = "FlammabilityBlasphemyMercenary", enabled = true, supports = { } }, + } + build.mercenaryTab.profile.mainSkillId = "AlchemistsMarkMercenary" + build.mercenaryTab:Changed() + local bow = new("Item"):Item("Rarity: Normal\nCrude Bow") + local quiver = new("Item"):Item("Rarity: Normal\nSerrated Arrow Quiver") + build.itemsTab:AddItem(bow, true) + build.itemsTab:AddItem(quiver, true) + equipmentSlot("Weapon 1").selItemId = bow.id + equipmentSlot("Weapon 2").selItemId = quiver.id + configSet = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(configSet) + configSet.customModsList[1].text = "You can apply an additional Curse" + build.skillsTab:PasteSocketGroup("Flammability 20/0 1") + env = calculate() + local mercCurses, curseNames = 0, { } + for _, slot in ipairs(env.curseSlots) do + table.insert(curseNames, slot.name..(slot.sourceActor == env.mercenary and "@merc" or "@other")) + if slot.sourceActor == env.mercenary then + mercCurses = mercCurses + 1 + end + end + assert.are.equal(1, env.mercenary.modDB:Sum("BASE", nil, "EnemyCurseLimit")) + assert.is_true(mercCurses <= 1, table.concat(curseNames, ", ")) + assert.are.equal(1, mercCurses, table.concat(curseNames, ", ")) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary", { + supports = { { id = "CombustionHigh", tier = 3 } }, + }) + local maul = new("Item"):Item("Rarity: Normal\nDriftwood Maul") + build.itemsTab:AddItem(maul, true) + equipmentSlot("Weapon 1").selItemId = maul.id + build.configTab.input.conditionEnemyIgnited = true + env = calculate() + local combustion + for _, value in ipairs(env.enemyDB:Tabulate("BASE", nil, "FireResist")) do + if value.mod.source == "Combustion" then combustion = value.value end + end + assert.are.equal(-10, combustion) + + fresh() + configureSkill("RallyingCryMercenary") + env = calculate() + assert.is_true(env.mercenary.modDB:Flag(nil, "RallyingActive")) + assert.is_true(env.mercenary.modDB:Sum("BASE", nil, "RallyingExertMoreDamagePerAlly") > 0) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "DeterminationMercenary") + local extraAura = modLib.createMod("Damage", "INC", 10, "TestExtraAura") + local extraHelmet = { + id = 9110, name = "Extra Aura Helm", type = "Helmet", base = { type = "Helmet" }, rarity = "RARE", + requirements = { str = 1 }, grantedSkills = { }, + modList = { + modLib.createMod("ExtraAuraEffect", "LIST", { mod = extraAura }), + modLib.createMod("ExtraAuraEffect", "LIST", { mod = copyTable(extraAura, true) }), + }, + } + build.itemsTab.items[extraHelmet.id] = extraHelmet + equipmentSlot("Helmet").selItemId = extraHelmet.id + env = calculate() + local extraAuraDamage = 0 + for _, value in ipairs(env.mercenary.modDB:Tabulate("INC", nil, "Damage")) do + if value.mod.source == "TestExtraAura" then extraAuraDamage = extraAuraDamage + value.value end + end + local auraEffect = calcLib.mod(env.mercenary.mainSkill.skillModList, env.mercenary.mainSkill.skillCfg, "AuraEffect", "BuffEffect", "BuffEffectOnSelf", "AuraEffectOnSelf") + assert.are.near(20 * auraEffect, extraAuraDamage, 0.51) + assert.is_true((env.mercenary.modDB.multipliers.AuraAffectingSelf or 0) >= 1) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "HeraldOfAshMercenary") + env = calculate() + assert.are.equal(1, env.mercenary.modDB.multipliers.Herald) + assert.is_true(env.mercenary.modDB.conditions.AffectedByHerald) + assert.is_nil(env.player.modDB.multipliers.Herald) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary") + local shaperHelmet = new("Item"):Item("Rarity: Rare\nShaper Helm\nIron Hat\nShaper Item") + local ironRing = new("Item"):Item("Rarity: Normal\nIron Ring") + build.itemsTab:AddItem(shaperHelmet, true) + build.itemsTab:AddItem(ironRing, true) + equipmentSlot("Helmet").selItemId = shaperHelmet.id + equipmentSlot("Ring 1").selItemId = ironRing.id + env = calculate() + assert.are.equal(1, env.mercenary.modDB.multipliers.ShaperItem) + assert.are.equal(1, env.mercenary.modDB.multipliers.HelmetItem) + assert.are.equal(1, env.mercenary.modDB.multipliers.RingItem) + assert.are.equal(1, env.mercenary.modDB.multipliers.IronRingEquipped) + + local wings = new("Item"):Item([[Rarity: Rare +Dual Test +Stone Axe +Implicits: 0 +Counts as Dual Wielding]]) + build.itemsTab:AddItem(wings, true) + equipmentSlot("Helmet").selItemId = 0 + equipmentSlot("Ring 1").selItemId = 0 + equipmentSlot("Weapon 1").selItemId = wings.id + equipmentSlot("Weapon 2").selItemId = 0 + env = calculate() + assert.is_not_nil(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + assert.is_true(env.mercenary.weaponData1.countsAsDualWielding) + assert.is_truthy(env.mercenary.weaponData2.type) + assert.is_true(env.mercenary.modDB.conditions.DualWielding) + local dualWieldSpeed + for _, mod in ipairs(env.mercenary.modDB.mods.Speed or { }) do + if mod.type == "MORE" and mod.source == "Base" and mod.value == constants["dual_wield_inherent_attack_speed_+%_final"] then + dualWieldSpeed = mod + end + end + assert.is_not_nil(dualWieldSpeed) + + fresh() + build.skillsTab:PasteSocketGroup("Flame Link 20/0 1") + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "DeterminationMercenary") + local granite = new("Item"):Item("Rarity: Magic\nChemist's Granite Flask of the Opossum\nImplicits: 0\nBlood Magic") + build.itemsTab:AddItem(granite, true) + build.itemsTab.slots["Flask 1"].selItemId = granite.id + build.itemsTab.slots["Flask 1"].active = true + build.itemsTab.activeItemSet["Flask 1"].selItemId = granite.id + build.itemsTab.activeItemSet["Flask 1"].active = true + local ceinture = new("Item"):Item("Rarity: Unique\nCeinture of Benevolence\nCloth Belt\nNon-Unique Utility Flasks you Use apply to Linked Targets") + build.itemsTab:AddItem(ceinture, true) + build.itemsTab.slots.Belt.selItemId = ceinture.id + build.itemsTab.activeItemSet.Belt.selItemId = ceinture.id + env = calculate() + assert.is_true(env.mercenary.modDB.conditions.UsingGraniteFlask) + local hasBloodMagic + for _, name in ipairs(env.mercenary.modDB:List(nil, "Keystone")) do + if name == "Blood Magic" then hasBloodMagic = true end + end + assert.is_true(hasBloodMagic) + + fresh() + configure("MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "InfernalCryMercenary") + local enemyMultHelmet = { + id = 9111, name = "Enemy Mult Helm", type = "Helmet", base = { type = "Helmet" }, rarity = "RARE", + requirements = { str = 1 }, grantedSkills = { }, + modList = { + modLib.createMod("Damage", "INC", 20, "Merc Enemy Totem Mult", { type = "Multiplier", var = "TotemsSummoned", actor = "enemy" }), + }, + } + build.itemsTab.items[enemyMultHelmet.id] = enemyMultHelmet + equipmentSlot("Helmet").selItemId = enemyMultHelmet.id + env = calculate() + local totemsConfig = { var = "TotemsSummoned", ifStat = "TotemsSummoned" } + assert.is_nil(configVisibility.usedForVar(env, "enemyMultipliersUsed", totemsConfig, "player").TotemsSummoned) + assert.is_not_nil(configVisibility.usedForVar(env, "enemyMultipliersUsed", totemsConfig, "mercenary").TotemsSummoned) + assert.is_false(configVisibility.isRelevantForBuild(totemsConfig, build, "player")) + assert.is_true(configVisibility.isRelevantForBuild(totemsConfig, build, "mercenary")) + + local usageEnv = { + actorUsage = { + player = { enemyMultipliers = { TotemsSummoned = true } }, + }, + enemyMultipliersUsed = { TotemsSummoned = true }, + } + local actorVar = { var = "TotemsSummoned", resolvedScope = "actor" } + assert.is_nil(configVisibility.usedForVar(usageEnv, "enemyMultipliersUsed", actorVar, "mercenary").TotemsSummoned) + assert.is_not_nil(configVisibility.usedForVar(usageEnv, "enemyMultipliersUsed", actorVar, "player").TotemsSummoned) + end) + + it("calculates every selectable exported inherent skill and support without runtime errors", function() + local function contains(values, wanted) + for _, value in ipairs(values or { }) do if value == wanted then return true end end + return false + end + local buildForSkill = { } + for _, buildId in ipairs(build.data.mercenaries.buildOrder) do + local mercenaryBuild = build.data.mercenaries.builds[buildId] + if #mercenaryBuild.weaponTypes > 0 then + for _, skillId in ipairs(mercenaryBuild.skillIds) do + for _, pool in ipairs(mercenaryBuild.skillPools) do + if contains(pool.skillIds, skillId) and (not pool.countMax or pool.countMax > 0) then + buildForSkill[skillId] = buildForSkill[skillId] or buildId + break + end + end + end + end + end + + local baseNameByType = { } + -- Shields are armour, so the lowest base of type Shield is not always legal. + -- Cache by type and build so Int Mercenaries do not receive a Dex buckler. + local function lowestBaseName(itemType, mercenaryBuild) + local cacheKey = itemType == "Shield" and itemType.."\0"..mercenaryBuild.id or itemType + if baseNameByType[cacheKey] then return baseNameByType[cacheKey] end + local bestName, bestLevel + for name, base in pairs(build.data.itemBases) do + if base.type == itemType then + local legal = true + if itemType == "Shield" then + legal = MercenaryTools.validateEquippedItem({ + type = "Shield", + rarity = "NORMAL", + requirements = { + level = base.req and base.req.level or 0, + str = base.req and base.req.str or 0, + dex = base.req and base.req.dex or 0, + int = base.req and base.req.int or 0, + }, + }, "Weapon 2", { + profile = { buildId = mercenaryBuild.id, foundAreaLevel = 68 }, + mercenaryData = build.data.mercenaries, + itemSet = { }, + playerItemSet = { }, + items = { }, + playerHasFlag = function() return false end, + }) + end + if legal then + local level = base.req and base.req.level or 0 + if not bestLevel or level < bestLevel or level == bestLevel and name < bestName then + bestName, bestLevel = name, level + end + end + end + end + baseNameByType[cacheKey] = assert(bestName, itemType) + return bestName + end + + local nextItemId = 990000 + local function equip(slotName, itemType, mercenaryBuild) + if not itemType or itemType == "None" then return end + local item = new("Item"):Item("Rarity: Normal\n"..lowestBaseName(itemType, mercenaryBuild)) + item.id = nextItemId + nextItemId = nextItemId + 1 + build.itemsTab.items[item.id] = item + equipmentSlot(slotName).selItemId = item.id + end + + build.configTab.input.enemyLevel = 83 + build.configTab:BuildModList() + build.mercenaryTab.profile.buildId = build.data.mercenaries.buildOrder[1] + build.mercenaryTab:Changed() + local skillIds = { } + for skillId in pairs(buildForSkill) do table.insert(skillIds, skillId) end + table.sort(skillIds) + local testedSupports = { } + local testedSupportCount = 0 + local inheritedFlagBySkillType = { + [SkillType.RemoteMined] = "mine", + [SkillType.SummonsTotem] = "totem", + [SkillType.Trapped] = "trap", + } + for _, skillId in ipairs(skillIds) do + equipmentSlot("Weapon 1").selItemId = 0 + equipmentSlot("Weapon 2").selItemId = 0 + local buildId = buildForSkill[skillId] + local mercenaryBuild = build.data.mercenaries.builds[buildId] + equip("Weapon 1", mercenaryBuild.weaponConfiguration.mainHandTypes[1], mercenaryBuild) + if mercenaryBuild.weaponConfiguration.offHandRequired then equip("Weapon 2", mercenaryBuild.weaponConfiguration.offHandTypes[1], mercenaryBuild) end + build.mercenaryTab.profile = { + classId = mercenaryBuild.classId, + buildId = buildId, + foundAreaLevel = 68, + mainSkillId = skillId, + lifeComparison = "AUTO", + skills = { { id = skillId, enabled = true, includeInFullDPS = true, count = 1, supports = { } } }, + } + build.spec.modFlag = true + build.buildFlag = true + local ok, errorMessage = xpcall(function() build.calcsTab:BuildOutput() end, debug.traceback) + assert.is_true(ok, skillId..": "..tostring(errorMessage)) + local env = build.calcsTab.mainEnv + local minionId = build.data.mercenaries.summonedMinions[skillId] + local noFallbackMinion = minionId and build.data.minions[minionId].noFallbackSkill + if noFallbackMinion then + assert.is_nil(env.mercenary, skillId) + assert.matches("has no exported skills", table.concat(env.mercenaryCalculationErrors or { }, "\n"), skillId) + else + assert.is_table(env.mercenary, skillId) + assert.is_table(env.mercenary.mainSkill, skillId) + for skillType, flag in pairs(inheritedFlagBySkillType) do + if env.mercenary.mainSkill.skillTypes[skillType] then assert.is_true(env.mercenary.mainSkill.skillFlags[flag], skillId.." must inherit "..flag) end + end + if skillId == "ToxicRainMercenary" then assert.is_true(env.mercenary.mainSkill.skillFlags.projectile) end + for _, supportId in ipairs(build.data.mercenaries.skills[skillId].possibleSupportIds) do + if not testedSupports[supportId] then + local support = build.data.mercenaries.supports[supportId] + build.mercenaryTab.profile.skills[1].supports = { { id = supportId, tier = support.variant } } + build.spec.modFlag = true + build.buildFlag = true + ok, errorMessage = xpcall(function() build.calcsTab:BuildOutput() end, debug.traceback) + assert.is_true(ok, supportId.." on "..skillId..": "..tostring(errorMessage)) + assert.is_table(build.calcsTab.mainEnv.mercenary, supportId.." on "..skillId) + testedSupports[supportId] = true + testedSupportCount = testedSupportCount + 1 + end + end + end + end + assert.are.equal(269, #skillIds) + assert.are.equal(261, testedSupportCount) + end) +end) diff --git a/spec/System/TestMercenaryEquipment_spec.lua b/spec/System/TestMercenaryEquipment_spec.lua new file mode 100644 index 00000000000..16251f579e2 --- /dev/null +++ b/spec/System/TestMercenaryEquipment_spec.lua @@ -0,0 +1,1216 @@ +describe("Mercenary equipment validation", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + local selectScionLuminary = MercenaryTest.selectScionLuminary + local MercenaryTools = require("Modules.MercenaryTools") + local tab, itemSet, mercenaryItemSet + + local function item(fields) + local value = { + id = 9001, + type = "Body Armour", + rarity = "RARE", + requirements = { level = 0, str = 0, dex = 0, int = 0 }, + grantedSkills = { }, + } + for key, fieldValue in pairs(fields or { }) do value[key] = fieldValue end + return value + end + + local function selectBuild(buildId, foundAreaLevel) + tab.profile.buildId = buildId + tab.profile.foundAreaLevel = foundAreaLevel or 68 + tab:Changed() + mercenaryItemSet = tab:GetItemSet(true) + end + + local function showMercenaryEquipment() + mercenaryItemSet = tab:GetItemSet(true) + build.itemsTab:SetViewItemSet(mercenaryItemSet.id) + return mercenaryItemSet + end + + local function validateEquippedItem(equippedItem, slotName, mercenarySet) + return MercenaryTools.validateEquippedItem(equippedItem, slotName, { + profile = tab.profile, + mercenaryData = tab.data, + itemSet = mercenarySet or mercenaryItemSet, + playerItemSet = itemSet, + items = build.itemsTab.items, + playerHasFlag = function(flagName) return tab:PlayerFlag(flagName) end, + }) + end + + local function allocatePassive(name) + local node = build.spec.tree.ascendancyMap[name] + if not node then + for _, candidate in pairs(build.spec.nodes) do + if candidate.name == name then node = candidate break end + end + end + node = assert(node, name) + node = build.spec.nodes[node.id] or node + node.alloc = true + build.spec.allocNodes[node.id] = node + build.spec.modFlag = true + build.buildFlag = true + runCallback("OnFrame") + end + + local function freshBuild() + newBuild() + selectScionLuminary() + tab = build.mercenaryTab + itemSet = build.itemsTab.activeItemSet + mercenaryItemSet = nil + tab:EnsureData() + end + + local function stubThrowingCalculator() + local originalGet = build.calcsTab.GetMiscCalculator + build.calcsTab.mainEnv = build.calcsTab.mainEnv or { } + build.calcsTab.GetMiscCalculator = function() + return function() error("calc boom") end, nil, { MERCENARY = { CombinedDPS = 1 } } + end + return originalGet + end + + local function tooltipUnavailableText(tooltip) + local tooltipText = { } + for _, line in ipairs(tooltip.lines) do + if line.text then + table.insert(tooltipText, line.text) + end + end + return table.concat(tooltipText, "\n") + end + + before_each(freshBuild) + + it("populates Class and build on first Mercenary tab view without a saved class", function() + newBuild() + selectScionLuminary() + tab = build.mercenaryTab + assert.is_nil(tab.profile.classId) + assert.is_nil(tab.profile.buildId) + assert.are.equal(0, #tab.controls.build.list) + + tab:EnsureData() + tab:RefreshControls() + + local classGroup = tab.classGroups[tab.controls.class.selIndex] + assert.is_not_nil(classGroup) + assert.is_true(#tab.controls.build.list > 0) + assert.are.equal(#classGroup.buildIds, #tab.controls.build.list) + assert.are.equal(classGroup.buildIds[1], tab.controls.build.list[1].id) + assert.is_nil(tab.profile.classId) + assert.is_nil(tab.profile.buildId) + end) + + + + it("persists Mercenary equipment in a generic ItemsTab set and actor assignment", function() + local mercSet = tab:GetItemSet(true) + assert.are.equal(mercSet, tab:GetItemSet(true)) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + mercSet = showMercenaryEquipment() + build.itemsTab.items[9001] = item({ id = 9001, name = "Mercenary Helmet", type = "Helmet", base = { type = "Helmet" } }) + mercSet["Helmet"].selItemId = 9001 + local itemsXml = { } + build.itemsTab:Save(itemsXml) + local savedItemId + local savedOwner + local savedActor + for _, node in ipairs(itemsXml) do + if node.elem == "ItemSet" and tonumber(node.attrib.id) == mercSet.id then + savedOwner = node.attrib.owner + for _, slot in ipairs(node) do + if slot.attrib and slot.attrib.name == "Helmet" then savedItemId = slot.attrib.itemId end + end + elseif node.elem == "ActorItemSet" and node.attrib.actor == "MERCENARY" then + savedActor = tonumber(node.attrib.itemSetId) + end + end + assert.are.equal("9001", savedItemId) + assert.is_nil(savedOwner) + assert.are.equal(mercSet.id, savedActor) + assert.is_nil(itemsXml.attrib.viewItemSet) + local mercenaryXml = { } + tab:Save(mercenaryXml) + assert.is_nil(mercenaryXml.attrib.itemSetId) + assert.is_nil(mercenaryXml.attrib.auxiliaryItemSetId) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + local itemsTab = build.itemsTab + local activePlayerSetId = itemsTab.activeItemSetId + tab:GetItemSet(true) + local secondSet = itemsTab:NewItemSet() + secondSet.title = "Alternate Mercenary Equipment" + table.insert(itemsTab.itemSetOrderList, secondSet.id) + assert(itemsTab:SetActorItemSet("MERCENARY", secondSet.id)) + assert.are.equal(secondSet.id, itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(secondSet.id, itemsTab.viewItemSetId) + assert.are.equal(activePlayerSetId, itemsTab.activeItemSetId) + + local saved = { } + tab:Save(saved) + assert.is_nil(saved.attrib.itemSetId) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + itemsTab = build.itemsTab + local validSet = tab:GetItemSet(false) + assert.is_table(validSet) + assert.is_false(itemsTab:SetActorItemSet("MERCENARY", 99999, false)) + assert.are.equal(validSet, tab:GetItemSet(false)) + assert.is_true(itemsTab:SetActorItemSet("MERCENARY", nil, false)) + assert.is_table(tab:GetItemSet(false)) + local created = tab:GetItemSet(true) + assert.is_table(created) + assert.are_not.equal(99999, created.id) + + freshBuild() + local playerSet = build.itemsTab:NewItemSet() + playerSet.title = "Animate Guardian" + table.insert(build.itemsTab.itemSetOrderList, playerSet.id) + itemsXml = { } + build.itemsTab:Save(itemsXml) + build.itemsTab:Load(itemsXml) + assert.are.equal("Animate Guardian", build.itemsTab.itemSets[playerSet.id].title) + assert.is_nil(build.itemsTab.itemSets[playerSet.id].owner) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + itemsTab = build.itemsTab + mercSet = showMercenaryEquipment() + local playerHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + local mercHelmet = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(playerHelmet, true) + itemsTab:AddItem(mercHelmet, true) + itemsTab.activeItemSet.Helmet.selItemId = playerHelmet.id + mercSet["Helmet"].selItemId = mercHelmet.id + activePlayerSetId = itemsTab.activeItemSetId + itemsXml, mercenaryXml = { }, { } + itemsTab:Save(itemsXml) + tab:Save(mercenaryXml) + itemsTab:Load(itemsXml) + tab:Load(mercenaryXml) + tab:PostLoad() + assert.are.equal(activePlayerSetId, itemsTab.activeItemSetId) + assert.are.equal(activePlayerSetId, itemsTab.viewItemSetId) + assert.are.equal(playerHelmet.id, itemsTab.itemSets[activePlayerSetId].Helmet.selItemId) + assert.are.equal(mercHelmet.id, tab:GetItemSet(true)["Helmet"].selItemId) + + freshBuild() + itemsTab = build.itemsTab + itemsTab:Load({ + attrib = { activeItemSet = "1", useSecondWeaponSet = "false" }, + { + elem = "ItemSet", + attrib = { id = "1", owner = "Player", title = "Branch Owner", useSecondWeaponSet = "false" }, + }, + }) + assert.are.equal("Branch Owner", itemsTab.itemSets[1].title) + assert.is_nil(itemsTab.itemSets[1].owner) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + mercSet = showMercenaryEquipment() + build.itemsTab.items[9001] = item({ id = 9001, name = "Mercenary Helmet", type = "Helmet", base = { type = "Helmet" } }) + mercSet["Helmet"].selItemId = 9001 + tab:Reset() + assert.are.equal(mercSet.id, build.itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(mercSet, build.itemsTab.itemSets[mercSet.id]) + assert.are.equal(9001, mercSet["Helmet"].selItemId) + end) + + + it("isolates Items undo from Mercenary profile edits", function() + selectBuild("MeleeAOEMarauderFireSlam") + local itemsTab = build.itemsTab + itemsTab:ResetUndo() + tab:ResetUndo() + local hat = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(hat, true) + itemsTab:AddUndoState() + tab.profile.title = "New Mercenary name" + tab.profile.foundAreaLevel = 80 + tab:Changed() + itemsTab:Undo() + assert.are.equal("New Mercenary name", tab.profile.title) + assert.are.equal(80, tab.profile.foundAreaLevel) + itemsTab:Redo() + assert.are.equal("New Mercenary name", tab.profile.title) + assert.is_truthy(itemsTab.items[hat.id]) + local cap = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(cap, true) + itemsTab:AddUndoState() + itemsTab:Undo() + assert.are.equal(80, tab.profile.foundAreaLevel) + tab:Undo() + assert.are.equal(68, tab.profile.foundAreaLevel) + assert.is_nil(itemsTab.items[cap.id]) + assert.is_truthy(itemsTab.items[hat.id]) + end) + + it("validates Mercenary equipment against class, level, and slot rules", function() + local armourCases = { + { "MeleeAOEMarauderFireSlam", { + { { str = 100, dex = 100 }, true }, + { { dex = 100 }, false }, + { { str = 1, dex = 1, int = 1 }, false }, + } }, + { "AurasMinionsTemplarStaff", { + { { str = 100, int = 100 }, true }, + { { str = 100, dex = 1 }, false }, + } }, + { "MiscScionPhysDot", { + { { str = 1, dex = 1, int = 1 }, true }, + } }, + } + for _, group in ipairs(armourCases) do + selectBuild(group[1]) + for _, case in ipairs(group[2]) do + assert.are.equal(case[2], validateEquippedItem(item({ requirements = case[1] }), "Body Armour")) + end + end + + selectBuild("MeleeAOEMarauderFireSlam", 47) + assert.is_false(validateEquippedItem(item({ requirements = { level = 68, str = 1 } }), "Body Armour")) + tab.profile.foundAreaLevel = 48 + assert.is_true(validateEquippedItem(item({ requirements = { level = 68, str = 1 } }), "Body Armour")) + + selectBuild("MeleeAOEMarauderFireSlam") + assert.is_false(validateEquippedItem(item({ rarity = "UNIQUE" }), "Body Armour")) + local helmet = item({ type = "Helmet", rarity = "UNIQUE", requirements = { str = 1 } }) + assert.is_false(validateEquippedItem(helmet, "Helmet")) + allocatePassive("Legendary Helmets") + assert.is_true(validateEquippedItem(helmet, "Helmet")) + + freshBuild() + selectBuild("MeleeStrikesMarauderFire") + local legendaryCases = { + { "Helmet", "Helmet", "Legendary Helmets", { str = 1 } }, + { "Gloves", "Gloves", "Legendary Gloves", { str = 1 } }, + { "Boots", "Boots", "Legendary Boots", { str = 1 } }, + { "Amulet", "Amulet", "Legendary Amulets" }, + { "Ring 1", "Ring", "Legendary Rings" }, + { "Ring 2", "Ring", "Legendary Rings" }, + { "Belt", "Belt", "Legendary Belts" }, + { "Weapon 1", "One Handed Sword", "Legendary Arms" }, + { "Weapon 2", "One Handed Sword", "Legendary Arms" }, + } + local allocated = { } + for index, case in ipairs(legendaryCases) do + local unique = item({ id = 9100 + index, type = case[2], rarity = "UNIQUE", requirements = case[4] or { } }) + if not allocated[case[3]] then + assert.is_false(validateEquippedItem(unique, case[1])) + allocatePassive(case[3]) + allocated[case[3]] = true + end + assert.is_true(validateEquippedItem(unique, case[1])) + end + + freshBuild() + selectBuild("TrapsMinesShadowLightning") + assert.is_true(validateEquippedItem(item({ type = "Dagger" }), "Weapon 1")) + assert.is_false(validateEquippedItem(item({ type = "Shield" }), "Weapon 2")) + + selectBuild("MeleeStrikesMarauderFire") + assert.is_true(validateEquippedItem(item({ type = "Shield", requirements = { str = 1 } }), "Weapon 2")) + assert.is_true(validateEquippedItem(item({ type = "One Handed Sword" }), "Weapon 2")) + + selectBuild("AurasMinionsTemplarSmite") + assert.is_true(validateEquippedItem(item({ type = "Shield" }), "Weapon 2")) + assert.is_false(validateEquippedItem(item({ type = "Sceptre" }), "Weapon 2")) + + selectBuild("NonEleBowRangerPhys") + assert.is_true(validateEquippedItem(item({ type = "Bow" }), "Weapon 1")) + assert.is_true(validateEquippedItem(item({ type = "Quiver" }), "Weapon 2")) + + selectBuild("MeleeStrikesMarauderFire") + assert.is_true(validateEquippedItem(item({ type = "Shield", requirements = { str = 100 } }), "Weapon 2")) + assert.is_true(validateEquippedItem(item({ type = "Shield", requirements = { str = 100, dex = 50 } }), "Weapon 2")) + assert.is_false(validateEquippedItem(item({ type = "Shield", requirements = { dex = 100 } }), "Weapon 2")) + assert.is_false(validateEquippedItem(item({ type = "Shield", requirements = { int = 15 } }), "Weapon 2")) + assert.is_false(validateEquippedItem(item({ type = "Shield", requirements = { str = 1, dex = 1, int = 1 } }), "Weapon 2")) + + selectBuild("AurasMinionsTemplarSmite") + assert.is_true(validateEquippedItem(item({ type = "Shield", requirements = { str = 100, int = 100 } }), "Weapon 2")) + assert.is_false(validateEquippedItem(item({ type = "Shield", requirements = { dex = 1 } }), "Weapon 2")) + assert.is_false(validateEquippedItem(item({ type = "Shield", requirements = { str = 100, dex = 1 } }), "Weapon 2")) + + selectBuild("MeleeAOEMarauderFireSlam") + local shared = item({ type = "Helmet", requirements = { str = 1 } }) + itemSet["Helmet"].selItemId = shared.id + assert.is_false(validateEquippedItem(shared, "Helmet")) + + local playerCopy = item({ id = 9100, type = "Helmet", requirements = { str = 1 }, uniqueID = "api-item-x", base = { type = "Helmet" } }) + local mercCopy = item({ id = 9101, type = "Helmet", requirements = { str = 1 }, uniqueID = "api-item-x", base = { type = "Helmet" } }) + build.itemsTab.items[playerCopy.id] = playerCopy + itemSet["Helmet"].selItemId = playerCopy.id + assert.is_false(validateEquippedItem(mercCopy, "Helmet")) + build.itemsTab.items[playerCopy.id] = nil + itemSet["Helmet"].selItemId = shared.id + + local grantedAura = item({ type = "Helmet", id = 9002, requirements = { str = 1 }, grantedSkills = { { skillId = "Anger" } } }) + assert.is_true(validateEquippedItem(grantedAura, "Helmet")) + + local mercSet = showMercenaryEquipment() + local invalidHelmet = item({ id = 9015, name = "Invalid Mercenary Helmet", type = "Helmet", base = { type = "Helmet" }, requirements = { int = 1 } }) + build.itemsTab.items[invalidHelmet.id] = invalidHelmet + build.itemsTab.slots["Helmet"]:SetSelItemId(invalidHelmet.id, build.itemsTab:GetVisibleItemSet()) + build.itemsTab:PopulateSlots() + assert.are.equal(invalidHelmet.id, mercSet["Helmet"].selItemId) + assert.matches("Helmet: armour attribute alignment", table.concat(tab:GetErrors(), "\n")) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + showMercenaryEquipment() + invalidHelmet = item({ id = 9018, name = "Selectable Invalid Helmet", type = "Helmet", base = { type = "Helmet" }, requirements = { int = 1 } }) + build.itemsTab.items[invalidHelmet.id] = invalidHelmet + build.itemsTab:PopulateSlots() + local helmetSlot = build.itemsTab.slots["Helmet"] + local candidateIndex + for index, itemId in ipairs(helmetSlot.items) do + if itemId == invalidHelmet.id then candidateIndex = index break end + end + assert.is_number(candidateIndex) + assert.matches(colorCodes[invalidHelmet.rarity], helmetSlot.list[candidateIndex], nil, true) + helmetSlot:SetSelItemId(invalidHelmet.id, build.itemsTab:GetVisibleItemSet()) + build.itemsTab:PopulateSlots() + assert.are.equal(invalidHelmet.id, helmetSlot.selItemId) + assert.matches("Helmet: armour attribute alignment", table.concat(tab:GetErrors(), "\n")) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + mercSet = showMercenaryEquipment() + local jewel = item({ id = 9016, name = "Mercenary Abyss Jewel", type = "Jewel", base = { type = "Jewel", subType = "Abyss" }, requirements = { level = 1 } }) + assert.is_false(validateEquippedItem(jewel, "Helmet Abyssal Socket 1")) + helmet = item({ id = 9017, name = "Mercenary Abyss Helmet", type = "Helmet", base = { type = "Helmet" }, requirements = { str = 1 }, abyssalSocketCount = 1 }) + build.itemsTab.items[helmet.id] = helmet + mercSet["Helmet"].selItemId = helmet.id + assert.is_true(validateEquippedItem(jewel, "Helmet Abyssal Socket 1", mercSet)) + assert.is_false(tab:IsSlotSupported("Jewel 12345")) + + local uniqueJewel = item({ id = 9024, name = "Mercenary Unique Abyss Jewel", type = "Jewel", base = { type = "Jewel", subType = "Abyss" }, rarity = "UNIQUE", requirements = { level = 1 } }) + build.itemsTab.items[uniqueJewel.id] = uniqueJewel + local abyssParents = { + { type = "Body Armour", slotName = "Body Armour" }, + { type = "Helmet", slotName = "Helmet" }, + } + for index, case in ipairs(abyssParents) do + local parent = item({ id = 9024 + index, name = "Mercenary Abyss "..case.type, type = case.type, base = { type = case.type }, requirements = { str = 1 }, abyssalSocketCount = 1 }) + build.itemsTab.items[parent.id] = parent + mercSet[case.slotName].selItemId = parent.id + assert.is_true(validateEquippedItem(uniqueJewel, case.slotName.." Abyssal Socket 1", mercSet)) + end + end) + + it("imports Warrant text into the active loadout without replacing gear", function() + selectBuild("MeleeAOEMarauderFireSlam") + local mercSet = showMercenaryEquipment() + local mercenaryHelmet = "Helmet" + mercSet[mercenaryHelmet].selItemId = 9001 + local warrantText = [[ +Item Class: Map Fragments +Rarity: Normal +Mercenary Warrant +-------- +Thalia, the Exquisite +-------- +Build: Kineticist +Mercenary Level: 83 +-------- +Elemental Weakness +Greater Curse Effect (Tier: 3) +Faster Casting (Tier: 2) +-------- +Right click this item to view Mercenary details. +-------- +Note: ~b/o 1 mirror +]] + tab.controls.importWarrant:Click() + local popup = main.popups[1] + assert.are.equal("Import Mercenary Warrant", popup.title) + popup.controls.edit:SetText(warrantText) + popup.controls.import:Click() + assert.are_not.equal(popup, main.popups[1]) + assert.are.equal("Kineticist", tab.data.builds[tab.profile.buildId].name) + assert.are.equal(83, tab.profile.foundAreaLevel) + assert.are.equal("Elemental Weakness", tab.data.skills[tab.profile.mainSkillId].name) + assert.is_true(tab.profile.importedWarrant) + assert.are.equal(9001, mercSet[mercenaryHelmet].selItemId) + local xml = { } + tab:Save(xml) + assert.are.equal("true", xml[1].attrib.importedWarrant) + tab:Reset() + tab:Load(xml) + assert.is_true(tab.profile.importedWarrant) + assert.are.equal("Kineticist", tab.data.builds[tab.profile.buildId].name) + end) + + + it("skill and support UI enforces capacity, selection, tooltips, and sort", function() + assert.matches("simultaneously sustainable", tab.controls.skillFullDPS.tooltipText) + assert.matches("does not simulate", tab.controls.skillFullDPS.tooltipText) + + local function mercenaryActiveSkill(possibleSupportIds) + local player = { } + return { + activeEffect = { grantedEffect = { modSource = "Skill:Test" } }, + actor = { isMercenary = true, enemy = { player = player } }, + skillTypes = { }, + mercenaryPossibleSupportIds = possibleSupportIds, + } + end + local listedSkill = mercenaryActiveSkill({ "FistOfWarHigh" }) + assert.is_true(calcLib.canGrantedEffectSupportActiveSkill({ + mercenarySupportId = "FistOfWarHigh", + isTrigger = true, + excludeSkillTypes = { }, + requireSkillTypes = { }, + }, listedSkill)) + assert.is_false(calcLib.canGrantedEffectSupportActiveSkill({ + mercenarySupportId = "FistOfWarHigh", + }, mercenaryActiveSkill({ "ArrowNovaHigh" }))) + assert.is_false(calcLib.canGrantedEffectSupportActiveSkill({ + isTrigger = true, + excludeSkillTypes = { }, + requireSkillTypes = { }, + }, listedSkill)) + + tab.profile.skills[1] = { id = "InfernalBlowMercenary", enabled = true, supports = { } } + tab.controls.skillCount.changeFunc("200") + assert.are.equal(99, tab.profile.skills[1].count) + tab.controls.skillCount.changeFunc("0") + assert.are.equal(1, tab.profile.skills[1].count) + + local skillOptions = require("Modules.SkillOptions") + assert.are.same(skillOptions.sortGemTypeList, tab.controls.sortGemsByDPSFieldControl.list) + local xml = { } + tab.sortGemsByDPS = false + tab.sortGemsByDPSField = "TotalDPS" + tab:Save(xml) + assert.are.equal("false", xml.attrib.sortGemsByDPS) + assert.are.equal("TotalDPS", xml.attrib.sortGemsByDPSField) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + tab:SetSkill(1, "ConsecratedPathMercenary") + local expectedSkillColor = data.skillColorMap[build.data.skills.ConsecratedPathMercenary.color] + local skillRow = tab.controls.skillList:GetRowValue(1, 1, tab.profile.skills[1]) + assert.are.equal(expectedSkillColor, skillRow:sub(1, #expectedSkillColor)) + assert.are.equal(14, tab.controls.skillTip.height) + assert.is_nil(skillRow:find("(Calcs)", 1, true)) + local skillOption + for _, option in ipairs(tab.controls.skill.list) do + if option.id == "ConsecratedPathMercenary" then skillOption = option break end + end + assert(skillOption) + assert.are.equal(expectedSkillColor, skillOption.label:sub(1, #expectedSkillColor)) + local tooltip = new("Tooltip"):Tooltip() + local function tooltipText() + local lines = { } + for _, line in ipairs(tooltip.lines) do if line.text then table.insert(lines, line.text) end end + return table.concat(lines, "\n") + end + + tab.controls.skillList:AddValueTooltip(tooltip, 1, tab.profile.skills[1]) + local skillTooltipText = tooltipText() + assert.matches("Consecrated Path", skillTooltipText) + assert.matches("Level:", skillTooltipText) + assert.matches("Slams the ground", skillTooltipText) + + tooltip:Clear(true) + tab.controls.skill.tooltipFunc(tooltip, "HOVER", 1, { id = "ConsecratedPathMercenary" }) + assert.matches("Consecrated Path", tooltipText()) + + tooltip:Clear(true) + local support = assert(tab.supportControls[1].list[2]) + tab.supportControls[1].tooltipFunc(tooltip, "HOVER", 2, support) + local supportTooltipText = tooltipText() + assert.is_true(supportTooltipText:find(tab.data.supports[support.id].name, 1, true) ~= nil) + assert.is_true(supportTooltipText:find("Mercenary Support, Tier ", 1, true) ~= nil) + assert.matches("Supported Skills gain", supportTooltipText) + + freshBuild() + selectBuild("TrapsMinesShadowLightning", 80) + build.configTab.enemyLevel = 60 + tab:SetSkill(1, "LightningTrapMercenary") + tooltip = new("Tooltip"):Tooltip() + tab.controls.skillList:AddValueTooltip(tooltip, 1, tab.profile.skills[1]) + local displayedLevel + for _, line in ipairs(tooltip.lines) do + displayedLevel = displayedLevel or line.text and line.text:match("Level: %^7(%d+)") + end + local actorLevel = MercenaryTools.effectiveLevel(80, 60) + assert.are.equal(MercenaryTools.skillLevel(build.data.skills.LightningTrapMercenary, actorLevel), tonumber(displayedLevel)) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + tab:SetSkill(1, "ConsecratedPathMercenary") + local selected = tab.profile.skills[1] + local preferredId = tab.supportControls[1].list[2].id + local originalCalculator = build.calcsTab.GetMiscCalculator + local ok, err = pcall(function() + build.calcsTab.GetMiscCalculator = function() + return function() + local supportId = selected.supports[1] and selected.supports[1].id + local dps = supportId == preferredId and 100 or 10 + return { CombinedDPS = dps, FullDPS = dps } + end + end + tab.sortGemsByDPS = true + tab.sortGemsByDPSField = "CombinedDPS" + tab:QueueSupportSort(1) + while tab.supportSortCoroutine do tab:ProcessSupportSort() end + assert.are.equal(preferredId, tab.supportControls[1].list[1].id) + assert.is_nil(selected.supports[1]) + end) + build.calcsTab.GetMiscCalculator = originalCalculator + assert.is_true(ok, err) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + assert(tab:SetSkill(1, "ConsecratedPathMercenary")) + local supportId = assert(tab.data.skills.ConsecratedPathMercenary.possibleSupportIds[1]) + assert(tab:SetSupport(5, supportId)) + assert.are.equal(1, #tab.profile.skills[1].supports) + assert.are.equal(supportId, tab.profile.skills[1].supports[1].id) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + tab:RefreshControls() + tab.controls.skillList.controls.new.onClick() + assert.are.equal(1, #tab.profile.skills) + local skillEntry + for _, candidate in ipairs(tab.controls.skill.list) do + if candidate.id and #(tab.data.skills[candidate.id].possibleSupportIds or { }) > 0 then skillEntry = candidate break end + end + assert(skillEntry) + tab.controls.skill.selFunc(2, skillEntry) + assert.are.equal(skillEntry.id, tab.profile.skills[1].id) + local supportEntry = assert(tab.supportControls[1].list[2]) + tab.supportControls[1].selFunc(2, supportEntry) + assert.are.equal(supportEntry.id, tab.profile.skills[1].supports[1].id) + tab.supportControls[1].selFunc(1, tab.supportControls[1].list[1]) + assert.are.equal(0, #tab.profile.skills[1].supports) + + freshBuild() + selectBuild("EleBowRangerClones") + assert(tab:SetSkill(1, "IceShotMercenary")) + assert.is_true(#tab.supportControls[1].list > 1) + for index = 1, 5 do + assert.are.equal(tab.supportControls[index], tab.controls["support"..index]) + assert.is_true(tab.supportControls[index]:IsShown()) + end + assert.is_nil(tab.controls.skillLink) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + assert(tab:SetSkill(1, "ConsecratedPathMercenary")) + assert.is_true(tab.supportControls[3].shown) + assert.is_true(not tab.supportControls[4].shown) + supportId = tab.data.skills.ConsecratedPathMercenary.possibleSupportIds[1] + support = tab.data.supports[supportId] + for index = 1, 4 do tab.profile.skills[1].supports[index] = { id = supportId, tier = support.variant } end + tab:RefreshControls() + assert.are.equal(4, #tab.profile.skills[1].supports) + assert.matches("has more than 3 supports", table.concat(tab:GetErrors(), "\n")) + local otherId = tab.data.skills.ConsecratedPathMercenary.possibleSupportIds[4] + assert.is_nil(select(1, tab:SetSupport(4, otherId))) + assert.are.equal(4, #tab.profile.skills[1].supports) + assert.are.equal(supportId, tab.profile.skills[1].supports[4].id) + + freshBuild() + tab:EnsureData() + tab.profile.classId = "AurasMinionsTemplar" + tab:RefreshControls() + for _, entry in ipairs(tab.controls.class.list) do + assert.not_matches("%[DNT%]", entry.label) + end + local labels = { } + for _, entry in ipairs(tab.controls.build.list) do labels[entry.id] = entry.label end + assert.are.equal("Warpriest", labels.AurasMinionsTemplarSmite) + assert.are.equal("Infamous Warpriest", labels.AurasMinionsTemplarSmiteNoble) + + freshBuild() + tab.profile.classId = "Crit1HShadow" + tab.profile.buildId = "Crit1HShadowSpectral" + tab:RefreshControls() + assert.is_true(not tab.controls.skillList.controls.new.enabled()) + tab.controls.skillList.controls.new.onClick() + assert.are.equal(0, #tab.profile.skills) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + tab:RefreshControls() + for _ = 1, 7 do tab.controls.skillList.controls.new.onClick() end + assert.are.equal(6, #tab.profile.skills) + assert.is_true(not tab.controls.skillList.controls.new.enabled()) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + assert(tab:SetSkill(1, "InfernalCryMercenary")) + assert.is_nil(select(1, tab:SetSkill(2, "InfernalCryMercenary"))) + assert.are.equal(1, #tab.profile.skills) + assert(tab:SetSkill(2, "FissureSlamMercenary")) + assert.is_nil(select(1, tab:SetSkill(3, "TectonicSlamFireMercenary"))) + assert.are.equal(2, #tab.profile.skills) + assert.are.equal("FissureSlamMercenary", tab.profile.skills[2].id) + + freshBuild() + assert.is_nil(tab.controls.skillMain) + assert.is_nil(tab.controls.skillMainLabel) + selectBuild("MeleeAOEMarauderFireSlam") + assert(tab:SetSkill(1, "InfernalCryMercenary")) + assert.are.equal("InfernalCryMercenary", tab.profile.mainSkillId) + assert(tab:SetSkill(1, "FissureSlamMercenary")) + assert.are.equal("FissureSlamMercenary", tab.profile.mainSkillId) + assert(tab:SetSkill(1, nil)) + assert.is_nil(tab.profile.mainSkillId) + + freshBuild() + selectBuild("ElementalWitchLightning") + assert(tab:SetSkill(1, "ArcMercenary")) + assert(tab:SetSkill(2, "SparkMercenary")) + tab.selectedSkillIndex = 1 + tab.controls.skillEnabled.changeFunc(false) + assert.are.equal(false, tab.profile.skills[1].enabled) + assert.are.equal(true, tab.profile.skills[2].enabled ~= false) + assert.are.equal("SparkMercenary", tab.profile.mainSkillId) + tab.selectedSkillIndex = 2 + tab.controls.skillEnabled.changeFunc(false) + assert.are.equal(false, tab.profile.skills[2].enabled) + assert.is_nil(tab.profile.mainSkillId) + tab.controls.skillEnabled.changeFunc(true) + assert.are.equal("SparkMercenary", tab.profile.mainSkillId) + + freshBuild() + tab.profile.buildId = "MeleeAOEMarauderFireSlam" + tab.profile.classId = "MeleeAOEMarauder" + tab.profile.skills = { { id = "FissureSlamMercenary", enabled = true, supports = { } } } + tab.profile.mainSkillId = "FissureSlamMercenary" + local before = #build.itemsTab.itemSetOrderList + assert(tab:SetSupport(1, "FistOfWarHigh")) + assert.are.equal(before, #build.itemsTab.itemSetOrderList) + assert.are.equal("FistOfWarHigh", tab.profile.skills[1].supports[1].id) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + assert(tab:SetSkill(1, "FissureSlamMercenary")) + local skill = tab.profile.skills[1] + skill.supports = { { id = "AddedFireHigh", tier = 3 } } + local original = copyTable(skill.supports, true) + local originalGet = build.calcsTab.GetMiscCalculator + build.calcsTab.GetMiscCalculator = function() error("preview boom") end + support = assert(tab.data.supports.FistOfWarHigh) + assert.has_error(function() + tab:AddSupportTooltip(new("Tooltip"):Tooltip(), support, 1, true) + end) + build.calcsTab.GetMiscCalculator = originalGet + assert.same(original, skill.supports) + + local originalId, originalSupports = skill.id, copyTable(skill.supports, true) + local originalMainSkillId = tab.profile.mainSkillId + originalGet = stubThrowingCalculator() + tooltip = new("Tooltip"):Tooltip() + support = assert(tab.data.supports.FistOfWarHigh) + ok, err = pcall(tab.AddSupportTooltip, tab, tooltip, support, 1, true) + build.calcsTab.GetMiscCalculator = originalGet + assert.is_false(ok) + assert.matches("calc boom", tostring(err)) + assert.same(original, skill.supports) + assert.does_not.match("Mercenary comparison unavailable", tooltipUnavailableText(tooltip)) + + originalGet = stubThrowingCalculator() + tooltip = new("Tooltip"):Tooltip() + ok, err = pcall(tab.AddSkillTooltip, tab, tooltip, { id = "InfernalCryMercenary" }, true) + build.calcsTab.GetMiscCalculator = originalGet + assert.is_false(ok) + assert.matches("calc boom", tostring(err)) + assert.are.equal(originalId, skill.id) + assert.same(originalSupports, skill.supports) + assert.are.equal(originalMainSkillId, tab.profile.mainSkillId) + assert.does_not.match("Mercenary comparison unavailable", tooltipUnavailableText(tooltip)) + + tab.sortGemsByDPS = true + tab:RefreshSupportLists() + originalGet = build.calcsTab.GetMiscCalculator + build.calcsTab.GetMiscCalculator = function() error("sort boom") end + local origDevMode = launch.devMode + launch.devMode = false + tab:QueueSupportSort(1) + assert.has_no.errors(function() + tab:ProcessSupportSort() + end) + assert.are.equal("Error", tab.supportSortStatus) + assert.is_nil(tab.supportSortCache[1]) + assert.is_nil(tab.supportSortCoroutine) + tab:QueueSupportSort(1) + launch.devMode = true + assert.has_error(function() + tab:ProcessSupportSort() + end) + launch.devMode = origDevMode + build.calcsTab.GetMiscCalculator = originalGet + assert.is_nil(tab.supportSortCoroutine) + + freshBuild() + local profile = build.mercenaryTab.profile + profile.classId = "EleBowRanger" + profile.buildId = "EleBowRangerClones" + profile.foundAreaLevel = 68 + profile.mainSkillId = "MirrorArrowMercenary" + profile.skills = { { + id = "MirrorArrowMercenary", + enabled = true, + skillMinionSkill = 1, + skillMinionSkillCalcs = 2, + supports = { }, + } } + + local saved = { elem = "Mercenary", attrib = { } } + build.mercenaryTab:Save(saved) + assert.are.equal("2", saved[1][1].attrib.skillMinionSkillCalcs) + + build.mercenaryTab:Reset() + build.mercenaryTab:Load(saved) + local loaded = build.mercenaryTab.profile.skills[1] + assert.are.equal(1, loaded.skillMinionSkill) + assert.are.equal(2, loaded.skillMinionSkillCalcs) + end) + + it("malformed Mercenary state is preserved but blocks calculation", function() + local function loadSet(attrib) + tab:Load({ + attrib = { }, + { + elem = "MercenarySet", + attrib = attrib, + { elem = "Skill", attrib = { id = "TectonicSlamFireMercenary", enabled = "true" } }, + }, + }) + end + + loadSet({ + id = "1", + buildId = "MeleeAOEMarauderFireSlam", + mainSkillId = "TectonicSlamFireMercenary", + }) + assert.is_nil(tab.profile.foundAreaLevel) + assert.matches("Mercenary level", table.concat(tab:GetErrors(), "\n")) + + loadSet({ + id = "1", + buildId = "MeleeAOEMarauderFireSlam", + foundAreaLevel = "not-a-number", + mainSkillId = "TectonicSlamFireMercenary", + }) + assert.is_nil(tab.profile.foundAreaLevel) + assert.matches("Mercenary level", table.concat(tab:GetErrors(), "\n")) + + loadSet({ + id = "1", + buildId = "MeleeAOEMarauderFireSlam", + foundAreaLevel = "83", + mainSkillId = "TectonicSlamFireMercenary", + }) + assert.are.equal(83, tab.profile.foundAreaLevel) + + freshBuild() + tab:EnsureData() + local skillIds = { } + for _, skillId in ipairs(tab.data.builds.MeleeAOEMarauderFireSlam.skillIds) do + table.insert(skillIds, skillId) + if #skillIds == 7 then break end + end + local setNode = { + elem = "MercenarySet", + attrib = { + id = "1", + buildId = "MeleeAOEMarauderFireSlam", + foundAreaLevel = "68", + mainSkillId = skillIds[1], + }, + } + for _, skillId in ipairs(skillIds) do + table.insert(setNode, { elem = "Skill", attrib = { id = skillId, enabled = "true" } }) + end + local mercenaryXml = { attrib = { }, setNode } + tab:Load(mercenaryXml) + assert.are.equal(7, #tab.profile.skills) + for index, skillId in ipairs(skillIds) do + assert.are.equal(skillId, tab.profile.skills[index].id) + end + + local mercSet = tab:GetItemSet(true) + local uniqueBody = new("Item"):Item("Rarity: Unique\nIllegal Unique Body\nPlate Vest") + build.itemsTab:AddItem(uniqueBody, true) + mercSet["Body Armour"].selItemId = uniqueBody.id + + local itemsXml, savedMercenary = { }, { } + build.itemsTab:Save(itemsXml) + tab:Save(savedMercenary) + newBuild() + selectScionLuminary() + tab = build.mercenaryTab + build.itemsTab:Load(itemsXml) + tab:Load(savedMercenary) + tab:PostLoad() + + assert.are.equal(7, #tab.profile.skills) + for index, skillId in ipairs(skillIds) do + assert.are.equal(skillId, tab.profile.skills[index].id) + end + assert.are.equal(uniqueBody.id, tab:GetItemSet(true)["Body Armour"].selItemId) + local errors = table.concat(tab:GetErrors(), "\n") + assert.matches("cannot have more than 6", errors) + assert.matches("Body Armour", errors) + assert.is_true(not tab.controls.skillList.controls.new.enabled()) + tab:AddSkill() + assert.are.equal(7, #tab.profile.skills) + + build.configTab.input.enemyLevel = 83 + build.configTab:BuildModList() + build.spec.modFlag = true + build.buildFlag = true + runCallback("OnFrame") + runCallback("OnFrame") + assert.is_nil(build.calcsTab.mainEnv.mercenary) + assert.is_nil(build.calcsTab.mainEnv.mercenaryCalculationErrors) + assert.matches("cannot have more than 6", table.concat(tab:GetErrors(), "\n")) + + local profile = { + buildId = "AurasMinionsTemplarSpectres", + foundAreaLevel = 68, + mainSkillId = "SSMHolySpectresMercenary", + skills = { { + id = "SSMHolySpectresMercenary", + enabled = true, + supports = { { tier = 3 } }, + } }, + } + local ok, validateErrors = pcall(MercenaryTools.validateProfile, profile, data.ensureMercenaries()) + assert.is_true(ok) + assert.matches("Invalid support", table.concat(validateErrors, "\n")) + + newBuild() + local runtimeProfile = build.mercenaryTab.profile + runtimeProfile.classId = "AurasMinionsTemplar" + runtimeProfile.buildId = "AurasMinionsTemplarSpectres" + runtimeProfile.foundAreaLevel = 68 + runtimeProfile.mainSkillId = "SSMHolySpectresMercenary" + runtimeProfile.skills = { { enabled = true, supports = { } } } + build.mercenaryTab:Changed() + build.configTab:BuildModList() + local calculated, calculationError = pcall(function() build.calcsTab:BuildOutput() end) + assert.is_true(calculated, calculationError) + assert.is_nil(build.calcsTab.mainEnv.mercenary) + assert.is_nil(build.calcsTab.mainEnv.mercenaryCalculationErrors) + assert.matches("Invalid skill for selected build", table.concat(build.mercenaryTab:GetErrors(), "\n")) + end) + + it("comparison actor follows Items vs Edit Equipment context, not who wears the set", function() + selectBuild("MeleeAOEMarauderFireSlam") + local itemsTab = build.itemsTab + local playerSetId = itemsTab.activeItemSetId + assert(itemsTab:SetActorItemSet("MERCENARY", playerSetId, false)) + tab.controls.editEquipment.onClick() + assert.are.equal("ITEMS", build.viewMode) + assert.are.equal(playerSetId, itemsTab.viewItemSetId) + assert.are.equal("MERCENARY", itemsTab:ComparisonActorForItemSet(playerSetId)) + assert.are.equal("MERCENARY", itemsTab:ItemCalculationOverride("Helmet", item()).comparisonActor) + + assert.are.equal("MERCENARY", itemsTab:ComparisonActorForItemSet(playerSetId)) + assert(itemsTab:SetViewItemSet(playerSetId)) + assert.are.equal("PLAYER", itemsTab:ComparisonActorForItemSet(playerSetId)) + assert.are.equal("PLAYER", itemsTab:ItemCalculationOverride("Helmet", item()).comparisonActor) + + freshBuild() + selectBuild("MeleeAOEMarauderFireSlam") + itemsTab = build.itemsTab + local mercSet = assert(tab:GetItemSet(true)) + assert(itemsTab:SetViewItemSet(mercSet.id)) + assert.are_not.equal(itemsTab.activeItemSetId, mercSet.id) + assert.are.equal("MERCENARY", itemsTab:ComparisonActorForItemSet(mercSet.id)) + assert.are.equal("MERCENARY", itemsTab:ItemCalculationOverride("Helmet", item()).comparisonActor) + + assert(tab:GetItemSet(true)) + local bossingSet = itemsTab:NewItemSet() + bossingSet.title = "Bossing" + table.insert(itemsTab.itemSetOrderList, bossingSet.id) + assert(itemsTab:SetActorItemSet("MERCENARY", bossingSet.id, false)) + assert(itemsTab:SetViewItemSet(bossingSet.id)) + assert.are_not.equal(itemsTab.activeItemSetId, bossingSet.id) + assert.are.equal("MERCENARY", itemsTab:ComparisonActorForItemSet(bossingSet.id)) + assert.are.equal("MERCENARY", itemsTab:ItemCalculationOverride("Helmet", item()).comparisonActor) + end) + + it("migrates legacy Slot XML into the fallback item set", function() + freshBuild() + local itemsTab = build.itemsTab + itemsTab:Load({ + attrib = { useSecondWeaponSet = "false" }, + { + elem = "Item", + attrib = { id = "1" }, + "Rarity: Normal\nIron Hat", + }, + { + elem = "Slot", + attrib = { name = "Helmet", itemId = "1" }, + }, + }) + assert.are.equal(1, itemsTab.activeItemSet.Helmet.selItemId) + assert.are.equal(1, itemsTab.slots.Helmet.selItemId) + end) + + it("copies a Mercenary loadout without cloning ItemsTab item sets", function() + selectBuild("MeleeAOEMarauderFireSlam") + local itemsTab = build.itemsTab + local mercSet = assert(tab:GetItemSet(true)) + local sourceItemSetId = itemsTab:GetActorItemSetId("MERCENARY") + local helmet = new("Item"):Item("Rarity: Normal\nLeather Cap") + itemsTab:AddItem(helmet, true) + mercSet.Helmet.selItemId = helmet.id + local setCount = #itemsTab.itemSetOrderList + tab:ResetUndo() + + local manager = new("MercenarySetListControl"):MercenarySetListControl(nil, { 0, 0, 350, 200 }, tab) + manager.selValue = tab.activeMercenarySetId + manager.selIndex = 1 + local popup + local originalOpenPopup = main.OpenPopup + local originalClosePopup = main.ClosePopup + main.OpenPopup = function(_, _, _, _, controls) popup = controls end + main.ClosePopup = function() end + local ok, err = pcall(function() + manager.controls.copy.onClick() + popup.edit.buf = "Copied Loadout" + popup.save.onClick() + end) + main.OpenPopup = originalOpenPopup + main.ClosePopup = originalClosePopup + assert.is_true(ok, err) + + local copied + for _, setId in ipairs(tab.mercenarySetOrderList) do + if tab.mercenarySets[setId].title == "Copied Loadout" then copied = tab.mercenarySets[setId] break end + end + assert.is_not_nil(copied) + assert.is_not_nil(copied.itemSetId) + assert.are_not.equal(sourceItemSetId, copied.itemSetId) + assert.are.equal(setCount + 1, #itemsTab.itemSetOrderList) + assert.are.equal(helmet.id, itemsTab.itemSets[copied.itemSetId].Helmet.selItemId) + assert.are.equal(sourceItemSetId, itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(helmet.id, mercSet.Helmet.selItemId) + + tab:Undo() + assert.is_nil(tab.mercenarySets[copied.id]) + assert.is_not_nil(itemsTab.itemSets[sourceItemSetId]) + assert.are.equal(sourceItemSetId, itemsTab:GetActorItemSetId("MERCENARY")) + end) + + it("isolates Mercenary undo from Items sets, assignment, and Config redo", function() + MercenaryTest.allocatePermanentHire() + tab = build.mercenaryTab + tab:EnsureData() + local itemsTab = build.itemsTab + tab.profile.buildId = "MeleeAOEMarauderFireSlam" + tab.profile.classId = tab.data.builds.MeleeAOEMarauderFireSlam.classId + tab.profile.foundAreaLevel = 68 + tab:Changed() + assert.is_nil(tab:GetItemSet(false)) + tab:ResetUndo() + tab.controls.editEquipment.onClick() + local createdId = itemsTab:GetActorItemSetId("MERCENARY") + local hat = new("Item"):Item("Rarity: Normal\nIron Hat") + itemsTab:AddItem(hat, true) + itemsTab.itemSets[createdId].Helmet.selItemId = hat.id + itemsTab:AddUndoState() + tab.profile.foundAreaLevel = 80 + tab:Changed() + tab:Undo() + assert.are.equal(68, tab.profile.foundAreaLevel) + assert.is_not_nil(itemsTab.itemSets[createdId]) + assert.are.equal(hat.id, itemsTab.itemSets[createdId].Helmet.selItemId) + local bossing = itemsTab:NewItemSet() + bossing.title = "Bossing" + table.insert(itemsTab.itemSetOrderList, bossing.id) + tab.profile.foundAreaLevel = 80 + tab:Changed() + itemsTab:ResetUndo() + assert(itemsTab:SetActorItemSet("MERCENARY", bossing.id, false)) + itemsTab:AddUndoState() + tab:Undo() + assert.are.equal(68, tab.profile.foundAreaLevel) + assert.are.equal(bossing.id, itemsTab:GetActorItemSetId("MERCENARY")) + itemsTab:Undo() + assert.are.equal(createdId, itemsTab:GetActorItemSetId("MERCENARY")) + tab:ResetUndo() + tab.profile.foundAreaLevel = 80 + tab:Changed() + tab:Undo() + assert.are.equal(68, tab.profile.foundAreaLevel) + assert.are.equal(1, #tab.redo) + local configTab = build.configTab + configTab:ResetUndo() + configTab.input.usePowerCharges = true + configTab:BuildModList() + configTab:AddUndoState() + configTab:Undo() + assert.are.equal(1, #tab.redo) + tab:Redo() + assert.are.equal(80, tab.profile.foundAreaLevel) + end) + + local function hireMarauder(skillId) + build.characterLevelAutoMode = false + build.characterLevel = 90 + MercenaryTest.allocatePermanentHire() + tab = build.mercenaryTab + tab:EnsureData() + skillId = skillId or "TectonicSlamFireMercenary" + local buildId = "MeleeAOEMarauderFireSlam" + tab.profile.classId = tab.data.builds[buildId].classId + tab.profile.buildId = buildId + tab.profile.foundAreaLevel = 68 + tab.profile.mainSkillId = skillId + tab.profile.skills = { { id = skillId, enabled = true, supports = { } } } + tab:GetItemSet(true) + tab:Changed() + return tab + end + + it("undo Reset and unhire restore mercenary configuration", function() + hireMarauder() + local config = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(config) + config.actors.mercenary.customModsList[1].text = "+1000 to maximum Life" + build.configTab:BuildModList() + local withMod = assert(MercenaryTest.calculateBuild().mercenary).output.Life + tab:ResetUndo() + tab:Reset() + MercenaryTest.calculateBuild() + tab:Undo() + assert.are.equal(withMod, assert(MercenaryTest.calculateBuild().mercenary).output.Life) + newBuild() + build.characterLevelAutoMode = false + build.characterLevel = 90 + MercenaryTest.allocatePermanentHire() + tab = build.mercenaryTab + config = build.configTab.configSets[build.configTab.activeConfigSetId] + build.configTab:EnsureActorConfig(config) + config.actors.mercenary.customModsList[1].text = "+1000 to maximum Life" + build.configTab:BuildModList() + MercenaryTest.calculateBuild() + tab:ResetUndo() + hireMarauder() + assert.is_not_nil(MercenaryTest.calculateBuild().mercenary) + tab:Undo() + assert.is_nil(MercenaryTest.calculateBuild().mercenary) + assert.is_false(build.configTab.modListHasHiredMercenary) + end) + + it("undo cancels in-flight support sorting", function() + hireMarauder("FissureSlamMercenary") + MercenaryTest.calculateBuild() + tab:ResetUndo() + tab.profile.foundAreaLevel = 80 + tab:Changed() + MercenaryTest.calculateBuild() + tab.sortGemsByDPS = true + tab.sortGemsByDPSField = "CombinedDPS" + tab:RefreshSupportLists() + local originalCalculator = build.calcsTab.GetMiscCalculator + local sortEnvironment = getfenv(tab.QueueSupportSort) + local originalTime = sortEnvironment.GetTime + local ticks = 0 + sortEnvironment.GetTime = function() + ticks = ticks + 100 + return ticks + end + build.calcsTab.GetMiscCalculator = function() + return function() + local skill = tab.profile.skills[tab.selectedSkillIndex] + local supportId = skill and skill.supports[1] and skill.supports[1].id + return { CombinedDPS = (tab.profile.foundAreaLevel or 0) + (supportId == "AddedFireHigh" and 1000 or 0) } + end + end + local ok, err = pcall(function() + tab:QueueSupportSort(1) + tab:ProcessSupportSort() + assert.is_not_nil(tab.supportSortCoroutine) + tab:Undo() + assert.is_nil(tab.supportSortCoroutine) + assert.is_nil(tab.supportSortCache[1]) + while tab.supportSortCoroutine do tab:ProcessSupportSort() end + local published = { } + for _, row in ipairs(tab.supportControls[1].list) do + if row.dps then published[row.id or "none"] = row.dps end + end + tab:InvalidateSupportSort() + tab:RefreshSupportLists() + tab:QueueSupportSort(1) + while tab.supportSortCoroutine do tab:ProcessSupportSort() end + local expected = { } + for _, row in ipairs(tab.supportControls[1].list) do + expected[row.id or "none"] = row.dps + end + assert.are.equal(68 + 1000, expected.AddedFireHigh) + for id, dps in pairs(published) do + assert.are.equal(expected[id], dps) + end + end) + sortEnvironment.GetTime = originalTime + build.calcsTab.GetMiscCalculator = originalCalculator + assert.is_true(ok, err) + end) + + it("trade set dropdown keeps the current comparison actor", function() + selectBuild("MeleeAOEMarauderFireSlam") + local itemsTab = build.itemsTab + local mercSet = assert(tab:GetItemSet(true)) + assert(itemsTab:SetViewItemSet(mercSet.id, "MERCENARY")) + local tradeQuery = itemsTab.tradeQuery + local originalOpenPopup = main.OpenPopup + local originalUpdateRealms = tradeQuery.UpdateRealms + local originalPullCXData = tradeQuery.PullCXData + main.OpenPopup = function() end + tradeQuery.UpdateRealms = function() end + tradeQuery.PullCXData = function() end + local ok, err = pcall(function() tradeQuery:PriceItem() end) + main.OpenPopup = originalOpenPopup + tradeQuery.UpdateRealms = originalUpdateRealms + tradeQuery.PullCXData = originalPullCXData + assert.is_true(ok, err) + local mercIndex = isValueInArray(itemsTab.itemSetOrderList, mercSet.id) + tradeQuery.controls.setSelect.selFunc(mercIndex) + assert.are.equal("MERCENARY", itemsTab.viewComparisonActor) + assert.are.equal(mercSet.id, itemsTab.viewItemSetId) + end) + + it("edits Mercenary supports as a dense list", function() + local supports = { { id = "FistOfWarHigh" }, { id = "AddedFireHigh" } } + MercenaryTools.setSkillSupport(supports, 1, nil) + assert.are.equal(1, #supports) + assert.are.equal("AddedFireHigh", supports[1].id) + supports = { } + MercenaryTools.setSkillSupport(supports, 3, { id = "AddedFireHigh", tier = 3 }) + assert.are.equal(1, #supports) + assert.are.equal("AddedFireHigh", supports[1].id) + local skill = { supports = { { id = "FistOfWarHigh" } } } + local seen + MercenaryTools.withEditedSupports(skill, 3, { id = "AddedFireHigh" }, function() + seen = copyTable(skill.supports, true) + end) + assert.are.equal(2, #seen) + assert.are.equal("AddedFireHigh", seen[2].id) + assert.are.equal(1, #skill.supports) + assert.are.equal("FistOfWarHigh", skill.supports[1].id) + end) +end) diff --git a/spec/System/TestMercenaryImport_spec.lua b/spec/System/TestMercenaryImport_spec.lua new file mode 100644 index 00000000000..1790bfd7206 --- /dev/null +++ b/spec/System/TestMercenaryImport_spec.lua @@ -0,0 +1,409 @@ +describe("Mercenary API import", function() + local Import = require("Modules.MercenaryImport") + local Tools = require("Modules.MercenaryTools") + local helpers = dofile("../spec/System/MercenaryTestHelpers.lua") + local source = { account = "fixture-account", realm = "pc", league = "Test League" } + local roster, tab + + local function skillEntry(data, skillId, withSupport) + local skill = assert(data.skills[skillId], skillId) + local supports = { } + if withSupport then + local supportId = skill.possibleSupportIds[1] + if supportId then + local support = data.supports[supportId] + supports[1] = { id = supportId, hash = support.hash, tier = support.variant } + end + end + return { id = skillId, hash = skill.hash, supports = supports } + end + + local function abyssJewel(uniqueId) + return { + abyssJewel = true, + name = "Morbid Stare", + typeLine = "Ghastly Eye Jewel", + frameType = 2, + id = uniqueId, + ilvl = 80, + socket = 0, + properties = { { name = "Abyss", values = { }, displayMode = 0 } }, + explicitMods = { { description = "+10 to maximum Life" } }, + } + end + + local function makeHire(data, name, buildId, uniqueSuffix, skillIds) + local mercBuild = assert(data.builds[buildId], buildId) + local skills = { } + for index, skillId in ipairs(skillIds) do + skills[index] = skillEntry(data, skillId, index == 1) + end + return { + name = name, + level = 83, + build = buildId, + build_hash = mercBuild.hash, + skills = skills, + items = { + { + id = "helm-"..uniqueSuffix, + name = "", + typeLine = "Leather Cap", + frameType = 0, + inventoryId = "Helm", + sockets = { { group = 0, attr = "A", sColour = "A" } }, + explicitMods = { { description = "Has 1 Abyssal Socket" } }, + socketedItems = { abyssJewel("abyss-helm-"..uniqueSuffix) }, + }, + { + id = "weapon-"..uniqueSuffix, + name = "", + typeLine = "Crude Bow", + frameType = 0, + inventoryId = "Weapon", + sockets = { { group = 0, attr = "G", sColour = "G" } }, + socketedItems = { { typeLine = "Fireball", socket = 0, properties = { } } }, + }, + { + id = "quiver-"..uniqueSuffix, + name = "", + typeLine = "Serrated Arrow Quiver", + frameType = 0, + inventoryId = "Offhand", + }, + { + id = "belt-"..uniqueSuffix, + name = "", + typeLine = "Stygian Vise", + frameType = 0, + inventoryId = "Belt", + sockets = { { group = 0, attr = "A", sColour = "A" } }, + implicitMods = { { description = "Has 1 Abyssal Socket" } }, + socketedItems = { abyssJewel("abyss-belt-"..uniqueSuffix) }, + }, + }, + } + end + + before_each(function() + newBuild() + build.characterLevel = 97 + tab = build.mercenaryTab + tab:EnsureData() + roster = { + mercenaries = { + makeHire(tab.data, "Ruktara, the Bullseye", "EleBowRangerLightning", "1", { "LightningArrowMercenary", "AssassinsMarkMercenary" }), + makeHire(tab.data, "Vorneka Azrus", "EleBowRangerClones", "2", { "MirrorArrowMercenary", "BlinkArrowMercenary" }), + }, + active_mercenary_index = 2, + } + end) + after_each(function() + while main.popups[1] do main:ClosePopup() end + end) + + local function import(index, destination) + local profile, err = build.importTab:ImportMercenary(roster.mercenaries[index], source, destination) + assert.is_table(profile, err) + return profile + end + + local function itemCount() + local count = 0 + for _ in pairs(build.itemsTab.items) do count = count + 1 end + return count + end + + local function mercSetId() + return build.itemsTab:GetActorItemSetId("MERCENARY") + end + + it("converts synthetic hires and resolves optional IDs through hashes", function() + for _, hire in ipairs(roster.mercenaries) do + local profile = assert(Import.profile(hire, tab.data)) + assert.same({ }, Tools.validateProfile(profile, tab.data)) + assert.equals(83, profile.foundAreaLevel) + assert.is_nil(profile.importedWarrant) + assert.is_true(#profile.skills >= 1) + for _, skill in ipairs(profile.skills) do + assert.is_true(skill.enabled) + assert.is_false(skill.includeInFullDPS) + assert.equals(1, skill.count) + end + end + local hire = roster.mercenaries[1] + local expected = assert(Import.profile(hire, tab.data)) + for _, skill in ipairs(hire.skills) do + skill.id = nil + skill.name = "Wrong display name" + for _, support in ipairs(skill.supports) do support.id = nil end + end + assert.same(expected, assert(Import.profile(hire, tab.data))) + hire.skills[2].supports = nil + assert.equals(0, #assert(Import.profile(hire, tab.data)).skills[2].supports) + hire.skills[2].supports = "nope" + assert.is_nil(Import.profile(hire, tab.data)) + end) + + for _, case in ipairs({ "build hash", "skill hash", "support hash", "skill ID", "support tier", "unknown hash" }) do + it("rejects "..case.." conflicts without mutating the build", function() + local hire = roster.mercenaries[1] + if case == "build hash" then hire.build_hash = -1 + elseif case == "skill hash" then hire.skills[1].hash = -1 + elseif case == "support hash" then hire.skills[1].supports[1].hash = -1 + elseif case == "skill ID" then hire.skills[1].id = "Unsupported" + elseif case == "support tier" then hire.skills[1].supports[1].tier = 99 + else hire.skills[1].id = nil hire.skills[1].hash = -1 end + local before = build:SaveDB("code") + assert.is_nil(build.importTab:ImportMercenary(hire, source)) + assert.equals(before, build:SaveDB("code")) + end) + end + + it("imports equipment through ItemsTab without displacing player or Guardian gear", function() + local itemsTab = build.itemsTab + build.importTab:ImportItemsAndSkills({ level = 97, equipment = {{ id = "player", name = "", typeLine = "Iron Hat", frameType = 0, inventoryId = "Helm" }} }, false, false, false) + local guardianSet = build.importTab:GetOrCreateGuardianItemSet() + build.importTab:ImportItem({ id = "guardian", name = "", typeLine = "Leather Belt", frameType = 0, inventoryId = "Belt" }, nil, false, guardianSet.id) + local playerBefore = copyTable(itemsTab.activeItemSet) + local guardianBefore = copyTable(guardianSet) + local skillsBefore = copyTable(build.skillsTab.socketGroupList) + local first = import(1) + local firstSetId = mercSetId() + assert.is_not_nil(firstSetId) + assert.are_not.equal(itemsTab.activeItemSetId, firstSetId) + assert.equals(firstSetId, first.itemSetId) + local second = import(2) + local secondSetId = mercSetId() + assert.are_not.equal(firstSetId, secondSetId) + local set = itemsTab.itemSets[secondSetId] + for _, slot in ipairs({"Helmet Abyssal Socket 1", "Belt Abyssal Socket 1"}) do + assert.is_true(set[slot].selItemId > 0) + assert.equals("Abyss", itemsTab.items[set[slot].selItemId].base.subType) + end + assert.same(playerBefore, itemsTab.activeItemSet) + assert.same(guardianBefore, itemsTab.itemSets[guardianSet.id]) + assert.same(skillsBefore, build.skillsTab.socketGroupList) + assert.equals(97, build.characterLevel) + tab:SetActiveMercenarySet(first.id) + assert.equals(firstSetId, mercSetId()) + assert.is_nil(build.configTab.configSets[build.configTab.activeConfigSetId].actors.mercenary.itemSetId) + end) + + it("reimports without duplication and keeps shared or player-worn items", function() + local first = import(1) + local second = import(2) + local firstBefore = copyTable(first) + second.title = "My renamed hire" + second.skills[1].includeInFullDPS = true + second.skills[1].count = 3 + local again = import(2) + assert.equals(second.id, again.id) + assert.equals(roster.mercenaries[2].name, again.title) + assert.equals(1, again.skills[1].count) + assert.is_false(again.skills[1].includeInFullDPS) + local afterSecond = itemCount() + for index, item in ipairs(roster.mercenaries[2].items) do + if item.inventoryId == "Helm" then table.remove(roster.mercenaries[2].items, index) break end + end + import(2) + local set = build.itemsTab.itemSets[mercSetId()] + assert.equals(0, set.Helmet.selItemId) + assert.equals(0, set["Helmet Abyssal Socket 1"].selItemId) + assert.is_true(itemCount() < afterSecond) + assert.same(firstBefore, tab.mercenarySets[first.id]) + + local helmetId = build.itemsTab.itemSets[first.itemSetId].Helmet.selItemId + local spare = build.itemsTab:NewItemSet() + table.insert(build.itemsTab.itemSetOrderList, spare.id) + spare.Helmet.selItemId = helmetId + import(1) + assert.equals(helmetId, spare.Helmet.selItemId) + assert.is_not_nil(build.itemsTab.items[helmetId]) + + build.skillsTab:PasteSocketGroup("Animate Guardian 20/0 1") + local gem = build.skillsTab.socketGroupList[1].gemList[1] + gem.skillMinionItemSet = first.itemSetId + assert.equals(first.itemSetId, import(1).itemSetId) + assert.equals(first.itemSetId, gem.skillMinionItemSet) + + local before = build:SaveDB("code") + roster.mercenaries[2].items[1].typeLine = "Unsupported item base" + assert.is_nil(build.importTab:ImportMercenary(roster.mercenaries[2], source)) + assert.equals(before, build:SaveDB("code")) + + local hire = copyTable(roster.mercenaries[1]) + local helmData + for _, itemData in ipairs(hire.items) do + if itemData.inventoryId == "Helm" then helmData = itemData break end + end + newBuild() + tab = build.mercenaryTab + tab:EnsureData() + build.importTab:ImportItemsAndSkills({ + level = 97, + equipment = {{ id = helmData.id, name = "", typeLine = "Iron Hat", frameType = 0, inventoryId = "Helm" }}, + }, false, false, false) + local imported, message = build.importTab:ImportMercenary(hire, source) + assert.is_nil(imported) + assert.matches("still equipped by the player", message) + end) + + it("maps equipment by inventoryId and applies socket occupancy without player gems", function() + local hire = roster.mercenaries[1] + local reversed = { } + for index = #hire.items, 1, -1 do table.insert(reversed, hire.items[index]) end + hire.items = reversed + local profile = import(1) + assert.equals(0, #build.skillsTab.socketGroupList) + local weapon = build.itemsTab.items[build.itemsTab.itemSets[mercSetId()]["Weapon 1"].selItemId] + assert.equals("Crude Bow", weapon.baseName) + assert.equals("Fireball", weapon.socketedGems[1].nameSpec) + assert.equals(0, #build.skillsTab.socketGroupList) + assert.equals(2, #profile.skills) + + newBuild() + build.characterLevel = 97 + tab = build.mercenaryTab + tab:EnsureData() + helpers.allocatePermanentHire() + helpers.allocate("Legendary Rings") + tab.profile.classId = "ElementalWitch" + tab.profile.buildId = "ElementalWitchLightning" + tab.profile.foundAreaLevel = 83 + tab.profile.mainSkillId = "ArcMercenary" + tab.profile.skills = { { id = "ArcMercenary", enabled = true, supports = { } } } + tab:Changed() + local set = tab:GetItemSet(true) + local function importRing(socketedItems) + build.importTab:ImportItem({ + id = "malachai-socket-test", frameType = 3, name = "Malachai's Artifice", typeLine = "Unset Ring", + sockets = { { group = 0, sColour = "W" } }, socketedItems = socketedItems, + implicitMods = { "Has 1 Socket" }, + explicitMods = { "-20% to all Elemental Resistances", "+100% to Fire Resistance when Socketed with a Red Gem", "All Sockets are White" }, + }, "Ring 1", false, set.id, { actor = "MERCENARY" }) + end + importRing({ }) + local env = helpers.calculateBuild() + assert.is_table(env.mercenary, table.concat(env.mercenaryCalculationErrors or { }, "\n")) + local before = env.mercenary.output.FireResistTotal + importRing({ { typeLine = "Heavy Strike", socket = 0, support = false, properties = { } } }) + env = helpers.calculateBuild() + assert.equals(before + 100, env.mercenary.output.FireResistTotal) + end) + + it("forks a new item set only for the player's active destination and unused default loadout", function() + assert.equals(1, Import.unusedEmptyId(tab.mercenarySets, tab.mercenarySetOrderList)) + local original = import(1) + assert.equals(1, original.id) + assert.is_nil(Import.unusedEmptyId(tab.mercenarySets, tab.mercenarySetOrderList)) + local destId = mercSetId() + assert(build.itemsTab:SetActiveItemSet(destId)) + for _, slot in pairs(build.itemsTab.activeItemSet) do + if type(slot) == "table" and slot.selItemId then slot.selItemId = 0 end + end + local playerSet = copyTable(build.itemsTab.activeItemSet) + import(1) + assert.not_equals(destId, mercSetId()) + assert.same(playerSet, build.itemsTab.activeItemSet) + local duplicate = import(1, 0) + assert.not_equals(original.id, duplicate.id) + assert.is_nil(build.importTab:ImportMercenary(roster.mercenaries[1], source)) + assert.equals(original.id, import(1, original.id).id) + local empty = tab:NewMercenarySet(nil, "Empty") + table.insert(tab.mercenarySetOrderList, empty.id) + assert.is_nil(empty.itemSetId) + end) + + it("persists associations through XML without the account UUID", function() + roster.mercenaries[1].level = 40 + local uuid = "550e8400-e29b-41d4-a716-446655440000" + local profile, err = build.importTab:ImportMercenary(roster.mercenaries[1], { + account = uuid, + realm = source.realm, + league = source.league, + }) + assert.is_table(profile, err) + assert.equals(40, profile.foundAreaLevel) + assert.matches("^%x+$", profile.importAssociation) + assert.equals(64, #profile.importAssociation) + assert.is_nil(profile.importAssociation:find(uuid, 1, true)) + local xml = { } + tab:Save(xml) + tab:Load(xml) + assert.equals(40, tab.profile.foundAreaLevel) + assert.equals(profile.importAssociation, tab.profile.importAssociation) + assert.is_nil(build:SaveDB("code"):find(uuid, 1, true)) + end) + + it("keeps Mercenary and Items undo isolated after import", function() + local first = import(1) + local firstSetId = mercSetId() + local original = copyTable(tab.profile.skills[1].supports) + import(2) + tab:Undo() + assert.equals(first.buildId, tab.profile.buildId) + assert.equals(firstSetId, mercSetId()) + table.remove(roster.mercenaries[1].skills[1].supports) + import(1, first.id) + assert.are.equal(#original - 1, #tab.profile.skills[1].supports) + build.itemsTab:Undo() + assert.are.equal(#original - 1, #tab.profile.skills[1].supports) + tab:Undo() + assert.same(original, tab.profile.skills[1].supports) + end) + + it("walks the popup from a valid active index and ignores an empty roster", function() + for _, index in ipairs({1, 2}) do + roster.active_mercenary_index = index + assert.equals(index, Import.activeIndex(roster)) + end + for _, index in ipairs({0, -1, 3, 1.5, "2", false}) do + roster.active_mercenary_index = index + assert.is_nil(Import.activeIndex(roster)) + end + roster.active_mercenary_index = 2 + build.importTab:OpenMercenaryImportPopup(roster, source) + local popup = main.popups[1] + assert.equals(2, popup.controls.hire.selIndex) + assert.matches("Vorneka", popup.controls.hire:GetSelValue().label) + assert.matches("%(Active%)", popup.controls.hire:GetSelValue().label) + popup.controls.import.onClick() + assert.equals("EleBowRangerClones", tab.profile.buildId) + main:ClosePopup() + roster.active_mercenary_index = 0 + build.importTab:OpenMercenaryImportPopup(roster, source) + assert.equals(1, main.popups[1].controls.hire.selIndex) + assert.is_nil((main.popups[1].controls.hire:GetSelValue().label):match("%(Active%)")) + main:ClosePopup() + build.importTab:OpenMercenaryImportPopup({ mercenaries = { } }, source) + assert.is_nil(main.popups[1]) + end) + + it("matches reimports by association fingerprint, not roster order or copied loadouts", function() + local hireA = { name = "Same Name", build_hash = 1, skills = { { hash = 10, supports = { { hash = 1, tier = 1 } } } } } + local hireB = { name = "Same Name", build_hash = 1, skills = { { hash = 20, supports = { { hash = 1, tier = 1 } } } } } + assert.not_equals(Import.association(source.account, source.realm, source.league, hireA), Import.association(source.account, source.realm, source.league, hireB)) + local ruktara = import(1) + local vorneka = import(2) + roster.mercenaries[1], roster.mercenaries[2] = roster.mercenaries[2], roster.mercenaries[1] + assert.equals(vorneka.id, build.importTab:ImportMercenary(roster.mercenaries[1], source).id) + assert.equals(ruktara.id, build.importTab:ImportMercenary(roster.mercenaries[2], source).id) + roster.mercenaries[1], roster.mercenaries[2] = roster.mercenaries[2], roster.mercenaries[1] + tab:OpenMercenarySetManagePopup() + local list = main.popups[1].controls[1] + list.selValue = ruktara.id + list.selIndex = 1 + list.controls.copy.onClick() + main.popups[1].controls.edit.buf = "Copied hire" + main.popups[1].controls.save.onClick() + local copyId + for _, id in ipairs(tab.mercenarySetOrderList) do + if id ~= ruktara.id and id ~= vorneka.id then copyId = id end + end + assert.equals("Copied hire", tab.mercenarySets[copyId].title) + assert.is_nil(tab.mercenarySets[copyId].importAssociation) + assert.equals(ruktara.id, import(1).id) + main:ClosePopup() + end) +end) diff --git a/spec/System/TestMercenaryLoadout_spec.lua b/spec/System/TestMercenaryLoadout_spec.lua new file mode 100644 index 00000000000..f653db574fa --- /dev/null +++ b/spec/System/TestMercenaryLoadout_spec.lua @@ -0,0 +1,262 @@ +describe("Build loadouts include Mercenary sets", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + + local function hire(profile, classId, buildId, skillId) + profile.classId = classId + profile.buildId = buildId + profile.foundAreaLevel = 68 + profile.mainSkillId = skillId + profile.skills = { { id = skillId, enabled = true, supports = { } } } + end + + local function addNamedLoadout(title) + local spec = new("PassiveSpec"):PassiveSpec(build, latestTreeVersion) + spec.title = title + table.insert(build.treeTab.specList, spec) + local itemSet = build.itemsTab:NewItemSet() + table.insert(build.itemsTab.itemSetOrderList, itemSet.id) + itemSet.title = title + local skillSet = build.skillsTab:NewSkillSet() + table.insert(build.skillsTab.skillSetOrderList, skillSet.id) + skillSet.title = title + local configSet = build.configTab:NewConfigSet() + table.insert(build.configTab.configSetOrderList, configSet.id) + configSet.title = title + return spec, itemSet, skillSet, configSet + end + + local function addNamedSets(title) + local spec, itemSet, skillSet, configSet = addNamedLoadout(title) + local mercenarySet = build.mercenaryTab:NewMercenarySet(nil, title) + table.insert(build.mercenaryTab.mercenarySetOrderList, mercenarySet.id) + return spec, itemSet, skillSet, configSet, mercenarySet + end + + local function selectLoadout(name) + build:SyncLoadouts() + local index = isValueInArray(build.controls.buildLoadouts.list, name) + assert.is_not_nil(index, "missing loadout "..tostring(name)) + build.controls.buildLoadouts.selIndex = nil + build.controls.buildLoadouts:SetSel(index) + assert.are.equal(name, build.controls.buildLoadouts.list[build.controls.buildLoadouts.selIndex]) + end + + local function bindHire(setId) + build.mercenaryTab:SetActiveMercenarySet(setId, false, true) + build.mercenaryTab:AddUndoState() + end + + before_each(function() + newBuild() + MercenaryTest.allocatePermanentHire() + build.treeTab.specList[1].title = "Default" + build.itemsTab.activeItemSet.title = "Default" + build.skillsTab.skillSets[build.skillsTab.activeSkillSetId].title = "Default" + build.configTab.configSets[build.configTab.activeConfigSetId].title = "Default" + build.mercenaryTab.profile.title = "Default" + hire(build.mercenaryTab.profile, "MeleeAOEMarauder", "MeleeAOEMarauderFireSlam", "TectonicSlamFireMercenary") + build.mercenaryTab:Changed() + end) + + it("does not create a Mercenary set when using New Loadout", function() + local popup + local originalOpenPopup = main.OpenPopup + local originalClosePopup = main.ClosePopup + main.OpenPopup = function(_, _, _, _, controls) popup = controls end + main.ClosePopup = function() end + local before = #build.mercenaryTab.mercenarySetOrderList + local ok, err = pcall(function() + local index = isValueInArray(build.controls.buildLoadouts.list, "^7^7New Loadout") + build.controls.buildLoadouts:SetSel(index) + popup.edit.buf = "Boss" + popup.save.enabled = true + popup.save.onClick() + end) + main.OpenPopup = originalOpenPopup + main.ClosePopup = originalClosePopup + assert.is_true(ok, err) + assert.are.equal(before, #build.mercenaryTab.mercenarySetOrderList) + assert.is_not_nil(isValueInArray(build.controls.buildLoadouts.list, "Boss")) + end) + + it("switches the hired Mercenary and restores that hire's equipment", function() + local _, playerItems, _, _, bossMerc = addNamedSets("Boss") + local _, _, _, _, mappingMerc = addNamedSets("Mapping") + hire(bossMerc, "TrapsMinesShadow", "TrapsMinesShadowLightning", "LightningTrapMercenary") + hire(mappingMerc, "EleBowRanger", "EleBowRangerFire", "BurningArrowMercenary") + build.mercenaryTab:SetActiveMercenarySet(bossMerc.id) + local bossItems = build.mercenaryTab:GetItemSet(true) + local bossHelm = new("Item"):Item("Rarity: Normal\nIron Hat") + build.itemsTab:AddItem(bossHelm, true) + bossItems.Helmet.selItemId = bossHelm.id + build.mercenaryTab:StoreActiveMercenaryItemSet() + build.mercenaryTab:SetActiveMercenarySet(mappingMerc.id) + local mappingItems = build.mercenaryTab:GetItemSet(true) + local mappingHelm = new("Item"):Item("Rarity: Normal\nLeather Cap") + build.itemsTab:AddItem(mappingHelm, true) + mappingItems.Helmet.selItemId = mappingHelm.id + build.mercenaryTab:StoreActiveMercenaryItemSet() + selectLoadout("Mapping") + assert.are.equal(mappingMerc.id, build.mercenaryTab.activeMercenarySetId) + assert.are.equal("EleBowRangerFire", build.mercenaryTab.profile.buildId) + assert.are.equal(mappingMerc.itemSetId, build.itemsTab:GetActorItemSetId("MERCENARY")) + assert.are.equal(mappingHelm.id, build.itemsTab:GetActorItemSet("MERCENARY").Helmet.selItemId) + selectLoadout("Boss") + assert.are.equal(bossMerc.id, build.mercenaryTab.activeMercenarySetId) + assert.are.equal(playerItems.id, build.itemsTab.activeItemSetId) + assert.are.equal(bossHelm.id, build.itemsTab:GetActorItemSet("MERCENARY").Helmet.selItemId) + end) + + it("does not hide player loadouts or wear Mercenary gear as the player set", function() + addNamedSets("Boss") + local extra = build.mercenaryTab:NewMercenarySet(nil, "Kaom") + table.insert(build.mercenaryTab.mercenarySetOrderList, extra.id) + build:SyncLoadouts() + assert.is_not_nil(isValueInArray(build.controls.buildLoadouts.list, "Boss")) + assert.is_not_nil(isValueInArray(build.controls.buildLoadouts.list, "Default")) + local _, playerItems, _, _, bossMerc = addNamedSets("Mapping") + build.mercenaryTab:SetActiveMercenarySet(bossMerc.id) + local mercItems = build.mercenaryTab:GetItemSet(true) + selectLoadout("Mapping") + assert.are.equal(playerItems.id, build.itemsTab.activeItemSetId) + assert.are.equal(mercItems.id, build.itemsTab:GetActorItemSetId("MERCENARY")) + end) + + it("links Mercenary sets through brace identifiers without treating Day1 as {1}", function() + build.treeTab.specList[1].title = "Tree {1}" + build.itemsTab.activeItemSet.title = "Items {1}" + build.skillsTab.skillSets[build.skillsTab.activeSkillSetId].title = "Skills {1}" + build.configTab.configSets[build.configTab.activeConfigSetId].title = "Config {1}" + build.mercenaryTab.profile.title = "Mercenary {1}" + local _, _, _, _, secondMerc = addNamedSets("Unused") + secondMerc.title = "Mercenary {2}" + build.treeTab.specList[#build.treeTab.specList].title = "Tree {2}" + build.itemsTab.itemSets[build.itemsTab.itemSetOrderList[#build.itemsTab.itemSetOrderList]].title = "Items {2}" + build.skillsTab.skillSets[build.skillsTab.skillSetOrderList[#build.skillsTab.skillSetOrderList]].title = "Skills {2}" + build.configTab.configSets[build.configTab.configSetOrderList[#build.configTab.configSetOrderList]].title = "Config {2}" + hire(secondMerc, "EleBowRanger", "EleBowRangerFire", "BurningArrowMercenary") + selectLoadout("Tree {2}") + assert.are.equal(secondMerc.id, build.mercenaryTab.activeMercenarySetId) + local _, itemSet, skillSet, configSet = addNamedLoadout("Boss {1}") + build.mercenaryTab.profile.title = "Day1" + local linked = build.mercenaryTab:NewMercenarySet(nil, "Hire {1}") + table.insert(build.mercenaryTab.mercenarySetOrderList, linked.id) + build.treeTab:SetActiveSpec(#build.treeTab.specList) + build.itemsTab:SetActiveItemSet(itemSet.id) + build.skillsTab:SetActiveSkillSet(skillSet.id) + build.configTab:SetActiveConfigSet(configSet.id) + build:SyncLoadouts() + assert.are_not.equal("Boss {1}", build.controls.buildLoadouts.list[build.controls.buildLoadouts.selIndex]) + end) + + it("binds the selected hire only when requested and falls back to the first set", function() + local _, _, _, day1Config = addNamedLoadout("Day1") + local _, _, _, armourConfig = addNamedLoadout("ArmourStackMerc") + local defaultMercId = build.mercenaryTab.activeMercenarySetId + local second = build.mercenaryTab:NewMercenarySet(nil, "2nd Merc") + table.insert(build.mercenaryTab.mercenarySetOrderList, second.id) + hire(second, "PhysicalDuelist", "PhysicalDuelistShields", "ABTTArmourEleMercenary") + selectLoadout("Day1") + bindHire(defaultMercId) + assert.are.equal(defaultMercId, day1Config.mercenarySetId) + selectLoadout("ArmourStackMerc") + build.mercenaryTab:SetActiveMercenarySet(second.id) + assert.is_nil(armourConfig.mercenarySetId) + bindHire(second.id) + assert.are.equal(second.id, armourConfig.mercenarySetId) + selectLoadout("Day1") + assert.are.equal(defaultMercId, build.mercenaryTab.activeMercenarySetId) + selectLoadout("ArmourStackMerc") + assert.are.equal(second.id, build.mercenaryTab.activeMercenarySetId) + addNamedLoadout("UnboundLoadout") + selectLoadout("UnboundLoadout") + assert.are.equal(build.mercenaryTab.mercenarySetOrderList[1], build.mercenaryTab.activeMercenarySetId) + end) + + it("persists loadout Mercenary bindings through Config XML and drops stale ids", function() + addNamedLoadout("ArmourStackMerc") + local second = build.mercenaryTab:NewMercenarySet(nil, "2nd Merc") + table.insert(build.mercenaryTab.mercenarySetOrderList, second.id) + local armourConfig + for _, configSetId in ipairs(build.configTab.configSetOrderList) do + if build.configTab.configSets[configSetId].title == "ArmourStackMerc" then + armourConfig = build.configTab.configSets[configSetId] + end + end + armourConfig.mercenarySetId = second.id + local xml = { elem = "Config" } + build.configTab:Save(xml) + build.configTab:Load(xml, "config.xml") + local loaded + for _, configSetId in ipairs(build.configTab.configSetOrderList) do + if build.configTab.configSets[configSetId].title == "ArmourStackMerc" then + loaded = build.configTab.configSets[configSetId] + end + end + assert.are.equal(second.id, loaded.mercenarySetId) + loaded.mercenarySetId = 99 + build.configTab.modFlag = false + build.mercenaryTab:PostLoad() + assert.is_nil(loaded.mercenarySetId) + assert.is_false(build.configTab.modFlag) + end) + + it("clears bindings on delete and marks Config dirty for undo and stale ids", function() + local _, _, _, armourConfig = addNamedLoadout("ArmourStackMerc") + local second = build.mercenaryTab:NewMercenarySet(nil, "2nd Merc") + table.insert(build.mercenaryTab.mercenarySetOrderList, second.id) + selectLoadout("ArmourStackMerc") + bindHire(second.id) + assert.are.equal(second.id, armourConfig.mercenarySetId) + local manager = new("MercenarySetListControl"):MercenarySetListControl(nil, { 0, 0, 350, 200 }, build.mercenaryTab) + local originalOpenConfirmPopup = main.OpenConfirmPopup + main.OpenConfirmPopup = function(_, _, _, _, onConfirm) onConfirm() end + local ok, err = pcall(function() + manager:OnSelDelete(isValueInArray(manager.list, second.id), second.id) + end) + main.OpenConfirmPopup = originalOpenConfirmPopup + assert.is_true(ok, err) + assert.is_nil(armourConfig.mercenarySetId) + armourConfig.mercenarySetId = 99 + build.configTab.modFlag = false + selectLoadout("ArmourStackMerc") + assert.is_nil(armourConfig.mercenarySetId) + assert.is_true(build.configTab.modFlag) + local rebound = build.mercenaryTab:NewMercenarySet(nil, "Rebound") + table.insert(build.mercenaryTab.mercenarySetOrderList, rebound.id) + build.mercenaryTab:AddUndoState() + bindHire(rebound.id) + build.configTab.modFlag = false + build.mercenaryTab:Undo() + assert.are_not.equal(rebound.id, armourConfig.mercenarySetId) + assert.is_true(build.configTab.modFlag) + end) + + it("does not treat mercenary-owned item sets as player loadout sets", function() + addNamedSets("Boss") + local mercIndex = 1 + for _, itemSetId in ipairs(copyTable(build.itemsTab.itemSetOrderList)) do + local setId = build.mercenaryTab.mercenarySetOrderList[mercIndex] + if not setId then + local extra = build.mercenaryTab:NewMercenarySet() + table.insert(build.mercenaryTab.mercenarySetOrderList, extra.id) + setId = extra.id + end + build.mercenaryTab.mercenarySets[setId].itemSetId = itemSetId + mercIndex = mercIndex + 1 + end + assert.are.equal(0, #build:GetPlayerItemSetOrderList()) + end) + + it("does not clear a Config created after the Mercenary undo snapshot", function() + local second = build.mercenaryTab:NewMercenarySet(nil, "2nd Merc") + table.insert(build.mercenaryTab.mercenarySetOrderList, second.id) + bindHire(second.id) + local newConfig = build.configTab:NewConfigSet() + table.insert(build.configTab.configSetOrderList, newConfig.id) + newConfig.title = "AfterSnapshot" + newConfig.mercenarySetId = second.id + build.mercenaryTab:Undo() + assert.are.equal(second.id, newConfig.mercenarySetId) + end) +end) diff --git a/spec/System/TestMercenaryTools_spec.lua b/spec/System/TestMercenaryTools_spec.lua new file mode 100644 index 00000000000..81a81e4a97a --- /dev/null +++ b/spec/System/TestMercenaryTools_spec.lua @@ -0,0 +1,694 @@ +describe("Mercenary tools", function() + local tools = require("Modules.MercenaryTools") + local data = { + builds = { build = { + skillIds = { "skill", "other_skill" }, + skillPools = { { skillIds = { "skill", "other_skill" }, countMax = 1 } }, + } }, + skills = { + skill = { supportCountId = "Low", possibleSupportIds = { "support_t1", "support_t2", "support_t3", "other_support", "support_no_family" } }, + other_skill = { supportCountId = "High", possibleSupportIds = { } }, + }, + supports = { + support_t1 = { variant = 1, familyId = "family" }, + support_t2 = { variant = 2, familyId = "family" }, + support_t3 = { variant = 3, familyId = "family" }, + other_support = { variant = 1, familyId = "other_family" }, + support_no_family = { variant = 1 }, + }, + supportCounts = { Low = { maximum = 2 }, High = { maximum = 5 } }, + } + + it("maps Mercenary-prefixed slot names to base slots", function() + assert.are.equal("Helmet", tools.baseItemSlotName("Mercenary Helmet")) + assert.is_nil(tools.baseItemSlotName("Helmet")) + assert.is_nil(tools.baseItemSlotName(1)) + end) + + it("routes comparison output by actor", function() + local playerOutput = { CombinedDPS = 100, FullDPS = 1000, FullDotDPS = 10 } + local mercenaryOutput = { CombinedDPS = 50, FullDPS = 50, FullDotDPS = 1 } + assert.are.equal(playerOutput, tools.comparisonBaseOutput(playerOutput, { PLAYER = playerOutput }, "PLAYER")) + assert.is_nil(tools.comparisonBaseOutput(playerOutput, { PLAYER = playerOutput }, "MERCENARY")) + assert.is_true(not tools.mercenaryOutputAvailable(nil)) + assert.is_true(not tools.mercenaryOutputAvailable({ ActorUnavailableMessage = "missing" })) + local routed = tools.comparisonBaseOutput(playerOutput, { + PLAYER = playerOutput, + MERCENARY = mercenaryOutput, + }, "MERCENARY") + assert.are.equal(50, routed.CombinedDPS) + assert.are.equal(1000, routed.FullDPS) + assert.are.equal(10, routed.FullDotDPS) + assert.are.equal(50, mercenaryOutput.FullDPS) + assert.are_not.equal(mercenaryOutput, routed) + assert.is_true(tools.mercenaryOutputAvailable(mercenaryOutput)) + assert.are.equal(mercenaryOutput, tools.buildComparisonOutput(mercenaryOutput, nil)) + local unavailable = { ActorUnavailableMessage = "missing" } + assert.are.equal(unavailable, tools.buildComparisonOutput(unavailable, playerOutput)) + end) + + it("classifies item overrides by comparison actor", function() + local playerOverride = { itemSetId = 1, comparisonActor = "PLAYER", repSlotName = "Helmet", repItem = { } } + assert.is_true(tools.overrideReplacesPlayerItem(playerOverride, 1)) + assert.is_false(tools.overrideReplacesMercenarySlot(playerOverride, "Helmet", 1)) + local mercOverride = { itemSetId = 1, comparisonActor = "MERCENARY", repSlotName = "Helmet", repItem = { } } + assert.is_false(tools.overrideReplacesPlayerItem(mercOverride, 1)) + assert.is_true(tools.overrideReplacesMercenarySlot(mercOverride, "Helmet", 1)) + local dedicatedMerc = { itemSetId = 2, repSlotName = "Helmet", repItem = { } } + assert.is_false(tools.overrideReplacesPlayerItem(dedicatedMerc, 1)) + assert.is_true(tools.overrideReplacesMercenarySlot(dedicatedMerc, "Helmet", 2)) + end) + + it("resolves equipped items and reports weapon-configuration errors", function() + local itemSet = { + Helmet = { selItemId = 1 }, + ["Helmet Abyssal Socket 1"] = { selItemId = 2 }, + } + local items = { + [1] = { name = "cap", abyssalSocketCount = 1 }, + [2] = { name = "jewel" }, + } + assert.are.equal(items[1], tools.equippedItem(itemSet, items, "Helmet")) + assert.are.equal(items[2], tools.equippedItem(itemSet, items, "Helmet Abyssal Socket 1")) + local goldrim = { name = "Goldrim", abyssalSocketCount = 0 } + local replaceHelmet = { comparisonActor = "MERCENARY", repSlotName = "Helmet", repItem = goldrim } + assert.are.equal(goldrim, tools.equippedItem(itemSet, items, "Helmet", replaceHelmet, 1)) + assert.is_nil(tools.equippedItem(itemSet, items, "Helmet Abyssal Socket 1", replaceHelmet, 1)) + local removeHelmet = { comparisonActor = "MERCENARY", repSlotName = "Helmet", repItem = nil } + assert.is_nil(tools.equippedItem(itemSet, items, "Helmet", removeHelmet, 1)) + assert.is_nil(tools.equippedItem(itemSet, items, "Helmet Abyssal Socket 1", removeHelmet, 1)) + + local dagger = { type = "Dagger", rarity = "NORMAL", base = { type = "Dagger" }, requirements = { } } + local wand = { id = 3, type = "Wand", rarity = "NORMAL", base = { type = "Wand" }, requirements = { } } + local weapons = { + ["Weapon 1"] = { selItemId = 1 }, + ["Weapon 2"] = { selItemId = 2 }, + } + local weaponItems = { [1] = dagger, [2] = dagger, [3] = wand } + local function weaponValid(item, slotName, itemSet, equippedLookup) + if slotName ~= "Weapon 2" then return true end + local weapon1 = equippedLookup and equippedLookup("Weapon 1") + if not weapon1 then + local sel = itemSet["Weapon 1"] and itemSet["Weapon 1"].selItemId + weapon1 = weaponItems[sel] + end + local weapon1Type = weapon1 and weapon1.base.type or "None" + if weapon1Type == "Wand" then + return item.type == "Wand" or item.type == "Shield" + end + return true + end + local weaponContext = { + profile = { buildId = "dual", foundAreaLevel = 68 }, + mercenaryData = { + builds = { dual = { + classId = "shadow", + weaponConfiguration = { + mainHandTypes = { "Dagger", "Wand" }, + offHandRequired = false, + offHandTypes = { "Dagger", "Wand" }, + }, + } }, + classes = { shadow = { attributeId = "Dex", attributeName = "Dexterity" } }, + }, + itemSet = weapons, + playerItemSet = { }, + items = weaponItems, + override = { comparisonActor = "MERCENARY", repSlotName = "Weapon 1", repItem = wand }, + mercenaryItemSetId = 1, + playerHasFlag = function() return false end, + isItemValidForSlot = weaponValid, + } + assert.are.equal(wand, tools.equippedItem(weapons, weaponItems, "Weapon 1", weaponContext.override, 1)) + assert.are.equal(dagger, tools.equippedItem(weapons, weaponItems, "Weapon 2", weaponContext.override, 1)) + assert.matches("Weapon 2: invalid base slot or weapon configuration", table.concat(tools.equipmentErrors(weaponContext), "\n")) + weaponContext.override = nil + assert.are.equal("", table.concat(tools.equipmentErrors(weaponContext), "\n")) + end) + + it("restores profile skills after withMainSkill and withReplacedSkill", function() + local profile = { mainSkillId = "A" } + assert.are.equal("B", tools.withMainSkill(profile, "B", function() + assert.are.equal("B", profile.mainSkillId) + return profile.mainSkillId + end)) + assert.are.equal("A", profile.mainSkillId) + assert.has_error(function() + tools.withMainSkill(profile, "B", function() error("boom") end) + end) + assert.are.equal("A", profile.mainSkillId) + + local skills = { { id = "A", supports = { "keep" } }, { id = "B" } } + local replaced = { id = "preview", supports = { } } + assert.are.equal("preview", tools.withReplacedSkill({ skills = skills }, 1, replaced, function() + assert.are.equal(replaced, skills[1]) + return skills[1].id + end)) + assert.are.equal("A", skills[1].id) + assert.are.same({ "keep" }, skills[1].supports) + assert.has_error(function() + tools.withReplacedSkill({ skills = skills }, 1, replaced, function() error("boom") end) + end) + assert.are.equal("A", skills[1].id) + end) + + it("reports missing attribute data and unique-item requirements", function() + local missingAttribute = { + profile = { buildId = "dual", foundAreaLevel = 68 }, + mercenaryData = { + builds = { dual = { + classId = "shadow", + weaponConfiguration = { mainHandTypes = { "Dagger" }, offHandTypes = { "Dagger" } }, + } }, + classes = { shadow = { attributeId = "", attributeName = "Dexterity" } }, + }, + itemSet = { Helmet = { selItemId = 1 } }, + playerItemSet = { }, + items = { [1] = { type = "Helmet", rarity = "RARE", requirements = { str = 1 }, base = { type = "Helmet" } } }, + playerHasFlag = function() return false end, + isItemValidForSlot = function() return true end, + } + assert.matches("missing attribute data", table.concat(tools.equipmentErrors(missingAttribute), "\n")) + + local uniqueHelmet = { type = "Helmet", rarity = "UNIQUE", requirements = { dex = 1 }, base = { type = "Helmet" } } + local uniqueContext = { + profile = { buildId = "dual", foundAreaLevel = 68 }, + mercenaryData = { + builds = { dual = { + classId = "shadow", + weaponConfiguration = { mainHandTypes = { "Dagger" }, offHandTypes = { "Dagger" } }, + } }, + classes = { shadow = { attributeId = "Dex", attributeName = "Dexterity" } }, + }, + itemSet = { Helmet = { selItemId = 1 } }, + playerItemSet = { }, + items = { [1] = uniqueHelmet }, + isItemValidForSlot = function() return true end, + } + uniqueContext.playerHasFlag = function() return nil end + assert.are.equal("", table.concat(tools.equipmentErrors(uniqueContext), "\n")) + uniqueContext.playerHasFlag = function() return false end + assert.matches("Unique Helmets", table.concat(tools.equipmentErrors(uniqueContext), "\n")) + end) + + it("treats a Mercenary as hired only with a profile and Noble Blood", function() + local profiled = { mercenaryTab = { profile = { buildId = "AnyBuild" } }, spec = { allocNodes = { } } } + assert.is_true(tools.hasProfile(profiled)) + assert.is_false(tools.playerCanHire(profiled)) + assert.is_false(tools.isHired(profiled)) + profiled.spec.allocNodes[1] = { modList = { { name = "CanHirePermanentMercenary" } } } + assert.is_true(tools.playerCanHire(profiled)) + assert.is_true(tools.isHired(profiled)) + assert.is_false(tools.isHired({ mercenaryTab = { profile = { } }, spec = profiled.spec })) + end) + + it("shows the Mercenary tab only for Scion and keeps unused builds quiet", function() + assert.is_true(tools.tabVisible({ spec = { curClassName = "Scion" } })) + assert.is_true(not tools.tabVisible({ spec = { curClassName = "Marauder" } })) + assert.is_true(not tools.tabVisible({ })) + assert.is_true(tools.isMercenaryCalculationActor("MERCENARY_MINION")) + assert.is_true(not tools.isMercenaryCalculationActor("PLAYER")) + + local actors = { + { label = "Player", actorId = "PLAYER" }, + { label = "Mercenary", actorId = "MERCENARY" }, + { label = "Mercenary Minion", actorId = "MERCENARY_MINION" }, + } + assert.are.equal(3, #tools.filterCalculationActors(actors, { spec = { curClassName = "Scion" } })) + local marauderActors = tools.filterCalculationActors(actors, { spec = { curClassName = "Marauder" } }) + assert.are.equal(1, #marauderActors) + assert.are.equal("PLAYER", marauderActors[1].actorId) + assert.are_not.equal(actors, marauderActors) + wipeTable(marauderActors) + assert.are.equal(3, #actors) + + assert.are.equal(2, #tools.configActorList({ spec = { curClassName = "Scion" } })) + assert.are.equal(1, #tools.configActorList({ spec = { curClassName = "Witch" } })) + + local unused = { spec = { curClassName = "Scion" }, viewMode = "TREE", mercenaryTab = { profile = { } } } + assert.is_true(not tools.includeInBuildWarnings(unused)) + unused.viewMode = "MERCENARY" + assert.is_true(tools.includeInBuildWarnings(unused)) + unused.viewMode = "TREE" + unused.mercenaryTab.profile.buildId = "AnyBuild" + assert.is_true(tools.includeInBuildWarnings(unused)) + assert.is_true(not tools.includeInBuildWarnings({ spec = { curClassName = "Marauder" }, viewMode = "MERCENARY", mercenaryTab = unused.mercenaryTab })) + + local marauder = { + spec = { curClassName = "Marauder" }, + viewMode = "MERCENARY", + calcsTab = { input = { actor = "MERCENARY" } }, + configTab = { viewActor = "mercenary", GetViewActor = function(self) return self.viewActor end }, + itemsTab = { + viewComparisonActor = "MERCENARY", + activeItemSetId = 1, + SetViewItemSet = function(self, itemSetId, actor) + self.viewComparisonActor = actor + end, + }, + } + tools.applyHiddenState(marauder) + assert.are.equal("TREE", marauder.viewMode) + assert.are.equal("PLAYER", marauder.calcsTab.input.actor) + assert.are.equal("player", marauder.configTab.viewActor) + assert.are.equal("PLAYER", marauder.itemsTab.viewComparisonActor) + local scion = { spec = { curClassName = "Scion" }, viewMode = "MERCENARY" } + tools.applyHiddenState(scion) + assert.are.equal("MERCENARY", scion.viewMode) + end) + + it("groups numbered class variants for the picker", function() + local groups, byClassId = tools.classGroups({ + classOrder = { "templar2", "witch2", "templar1", "scion" }, + classes = { + templar2 = { name = "[DNT] Merc Templar 2", attributeName = "Str / Int", buildIds = { "build2" } }, + witch2 = { name = "[DNT] Witch Merc 2", attributeName = "Int", buildIds = { "build3" } }, + templar1 = { name = "[DNT] Merc Templar 1", attributeName = "Str / Int", buildIds = { "build1" } }, + scion = { name = "[DNT] Merc Scion 1", attributeName = "Str / Dex / Int", buildIds = { "scionBuild" } }, + }, + }) + assert.are.equal(3, #groups) + assert.are.equal("Templar (Str / Int)", groups[1].label) + assert.same({ "templar2", "templar1" }, groups[1].classIds) + assert.same({ "build2", "build1" }, groups[1].buildIds) + assert.are.equal(groups[1], byClassId.templar1) + assert.are.equal("Scion (Str / Dex / Int)", groups[3].label) + assert.are.equal(byClassId.scion, groups[3]) + end) + + it("imports a Warrant and rejects invalid input", function() + _G.data.ensureMercenaries() + local mercenaryData = LoadModule("Data/Mercenaries") + mercenaryData.supportCounts = _G.data.mercenaryStatData.supportCounts + local imported, err = tools.importWarrant([[ +Item Class: Map Fragments +Rarity: Normal +Mercenary Warrant +-------- +Mercenary +-------- +Build: Toxicologist +Mercenary Level: 83 +-------- +Withering Step +Increased Area of Effect (Tier: 2) +Gilded Wither Stacks (Tier: 3) +-------- +Chaotic Burst +Wither on Hit (Tier: 2) +Increased Area of Effect (Tier: 2) +-------- +Chaotic Shot +Physical as Extra Chaos (Tier: 2) +Chance to Poison (Tier: 2) +Chaos Penetration (Tier: 2) +Faster Projectiles (Tier: 2) +Greater Multiple Projectiles (Tier: 3) +-------- +Scourge Arrow of Menace +Greater Faster Attacks (Tier: 3) +Greater DoT Multiplier (Tier: 3) +Physical as Extra Chaos (Tier: 2) +Chance to Poison (Tier: 2) +-------- +Blink Arrow +Faster Attacks (Tier: 2) +Minion Life (Tier: 2) +Greater Minion Damage (Tier: 3) +-------- +Trarthan Agility +Cooldown Recovery (Tier: 2) +Greater Area of Effect (Tier: 3) +-------- +Right click this item to view Mercenary details. +Can be used in a personal Map Device alongside a Map to have this previously fought Mercenary reappear in the area for a rematch. +]], mercenaryData) + assert.is_nil(err) + assert.are.equal("Toxicologist", mercenaryData.builds[imported.buildId].name) + assert.are.equal(6, #imported.skills) + assert.are.equal("Withering Step", mercenaryData.skills[imported.mainSkillId].name) + assert.is_true(imported.importedWarrant) + + local header = "Mercenary Warrant\n--------\nBuild: Toxicologist\nMercenary Level: 83\n--------\n" + for _, case in ipairs({ + { text = string.rep("x", 256 * 1024 + 1), pattern = "256 KiB" }, + { text = header.."Withering Step\nIncreased Area of Effect (Tier: 2)\nIncreased Area of Effect (Tier: 2)\n", pattern = "Duplicate support" }, + { text = header.."Withering Step\nIncreased Area of Effect (Tier: 9)\n", pattern = "is not valid" }, + }) do + _, err = tools.importWarrant(case.text, mercenaryData) + assert.matches(case.pattern, err) + end + + local fake = { + builds = { + a = { id = "a", name = "Dup", classId = "c", skillIds = { "s" } }, + b = { id = "b", name = "Dup", classId = "c", skillIds = { "s" } }, + }, + buildOrder = { "a", "b" }, + skills = { s = { id = "s", name = "Skill", possibleSupportIds = { }, supportCountId = "None" } }, + supports = { }, + supportCounts = { None = { maximum = 0 } }, + } + _, err = tools.importWarrant("Mercenary Warrant\n--------\nBuild: Dup\nMercenary Level: 10\n--------\nSkill\n", fake) + assert.matches("Ambiguous Mercenary build", err) + end) + + it("scales level, passives, and the damage taper", function() + assert.are.equal(68, tools.effectiveLevel(50, 84)) + assert.are.equal(100, tools.effectiveLevel(100, 85)) + assert.are.equal(100, tools.effectiveLevel(150, 85)) + assert.are.equal(1, tools.effectiveLevel(0, 0)) + assert.are.equal(48, tools.requiredFoundAreaLevel(68)) + + local values = { 60, 120, 160 } + assert.are.equal(60, tools.passiveStatValue(values, 1)) + assert.are.equal(60, tools.passiveStatValue(values, 24)) + assert.are.equal(95, tools.passiveStatValue(values, 50)) + assert.are.equal(120, tools.passiveStatValue(values, 68)) + assert.are.equal(140, tools.passiveStatValue(values, 76)) + assert.are.equal(160, tools.passiveStatValue(values, 84)) + assert.are.equal(60, tools.passiveStatValue(values, 0)) + assert.are.equal(160, tools.passiveStatValue(values, 120)) + assert.are.equal(93, tools.passiveStatValue({ 38, 75, 100 }, 80)) + + local maxMore = -30 + for _, case in ipairs({ + { 1, 0 }, { 44, 0 }, { 45, 0 }, { 46, -1 }, { 82, -29 }, { 83, -30 }, { 100, -30 }, + }) do + assert.are.equal(case[2], tools.permanentDamageMore(case[1], maxMore)) + end + end) + + it("validates profiles without repairing them", function() + local profile = { + buildId = "build", + foundAreaLevel = 0, + mainSkillId = "missing", + skills = { { + id = "skill", + enabled = true, + supports = { { id = "support_t1", tier = 2 }, { id = "support_t2", tier = 2 } }, + } }, + } + local errors = table.concat(tools.validateProfile(profile, data), "\n") + assert.matches("Mercenary level", errors) + assert.matches("Invalid tier", errors) + assert.matches("Duplicate support family", errors) + assert.matches("Selected Calcs skill", errors) + assert.are.equal("missing", profile.mainSkillId) + profile.foundAreaLevel = 68.5 + assert.matches("must be an integer", table.concat(tools.validateProfile(profile, data), "\n")) + + local ok, noIdErrors = pcall(tools.validateProfile, { + buildId = "build", + foundAreaLevel = 68, + mainSkillId = "skill", + skills = { { enabled = true, supports = { } } }, + }, data) + assert.is_true(ok) + assert.matches("Invalid skill", table.concat(noIdErrors, "\n")) + + for _, count in ipairs({ 0, 1.5, 100, "2" }) do + assert.matches("must be an integer from 1 to 99", table.concat(tools.validateProfile({ + buildId = "build", + foundAreaLevel = 68, + mainSkillId = "skill", + skills = { { id = "skill", enabled = true, count = count, supports = { } } }, + }, data), "\n")) + end + + profile = { + buildId = "build", + foundAreaLevel = 68, + skills = { { id = "skill", enabled = false, supports = { } } }, + } + assert.matches("Enable at least one", table.concat(tools.validateProfile(profile, data), "\n")) + profile.skills[1].enabled = true + assert.matches("Select a Mercenary skill for Calcs", table.concat(tools.validateProfile(profile, data), "\n")) + profile.mainSkillId = "skill" + profile.skills[1].enabled = false + assert.matches("Enable at least one", table.concat(tools.validateProfile(profile, data), "\n")) + + assert.matches("Skill pool 1 allows at most 1", table.concat(tools.validateProfile({ + buildId = "build", + foundAreaLevel = 68, + mainSkillId = "skill", + skills = { + { id = "skill", enabled = true, supports = { } }, + { id = "other_skill", enabled = true, supports = { } }, + }, + }, data), "\n")) + + assert.are.equal(2, tools.supportLimit(data, data.skills.skill)) + data.supportCounts.None = { maximum = 0 } + assert.are.equal(0, tools.supportLimit(data, { id = "zero", supportCountId = "None" })) + assert.is_nil(tools.supportLimit(data, { id = "drift", supportCountId = "MissingPolicy" })) + data.skills.skill.supportCountId = "MissingPolicy" + assert.matches("Missing support%-count policy for MissingPolicy", table.concat(tools.validateProfile({ + buildId = "build", + foundAreaLevel = 68, + mainSkillId = "skill", + skills = { { id = "skill", enabled = true, supports = { } } }, + }, data), "\n")) + data.skills.skill.supportCountId = "Low" + data.supportCounts.None = nil + + profile = { + buildId = "build", + foundAreaLevel = 68, + mainSkillId = "skill", + skills = { { id = "skill", enabled = true, supports = { } } }, + } + assert.matches("Duplicate skill", tools.skillCandidateError(profile, data, 2, "skill")) + assert.matches("allows at most 1", tools.skillCandidateError(profile, data, 2, "other_skill")) + assert.is_nil(tools.firstLegalSkillId(profile, data)) + assert.matches("Duplicate support family", tools.supportCandidateError({ + skills = { { id = "skill", supports = { { id = "support_t1", tier = 1 } } } }, + }, data, 1, 2, "support_t2")) + assert.is_nil(tools.supportCandidateError({ + skills = { { id = "skill", supports = { } } }, + }, data, 1, 1, "support_t1")) + end) +end) + +describe("Generated Mercenary data", function() + local tools = require("Modules.MercenaryTools") + local mercenaries = data.ensureMercenaries() + + it("has deterministic orders and resolvable references", function() + local classGroups = select(1, tools.classGroups(mercenaries)) + local classLabels = { } + for _, group in ipairs(classGroups) do table.insert(classLabels, group.label) end + assert.same({ + "Templar (Str / Int)", + "Witch (Int)", + "Shadow (Dex / Int)", + "Ranger (Dex)", + "Marauder (Str)", + "Duelist (Str / Dex)", + "Scion (Str / Dex / Int)", + }, classLabels) + local function has(values, wanted) + for _, value in ipairs(values) do if value == wanted then return true end end + return false + end + assert.are.equal(13, #mercenaries.classOrder) + for index = 2, #mercenaries.classOrder do + assert.is_true(mercenaries.classOrder[index - 1] < mercenaries.classOrder[index]) + end + for index = 2, #mercenaries.buildOrder do + assert.is_true(mercenaries.buildOrder[index - 1] < mercenaries.buildOrder[index]) + end + for _, classId in ipairs(mercenaries.classOrder) do + local class = assert(mercenaries.classes[classId]) + assert.is_table(class.monster) + for _, buildId in ipairs(class.buildIds) do + assert.are.equal(classId, assert(mercenaries.builds[buildId]).classId) + end + for _, skillId in ipairs(class.skillIds) do + assert.is_table(mercenaries.skills[skillId]) + end + end + for skillId, skill in pairs(mercenaries.skills) do + assert.is_true(data.skills[skillId].mercenary, skillId) + local resolved = mercenaries.skillsByHash[tostring(skill.hash)] + assert.is_table(resolved) + assert.is_true(has(resolved, skillId)) + assert.is_table(mercenaries.supportCounts[skill.supportCountId], skillId..": "..tostring(skill.supportCountId)) + for _, supportId in ipairs(skill.possibleSupportIds) do + assert.is_table(mercenaries.supports[supportId]) + end + end + for supportId, support in pairs(mercenaries.supports) do + local resolved = mercenaries.supportsByHash[tostring(support.hash)] + assert.is_table(resolved) + assert.is_true(has(resolved, supportId)) + for _, stat in ipairs(support.stats) do + assert.are.equal("string", type(stat.id), supportId) + assert.are.equal("number", type(stat.value), supportId..": "..stat.id) + end + end + for skillId, skill in pairs(mercenaries.skills) do + local grantedEffect = data.skills[skillId] + for _, supportId in ipairs(skill.possibleSupportIds) do + for _, stat in ipairs(mercenaries.supports[supportId].stats) do + assert.is_true(grantedEffect.statMap[stat.id] ~= nil or data.mercenarySupportStatMap[stat.id] ~= nil, skillId.." + "..supportId..": "..stat.id) + end + local supportEffect = assert(data.mercenarySupportGrantedEffect(supportId, skillId), skillId.." + "..supportId) + assert.are.equal(supportId, supportEffect.mercenarySupportId) + assert.is_nil(supportEffect.unsupportedMercenaryStats) + end + end + local seenKnownUncalculated = { } + for skillId in pairs(mercenaries.skills) do + local grantedEffect = assert(data.skills[skillId]) + for _, statId in ipairs(grantedEffect.stats or { }) do + assert.is_true(grantedEffect.statMap[statId] ~= nil or data.knownUncalculatedSkillStats[statId] == true, skillId..": "..statId) + if not grantedEffect.statMap[statId] then seenKnownUncalculated[statId] = true end + end + for _, stat in ipairs(grantedEffect.constantStats or { }) do + assert.is_true(grantedEffect.statMap[stat[1]] ~= nil or data.knownUncalculatedSkillStats[stat[1]] == true, skillId..": "..stat[1]) + if not grantedEffect.statMap[stat[1]] then seenKnownUncalculated[stat[1]] = true end + end + end + for statId in pairs(data.knownUncalculatedSkillStats) do + assert.is_true(seenKnownUncalculated[statId] == true, "stale Mercenary stat exemption: "..statId) + end + for _, classId in ipairs(mercenaries.classOrder) do + for _, stat in ipairs(mercenaries.classes[classId].monster.stats or { }) do + assert.is_true(data.mercenaryStatData.knownMonsterStats[stat.id] == true, classId..": "..stat.id) + end + end + local seenKnownUncalculatedMinion = { } + local unmappedMinionStats = { } + for minionId, minion in pairs(mercenaries.minions or { }) do + for _, stat in ipairs(minion.stats or { }) do + local mapped = data.mercenarySupportStatMap[stat.id] ~= nil + local knownMinion = data.knownUncalculatedMinionStats[stat.id] == true + local knownMonster = data.mercenaryStatData.knownMonsterStats[stat.id] == true + if not (mapped or knownMinion or knownMonster) then + table.insert(unmappedMinionStats, minionId..": "..stat.id) + end + if knownMinion then seenKnownUncalculatedMinion[stat.id] = true end + end + end + table.sort(unmappedMinionStats) + assert.same({ }, unmappedMinionStats) + for statId in pairs(data.knownUncalculatedMinionStats) do + assert.is_true(seenKnownUncalculatedMinion[statId] == true, "stale Mercenary minion stat exemption: "..statId) + assert.is_true(data.mercenarySupportStatMap[statId] == nil, "mapped minion stat listed as uncalculated: "..statId) + end + local relic = assert(data.minions["Metadata/Monsters/Mercenaries/MercenaryUnholyRelic_"]) + local curseImmune + for _, mod in ipairs(relic.modList) do + if mod.name == "CurseImmune" then curseImmune = true break end + end + assert.is_true(curseImmune) + for supportId, templateId in pairs(data.mercenaryStatData.supportTemplates) do + assert.is_table(mercenaries.supports[supportId], supportId) + assert.is_table(data.skills[templateId], templateId) + local grantedEffect = assert(data.mercenarySupportGrantedEffect(supportId), supportId) + assert.is_true(grantedEffect.support, supportId) + assert.are.equal(supportId, grantedEffect.mercenarySupportId) + assert.are.equal("MercenarySupport:"..supportId, grantedEffect.id) + assert.are.equal("Mercenary Support:"..supportId, grantedEffect.modSource) + end + assert.are.equal(5, mercenaries.supportCounts.High.maximum) + assert.are.equal(0, mercenaries.supportCounts.None.maximum) + for skillId, skill in pairs(mercenaries.skills) do + assert.are.equal(skillId, skill.id) + end + for _, buildId in ipairs(mercenaries.buildOrder) do + assert.is_table(assert(mercenaries.builds[buildId]).weaponConfiguration, buildId) + end + for policyId in pairs(data.mercenaryStatData.supportCounts) do + local used = false + for _, skill in pairs(mercenaries.skills) do + if skill.supportCountId == policyId then used = true break end + end + assert.is_true(used, "unused support-count policy: "..policyId) + end + + local statData = data.mercenaryStatData + local problems = { } + local declarationUsedBy = { } + for skillId, grantedEffect in pairs(data.skills) do + if grantedEffect.mercenary then + local baseEffect = grantedEffect.inheritedFrom and data.skills[grantedEffect.inheritedFrom] + for _, message in ipairs(tools.preDamageFuncErrors(grantedEffect, baseEffect, statData) or { }) do + table.insert(problems, message) + end + if grantedEffect.inheritedFrom then + assert.is_table(baseEffect, skillId) + if grantedEffect.preDamageFunc == baseEffect.preDamageFunc then + declarationUsedBy[grantedEffect.inheritedFrom] = skillId + end + end + end + end + table.sort(problems) + assert.are.equal("", table.concat(problems, "\n")) + for skillId, reason in pairs(statData.droppedPreDamageFuncs) do + local grantedEffect = assert(data.skills[skillId], skillId) + assert.is_true(grantedEffect.mercenary, skillId) + assert.is_string(reason) + assert.is_nil(grantedEffect.preDamageFunc, skillId) + assert.is_function(assert(data.skills[grantedEffect.inheritedFrom], skillId).preDamageFunc, skillId) + local missing = assert(tools.missingPreDamageFuncInputs(grantedEffect, grantedEffect.inheritedFrom, statData), skillId) + assert.is_true(#missing > 0, "no longer needs to drop its preDamageFunc: "..skillId) + declarationUsedBy[grantedEffect.inheritedFrom] = skillId + end + for baseSkillId in pairs(statData.preDamageFuncInputs) do + assert.is_function(assert(data.skills[baseSkillId], baseSkillId).preDamageFunc, baseSkillId) + assert.is_string(declarationUsedBy[baseSkillId], "stale preDamageFunc input declaration: "..baseSkillId) + end + + local gemSkills = { } + for _, gem in pairs(data.gems) do + if not gem.support then + for _, skillId in ipairs({ gem.grantedEffectId, gem.secondaryGrantedEffectId }) do + if skillId then gemSkills[skillId] = true end + end + end + end + local gemSkillByName = { } + for skillId in pairs(gemSkills) do + local name = data.skills[skillId].name + if name and (not gemSkillByName[name] or skillId < gemSkillByName[name]) then + gemSkillByName[name] = skillId + end + end + for skillId, grantedEffect in pairs(data.skills) do + local base = grantedEffect.mercenary and grantedEffect.inheritedFrom + if base and not gemSkills[base] then + assert.is_nil(gemSkillByName[data.skills[base].name], skillId.." inherits from "..base) + end + end + + local function stub() return { } end + local export = require("Export.MercenaryExport") + local statMap = LoadModule("Data/MercenaryStatMap")(stub, stub, stub) + assert.is_nil(export.shieldPolicyError(data.mercenaries.builds, statMap.shieldPolicy)) + for buildId, mercBuild in pairs(data.mercenaries.builds) do + local hasShield = false + for _, itemType in ipairs(mercBuild.weaponTypes or { }) do + if itemType == "Shield" then hasShield = true break end + end + if hasShield then + local optional = statMap.shieldPolicy[buildId] == "optional" + assert.are.equal(not optional, mercBuild.weaponConfiguration.offHandRequired, buildId) + end + end + end) + + it("does not replace canonical item-granted skills with Mercenary variants", function() + for modLine, expectedSkillId in pairs({ + ["Grants Level 1 Icestorm Skill"] = "Icestorm", + ["Grants Level 15 Envy Skill"] = "Envy", + ["Grants Level 20 Aspect of the Spider Skill"] = "AspectOfTheSpider", + }) do + local mods = assert(modLib.parseMod(modLine)) + assert.are.equal(expectedSkillId, mods[1].value.skillId, modLine) + end + end) +end) diff --git a/spec/System/TestModStore_spec.lua b/spec/System/TestModStore_spec.lua new file mode 100644 index 00000000000..22f888bafbe --- /dev/null +++ b/spec/System/TestModStore_spec.lua @@ -0,0 +1,43 @@ +describe("ModStore PerStat.subtract", function() + local function perStatValue(statValue, div, subtract) + local modDB = new("ModDB"):ModDB() + modDB.actor = { output = { Str = statValue } } + modDB:NewMod("Damage", "INC", 1, "Test", { type = "PerStat", stat = "Str", div = div, subtract = subtract }) + return modDB:Sum("INC", nil, "Damage") + end + + it("divides before subtracting", function() + -- floor(12 / 5) - 2 = 0. Subtract-then-divide would be floor(10 / 5) = 2. + assert.are.equal(0, perStatValue(12, 5, 2)) + assert.are.equal(3, perStatValue(20, 5, 1)) + end) + + it("clamps a negative PerStat multiplier to zero", function() + assert.are.equal(0, perStatValue(3, 5, 1)) + assert.are.equal(0, perStatValue(1, 1, 5)) + end) +end) + +describe("ModStore source-owned enemy overlay", function() + local function damageIfChilledByYou(sourceOwned) + local shared = new("ModDB"):ModDB() + local overlay = new("ModDB"):ModDB() + overlay.conditions.ChilledByYou = true + local actor = { + enemySourceDB = overlay, + enemy = { modDB = shared }, + } + shared.actor = actor + overlay.actor = actor + local playerDB = new("ModDB"):ModDB() + playerDB.actor = actor + playerDB:NewMod("Damage", "INC", 10, "Test", { type = "ActorCondition", actor = "enemy", var = "ChilledByYou", sourceOwned = sourceOwned }) + return playerDB:Sum("INC", nil, "Damage") + end + + it("reads the actor overlay only when tag.sourceOwned is true", function() + assert.are.equal(10, damageIfChilledByYou(true)) + assert.are.equal(0, damageIfChilledByYou(nil)) + assert.are.equal(0, damageIfChilledByYou(false)) + end) +end) diff --git a/spec/System/TestOffence_spec.lua b/spec/System/TestOffence_spec.lua index da782f9f679..908ddf3ef49 100644 --- a/spec/System/TestOffence_spec.lua +++ b/spec/System/TestOffence_spec.lua @@ -352,4 +352,36 @@ describe("TestOffence", function() assert.are.equals(1, build.calcsTab.mainOutput[outputName]) end) end + + it("applies Fist of War to player Ground Slam", function() + build.itemsTab:CreateDisplayItemFromRaw("New Item\nDriftwood Maul") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Ground Slam 20/0 1\nFist of War 20/0 1\n") + runCallback("OnFrame") + assert.is_true(build.calcsTab.mainEnv.player.mainSkill.skillTypes[SkillType.Slam]) + assert.is_true(build.calcsTab.mainOutput.FistOfWarUptimeRatio > 0) + end) + + it("does not apply Fist of War to player Cleave", function() + build.itemsTab:CreateDisplayItemFromRaw("New Item\nRusted Hatchet") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Cleave 20/0 1\nFist of War 20/0 1\n") + runCallback("OnFrame") + assert.is_true(not build.calcsTab.mainEnv.player.mainSkill.skillTypes[SkillType.Slam]) + assert.is_true(not build.calcsTab.mainOutput.FistOfWarUptimeRatio or build.calcsTab.mainOutput.FistOfWarUptimeRatio == 0) + end) + + it("does not apply injected Fist of War mods to player Cleave", function() + build.itemsTab:CreateDisplayItemFromRaw("New Item\nRusted Hatchet") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Cleave 20/0 1\n") + build.configTab:BuildModList() + build.configTab.modList:NewMod("FistOfWarCooldown", "BASE", 1, "Test") + build.configTab.modList:NewMod("FistOfWarDamageMultiplier", "BASE", 100, "Test") + build.calcsTab:BuildOutput() + local skill = build.calcsTab.mainEnv.player.mainSkill + assert.is_true(not skill.skillTypes[SkillType.Slam]) + assert.is_true(skill.skillModList:Sum("BASE", skill.skillCfg, "FistOfWarCooldown") > 0) + assert.is_true(not build.calcsTab.mainOutput.FistOfWarUptimeRatio or build.calcsTab.mainOutput.FistOfWarUptimeRatio == 0) + end) end) diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index 8075f75884c..b9b66a0d337 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -65,6 +65,25 @@ describe("TestSkills", function() assert.True(build.calcsTab.mainOutput.MirageDPS ~= nil) assert.True(build.calcsTab.mainOutput.SkillTriggerRate == build.calcsTab.mainOutput.Speed) + assert.is_true(not build.calcsTab.mainEnv.player.mainSkill.skillCfg.skillCond.usedByMirage) + end) + + it("calculates The Saviour Reflection mirages for a player sword attack", function() + build.itemsTab:CreateDisplayItemFromRaw([[Rarity: Unique +The Saviour +Legion Sword +Implicits: 1 +40% increased Global Accuracy Rating +Triggers Level 20 Reflection when Equipped +(130-150)% increased Physical Damage +Adds (16-22) to (40-45) Physical Damage +(8-12)% increased Attack Speed +(8-12)% increased Critical Strike Chance]]) + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Double Strike 20/0 1\n") + runCallback("OnFrame") + local player = build.calcsTab.mainEnv.player + assert.is_true(not player.mainSkill.skillCfg.skillCond.usedByMirage) end) it("Test Sacred wisps using current skill", function() diff --git a/spec/System/TestTradeQuery_spec.lua b/spec/System/TestTradeQuery_spec.lua index c700a332cf8..3e04d497041 100644 --- a/spec/System/TestTradeQuery_spec.lua +++ b/spec/System/TestTradeQuery_spec.lua @@ -2,9 +2,33 @@ describe("TradeQuery", function() local mock_tradeQuery local mock_queryGen + local function stubItemsTab(itemsTab) + itemsTab = itemsTab or { } + function itemsTab:ComparisonActorForSlot(slotName, itemSetId) + if type(slotName) == "string" and slotName:match("^Jewel ") then + return "PLAYER" + end + if type(slotName) == "string" and slotName:match("^Mercenary ") then + return "MERCENARY" + end + return "PLAYER" + end + function itemsTab:ItemCalculationOverride(slotName, item, itemSetId) + itemSetId = itemSetId or self.viewItemSetId + local isTreeJewel = type(slotName) == "string" and slotName:match("^Jewel ") ~= nil + return { + itemSetId = (not isTreeJewel) and itemSetId or nil, + comparisonActor = self:ComparisonActorForSlot(slotName, itemSetId), + repSlotName = slotName, + repItem = item, + } + end + return itemsTab + end + before_each(function() - mock_tradeQuery = new("TradeQuery"):TradeQuery({ itemsTab = {} }) - mock_queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = {} }) + mock_tradeQuery = new("TradeQuery"):TradeQuery(stubItemsTab()) + mock_queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = stubItemsTab() }) end) describe("result dropdown tooltipFunc", function() -- Builds a TradeQuery with the strict minimum needed for @@ -14,9 +38,10 @@ describe("TradeQuery", function() -- lives behind a callback we never trigger, or is already initialized -- by the TradeQuery constructor. local function newTradeQuery(state) - local tq = new("TradeQuery"):TradeQuery({ itemsTab = {} }) + local tq = new("TradeQuery"):TradeQuery(stubItemsTab()) tq.itemsTab.activeItemSet = {} tq.itemsTab.slots = {} + tq.itemsTab.GetVisibleItemSet = function(itemsTab) return itemsTab.activeItemSet end tq.slotTables[1] = { slotName = "Ring 1" } if state.resultTbl then tq.resultTbl = state.resultTbl end if state.sortedResultTbl then tq.sortedResultTbl = state.sortedResultTbl end @@ -60,12 +85,51 @@ describe("TradeQuery", function() end) assert.are.equal(0, #tooltip.lines) end) + + it("imports a result into the visible item set slot", function() + local visibleItemSet = { Helmet = { selItemId = 0 } } + local currentVisibleItemSet = visibleItemSet + local helmetSlot = { + slotName = "Helmet", + label = "Helmet", + selItemId = 0, + IsShown = function() return true end, + SetSelItemId = function(self, itemId, itemSet) + self.selItemId = itemId + itemSet[self.slotName].selItemId = itemId + end, + } + local tq = newTradeQuery({ + resultTbl = { [1] = { [1] = { item_string = "Rarity: NORMAL\nIron Hat", amount = 1, currency = "chaos" } } }, + sortedResultTbl = { [1] = { { index = 1 } } }, + }) + tq.itemsTab.viewItemSet = visibleItemSet + tq.itemsTab.GetVisibleItemSet = function() return currentVisibleItemSet end + tq.itemsTab.slots = { [helmetSlot.slotName] = helmetSlot } + tq.itemsTab.IsItemValidForSlot = function() return true end + tq.itemsTab.CreateDisplayItemFromRaw = function(itemsTab) itemsTab.displayItem = { id = 77 } end + tq.itemsTab.AddDisplayItem = function() end + tq.itemsTab.PopulateSlots = function() end + tq.itemsTab.AddUndoState = function() end + tq.itemsTab.build = { buildFlag = false } + tq.slotTables[1] = { slotName = helmetSlot.slotName } + tq.itemIndexTbl[1] = 1 + + buildRow1Dropdown(tq) + local nextVisibleItemSet = { Helmet = { selItemId = 0 } } + currentVisibleItemSet = nextVisibleItemSet + tq.controls.importButton1:Click() + + assert.are.equal(77, helmetSlot.selItemId) + assert.are.equal(0, visibleItemSet.Helmet.selItemId) + assert.are.equal(77, nextVisibleItemSet.Helmet.selItemId) + end) end) describe("GetResultEvaluation", function() it("uses the first visible ring for a Pearl result without a selected slot", function() - local tq = new("TradeQuery"):TradeQuery({ itemsTab = {} }) + local tq = new("TradeQuery"):TradeQuery(stubItemsTab()) tq.statSortSelectionList = {} - tq.tradeQueryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = {} }) + tq.tradeQueryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = stubItemsTab() }) tq.itemsTab.slots = { ["Ring 1"] = { slotName = "Ring 1", shown = function() return false end }, ["Ring 2"] = { slotName = "Ring 2", shown = function() return true end }, @@ -89,9 +153,9 @@ describe("TradeQuery", function() local slotTbl = { slotName = "Megalomaniac", unique = true, alreadyCorrupted = true, selectedJewelNodeId = 12345, } - local tq = new("TradeQuery"):TradeQuery({ itemsTab = {} }) + local tq = new("TradeQuery"):TradeQuery(stubItemsTab()) tq.statSortSelectionList = {} - tq.tradeQueryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = {} }) + tq.tradeQueryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = stubItemsTab() }) tq.itemsTab.build = { spec = { tree = { @@ -122,6 +186,66 @@ describe("TradeQuery", function() assert.is_true(#entry.DNs >= 2) end end) + it("weights Mercenary slots against Mercenary output", function() + mock_tradeQuery.tradeQueryGenerator = mock_queryGen + mock_tradeQuery.itemsTab.build = { calcsTab = { GetMiscCalculator = function() + return function() return { Life = 200 } end, { Life = 10 }, { + PLAYER = { Life = 10 }, + MERCENARY = { Life = 100 }, + } + end } } + mock_tradeQuery.slotTables[1] = { slotName = "Mercenary Helmet" } + mock_tradeQuery.resultTbl[1] = { { item_string = "Rarity: NORMAL\nIron Hat" } } + mock_tradeQuery.statSortSelectionList = { { stat = "Life", weightMult = 1 } } + + local evaluation = mock_tradeQuery:GetResultEvaluation(1, 1) + assert.are.equal(2, evaluation[1].weight) + + mock_tradeQuery.itemsTab.build = { calcsTab = { GetMiscCalculator = function() + return function() return { Life = 200 } end, { Life = 10 }, { + PLAYER = { Life = 10 }, + } + end } } + evaluation = mock_tradeQuery:GetResultEvaluation(1, 1) + assert.same({ }, evaluation) + end) + end) + describe("PriceItem slot rows", function() + it("only includes slots shown by the visible item set", function() + newBuild() + local itemsTab = build.itemsTab + local tradeQuery = itemsTab.tradeQuery + local originalOpenPopup = main.OpenPopup + local originalUpdateRealms = tradeQuery.UpdateRealms + local originalPullCXData = tradeQuery.PullCXData + local ok, err + + itemsTab.activeItemSet.useSecondWeaponSet = false + itemsTab.build.spec.treeVersion = "3_26" + itemsTab.build.calcsTab.mainEnv = { modDB = { Flag = function() return false end } } + tradeQuery.pbRealm = "pc" + tradeQuery.UpdateRealms = function() end + tradeQuery.PullCXData = function() end + main.OpenPopup = function() end + ok, err = pcall(function() tradeQuery:PriceItem() end) + + main.OpenPopup = originalOpenPopup + tradeQuery.UpdateRealms = originalUpdateRealms + tradeQuery.PullCXData = originalPullCXData + assert.is_true(ok, err) + + local slotNames = { } + for _, slotTable in ipairs(tradeQuery.slotTables) do + if not slotTable.unique and not slotTable.nodeId then + slotNames[slotTable.slotName] = true + end + end + assert.is_true(slotNames["Weapon 1"]) + assert.is_nil(slotNames["Weapon 1 Swap"]) + assert.is_nil(slotNames["Weapon 2 Swap"]) + assert.is_nil(slotNames["Ring 3"]) + assert.is_nil(slotNames["Graft 1"]) + end) end) describe("ReduceOutput", function() it("preserves lower-is-better values for weighted result comparison", function() @@ -177,3 +301,154 @@ describe("TradeQuery", function() end) end) end) + +describe("Light Radius integration", function() + local MercenaryTest = dofile("../spec/System/MercenaryTestHelpers.lua") + + local function configureMercenary() + local profile = build.mercenaryTab.profile + profile.classId = "TrapsMinesShadow" + profile.buildId = "TrapsMinesShadowLightning" + profile.foundAreaLevel = 83 + profile.mainSkillId = "LightningTrapMercenary" + profile.skills = { { + id = profile.mainSkillId, + enabled = true, + includeInFullDPS = true, + count = 1, + supports = { }, + } } + build.mercenaryTab:Changed() + end + + local function equipRings() + local itemsTab = build.itemsTab + local playerRing = new("Item"):Item("Rarity: Normal\nPaua Ring") + local mercenaryRing = new("Item"):Item("Rarity: Normal\nPaua Ring") + itemsTab:AddItem(playerRing, true) + itemsTab:AddItem(mercenaryRing, true) + itemsTab.activeItemSet["Ring 1"].selItemId = playerRing.id + local mercenaryItemSet = assert(build.mercenaryTab:GetItemSet(true)) + mercenaryItemSet["Ring 1"].selItemId = mercenaryRing.id + return mercenaryItemSet + end + + local function tradeOptions(statWeights) + return { + influence1 = 1, + influence2 = 1, + includeTalisman = false, + includeCorrupted = false, + includeScourge = false, + includeEldritch = false, + includeMirrored = false, + statWeights = statWeights, + requiredMods = { }, + } + end + + local function lightRadiusStat() + for _, stat in ipairs(data.powerStatList) do + if stat.stat == "LightRadiusMod" then return stat end + end + return assert(nil, "LightRadiusMod is missing from the power stat list") + end + + local function findRingLightRadiusMod(queryGenerator) + for _, mod in pairs(queryGenerator.modData.Explicit) do + if mod.tradeMod and mod.tradeMod.id == "explicit.stat_1263695895" and mod.Ring then + return mod + end + end + return assert(nil, "Light Radius ring trade modifier is missing") + end + + local function generateLightRadiusQuery(slotName, expectedBaseLightRadius) + local stat = lightRadiusStat() + local slot = assert(build.itemsTab.slots[slotName]) + local queryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator(build.itemsTab.tradeQuery) + local queryJson, queryError + queryGenerator.tradeTypeIndex = 1 + queryGenerator.requesterCallback = function(_, json, errMsg) + queryJson, queryError = json, errMsg + end + queryGenerator:StartQuery(slot, tradeOptions({ { stat = stat.stat, weightMult = 1 } })) + queryGenerator.calcContext.co = nil + + local function calculationOverride(item) + return { + itemSetId = queryGenerator.calcContext.itemSetId, + comparisonActor = build.itemsTab:ComparisonActorForSlot(slot.slotName, queryGenerator.calcContext.itemSetId), + repSlotName = slot.slotName, + repItem = item, + } + end + local baseOutput = assert(queryGenerator.calcContext.baseOutput) + assert.are.near(expectedBaseLightRadius, baseOutput.LightRadiusMod, 10 ^ -9) + local blankOutput = queryGenerator.calcContext.calcFunc(calculationOverride(queryGenerator.calcContext.testItem)) + assert.are.near(expectedBaseLightRadius, blankOutput.LightRadiusMod, 10 ^ -9) + + local lightRadiusMod = findRingLightRadiusMod(queryGenerator) + queryGenerator.modWeights = { } + queryGenerator.alreadyWeightedMods = { } + queryGenerator:GenerateModWeights({ LightRadius = lightRadiusMod }) + assert.are.equal(1, #queryGenerator.modWeights) + local generatedWeight = queryGenerator.modWeights[1] + assert.are.equal("explicit.stat_1263695895", generatedWeight.tradeModId) + assert.is_false(generatedWeight.invert) + local weightedOutput = queryGenerator.calcContext.calcFunc(calculationOverride(queryGenerator.calcContext.testItem)) + local modValue = tonumber(queryGenerator.calcContext.testItem.explicitModLines[1].line:match("^(%d+)%% increased Light Radius$")) + assert.is_number(modValue) + local expectedWeight = ( + weightedOutput.LightRadiusMod / baseOutput.LightRadiusMod + - blankOutput.LightRadiusMod / baseOutput.LightRadiusMod + ) * 1000 / modValue + assert.are.near(expectedWeight, generatedWeight.weight, 10 ^ -9) + + queryGenerator:FinishQuery() + assert.is_nil(queryError) + local query = assert(require("dkjson").decode(queryJson)) + assert.are.equal("accessory.ring", query.query.filters.type_filters.filters.category.option) + assert.are.equal("securable", query.query.status.option) + assert.are.equal("explicit.stat_1263695895", query.query.stats[1].filters[1].id) + assert.are.near(generatedWeight.weight, query.query.stats[1].filters[1].value.weight, 10 ^ -9) + end + + before_each(function() + newBuild() + MercenaryTest.allocatePermanentHire() + build.characterLevel = 90 + build.characterLevelAutoMode = false + configureMercenary() + equipRings() + end) + + it("calculates Light Radius from programmatic equipment and selected-actor trade weights", function() + build.configTab.input.customMods = "100% increased Light Radius" + local baseline = MercenaryTest.calculateBuild() + generateLightRadiusQuery("Ring 1", baseline.player.output.LightRadiusMod) + build.itemsTab:SetViewItemSet(assert(build.mercenaryTab:GetItemSet(true)).id) + generateLightRadiusQuery("Ring 1", baseline.mercenary.output.LightRadiusMod) + + local baselinePlayerLightRadiusInc = baseline.player.modDB:Sum("INC", nil, "LightRadius") + local baselineMercenaryLightRadiusInc = baseline.mercenary.modDB:Sum("INC", nil, "LightRadius") + local baselinePlayerLightRadius = baseline.player.output.LightRadiusMod + local baselineMercenaryLightRadius = baseline.mercenary.output.LightRadiusMod + local mercenaryItemSet = assert(build.mercenaryTab:GetItemSet(true)) + local lightRadiusRing = new("Item"):Item([[Rarity: Rare +Mercenary Light Radius Test +Paua Ring +-------- +100% increased Light Radius]]) + build.itemsTab:AddItem(lightRadiusRing, true) + mercenaryItemSet["Ring 1"].selItemId = lightRadiusRing.id + + local env = MercenaryTest.calculateBuild() + assert.are.equal(baselinePlayerLightRadiusInc, env.player.modDB:Sum("INC", nil, "LightRadius")) + assert.are.equal(baselineMercenaryLightRadiusInc + 100, env.mercenary.modDB:Sum("INC", nil, "LightRadius")) + assert.are.near(baselinePlayerLightRadius, env.player.output.LightRadiusMod, 10 ^ -9) + assert.are.near(baselineMercenaryLightRadius + 1, env.mercenary.output.LightRadiusMod, 10 ^ -9) + assert.is_true(env.mercenary.output.FullDPS > 0) + assert.are.near(env.mercenary.output.FullDPS, env.player.output.FullDPS, 10 ^ -6) + end) +end) diff --git a/src/Classes/CalcBreakdownControl.lua b/src/Classes/CalcBreakdownControl.lua index 6db2299accb..ec02e6ed978 100644 --- a/src/Classes/CalcBreakdownControl.lua +++ b/src/Classes/CalcBreakdownControl.lua @@ -48,7 +48,7 @@ end function CalcBreakdownClass:GetActor() local env = self.calcsTab[self.envName or "calcsEnv"] - local actor = self.calcsTab.input.showMinion and env.minion or env.player + local actor = self.calcsTab:GetDisplayActor(env) if self.forceActor then actor = env[self.forceActor] end @@ -146,6 +146,7 @@ end -- Add sections based on the breakdown data generated by the Calcs module function CalcBreakdownClass:AddBreakdownSection(sectionData) local actor = self:GetActor() + if not actor then return end local breakdown local ns, name = sectionData.breakdown:match("^(%a+)%.(%a+)$") if ns then @@ -299,6 +300,7 @@ end -- Add a table section showing a list of modifiers function CalcBreakdownClass:AddModSection(sectionData, modList) local actor = self:GetActor() + if not actor then return end local build = self.calcsTab.build -- Build list of modifiers to display diff --git a/src/Classes/CalcSectionControl.lua b/src/Classes/CalcSectionControl.lua index 668e742d437..ba0b0a406ba 100644 --- a/src/Classes/CalcSectionControl.lua +++ b/src/Classes/CalcSectionControl.lua @@ -184,10 +184,19 @@ function CalcSectionClass:UpdatePos() end end +local function sectionFormatActor(calcsTab) + local actor = calcsTab:GetDisplayActor(calcsTab.calcsEnv) + if actor then + return actor + end + -- Actor Status formats calcsOutput directly. Do not invent mainSkill/skillFlags. + return { output = calcsTab.calcsOutput or { } } +end + function CalcSectionClass:Draw(viewPort, noTooltip) local x, y = self:GetPos() local width, height = self:GetSize() - local actor = self.calcsTab.input.showMinion and self.calcsTab.calcsEnv.minion or self.calcsTab.calcsEnv.player + local actor = sectionFormatActor(self.calcsTab) -- Draw border and background SetDrawLayer(nil, -10) SetDrawColor(self.colour) @@ -385,7 +394,7 @@ function CalcSectionClass:DrawOverlay(viewPort, inputEvents) local x = self.overlayX local y = self.overlayY local overlayWidth = self.width - local actor = self.calcsTab.calcsEnv and (self.calcsTab.input.showMinion and self.calcsTab.calcsEnv.minion or self.calcsTab.calcsEnv.player) + local actor = sectionFormatActor(self.calcsTab) -- Calculate content height local totalHeight = self:GetOverlayHeight() @@ -548,4 +557,4 @@ function CalcSectionClass:DrawContent(drawX, startLineY, drawWidth, actor, viewP end end end -end \ No newline at end of file +end diff --git a/src/Classes/CalcsTab.lua b/src/Classes/CalcsTab.lua index 7d79e865d98..1e148c75975 100644 --- a/src/Classes/CalcsTab.lua +++ b/src/Classes/CalcsTab.lua @@ -8,6 +8,7 @@ local ipairs = ipairs local t_insert = table.insert local m_max = math.max local m_floor = math.floor +local MercenaryTools = require("Modules.MercenaryTools") local buffModeDropList = { { label = "Unbuffed", buffMode = "UNBUFFED" }, @@ -34,6 +35,7 @@ function CalcsTabClass:CalcsTab(build) self.input = { } self.input.skill_number = 1 self.input.misc_buffMode = "EFFECTIVE" + self.input.actor = "PLAYER" self.colWidth = 230 self.sectionList = { } @@ -45,6 +47,7 @@ function CalcsTabClass:CalcsTab(build) self:NewSection(3, "SkillSelect", 1, colorCodes.NORMAL, {{ defaultCollapsed = false, label = "View Skill Details", data = { { label = "Socket Group", { controlName = "mainSocketGroup", control = new("DropDownControl"):DropDownControl(nil, {0, 0, 300, 16}, nil, function(index, value) + if self:IsMercenaryActor() then return end self.input.skill_number = index self:AddUndoState() self.build.buildFlag = true @@ -59,13 +62,27 @@ function CalcsTabClass:CalcsTab(build) }, }, { label = "Active Skill", { controlName = "mainSkill", control = new("DropDownControl"):DropDownControl(nil, {0, 0, 300, 16}, nil, function(index, value) + if self:IsMercenaryActor() then + local profile = self.build.mercenaryTab.profile + if value and value.skillId then profile.mainSkillId = value.skillId end + self.build.mercenaryTab:Changed() + return + end local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number] mainSocketGroup.mainActiveSkillCalcs = index self.build.buildFlag = true end) }, }, - { label = "Skill Part", playerFlag = "multiPart", { controlName = "mainSkillPart", + { label = "Skill Part", playerFlag = "multiPart", { controlName = "mainSkillPart", control = new("DropDownControl"):DropDownControl(nil, {0, 0, 250, 16}, nil, function(index, value) + if self:IsMercenaryActor() then + local skill = self:GetMercenaryCalcsSkill() + if skill then + skill.skillPart = index + self.build.mercenaryTab:Changed() + end + return + end local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number] local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance srcInstance.skillPartCalcs = index @@ -74,6 +91,14 @@ function CalcsTabClass:CalcsTab(build) end) }, },{ label = "Skill Stages", playerFlag = "multiStage", { controlName = "mainSkillStageCount", control = new("EditControl"):EditControl(nil, {0, 0, 52, 16}, nil, nil, "%D", nil, function(buf) + if self:IsMercenaryActor() then + local skill = self:GetMercenaryCalcsSkill() + if skill then + skill.skillStageCount = tonumber(buf) + self.build.mercenaryTab:Changed() + end + return + end local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number] local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance srcInstance.skillStageCountCalcs = tonumber(buf) @@ -83,6 +108,14 @@ function CalcsTabClass:CalcsTab(build) }, }, { label = "Active Mines", playerFlag = "mine", { controlName = "mainSkillMineCount", control = new("EditControl"):EditControl(nil, {0, 0, 52, 16}, nil, nil, "%D", nil, function(buf) + if self:IsMercenaryActor() then + local skill = self:GetMercenaryCalcsSkill() + if skill then + skill.skillMineCount = tonumber(buf) + self.build.mercenaryTab:Changed() + end + return + end local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number] local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance srcInstance.skillMineCountCalcs = tonumber(buf) @@ -90,12 +123,14 @@ function CalcsTabClass:CalcsTab(build) self.build.buildFlag = true end) }, }, - { label = "Show Minion Stats", flag = "haveMinion", { controlName = "showMinion", - control = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state) - self.input.showMinion = state + { label = "Calculation Actor", { controlName = "actor", + control = new("DropDownControl"):DropDownControl(nil, {0, 0, 160, 16}, nil, function(index, value) + self:SetCalculationActor(value.actorId) self:AddUndoState() - end, "Show stats for the minion instead of the player.") + self.build.buildFlag = true + end) }, }, + { label = "Actor Status", haveOutput = "ActorUnavailableMessage", textSize = 12, { format = "{output:ActorUnavailableMessage}" }, }, { label = "Minion", flag = "minion", { controlName = "mainSkillMinion", control = new("DropDownControl"):DropDownControl(nil, {0, 0, 160, 16}, nil, function(index, value) local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number] @@ -116,6 +151,14 @@ function CalcsTabClass:CalcsTab(build) } }, { label = "Minion Skill", flag = "haveMinion", { controlName = "mainSkillMinionSkill", control = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 16}, nil, function(index, value) + if self:IsMercenaryActor() then + local skill = self:GetMercenaryCalcsSkill() + if skill then + skill.skillMinionSkillCalcs = index + self.build.mercenaryTab:Changed() + end + return + end local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number] local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance srcInstance.skillMinionSkillCalcs = index @@ -143,9 +186,19 @@ Effective DPS: Curses and enemy properties (such as resistances and status condi { label = "Curses and Debuffs", flag = "effective", textSize = 12, { format = "{output:CurseList}", { breakdown = "SkillDebuffs" } }, }, }}}, function(section) self.build:RefreshSkillSelectControls(section.controls, self.input.skill_number, "Calcs") - section.controls.showMinion.state = self.input.showMinion + self:RefreshMercenarySkillSelectControls(section.controls, "Calcs") + self:SyncActorList() section.controls.mode:SelByValue(self.input.misc_buffMode, "buffMode") + local minionList = section.controls.mainSkillMinion and section.controls.mainSkillMinion.list + local usesItemSet = minionList and minionList[1] and minionList[1].itemSetId + for _, row in ipairs(section.subSection[1].data) do + if row[1] and row[1].controlName == "mainSkillMinion" then + row.label = usesItemSet and "Item Set" or "Minion" + break + end + end end) + self.skillSelectSection = self.sectionList[#self.sectionList] -- Add sections from the CalcSections module local sectionData = LoadModule("Modules/CalcSections") @@ -160,7 +213,85 @@ Effective DPS: Curses and enemy properties (such as resistances and status condi return self end +function CalcsTabClass:IsMercenaryActor() + return MercenaryTools.isMercenaryCalculationActor(self.input.actor) +end + +function CalcsTabClass:SyncActorList() + local actor = self.skillSelectSection.controls.actor + actor:SetList(MercenaryTools.filterCalculationActors(calcLib.calculationActorList, self.build)) + actor:SelByValue(self.input.actor, "actorId") +end + +function CalcsTabClass:GetMercenaryCalcsSkill() + local profile = self.build.mercenaryTab.profile + for _, skill in ipairs(profile.skills or { }) do + if skill.id == profile.mainSkillId then return skill end + end +end + +function CalcsTabClass:RefreshMercenarySkillSelectControls(controls, suffix) + if not self:IsMercenaryActor() then return end + local minionSkillField = suffix == "Calcs" and "skillMinionSkillCalcs" or "skillMinionSkill" + local profile = self.build.mercenaryTab.profile + controls.mainSocketGroup:SetList({ { label = "Mercenary Skills" } }) + controls.mainSocketGroup.selIndex = 1 + controls.mainSocketGroup.enabled = false + controls.mainSocketGroup.shown = true + local skillList, selectedIndex = { }, 1 + for _, skill in ipairs(profile.skills or { }) do + if skill.enabled ~= false then + t_insert(skillList, { skillId = skill.id, label = self.build.data.skills[skill.id] and self.build.data.skills[skill.id].name or skill.id }) + if skill.id == profile.mainSkillId then selectedIndex = #skillList end + end + end + if #skillList == 0 then skillList[1] = { label = "" } end + controls.mainSkill:SetList(skillList) + controls.mainSkill.selIndex = selectedIndex + controls.mainSkill.enabled = #skillList > 1 + controls.mainSkill.shown = true + controls.mainSkillPart.shown = false + controls.mainSkillStageCount.shown = false + controls.mainSkillMineCount.shown = false + controls.mainSkillMinion.shown = false + controls.mainSkillMinionLibrary.shown = false + controls.mainSkillMinionSkill.shown = false + local selectedSkill = self:GetMercenaryCalcsSkill() + local mercenary = self.calcsEnv and self.calcsEnv.mercenary + local mercenaryMinion = self.calcsEnv and self.calcsEnv.mercenaryMinion + local grantedEffect = selectedSkill and self.build.data.skills[selectedSkill.id] + local activeSkill = mercenary and mercenary.mainSkill + mercenaryMinion = mercenaryMinion or activeSkill and activeSkill.minion + if mercenaryMinion and #(mercenaryMinion.activeSkillList or { }) > 0 then + local minionSkillList = { } + local selectedIndex = selectedSkill and (selectedSkill[minionSkillField] or (suffix == "Calcs" and selectedSkill.skillMinionSkill)) or 1 + for index, minionSkill in ipairs(mercenaryMinion.activeSkillList) do + minionSkillList[#minionSkillList + 1] = { index = index, label = minionSkill.activeEffect.grantedEffect.name } + end + controls.mainSkillMinionSkill:SetList(minionSkillList) + controls.mainSkillMinionSkill:SelByValue(selectedIndex, "index") + controls.mainSkillMinionSkill.enabled = #minionSkillList > 1 + controls.mainSkillMinionSkill.shown = true + end + if grantedEffect and grantedEffect.parts and #grantedEffect.parts > 1 then + local partList = { } + for index, part in ipairs(grantedEffect.parts) do t_insert(partList, { label = part.name, index = index }) end + controls.mainSkillPart:SetList(partList) + controls.mainSkillPart:SelByValue(selectedSkill.skillPart or self.build.data.mercenaryStatData.defaultSkillParts[selectedSkill.id] or 1, "index") + controls.mainSkillPart.shown = true + end + if activeSkill and activeSkill.skillFlags.multiStage then + controls.mainSkillStageCount.buf = tostring(selectedSkill and selectedSkill.skillStageCount or activeSkill.skillData.stagesMax or activeSkill.skillData.stagesMin or 1) + controls.mainSkillStageCount.shown = true + end + if activeSkill and activeSkill.skillFlags.mine then + controls.mainSkillMineCount.buf = tostring(selectedSkill and selectedSkill.skillMineCount or "") + controls.mainSkillMineCount.shown = true + end +end + function CalcsTabClass:Load(xml, dbFileName) + local savedActor for _, node in ipairs(xml) do if type(node) == "table" then if node.elem == "Input" then @@ -178,6 +309,9 @@ function CalcsTabClass:Load(xml, dbFileName) launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing number, string or boolean attribute", dbFileName) return true end + if node.attrib.name == "actor" then + savedActor = self.input.actor + end elseif node.elem == "Section" then if not node.attrib.id then launch:ShowErrMsg("^1Error parsing '%s': 'Section' element missing id attribute", dbFileName) @@ -197,6 +331,11 @@ function CalcsTabClass:Load(xml, dbFileName) end end end + if not savedActor then + self.input.legacyShowMinion = not not self.input.showMinion + self.input.actor = self.input.showMinion and "PLAYER_MINION" or "PLAYER" + end + self.input.showMinion = nil self:ResetUndo() end @@ -394,8 +533,8 @@ function CalcsTabClass:SetDisplayStat(displayData, pin) end function CalcsTabClass:CheckFlag(obj, actor, player) - actor = actor or (self.input.showMinion and self.calcsEnv.minion or self.calcsEnv.player) - local skillFlags = actor.mainSkill.skillFlags + actor = actor or self:GetDisplayActor(self.calcsEnv) + local skillFlags = actor and actor.mainSkill and actor.mainSkill.skillFlags or { } if obj.flag and not skillFlags[obj.flag] then return end @@ -406,8 +545,11 @@ function CalcsTabClass:CheckFlag(obj, actor, player) end end end - if obj.playerFlag and not (player or self.calcsEnv.player).mainSkill.skillFlags[obj.playerFlag] then - return + if obj.playerFlag then + local sourceActor = self:IsMercenaryActor() and self.calcsEnv.mercenary or (player or self.calcsEnv.player) + if not sourceActor or not sourceActor.mainSkill or not sourceActor.mainSkill.skillFlags[obj.playerFlag] then + return + end end if obj.notFlag and skillFlags[obj.notFlag] then return @@ -420,18 +562,45 @@ function CalcsTabClass:CheckFlag(obj, actor, player) end end if obj.haveOutput then + local output = actor and actor.output or self.calcsOutput local ns, var = obj.haveOutput:match("^(%a+)%.(%a+)$") if ns then - if not actor.output[ns] or not actor.output[ns][var] or actor.output[ns][var] == 0 then + if not output or not output[ns] or not output[ns][var] or output[ns][var] == 0 then return end - elseif not actor.output[obj.haveOutput] or actor.output[obj.haveOutput] == 0 then + elseif not output or not output[obj.haveOutput] or output[obj.haveOutput] == 0 then return end end return true end +function CalcsTabClass:SetCalculationActor(actorId) + self.input.actor = actorId + self.input.legacyShowMinion = nil +end + +function CalcsTabClass:GetDisplayActor(env) + if not env then + return + end + local actors = { + PLAYER = env.player, + PLAYER_MINION = env.minion, + MERCENARY = env.mercenary, + MERCENARY_MINION = env.mercenaryMinion, + } + local actor = actors[self.input.actor or "PLAYER"] + if actor then + return actor + end + -- Only the showMinion XML migration falls back; an explicit Player Minion + -- selection stays unavailable when this build has no minion. + if self.input.legacyShowMinion and self.input.actor == "PLAYER_MINION" then + return env.player + end +end + function CalcsTabClass:SearchMatch(txt) local searchStr = self.controls.search.buf:lower() return string.len(searchStr) > 0 and txt:lower():find(searchStr) @@ -459,7 +628,13 @@ function CalcsTabClass:BuildOutput() self.mainEnv = self.calcs.buildOutput(self.build, "MAIN") self.mainOutput = self.mainEnv.player.output self.calcsEnv = self.calcs.buildOutput(self.build, "CALCS") - self.calcsOutput = self.calcsEnv.player.output + self.calcsActor = self:GetDisplayActor(self.calcsEnv) + if self.calcsActor then + self.calcsOutput = self.calcsActor.output + else + local actorLabel = (self.input.actor or "PLAYER"):gsub("_", " "):lower() + self.calcsOutput = { ActorUnavailableMessage = "The selected "..actorLabel.." is unavailable for this build." } + end if self.displayData then self.controls.breakdown:SetBreakdownData() @@ -467,8 +642,8 @@ function CalcsTabClass:BuildOutput() end -- Retrieve calculator functions - local miscCalcFunc, miscCalcBase = self.calcs.getMiscCalculator(self.build) - self.miscCalculator = { miscCalcFunc, miscCalcBase } + local miscCalcFunc, miscCalcBase, actorOutputs = self.calcs.getMiscCalculator(self.build) + self.miscCalculator = { miscCalcFunc, miscCalcBase, actorOutputs } end -- Controls the coroutine that calculates node power @@ -758,7 +933,7 @@ function CalcsTabClass:CalculateCombinedOffDefStat(original, modified) end function CalcsTabClass:GetMiscCalculator() - return self.miscCalculator[1], self.miscCalculator[2] + return self.miscCalculator[1], self.miscCalculator[2], self.miscCalculator[3] end function CalcsTabClass:CreateUndoState() diff --git a/src/Classes/CompareCalcsHelpers.lua b/src/Classes/CompareCalcsHelpers.lua index 1a5254e8d01..c77ae4d1e94 100644 --- a/src/Classes/CompareCalcsHelpers.lua +++ b/src/Classes/CompareCalcsHelpers.lua @@ -144,7 +144,7 @@ end ---@param build Build function M.GetBreakdownLines(sectionData, build) if not sectionData.breakdown then return nil end - local calcsActor = build.calcsTab and build.calcsTab.calcsEnv and build.calcsTab.calcsEnv.player + local calcsActor = build.calcsTab and build.calcsTab:GetDisplayActor(build.calcsTab.calcsEnv) if not calcsActor or not calcsActor.breakdown then return nil end local breakdown @@ -173,13 +173,11 @@ end function M.DrawCalcsTooltip(tooltip, primaryBuild, primaryLabel, colData, rowLabel, rowX, rowY, rowW, rowH, vp, compareEntry) if tooltip:CheckForUpdate(colData, rowLabel) then -- Get calcsEnv actors (these have breakdown data populated) - local primaryCalcsActor = primaryBuild.calcsTab and primaryBuild.calcsTab.calcsEnv - and primaryBuild.calcsTab.calcsEnv.player - local compareCalcsActor = compareEntry.calcsTab and compareEntry.calcsTab.calcsEnv - and compareEntry.calcsTab.calcsEnv.player + local primaryCalcsActor = primaryBuild.calcsTab and primaryBuild.calcsTab:GetDisplayActor(primaryBuild.calcsTab.calcsEnv) + local compareCalcsActor = compareEntry.calcsTab and compareEntry.calcsTab:GetDisplayActor(compareEntry.calcsTab.calcsEnv) - local primaryActor = primaryCalcsActor or (primaryBuild.calcsTab.mainEnv and primaryBuild.calcsTab.mainEnv.player) - local compareActor = compareCalcsActor or (compareEntry.calcsTab.mainEnv and compareEntry.calcsTab.mainEnv.player) + local primaryActor = primaryCalcsActor or (primaryBuild.calcsTab.mainEnv and primaryBuild.calcsTab:GetDisplayActor(primaryBuild.calcsTab.mainEnv)) + local compareActor = compareCalcsActor or (compareEntry.calcsTab.mainEnv and compareEntry.calcsTab:GetDisplayActor(compareEntry.calcsTab.mainEnv)) if not primaryActor and not compareActor then return @@ -362,11 +360,10 @@ end -- Draw a breakdown panel for a single build's SkillBuffs or SkillDebuffs, ---@param build Build function M.DrawSkillBreakdownPanel(build, breakdownKey, label, cellX, cellY, cellW, cellH, vp) - local player = build.calcsTab and build.calcsTab.calcsEnv - and build.calcsTab.calcsEnv.player - if not player or not player.breakdown then return end + local actor = build.calcsTab and build.calcsTab:GetDisplayActor(build.calcsTab.calcsEnv) + if not actor or not actor.breakdown then return end - local breakdown = player.breakdown[breakdownKey] + local breakdown = actor.breakdown[breakdownKey] if not breakdown or not breakdown.modList or #breakdown.modList == 0 then return end local modList = breakdown.modList diff --git a/src/Classes/CompareEntry.lua b/src/Classes/CompareEntry.lua index 58529fb285d..65bc48e1172 100644 --- a/src/Classes/CompareEntry.lua +++ b/src/Classes/CompareEntry.lua @@ -111,6 +111,7 @@ function CompareEntryClass:LoadFromXML(xmlText) self.partyTab = { enemyModList = new("ModList"):ModList(), actor = partyActor } self.configTab = new("ConfigTab"):ConfigTab(self) self.itemsTab = new("ItemsTab"):ItemsTab(self) + self.mercenaryTab = new("MercenaryTab"):MercenaryTab(self) self.treeTab = new("TreeTab"):TreeTab(self) self.skillsTab = new("SkillsTab"):SkillsTab(self) self.calcsTab = new("CalcsTab"):CalcsTab(self) @@ -118,6 +119,7 @@ function CompareEntryClass:LoadFromXML(xmlText) -- Set up savers table self.savers = { ["Config"] = self.configTab, + ["Mercenary"] = self.mercenaryTab, ["Tree"] = self.treeTab, ["TreeView"] = self.treeTab.viewer, ["Items"] = self.itemsTab, @@ -227,6 +229,7 @@ function CompareEntryClass:GetSpec() end function CompareEntryClass:SyncCalcsSkillSelection() + if self.calcsTab:IsMercenaryActor() then return end self.calcsTab.input.skill_number = self.mainSocketGroup local mainGroup = self.skillsTab and self.skillsTab.socketGroupList[self.mainSocketGroup] @@ -269,6 +272,13 @@ function CompareEntryClass:SetActiveItemSet(id) end end +function CompareEntryClass:SetViewItemSet(id, comparisonActor) + if self.itemsTab and self.itemsTab.SetViewItemSet then + self.itemsTab:SetViewItemSet(id, comparisonActor) + self:Rebuild() + end +end + function CompareEntryClass:SetActiveSkillSet(id) if self.skillsTab and self.skillsTab.SetActiveSkillSet then self.skillsTab:SetActiveSkillSet(id) @@ -289,6 +299,11 @@ end function CompareEntryClass:RefreshSkillSelectControls(controls, mainGroup, suffix) -- Populate skill select controls if not controls or not controls.mainSocketGroup then return end + if self.calcsTab:IsMercenaryActor() then + self.calcsTab:RefreshMercenarySkillSelectControls(controls, suffix) + return + end + controls.mainSocketGroup.enabled = true controls.mainSocketGroup.selIndex = mainGroup wipeTable(controls.mainSocketGroup.list) for i, socketGroup in pairs(self.skillsTab.socketGroupList) do diff --git a/src/Classes/CompareTab.lua b/src/Classes/CompareTab.lua index bcd470eab79..55d115dcc67 100644 --- a/src/Classes/CompareTab.lua +++ b/src/Classes/CompareTab.lua @@ -15,10 +15,51 @@ local calcsHelpers = require("Classes.CompareCalcsHelpers") local buildListHelpers = require("Modules.BuildListHelpers") local itemSlotHelper = require("Modules.ItemSlotHelper") local configVisibility = require("Modules.ConfigVisibility") +local ConfigScope = require("Modules.ConfigScope") +local MercenaryTools = require("Modules.MercenaryTools") -- Node IDs below this value are normal passive tree nodes; IDs at or above are cluster jewel nodes local CLUSTER_NODE_OFFSET = 65536 +local function getComparisonItemSet(itemsTab) + if not itemsTab then return end + return itemsTab:GetVisibleItemSet() +end + +local function isMercenaryComparisonSet(itemsTab) + return itemsTab and itemsTab:ComparisonActorForItemSet() == "MERCENARY" +end + +local function getActiveItemSetSlot(itemsTab, slotName) + local itemSet = itemsTab and itemsTab:GetVisibleItemSet() + return itemSet and itemSet[slotName] +end + +local function getActiveItem(itemsTab, slotName) + local itemSlot = getActiveItemSetSlot(itemsTab, slotName) + return itemSlot and itemsTab.items and itemsTab.items[itemSlot.selItemId] +end + +local function hasActiveAbyssalSocket(itemsTab, slotName, socketIndex) + if not itemsTab then return false end + local itemSet = itemsTab:GetVisibleItemSet() + local slot = itemsTab.slots and (itemsTab.slots[slotName]) + if slot and slot.weaponSet and itemSet and slot.weaponSet ~= (itemSet.useSecondWeaponSet and 2 or 1) then + return false + end + local item = getActiveItem(itemsTab, slotName) + return item and (item.abyssalSocketCount or 0) >= socketIndex +end + +local function getComparisonItemSetOrderList(itemsTab) + if not itemsTab then return { } end + return itemsTab.itemSetOrderList +end + +local function getComparisonItemSetId(itemsTab) + return itemsTab and itemsTab.viewItemSetId +end + -- Wrap a string into lines for a given pixel width at font height 14 ("VAR"). -- Breaks BEFORE a word that would exceed the width, so rendered lines never -- overshoot into the next column. @@ -173,6 +214,7 @@ function CompareTabClass:CompareTab(primaryBuild) self.configControlList = {} -- ordered list for layout self.configNeedsRebuild = true -- trigger initial build self.configCompareId = nil -- track which compare entry controls were built for + self.configViewActor = "player" self.configToggle = false -- show all / hide ineligible toggle self.configSections = {} -- section groups from ConfigOptions self.configSectionLayout = {} -- computed section layout for drawing @@ -324,8 +366,9 @@ function CompareTabClass:InitControls() self.controls.compareItemSetLabel.shown = setsEnabled self.controls.compareItemSetSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.compareItemSetLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value) local entry = self:GetActiveCompare() - if entry and entry.itemsTab and entry.itemsTab.itemSetOrderList[index] then - entry:SetActiveItemSet(entry.itemsTab.itemSetOrderList[index]) + local itemSetOrderList = entry and getComparisonItemSetOrderList(entry.itemsTab) + if entry and itemSetOrderList and itemSetOrderList[index] then + entry:SetViewItemSet(itemSetOrderList[index], entry.itemsTab.viewComparisonActor) end end) self.controls.compareItemSetSelect.enabled = setsEnabled @@ -357,6 +400,7 @@ function CompareTabClass:InitControls() self.controls.cmpSocketGroup = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpSkillLabel, "RIGHT"}, {4, 0, 200, 20}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then return end entry:SetMainSocketGroup(index) end end) @@ -369,6 +413,11 @@ function CompareTabClass:InitControls() self.controls.cmpMainSkill = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpSocketGroup, "RIGHT"}, {4, 0, 225, 20}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + if value and value.skillId then entry.mercenaryTab.profile.mainSkillId = value.skillId end + entry.mercenaryTab:Changed() + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup] if mainSocketGroup then mainSocketGroup.mainActiveSkill = index @@ -383,6 +432,11 @@ function CompareTabClass:InitControls() self.controls.cmpSkillPart = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpMainSkill, "RIGHT"}, {4, 0, 200, 20}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillPart = index; entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillList @@ -404,6 +458,11 @@ function CompareTabClass:InitControls() self.controls.cmpStageCount = new("EditControl"):EditControl({ "LEFT", self.controls.cmpStageCountLabel, "RIGHT" }, { 4, 0, 52, 20 }, "", nil, "%D", 5, function(buf) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillStageCount = tonumber(buf); entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillList @@ -425,6 +484,11 @@ function CompareTabClass:InitControls() self.controls.cmpMineCount = new("EditControl"):EditControl({ "LEFT", self.controls.cmpMineCountLabel, "RIGHT" }, { 4, 0, 52, 20 }, "", nil, "%D", 5, function(buf) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillMineCount = tonumber(buf); entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillList @@ -468,6 +532,11 @@ function CompareTabClass:InitControls() self.controls.cmpMinionSkill = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpMinion, "RIGHT"}, {4, 0, 140, 20}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillMinionSkill = index; entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillList @@ -493,6 +562,7 @@ function CompareTabClass:InitControls() } -- Primary build calcs skill controls self.controls.primCalcsSocketGroup = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value) + if self.primaryBuild.calcsTab:IsMercenaryActor() then return end self.primaryBuild.calcsTab.input.skill_number = index self.primaryBuild.buildFlag = true end) @@ -501,6 +571,11 @@ function CompareTabClass:InitControls() self.controls.primCalcsSocketGroup.enableDroppedWidth = true self.controls.primCalcsMainSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value) + if self.primaryBuild.calcsTab:IsMercenaryActor() then + if value and value.skillId then self.primaryBuild.mercenaryTab.profile.mainSkillId = value.skillId end + self.primaryBuild.mercenaryTab:Changed() + return + end local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number] if mainSocketGroup then mainSocketGroup.mainActiveSkillCalcs = index @@ -510,6 +585,11 @@ function CompareTabClass:InitControls() self.controls.primCalcsMainSkill.shown = false self.controls.primCalcsSkillPart = new("DropDownControl"):DropDownControl(nil, {0, 0, 150, 18}, {}, function(index, value) + if self.primaryBuild.calcsTab:IsMercenaryActor() then + local skill = self.primaryBuild.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillPart = index; self.primaryBuild.mercenaryTab:Changed() end + return + end local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -523,6 +603,11 @@ function CompareTabClass:InitControls() self.controls.primCalcsSkillPart.shown = false self.controls.primCalcsStageCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf) + if self.primaryBuild.calcsTab:IsMercenaryActor() then + local skill = self.primaryBuild.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillStageCount = tonumber(buf); self.primaryBuild.mercenaryTab:Changed() end + return + end local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -536,6 +621,11 @@ function CompareTabClass:InitControls() self.controls.primCalcsStageCount.shown = false self.controls.primCalcsMineCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf) + if self.primaryBuild.calcsTab:IsMercenaryActor() then + local skill = self.primaryBuild.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillMineCount = tonumber(buf); self.primaryBuild.mercenaryTab:Changed() end + return + end local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -548,10 +638,10 @@ function CompareTabClass:InitControls() end) self.controls.primCalcsMineCount.shown = false - self.controls.primCalcsShowMinion = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state) - self.primaryBuild.calcsTab.input.showMinion = state + self.controls.primCalcsShowMinion = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value) + self.primaryBuild.calcsTab:SetCalculationActor(value.actorId) self.primaryBuild.buildFlag = true - end, "Show stats for the minion instead of the player.") + end) self.controls.primCalcsShowMinion.shown = false self.controls.primCalcsMinion = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value) @@ -575,6 +665,11 @@ function CompareTabClass:InitControls() self.controls.primCalcsMinion.shown = false self.controls.primCalcsMinionSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value) + if self.primaryBuild.calcsTab:IsMercenaryActor() then + local skill = self.primaryBuild.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillMinionSkillCalcs = index; self.primaryBuild.mercenaryTab:Changed() end + return + end local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -597,6 +692,7 @@ function CompareTabClass:InitControls() self.controls.cmpCalcsSocketGroup = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then return end entry.calcsTab.input.skill_number = index entry.buildFlag = true end @@ -608,6 +704,11 @@ function CompareTabClass:InitControls() self.controls.cmpCalcsMainSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + if value and value.skillId then entry.mercenaryTab.profile.mainSkillId = value.skillId end + entry.mercenaryTab:Changed() + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number] if mainSocketGroup then mainSocketGroup.mainActiveSkillCalcs = index @@ -620,6 +721,11 @@ function CompareTabClass:InitControls() self.controls.cmpCalcsSkillPart = new("DropDownControl"):DropDownControl(nil, {0, 0, 150, 18}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillPart = index; entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -636,6 +742,11 @@ function CompareTabClass:InitControls() self.controls.cmpCalcsStageCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillStageCount = tonumber(buf); entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -652,6 +763,11 @@ function CompareTabClass:InitControls() self.controls.cmpCalcsMineCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillMineCount = tonumber(buf); entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -665,13 +781,13 @@ function CompareTabClass:InitControls() end) self.controls.cmpCalcsMineCount.shown = false - self.controls.cmpCalcsShowMinion = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state) + self.controls.cmpCalcsShowMinion = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then - entry.calcsTab.input.showMinion = state + entry.calcsTab:SetCalculationActor(value.actorId) entry.buildFlag = true end - end, "Show stats for the minion instead of the player.") + end) self.controls.cmpCalcsShowMinion.shown = false self.controls.cmpCalcsMinion = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value) @@ -700,6 +816,11 @@ function CompareTabClass:InitControls() self.controls.cmpCalcsMinionSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value) local entry = self:GetActiveCompare() if entry then + if entry.calcsTab:IsMercenaryActor() then + local skill = entry.calcsTab:GetMercenaryCalcsSkill() + if skill then skill.skillMinionSkillCalcs = index; entry.mercenaryTab:Changed() end + return + end local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number] if mainSocketGroup then local displaySkillList = mainSocketGroup.displaySkillListCalcs @@ -784,9 +905,11 @@ function CompareTabClass:InitControls() self.controls.primaryItemSetLabel = new("LabelControl"):LabelControl(nil, {0, 0, 0, 16}, "^7Item set:") self.controls.primaryItemSetLabel.shown = itemsShown self.controls.primaryItemSetSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 216, 20}, {}, function(index, value) - if self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.itemSetOrderList[index] then - self.primaryBuild.itemsTab:SetActiveItemSet(self.primaryBuild.itemsTab.itemSetOrderList[index]) - self.primaryBuild.itemsTab:AddUndoState() + local itemSetOrderList = getComparisonItemSetOrderList(self.primaryBuild.itemsTab) + if itemSetOrderList and itemSetOrderList[index] then + local itemsTab = self.primaryBuild.itemsTab + itemsTab:SetViewItemSet(itemSetOrderList[index], itemsTab.viewComparisonActor) + itemsTab:AddUndoState() end end) self.controls.primaryItemSetSelect.enabled = itemsShown @@ -797,8 +920,9 @@ function CompareTabClass:InitControls() self.controls.compareItemSetLabel2.shown = itemsShown self.controls.compareItemSetSelect2 = new("DropDownControl"):DropDownControl(nil, {0, 0, 216, 20}, {}, function(index, value) local entry = self:GetActiveCompare() - if entry and entry.itemsTab and entry.itemsTab.itemSetOrderList[index] then - entry:SetActiveItemSet(entry.itemsTab.itemSetOrderList[index]) + local itemSetOrderList = entry and getComparisonItemSetOrderList(entry.itemsTab) + if entry and itemSetOrderList and itemSetOrderList[index] then + entry:SetViewItemSet(itemSetOrderList[index], entry.itemsTab.viewComparisonActor) end end) self.controls.compareItemSetSelect2.enabled = itemsShown @@ -963,6 +1087,16 @@ function CompareTabClass:InitControls() return #self.primaryBuild.configTab.configSetOrderList > 1 end + self.controls.configActorLabel = new("LabelControl"):LabelControl(nil, {0, 0, 0, 16}, "^7Actor:") + self.controls.configActorLabel.shown = configShown + self.controls.configActorSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 20}, MercenaryTools.configActorList(self.primaryBuild), function(_, value) + if value then + self.configViewActor = value.id + end + end) + self.controls.configActorSelect.shown = configShown + self.controls.configActorSelect.enableDroppedWidth = true + -- ============================================================ -- Compare Power Report controls (Summary view) -- ============================================================ @@ -1089,6 +1223,10 @@ function CompareTabClass:PopulateSetDropdown(tab, orderListField, setsField, act local orderList = tab[orderListField] local sets = tab[setsField] local activeId = tab[activeIdField] + if orderListField == "itemSetOrderList" then + orderList = getComparisonItemSetOrderList(tab) + activeId = getComparisonItemSetId(tab) + end if orderList then for index, setId in ipairs(orderList) do local set = sets[setId] @@ -1130,12 +1268,12 @@ function CompareTabClass:NormalizeConfigVals(varData, pVal, cVal) end -- Create a single config control for a given varData, writing to the specified input/configTab/build -local function makeConfigControl(varData, inputTable, configTab, buildObj, sourceControl) +local function makeConfigControl(varData, getInput, configTab, buildObj, sourceControl, getViewActor) local control - local pVal = inputTable[varData.var] + local pVal = getInput()[varData.var] if varData.type == "check" then control = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state) - inputTable[varData.var] = state + getInput()[varData.var] = state configTab:UpdateControls() configTab:BuildModList() buildObj.buildFlag = true @@ -1148,7 +1286,7 @@ local function makeConfigControl(varData, inputTable, configTab, buildObj, sourc control = new("EditControl"):EditControl(nil, {0, 0, 90, 18}, tostring(pVal or ""), nil, filter, 7, function(buf) - inputTable[varData.var] = tonumber(buf) + getInput()[varData.var] = tonumber(buf) configTab:UpdateControls() configTab:BuildModList() buildObj.buildFlag = true @@ -1156,7 +1294,7 @@ local function makeConfigControl(varData, inputTable, configTab, buildObj, sourc elseif varData.type == "list" and varData.list then control = new("DropDownControl"):DropDownControl(nil, {0, 0, 150, 18}, varData.list, function(index, value) - inputTable[varData.var] = value.val + getInput()[varData.var] = value.val configTab:UpdateControls() configTab:BuildModList() buildObj.buildFlag = true @@ -1165,11 +1303,24 @@ local function makeConfigControl(varData, inputTable, configTab, buildObj, sourc end if control then control.shown = function() return false end - -- Reuse tooltip behavior from the source ConfigTab control so compare view - -- matches normal Config tab hover help (including dynamic tooltip funcs). + -- Copy help text only. The source ConfigTab tooltipFunc closes over that + -- tab's viewActor, so Compare must wrap comparison against getViewActor(). + -- Invoke varData.tooltipFunc (bandit, pantheon, boss skills) rather than + -- the source control's wrapped closure. if sourceControl then control.tooltipText = sourceControl.tooltipText - control.tooltipFunc = sourceControl.tooltipFunc + end + control.tooltipFunc = function(tooltip, mode, index, value) + tooltip:Clear() + if varData.tooltipFunc then + varData.tooltipFunc(tooltip, mode, index, value) + else + local tooltipText = control:GetProperty("tooltipText") + if tooltipText and tooltipText ~= '' then + tooltip:AddLine(14, tooltipText) + end + end + configTab:AddOptionStatComparison(tooltip, varData, value, getViewActor(), true) end end return control @@ -1189,9 +1340,12 @@ function CompareTabClass:RebuildConfigControls(compareEntry) if not compareEntry then return end local configOptions = self.configOptions - local pInput = self.primaryBuild.configTab.input or {} - local cInput = compareEntry.configTab.input or {} local primaryBuild = self.primaryBuild + local function getInput(configTab, var) + return function() + return self:ConfigInputTable(configTab, var) + end + end local currentSection = nil for _, varData in ipairs(configOptions) do @@ -1206,8 +1360,8 @@ function CompareTabClass:RebuildConfigControls(compareEntry) elseif currentSection and varData.var and varData.type ~= "text" then local pSource = self.primaryBuild.configTab.varControls and self.primaryBuild.configTab.varControls[varData.var] local cSource = compareEntry.configTab.varControls and compareEntry.configTab.varControls[varData.var] - local pCtrl = makeConfigControl(varData, pInput, self.primaryBuild.configTab, primaryBuild, pSource) - local cCtrl = makeConfigControl(varData, cInput, compareEntry.configTab, compareEntry, cSource) + local pCtrl = makeConfigControl(varData, getInput(self.primaryBuild.configTab, varData.var), self.primaryBuild.configTab, primaryBuild, pSource, function() return self:ConfigViewActor() end) + local cCtrl = makeConfigControl(varData, getInput(compareEntry.configTab, varData.var), compareEntry.configTab, compareEntry, cSource, function() return self:ConfigViewActor() end) if pCtrl and cCtrl then self.controls["cfg_p_" .. varData.var] = pCtrl @@ -1231,16 +1385,35 @@ end function CompareTabClass:CopyCompareConfig() local compareEntry = self:GetActiveCompare() if not compareEntry then return end - local cInput = compareEntry.configTab.input - for k, v in pairs(cInput) do - self.primaryBuild.configTab.input[k] = v - end - self.primaryBuild.configTab:UpdateControls() - self.primaryBuild.configTab:BuildModList() + local srcTab = compareEntry.configTab + local dstTab = self.primaryBuild.configTab + local srcSet = srcTab.configSets[srcTab.activeConfigSetId] + local dstSet = dstTab.configSets[dstTab.activeConfigSetId] + srcTab:EnsureActorConfig(srcSet) + dstTab:EnsureActorConfig(dstSet) + for k, v in pairs(srcTab.input) do + dstTab.input[k] = v + end + for k, v in pairs(srcSet.actors.mercenary.input) do + dstSet.actors.mercenary.input[k] = v + end + dstTab:UpdateControls() + dstTab:BuildModList() self.primaryBuild.buildFlag = true self.configNeedsRebuild = true end +function CompareTabClass:ConfigViewActor() + if self.configViewActor == "mercenary" and MercenaryTools.tabVisible(self.primaryBuild) then + return "mercenary" + end + return "player" +end + +function CompareTabClass:ConfigInputTable(configTab, var) + return select(1, configTab:GetVarTablesForActor(var, self:ConfigViewActor())) +end + -- Import a comparison build from XML text function CompareTabClass:ImportBuild(xmlText, label) local entry = new("CompareEntry"):CompareEntry(xmlText, label) @@ -1375,6 +1548,9 @@ end -- Build a list of jewel comparison entries between the primary and compare builds. -- Returns a sorted list of { label, nodeId, pItem, cItem, pSlotName, cSlotName } records. function CompareTabClass:GetJewelComparisonSlots(compareEntry) + if isMercenaryComparisonSet(self.primaryBuild.itemsTab) or isMercenaryComparisonSet(compareEntry.itemsTab) then + return { } + end local pSpec = self.primaryBuild.spec local cSpec = compareEntry.spec if not pSpec or not cSpec then return {} end @@ -1442,19 +1618,19 @@ end -- Copy a compared build's item into the primary build function CompareTabClass:CopyCompareItemToPrimary(slotName, compareEntry, andUse) - local cSlot = compareEntry.itemsTab and compareEntry.itemsTab.slots and compareEntry.itemsTab.slots[slotName] - local cItem = cSlot and compareEntry.itemsTab.items and compareEntry.itemsTab.items[cSlot.selItemId] + local cItem = getActiveItem(compareEntry.itemsTab, slotName) if not cItem or not cItem.raw then return end local newItem = new("Item"):Item(cItem.raw) newItem:NormaliseQuality() local pItemsTab = self.primaryBuild.itemsTab + local primaryItemSet = getComparisonItemSet(pItemsTab) pItemsTab:AddItem(newItem, true) -- true = noAutoEquip if andUse then local pSlot = pItemsTab.slots[slotName] if pSlot then - pSlot:SetSelItemId(newItem.id) + pSlot:SetSelItemId(newItem.id, primaryItemSet) end end @@ -2055,12 +2231,10 @@ function CompareTabClass:LayoutConfigView(contentVP, compareEntry) end -- Sync control values with current input (in case changed from normal Config tab or externally) - local pInput = self.primaryBuild.configTab.input or {} - local cInput = compareEntry.configTab.input or {} for var, ctrlInfo in pairs(self.configControls) do local varData = ctrlInfo.varData - syncControlValue(ctrlInfo.primaryControl, varData, pInput[var]) - syncControlValue(ctrlInfo.compareControl, varData, cInput[var]) + syncControlValue(ctrlInfo.primaryControl, varData, self:ConfigInputTable(self.primaryBuild.configTab, var)[var]) + syncControlValue(ctrlInfo.compareControl, varData, self:ConfigInputTable(compareEntry.configTab, var)[var]) end -- Position header controls @@ -2069,7 +2243,10 @@ function CompareTabClass:LayoutConfigView(contentVP, compareEntry) local configHeaderLeftX = contentVP.x + 10 local configSetSelectX = contentVP.x + 80 local configSetSelectW = 225 - local inputEndX = configSetSelectX + configSetSelectW + local actorLabelX = configSetSelectX + configSetSelectW + 12 + local actorSelectX = actorLabelX + 46 + local actorSelectW = 140 + local inputEndX = actorSelectX + actorSelectW local actionX = inputEndX + 10 self.controls.copyConfigBtn.x = actionX @@ -2098,6 +2275,14 @@ function CompareTabClass:LayoutConfigView(contentVP, compareEntry) self.controls.configPrimarySetSelect.width = configSetSelectW self.controls.configPrimarySetSelect.y = row1Y + self.controls.configActorSelect:SetList(MercenaryTools.configActorList(self.primaryBuild)) + self.controls.configActorSelect:SelByValue(self:ConfigViewActor(), "id") + self.controls.configActorLabel.x = actorLabelX + self.controls.configActorLabel.y = row1Y + 2 + self.controls.configActorSelect.x = actorSelectX + self.controls.configActorSelect.width = actorSelectW + self.controls.configActorSelect.y = row1Y + -- Build section layout: multi-column grid, mirroring regular ConfigTab local rowHeight = LAYOUT.configRowHeight local sectionInnerPad = LAYOUT.configSectionInnerPad @@ -2123,21 +2308,23 @@ function CompareTabClass:LayoutConfigView(contentVP, compareEntry) end -- First pass: compute rows and height for each section + local viewActor = self:ConfigViewActor() local visibleSections = {} for _, section in ipairs(self.configSections) do local diffs = {} local commons = {} for _, ctrlInfo in ipairs(section.items) do - if searchMatch(ctrlInfo.varData) then + if searchMatch(ctrlInfo.varData) and not (ConfigScope.forVarData(ctrlInfo.varData) == "player" and viewActor == "mercenary") then local pVal, cVal = self:NormalizeConfigVals(ctrlInfo.varData, - pInput[ctrlInfo.varData.var], cInput[ctrlInfo.varData.var]) + self:ConfigInputTable(self.primaryBuild.configTab, ctrlInfo.varData.var)[ctrlInfo.varData.var], + self:ConfigInputTable(compareEntry.configTab, ctrlInfo.varData.var)[ctrlInfo.varData.var]) local isDiff = tostring(pVal) ~= tostring(cVal) if isDiff then t_insert(diffs, ctrlInfo) else local varData = ctrlInfo.varData - local relevant = configVisibility.isRelevantForBuild(varData, self.primaryBuild) - or configVisibility.isRelevantForBuild(varData, compareEntry) + local relevant = configVisibility.isRelevantForBuild(varData, self.primaryBuild, viewActor) + or configVisibility.isRelevantForBuild(varData, compareEntry, viewActor) if relevant or (self.configToggle and not configVisibility.isShowAllExcluded(varData)) then t_insert(commons, ctrlInfo) end @@ -2260,6 +2447,7 @@ end -- Refresh calcs skill detail controls for both builds. function CompareTabClass:RefreshCalcsSkillControls(compareEntry) + MercenaryTools.applyHiddenState(compareEntry) -- Build control maps for RefreshSkillSelectControls local primControls = { mainSocketGroup = self.controls.primCalcsSocketGroup, @@ -2271,12 +2459,17 @@ function CompareTabClass:RefreshCalcsSkillControls(compareEntry) mainSkillMinionLibrary = { shown = false }, mainSkillMinionSkill = self.controls.primCalcsMinionSkill, } - self.primaryBuild:RefreshSkillSelectControls(primControls, self.primaryBuild.calcsTab.input.skill_number, "Calcs") + if self.primaryBuild.calcsTab:IsMercenaryActor() then + self.primaryBuild.calcsTab:RefreshMercenarySkillSelectControls(primControls, "Calcs") + else + self.primaryBuild:RefreshSkillSelectControls(primControls, self.primaryBuild.calcsTab.input.skill_number, "Calcs") + end self.controls.primCalcsSocketGroup.shown = true self.controls.primCalcsMode.shown = true self.controls.primCalcsMode:SelByValue(self.primaryBuild.calcsTab.input.misc_buffMode, "buffMode") - self.controls.primCalcsShowMinion.shown = self.controls.primCalcsMinion.shown == true - self.controls.primCalcsShowMinion.state = self.primaryBuild.calcsTab.input.showMinion and true or false + self.controls.primCalcsShowMinion.shown = true + self.controls.primCalcsShowMinion:SetList(MercenaryTools.filterCalculationActors(calcLib.calculationActorList, self.primaryBuild)) + self.controls.primCalcsShowMinion:SelByValue(self.primaryBuild.calcsTab.input.actor, "actorId") local cmpControls = { mainSocketGroup = self.controls.cmpCalcsSocketGroup, @@ -2288,12 +2481,17 @@ function CompareTabClass:RefreshCalcsSkillControls(compareEntry) mainSkillMinionLibrary = { shown = false }, mainSkillMinionSkill = self.controls.cmpCalcsMinionSkill, } - compareEntry:RefreshSkillSelectControls(cmpControls, compareEntry.calcsTab.input.skill_number, "Calcs") + if compareEntry.calcsTab:IsMercenaryActor() then + compareEntry.calcsTab:RefreshMercenarySkillSelectControls(cmpControls, "Calcs") + else + compareEntry:RefreshSkillSelectControls(cmpControls, compareEntry.calcsTab.input.skill_number, "Calcs") + end self.controls.cmpCalcsSocketGroup.shown = true self.controls.cmpCalcsMode.shown = true self.controls.cmpCalcsMode:SelByValue(compareEntry.calcsTab.input.misc_buffMode, "buffMode") - self.controls.cmpCalcsShowMinion.shown = self.controls.cmpCalcsMinion.shown == true - self.controls.cmpCalcsShowMinion.state = compareEntry.calcsTab.input.showMinion and true or false + self.controls.cmpCalcsShowMinion.shown = true + self.controls.cmpCalcsShowMinion:SetList(MercenaryTools.filterCalculationActors(calcLib.calculationActorList, compareEntry)) + self.controls.cmpCalcsShowMinion:SelByValue(compareEntry.calcsTab.input.actor, "actorId") -- Wrap .shown booleans set by RefreshSkillSelectControls with a view-mode gate, -- so controls auto-hide when not in CALCS mode (matching configShown pattern) @@ -2518,7 +2716,11 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories local useFullDPS = powerStat.stat == "FullDPS" -- Get calculator for primary build - local calcFunc, calcBase = self.calcs.getMiscCalculator(self.primaryBuild) + local calcFunc, calcBase, actorOutputs = self.calcs.getMiscCalculator(self.primaryBuild) + local itemCalcBase = calcBase + if isMercenaryComparisonSet(self.primaryBuild.itemsTab) and MercenaryTools.mercenaryOutputAvailable(actorOutputs and actorOutputs.MERCENARY) then + itemCalcBase = actorOutputs.MERCENARY + end -- Find display stat for formatting local displayStat = nil @@ -2559,8 +2761,7 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories self:AddAbyssSockets(compareEntry, baseSlots, true) for _, slotName in ipairs(baseSlots) do - local cSlot = compareEntry.itemsTab and compareEntry.itemsTab.slots[slotName] - local cItem = cSlot and compareEntry.itemsTab.items[cSlot.selItemId] + local cItem = getActiveItem(compareEntry.itemsTab, slotName) if cItem then total = total + 1 end @@ -2715,6 +2916,7 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories -- Items -- ========================================== if categories.items then + local primaryItemSet = getComparisonItemSet(self.primaryBuild.itemsTab) local baseSlots = { "Weapon 1", "Weapon 2", "Helmet", "Body Armour", "Gloves", "Boots", "Amulet", "Ring 1", "Ring 2", "Belt", "Flask 1", "Flask 2", "Flask 3", "Flask 4", "Flask 5" } if self:ShouldShowRing3(compareEntry) then t_insert(baseSlots, 10, "Ring 3") @@ -2724,10 +2926,8 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories self:AddAbyssSockets(compareEntry, baseSlots, true) for _, slotName in ipairs(baseSlots) do - local cSlot = compareEntry.itemsTab and compareEntry.itemsTab.slots[slotName] - local cItem = cSlot and compareEntry.itemsTab.items[cSlot.selItemId] - local pSlot = self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.slots[slotName] - local pItem = pSlot and self.primaryBuild.itemsTab.items[pSlot.selItemId] + local cItem = getActiveItem(compareEntry.itemsTab, slotName) + local pItem = getActiveItem(self.primaryBuild.itemsTab, slotName) if cItem and cItem.raw and not (pItem and pItem.name == cItem.name) then local newItem = new("Item"):Item(cItem.raw) newItem:NormaliseQuality() @@ -2740,12 +2940,13 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories if newItem.abyssalSocketCount > 0 then for idx = 1, newItem.abyssalSocketCount do local abyssSlotName = string.format("%s Abyssal Socket %d", slotName, idx) - local cmpJewelSlot = compareEntry.itemsTab.slots[abyssSlotName] + local cmpJewelSlot = getActiveItemSetSlot(compareEntry.itemsTab, abyssSlotName) -- save old id and unequip existing - local primaryJewelSlot = self.primaryBuild.itemsTab.slots[abyssSlotName] - oldEquipped[abyssSlotName] = primaryJewelSlot.selItemId - primaryJewelSlot:SetSelItemId(0) - if cmpJewelSlot.selItemId > 0 then + local primaryJewelSlot = getActiveItemSetSlot(self.primaryBuild.itemsTab, abyssSlotName) + oldEquipped[abyssSlotName] = primaryJewelSlot and primaryJewelSlot.selItemId or 0 + local primarySlot = self.primaryBuild.itemsTab.slots[abyssSlotName] + if primarySlot then primarySlot:SetSelItemId(0, primaryItemSet) end + if cmpJewelSlot and cmpJewelSlot.selItemId > 0 then local cmpJewel = compareEntry.itemsTab.items[cmpJewelSlot.selItemId] -- due to a previous bug where jewel slots didn't -- get cleared when becoming inactive, so the item @@ -2757,21 +2958,22 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories self.primaryBuild.itemsTab:AddItem(itemCopy, false) -- equip copied - self.primaryBuild.itemsTab.slots[abyssSlotName]:SetSelItemId(itemCopy.id) + if primarySlot then primarySlot:SetSelItemId(itemCopy.id, primaryItemSet) end end end end end - local output = calcFunc({ repSlotName = slotName, repItem = newItem }, useFullDPS) - local impact = self.primaryBuild.calcsTab:CalculatePowerStat(powerStat, output, calcBase) + local output = calcFunc(self.primaryBuild.itemsTab:ItemCalculationOverride(slotName, newItem), useFullDPS) + local impact = self.primaryBuild.calcsTab:CalculatePowerStat(powerStat, output, itemCalcBase) local impactStr, impactVal, combinedImpactStr, impactPercent, impactIsZero = formatImpact(impact) -- restore abyss jewel state if newItem.abyssalSocketCount > 0 then for k, v in pairs(oldEquipped) do - self.primaryBuild.itemsTab.slots[k]:SetSelItemId(v) + local primarySlot = self.primaryBuild.itemsTab.slots[k] + if primarySlot then primarySlot:SetSelItemId(v, primaryItemSet) end end for _, item in ipairs(cmpJewels) do self.primaryBuild.itemsTab:DeleteItem(item) @@ -2845,14 +3047,14 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories if jEntry.pNodeAllocated then -- Socket is allocated in primary build, test directly in that socket - local output = calcFunc({ repSlotName = jEntry.cSlotName, repItem = newItem }, useFullDPS) + local output = calcFunc(self.primaryBuild.itemsTab:ItemCalculationOverride(jEntry.cSlotName, newItem), useFullDPS) bestImpactVal = self.primaryBuild.calcsTab:CalculatePowerStat(powerStat, output, calcBase) else -- Socket is NOT allocated in primary build; try the jewel in every -- jewel socket on the primary build's tree, temporarily allocating -- unallocated sockets via addNodes so CalcSetup doesn't skip them for _, socketInfo in ipairs(primaryJewelSockets) do - local override = { repSlotName = socketInfo.slotName, repItem = newItem } + local override = self.primaryBuild.itemsTab:ItemCalculationOverride(socketInfo.slotName, newItem) if not socketInfo.allocated then override.addNodes = { [socketInfo.node] = true } end @@ -3682,8 +3884,8 @@ function CompareTabClass:AddAbyssSockets(comparison, destTable, requireBothSides for _, slot in ipairs(equipmentSlots) do for number = 1, 6 do local abyssalSocketName = string.format("%s Abyssal Socket %d", slot, number) - local mainHas = self.primaryBuild.itemsTab.slots[abyssalSocketName].shown() - local comparisonHas = comparison.itemsTab.slots[abyssalSocketName].shown() + local mainHas = hasActiveAbyssalSocket(self.primaryBuild.itemsTab, slot, number) + local comparisonHas = hasActiveAbyssalSocket(comparison.itemsTab, slot, number) if (requireBothSides and mainHas and comparisonHas) or ((not requireBothSides) and (mainHas or comparisonHas)) then table.insert(destTable, abyssalSocketName) @@ -3725,11 +3927,8 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents) if self.itemsExpandedMode then -- Expanded mode: measure the widest rendered line of every primary item card local widest = 0 - local pItems = self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.items - local pSlots = self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.slots for _, slotName in ipairs(baseSlots) do - local pSlot = pSlots and pSlots[slotName] - local pItem = pSlot and pItems and pItems[pSlot.selItemId] + local pItem = getActiveItem(self.primaryBuild.itemsTab, slotName) if pItem then local w = self:DrawItemExpanded(pItem, 0, 0, 0, nil, true) or 0 if w > widest then widest = w end @@ -3748,10 +3947,6 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents) else -- Compact mode local maxDiffW = 0 - local pItems = self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.items - local pSlots = self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.slots - local cItems = compareEntry.itemsTab and compareEntry.itemsTab.items - local cSlots = compareEntry.itemsTab and compareEntry.itemsTab.slots local function measureDiff(pItem, cItem) local lbl = tradeHelpers.getSlotDiffLabel(pItem, cItem) if lbl and lbl ~= "" then @@ -3760,10 +3955,8 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents) end end for _, slotName in ipairs(baseSlots) do - local pSlot = pSlots and pSlots[slotName] - local cSlot = cSlots and cSlots[slotName] - local pItem = pSlot and pItems and pItems[pSlot.selItemId] - local cItem = cSlot and cItems and cItems[cSlot.selItemId] + local pItem = getActiveItem(self.primaryBuild.itemsTab, slotName) + local cItem = getActiveItem(compareEntry.itemsTab, slotName) measureDiff(pItem, cItem) end for _, jE in ipairs(jewelSlots) do @@ -3914,10 +4107,8 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents) for _, slotName in ipairs(baseSlots) do -- Get items from both builds - local pSlot = self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.slots and self.primaryBuild.itemsTab.slots[slotName] - local cSlot = compareEntry.itemsTab and compareEntry.itemsTab.slots and compareEntry.itemsTab.slots[slotName] - local pItem = pSlot and self.primaryBuild.itemsTab.items and self.primaryBuild.itemsTab.items[pSlot.selItemId] - local cItem = cSlot and compareEntry.itemsTab and compareEntry.itemsTab.items and compareEntry.itemsTab.items[cSlot.selItemId] + local pItem = getActiveItem(self.primaryBuild.itemsTab, slotName) + local cItem = getActiveItem(compareEntry.itemsTab, slotName) local slotMissing = slotName == "Ring 3" and not primaryHasRing3 drawSlotEntry(slotName, pItem, cItem, slotName, slotName, maxLabelW, nil, nil, slotMissing) @@ -3995,18 +4186,19 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents) if not main.popups[1] and hoverEquipItem and hoverEquipSlotName and not hoverItem then self.itemTooltip:Clear() self.itemTooltip.maxWidth = maxTooltipWidth - local calcFunc, calcBase = self.calcs.getMiscCalculator(self.primaryBuild) + local calcFunc, calcBase, actorOutputs = self.calcs.getMiscCalculator(self.primaryBuild) if calcFunc then -- Create a fresh item to evaluate local newItem = new("Item"):Item(hoverEquipItem.raw) newItem:NormaliseQuality() -- Determine what's currently in the target slot - local pSlot = self.primaryBuild.itemsTab.slots[hoverEquipSlotName] - local selItem = pSlot and self.primaryBuild.itemsTab.items[pSlot.selItemId] + local itemsTab = self.primaryBuild.itemsTab + local pSlot = itemsTab.slots[hoverEquipSlotName] + local selItem = getActiveItem(itemsTab, hoverEquipSlotName) -- For jewel sockets that aren't allocated, temporarily allocate the node - local override = { repSlotName = hoverEquipSlotName, repItem = newItem } + local override = itemsTab:ItemCalculationOverride(hoverEquipSlotName, newItem) if pSlot and pSlot.nodeId then local pSpec = self.primaryBuild.spec if pSpec and pSpec.allocNodes and not pSpec.allocNodes[pSlot.nodeId] then @@ -4025,7 +4217,11 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents) else header = string.format("^7Equipping this item in %s will give you:", slotLabel) end - local count = self.primaryBuild:AddStatComparesToTooltip(self.itemTooltip, calcBase, output, header) + local compareBase = calcBase + if isMercenaryComparisonSet(itemsTab) and MercenaryTools.mercenaryOutputAvailable(actorOutputs and actorOutputs.MERCENARY) then + compareBase = actorOutputs.MERCENARY + end + local count = self.primaryBuild:AddStatComparesToTooltip(self.itemTooltip, compareBase, output, header) if count == 0 then self.itemTooltip:AddLine(14, header) self.itemTooltip:AddLine(14, "^7No changes.") @@ -4557,8 +4753,8 @@ function CompareTabClass:DrawCalcsSkillHeader(vp, compareEntry, headerHeight, pr if drawLabel("Mines", rightX, rightY, self.controls.cmpCalcsMineCount) then rightY = rightY + rowH end -- Show Minion Stats - if drawLabel("Show Minion Stats", leftX, leftY, self.controls.primCalcsShowMinion) then leftY = leftY + rowH end - if drawLabel("Show Minion Stats", rightX, rightY, self.controls.cmpCalcsShowMinion) then rightY = rightY + rowH end + if drawLabel("Calculation Actor", leftX, leftY, self.controls.primCalcsShowMinion) then leftY = leftY + rowH end + if drawLabel("Calculation Actor", rightX, rightY, self.controls.cmpCalcsShowMinion) then rightY = rightY + rowH end -- Minion if drawLabel("Minion", leftX, leftY, self.controls.primCalcsMinion) then leftY = leftY + rowH end @@ -4686,8 +4882,8 @@ function CompareTabClass:DrawCalcs(vp, compareEntry) local primaryEnv = self.primaryBuild.calcsTab.calcsEnv local compareEnv = compareEntry.calcsTab and compareEntry.calcsTab.calcsEnv if not primaryEnv or not compareEnv then return end - local primaryActor = (self.primaryBuild.calcsTab.input.showMinion and primaryEnv.minion) or primaryEnv.player - local compareActor = (compareEntry.calcsTab.input.showMinion and compareEnv.minion) or compareEnv.player + local primaryActor = self.primaryBuild.calcsTab:GetDisplayActor(primaryEnv) + local compareActor = compareEntry.calcsTab:GetDisplayActor(compareEnv) if not primaryActor or not compareActor then return end -- Skill detail header height diff --git a/src/Classes/ConfigSetListControl.lua b/src/Classes/ConfigSetListControl.lua index f9440970822..8fef2cac3a2 100644 --- a/src/Classes/ConfigSetListControl.lua +++ b/src/Classes/ConfigSetListControl.lua @@ -15,6 +15,7 @@ function ConfigSetListClass:ConfigSetListControl(anchor, rect, configTab) self.configTab = configTab self.controls.copy = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function() local configSet = configTab.configSets[self.selValue] + -- copyTable keeps mercenarySetId so a duplicated Config still binds the same hire. local newConfigSet = copyTable(configSet) newConfigSet.id = 1 while configTab.configSets[newConfigSet.id] do diff --git a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua index 3d1f007cd63..64bbc24122d 100644 --- a/src/Classes/ConfigTab.lua +++ b/src/Classes/ConfigTab.lua @@ -12,6 +12,9 @@ local s_upper = string.upper local varList = require("Modules.ConfigOptions") local configVisibility = require("Modules.ConfigVisibility") local configModBrowser = require("Modules.ConfigModBrowser") +local ConfigScope = require("Modules.ConfigScope") +local MercenaryTools = require("Modules.MercenaryTools") +ConfigScope.index(varList) ---@class CustomModBlockControl: ControlHost, Control local CustomModBlockClass = newClass("CustomModBlockControl", "ControlHost", "Control") @@ -30,7 +33,7 @@ function CustomModBlockClass:CustomModBlockControl(anchor, rect, configTab, bloc self.blockData = blockData self.controls.deleteBtn = new("ButtonControl"):ButtonControl({"TOPLEFT", self, "TOPLEFT"}, {0, 0, 20, 18}, "^1X", function() - local customModsList = configTab.configSets[configTab.activeConfigSetId].customModsList + local customModsList = configTab:GetActorCustomModsList() table.remove(customModsList, blockIndex) if #customModsList == 0 then table.insert(customModsList, { title = "Default", enabled = true, text = "" }) @@ -62,15 +65,15 @@ function CustomModBlockClass:CustomModBlockControl(anchor, rect, configTab, bloc self.controls.enableCheck.tooltipFunc = function(tooltip) if tooltip:CheckForUpdate(configTab.build.outputRevision, blockData) then if configTab.build.calcsTab then - local calcFunc, calcBase = configTab.build.calcsTab:GetMiscCalculator(configTab.build) + local calcFunc, calcBase, actor = configTab:GetComparisonCalculator() if calcFunc then local curState = blockData.enabled ~= false blockData.enabled = not curState configTab:BuildModList() - local output = calcFunc() + local output = configTab:RunComparisonCalc(calcFunc, actor) blockData.enabled = curState configTab:BuildModList() - configTab.build:AddStatComparesToTooltip(tooltip, calcBase, output, curState and "^7Disabling this group will give you:" or "^7Enabling this group will give you:") + configTab.build:AddStatComparesToTooltip(tooltip, calcBase, output, curState and "^7Disabling this group will give you:" or "^7Enabling this group will give you:", nil, actor) end end end @@ -160,6 +163,7 @@ function ConfigTabClass:ConfigTab(build) -- A calculator base output matching the calcFunc which is updated by the build when it is rebuilt ---@type table self.calcBase = nil + self.calcActorOutputs = nil self.controls.sectionAnchor = new("LabelControl"):LabelControl({ "TOPLEFT", self, "TOPLEFT" }, { 0, 20, 0, 0 }, "") -- Set selector @@ -176,7 +180,18 @@ function ConfigTabClass:ConfigTab(build) self:OpenConfigSetManagePopup() end) - self.controls.search = new("EditControl"):EditControl({ "TOPLEFT", self.controls.sectionAnchor, "TOPLEFT" }, { 8, 15, 360, 20 }, "", "Search", "%c", 100, function() + self.viewActor = "player" + self.controls.actorLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.sectionAnchor, "TOPLEFT" }, { 0, 14, 0, 16 }, "^7Actor:") + self.controls.actorSelect = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.actorLabel, "RIGHT" }, { 4, 0, 140, 20 }, { + { id = "player", label = "Player" }, + { id = "mercenary", label = "Mercenary" }, + }, function(_, value) + if value then + self:SetViewActor(value.id) + end + end) + + self.controls.search = new("EditControl"):EditControl({ "TOPLEFT", self.controls.sectionAnchor, "TOPLEFT" }, { 8, 42, 360, 20 }, "", "Search", "%c", 100, function() self:UpdateControls() end, nil, nil, true) self.controls.toggleConfigs = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.search, "RIGHT" }, { 10, 0, 200, 20 }, function() @@ -209,23 +224,7 @@ function ConfigTabClass:ConfigTab(build) end local function implyCond(varData) - local mainEnv = self.build.calcsTab.mainEnv - if self.configSets[self.activeConfigSetId].input[varData.var] then - if varData.implyCondList then - for _, implyCond in ipairs(varData.implyCondList) do - if (implyCond and mainEnv.conditionsUsed[implyCond]) then - return true - end - end - end - if (varData.implyCond and mainEnv.conditionsUsed[varData.implyCond]) or - (varData.implyMinionCond and mainEnv.minionConditionsUsed[varData.implyMinionCond]) or - (varData.implyEnemyCond and mainEnv.enemyConditionsUsed[varData.implyEnemyCond]) then - return true - end - end - - return false + return configVisibility.implyCondActive(varData, self.build, self:GetViewActor()) end local function listOrSingleIfOption(ifOption, ifFunc) @@ -296,7 +295,7 @@ function ConfigTabClass:ConfigTab(build) local control if varData.type == "check" then control = new("CheckBoxControl"):CheckBoxControl({"TOPLEFT",lastSection,"TOPLEFT"}, {234, 0, 18}, varData.label, function(state) - self.configSets[self.activeConfigSetId].input[varData.var] = state + self:SetConfigValue(varData.var, state) self:AddUndoState() self:BuildModList() self.build.buildFlag = true @@ -304,9 +303,9 @@ function ConfigTabClass:ConfigTab(build) elseif varData.type == "count" or varData.type == "integer" or varData.type == "countAllowZero" or varData.type == "float" then control = new("EditControl"):EditControl({"TOPLEFT",lastSection,"TOPLEFT"}, {234, 0, 90, 18}, "", nil, ((varData.type == "integer" or varData.type == "countAllowZero") and "^%-%d") or (varData.type == "float" and "^%d.") or "%D", 10, function(buf, placeholder) if placeholder then - self.configSets[self.activeConfigSetId].placeholder[varData.var] = tonumber(buf) + self:SetConfigPlaceholder(varData.var, tonumber(buf)) else - self.configSets[self.activeConfigSetId].input[varData.var] = tonumber(buf) + self:SetConfigValue(varData.var, tonumber(buf)) self:AddUndoState() self:BuildModList() end @@ -314,7 +313,7 @@ function ConfigTabClass:ConfigTab(build) end) elseif varData.type == "list" then control = new("DropDownControl"):DropDownControl({"TOPLEFT",lastSection,"TOPLEFT"}, {234, 0, 118, 16}, varData.list, function(index, value) - self.configSets[self.activeConfigSetId].input[varData.var] = value.val + self:SetConfigValue(varData.var, value.val) self:AddUndoState() self:BuildModList() self.build.buildFlag = true @@ -322,9 +321,9 @@ function ConfigTabClass:ConfigTab(build) elseif varData.type == "text" and not varData.resizable then control = new("EditControl"):EditControl({"TOPLEFT",lastSection,"TOPLEFT"}, {8, 0, 344, 118}, "", nil, "^%C\t\n", nil, function(buf, placeholder) if placeholder then - self.configSets[self.activeConfigSetId].placeholder[varData.var] = tostring(buf) + self:SetConfigPlaceholder(varData.var, tostring(buf)) else - self.configSets[self.activeConfigSetId].input[varData.var] = tostring(buf) + self:SetConfigValue(varData.var, tostring(buf)) self:AddUndoState() self:BuildModList() end @@ -333,9 +332,9 @@ function ConfigTabClass:ConfigTab(build) elseif varData.type == "text" and varData.resizable then control = new("ResizableEditControl"):ResizableEditControl({"TOPLEFT",lastSection,"TOPLEFT"}, {8, 0, 344, 118, nil, nil, nil, 118 + 16 * 40}, "", nil, "^%C\t\n", nil, function(buf, placeholder) if placeholder then - self.configSets[self.activeConfigSetId].placeholder[varData.var] = tostring(buf) + self:SetConfigPlaceholder(varData.var, tostring(buf)) else - self.configSets[self.activeConfigSetId].input[varData.var] = tostring(buf) + self:SetConfigValue(varData.var, tostring(buf)) self:AddUndoState() self:BuildModList() end @@ -354,6 +353,9 @@ function ConfigTabClass:ConfigTab(build) if not searchMatch(varData) then return false end + if ConfigScope.forVarData(varData) == "player" and self:GetViewActor() == "mercenary" then + return false + end for _, shownFunc in ipairs(shownFuncs) do if not shownFunc() and not isShowAllConfig(varData) then @@ -395,7 +397,7 @@ function ConfigTabClass:ConfigTab(build) end if varData.ifOption then t_insert(shownFuncs, listOrSingleIfOption(varData.ifOption, function(ifOption) - return self.configSets[self.activeConfigSetId].input[ifOption] + return self:GetConfigValue(ifOption) end)) end if varData.ifCond then @@ -403,21 +405,13 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.conditionsUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "conditionsUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifCond, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.conditionsUsed[ifOption] - if not mods then - return out - end - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - return out + return configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "conditionsUsed", varData, self:GetViewActor(), ifOption) end)) end if varData.ifMinionCond then @@ -425,21 +419,13 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.minionConditionsUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "minionConditionsUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifMinionCond, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.minionConditionsUsed[ifOption] - if not mods then - return out - end - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - return out + return configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "minionConditionsUsed", varData, self:GetViewActor(), ifOption) end)) end if varData.ifEnemyCond then @@ -447,33 +433,26 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.enemyConditionsUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "enemyConditionsUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifEnemyCond, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.enemyConditionsUsed[ifOption] - if not mods then - return out - end - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - return out + return configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "enemyConditionsUsed", varData, self:GetViewActor(), ifOption) end)) end if varData.ifCondTrue then t_insert(shownFuncs, listOrSingleIfOption(varData.ifCondTrue, function(ifOption) - return self.build.calcsTab.mainEnv.player.modDB.conditions[ifOption] + return configVisibility.anyPrimaryActor(self.build.calcsTab.mainEnv, function(actor) + return actor.modDB.conditions[ifOption] + end, configVisibility.actorKeysForVar(varData, self:GetViewActor())) end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifCondTrue, function(ifOption) if not launch.devModeAlt then return end - local out = "Condition state: " .. ifOption .. "=" .. tostring(self.build.calcsTab.mainEnv.player.modDB.conditions[ifOption]) - return out + return configVisibility.formatCondTrue(self.build.calcsTab.mainEnv, varData, self:GetViewActor(), ifOption) end)) end if varData.ifMult then @@ -481,21 +460,13 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.multipliersUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "multipliersUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifMult, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.multipliersUsed[ifOption] - if not mods then - return out - end - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - return out + return configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "multipliersUsed", varData, self:GetViewActor(), ifOption) end)) end if varData.ifEnemyMult then @@ -503,21 +474,13 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.enemyMultipliersUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "enemyMultipliersUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifEnemyMult, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.enemyMultipliersUsed[ifOption] - if not mods then - return out - end - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - return out + return configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "enemyMultipliersUsed", varData, self:GetViewActor(), ifOption) end)) end if varData.ifStat then @@ -525,24 +488,16 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.perStatsUsed[ifOption] or self.build.calcsTab.mainEnv.enemyMultipliersUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "perStatsUsed", varData, self:GetViewActor())[ifOption] or configVisibility.usedForVar(self.build.calcsTab.mainEnv, "enemyMultipliersUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifStat, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.perStatsUsed[ifOption] - if mods then - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - end - local mods2 = self.build.calcsTab.mainEnv.enemyMultipliersUsed[ifOption] - if mods2 then - for _, mod in ipairs(mods2) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end + local out = configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "perStatsUsed", varData, self:GetViewActor(), ifOption) + local enemyMods = configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "enemyMultipliersUsed", varData, self:GetViewActor(), ifOption) + if enemyMods then + out = (out and out.."\n" or "") .. enemyMods end return out end)) @@ -552,21 +507,13 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.enemyPerStatsUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "enemyPerStatsUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifEnemyStat, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.enemyPerStatsUsed[ifOption] - if not mods then - return out - end - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - return out + return configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "enemyPerStatsUsed", varData, self:GetViewActor(), ifOption) end)) end if varData.ifTagType then @@ -593,10 +540,10 @@ function ConfigTabClass:ConfigTab(build) end if varData.ifFlag then t_insert(shownFuncs, listOrSingleIfOption(varData.ifFlag, function(ifOption) - local skillModList = self.build.calcsTab.mainEnv.player.mainSkill.skillModList - local skillFlags = self.build.calcsTab.mainEnv.player.mainSkill.skillFlags - -- Check both the skill mods for flags and flags that are set via calcPerform - return skillFlags[ifOption] or skillModList:Flag(nil, ifOption) + return configVisibility.anyMainSkill(self.build.calcsTab.mainEnv, function(mainSkill) + -- Check both the skill mods for flags and flags that are set via calcPerform + return mainSkill.skillFlags[ifOption] or mainSkill.skillModList:Flag(nil, ifOption) + end, configVisibility.actorKeysForVar(varData, self:GetViewActor())) end)) end if varData.ifMod then @@ -604,60 +551,34 @@ function ConfigTabClass:ConfigTab(build) if implyCond(varData) then return true end - return self.build.calcsTab.mainEnv.modsUsed[ifOption] + return configVisibility.usedForVar(self.build.calcsTab.mainEnv, "modsUsed", varData, self:GetViewActor())[ifOption] end)) t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifMod, function(ifOption) if not launch.devModeAlt then return end - local out - local mods = self.build.calcsTab.mainEnv.modsUsed[ifOption] - if not mods then - return out - end - for _, mod in ipairs(mods) do - out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source - end - return out + return configVisibility.formatUsedMods(self.build.calcsTab.mainEnv, "modsUsed", varData, self:GetViewActor(), ifOption) end)) end if varData.ifSkill then - if varData.includeTransfigured then - t_insert(shownFuncs, listOrSingleIfOption(varData.ifSkill, function(ifOption) - if not calcLib.getGameIdFromGemName(ifOption, true) then - return false - end - for skill,_ in pairs(self.build.calcsTab.mainEnv.skillsUsed) do - if calcLib.isGemIdSame(skill, ifOption, true) then - return true - end - end - return false - end)) - else - t_insert(shownFuncs, listOrSingleIfOption(varData.ifSkill, function(ifOption) - return self.build.calcsTab.mainEnv.skillsUsed[ifOption] - end)) - end + t_insert(shownFuncs, listOrSingleIfOption(varData.ifSkill, function(ifOption) + return configVisibility.anyPrimaryActor(self.build.calcsTab.mainEnv, function(actor) + return configVisibility.actorUsesSkill(actor, ifOption, varData.includeTransfigured) + end, configVisibility.actorKeysForVar(varData, self:GetViewActor())) + end)) end if varData.ifSkillFlag then t_insert(shownFuncs, listOrSingleIfOption(varData.ifSkillFlag, function(ifOption) - for _, activeSkill in ipairs(self.build.calcsTab.mainEnv.player.activeSkillList) do - if activeSkill.skillFlags[ifOption] then - return true - end - end - return false + return configVisibility.anyActiveSkill(self.build.calcsTab.mainEnv, function(activeSkill) + return activeSkill.skillFlags[ifOption] + end, configVisibility.actorKeysForVar(varData, self:GetViewActor())) end)) end if varData.ifSkillData then t_insert(shownFuncs, listOrSingleIfOption(varData.ifSkillData, function(ifOption) - for _, activeSkill in ipairs(self.build.calcsTab.mainEnv.player.activeSkillList) do - if activeSkill.skillData[ifOption] then - return true - end - end - return false + return configVisibility.anyActiveSkill(self.build.calcsTab.mainEnv, function(activeSkill) + return activeSkill.skillData[ifOption] + end, configVisibility.actorKeysForVar(varData, self:GetViewActor())) end)) end @@ -696,7 +617,7 @@ function ConfigTabClass:ConfigTab(build) if not varData.doNotHighlight then control.borderFunc = function() local shown = type(innerShown) == "boolean" and innerShown or innerShown() - local cur = self.configSets[self.activeConfigSetId].input[varData.var] + local cur = self:GetConfigValue(varData.var) local def = self:GetDefaultState(varData.var, type(cur)) if cur ~= nil and cur ~= def then if not shown then @@ -713,23 +634,24 @@ function ConfigTabClass:ConfigTab(build) if not searchMatch(varData) then return false end + if ConfigScope.forVarData(varData) == "player" and self:GetViewActor() == "mercenary" then + return false + end local shown = type(innerShown) == "boolean" and innerShown or innerShown() - local cur = self.configSets[self.activeConfigSetId].input[varData.var] + local cur = self:GetConfigValue(varData.var) local def = self:GetDefaultState(varData.var, type(cur)) return not shown and cur ~= nil and cur ~= def or shown end local innerLabel = labelControl.label labelControl.label = function() local shown = type(innerShown) == "boolean" and innerShown or innerShown() - local cur = self.configSets[self.activeConfigSetId].input[varData.var] + local cur = self:GetConfigValue(varData.var) local def = self:GetDefaultState(varData.var, type(cur)) if not shown and cur ~= nil and cur ~= def then return colorCodes.NEGATIVE..StripEscapes(innerLabel) end return innerLabel end - local outputCache = {} - local outputCacheRevision = nil local innerTooltipFunc = control.tooltipFunc control.tooltipFunc = function(tooltip, mode, index, value) tooltip:Clear() @@ -744,57 +666,7 @@ function ConfigTabClass:ConfigTab(build) end local shown = type(innerShown) == "boolean" and innerShown or innerShown() - local inputs = self.configSets[self.activeConfigSetId].input - local cur = inputs[varData.var] - local def = self:GetDefaultState(varData.var, type(cur)) - if not shown and cur ~= nil and cur ~= def then - tooltip:AddLine(14, colorCodes.NEGATIVE.."This config option is conditional with missing source and is invalid.") - else - -- avoid adding comparisons for number inputs as the - -- input gets applied as soon as the user types, which - -- means comparisons don't make sense here - if not self.calcFunc then - self.calcFunc, self.calcBase = self.build.calcsTab:GetMiscCalculator(self.build) - end - if (varData.type == "check") or (varData.type == "list") then - local valueMapped - if varData.type == "check" then - valueMapped = not cur - else - valueMapped = type(value) == "table" and value.val or value - end - if (valueMapped ~= cur) then - local buildFlag = self.build.buildFlag - tooltip:AddSeparator(10) - -- clear cache if build has been edited - if outputCacheRevision ~= self.build.outputRevision then - outputCache = {} - outputCacheRevision = self.build.outputRevision - end - local key = string.format("%s:%s", tostring(valueMapped), tostring(cur)) - if not outputCache[key] then - inputs[varData.var] = valueMapped - self:BuildModList() - - outputCache[key] = self.calcFunc() - - inputs[varData.var] = cur - self:BuildModList() - end - -- building the mod lists flags the build for a - -- rebuild, but we don't actually want that as - -- we restore the previous state if the user - -- hasn't actually clicked - self.build.buildFlag = buildFlag - local prefix = (varData.type == "check") and "^7Toggling this" or "^7Selecting this" - self.build:AddStatComparesToTooltip(tooltip, self.calcBase, outputCache[key], prefix .. " option will give you:") - -- clear tooltip if it only has our separator - if #tooltip.lines == 1 then - tooltip:Clear() - end - end - end - end + self:AddOptionStatComparison(tooltip, varData, value, self:GetViewActor(), shown) end end @@ -814,7 +686,7 @@ function ConfigTabClass:ConfigTab(build) self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({"TOPRIGHT",self,"TOPRIGHT"}, {0, 0, 18, 0}, 50, "VERTICAL", true) if self.customSection then self.controls.customModsAddBlock = new("ButtonControl"):ButtonControl({"TOPLEFT", self.customSection, "TOPLEFT"}, {8, 0, 120, 20}, "^7Add Mod Group", function() - local customModsList = self.configSets[self.activeConfigSetId].customModsList + local customModsList = self:GetActorCustomModsList() t_insert(customModsList, { title = "Group " .. (#customModsList + 1), enabled = true, text = "" }) self:UpdateCustomModsControls() self:AddUndoState() @@ -841,26 +713,25 @@ function ConfigTabClass:Load(xml, fileName) self.configSets = { } self.configSetOrderList = { 1 } - local function setInputAndPlaceholder(node, configSetId) + local function applyNode(node, input, placeholder) if node.elem == "Input" then if not node.attrib.name then launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing name attribute", fileName) return true end if node.attrib.number then - self.configSets[configSetId].input[node.attrib.name] = tonumber(node.attrib.number) + input[node.attrib.name] = tonumber(node.attrib.number) elseif node.attrib.string then if node.attrib.name == "enemyIsBoss" then - self.configSets[configSetId].input[node.attrib.name] = node.attrib.string:lower():gsub("(%l)(%w*)", function(a,b) return s_upper(a)..b end) + input[node.attrib.name] = node.attrib.string:lower():gsub("(%l)(%w*)", function(a,b) return s_upper(a)..b end) :gsub("Uber Atziri", "Boss"):gsub("Shaper", "Pinnacle"):gsub("Sirus", "Pinnacle") - -- backwards compat <=3.20, Uber Atziri Flameblast -> Atziri Flameblast elseif node.attrib.name == "presetBossSkills" then - self.configSets[configSetId].input[node.attrib.name] = node.attrib.string:gsub("^Uber ", "") + input[node.attrib.name] = node.attrib.string:gsub("^Uber ", "") else - self.configSets[configSetId].input[node.attrib.name] = node.attrib.string + input[node.attrib.name] = node.attrib.string end elseif node.attrib.boolean then - self.configSets[configSetId].input[node.attrib.name] = node.attrib.boolean == "true" + input[node.attrib.name] = node.attrib.boolean == "true" else launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing number, string or boolean attribute", fileName) return true @@ -871,9 +742,9 @@ function ConfigTabClass:Load(xml, fileName) return true end if node.attrib.number then - self.configSets[configSetId].placeholder[node.attrib.name] = tonumber(node.attrib.number) + placeholder[node.attrib.name] = tonumber(node.attrib.number) elseif node.attrib.string then - self.configSets[configSetId].input[node.attrib.name] = node.attrib.string + input[node.attrib.name] = node.attrib.string else launch:ShowErrMsg("^1Error parsing '%s': 'Placeholder' element missing number", fileName) return true @@ -881,6 +752,46 @@ function ConfigTabClass:Load(xml, fileName) end end + local function setInputAndPlaceholder(node, configSetId) + local configSet = self.configSets[configSetId] + return applyNode(node, configSet.input, configSet.placeholder) + end + + local function loadCustomBlock(node) + return { + title = node.attrib.title or "Default", + enabled = (node.attrib.enabled == "true" or node.attrib.enabled == nil), + text = node[1] or "" + } + end + + local function loadActor(actorNode, configSet) + local actorId = actorNode.attrib.id + if actorId ~= "player" and actorId ~= "mercenary" then + return + end + self:EnsureActorConfig(configSet) + local actor = configSet.actors[actorId] + actor.customModsList = { } + if actorId == "player" then + configSet.customModsList = actor.customModsList + end + local input, placeholder = configSet.input, configSet.placeholder + if actorId == "mercenary" then + input, placeholder = actor.input, actor.placeholder + end + for _, child in ipairs(actorNode) do + if child.elem == "CustomModifierBlock" then + t_insert(actor.customModsList, loadCustomBlock(child)) + else + applyNode(child, input, placeholder) + end + end + if #actor.customModsList == 0 then + t_insert(actor.customModsList, { title = "Default", enabled = true, text = "" }) + end + end + -- Catch special case of empty Config if xml.empty then self:NewConfigSet(1, "Default") @@ -905,8 +816,12 @@ function ConfigTabClass:Load(xml, fileName) self:NewConfigSet(configSetId, node.attrib.title or "Default") self.configSetOrderList[index] = configSetId self.configSets[configSetId].customModsList = { } + -- Validated in MercenaryTab:PostLoad once mercenarySets exist. + self.configSets[configSetId].mercenarySetId = tonumber(node.attrib.mercenarySetId) for _, child in ipairs(node) do - if child.elem == "CustomModifierBlock" then + if child.elem == "Actor" then + loadActor(child, self.configSets[configSetId]) + elseif child.elem == "CustomModifierBlock" then local block = { title = child.attrib.title or "Default", enabled = (child.attrib.enabled == "true" or child.attrib.enabled == nil), @@ -934,13 +849,19 @@ function ConfigTabClass:Load(xml, fileName) end end - self:SetActiveConfigSet(tonumber(xml.attrib.activeConfigSet) or 1) + self:SetActiveConfigSet(tonumber(xml.attrib.activeConfigSet) or 1, true) self:ResetUndo() end +function ConfigTabClass:PostLoad() + self:UpdateControls() + self:BuildModList() +end + function ConfigTabClass:GetDefaultState(var, varType) - if self.configSets[self.activeConfigSetId].placeholder[var] ~= nil then - return self.configSets[self.activeConfigSetId].placeholder[var] + local _, placeholder = self:GetVarTables(var) + if placeholder[var] ~= nil then + return placeholder[var] end if self.defaultState[var] ~= nil then @@ -962,60 +883,102 @@ function ConfigTabClass:Save(xml) xml.attrib = { activeConfigSet = tostring(self.activeConfigSetId) } + local function writeValueNode(parent, elem, name, value) + local node = { elem = elem, attrib = { name = name } } + if type(value) == "number" then + node.attrib.number = tostring(value) + elseif type(value) == "boolean" then + node.attrib.boolean = tostring(value) + else + node.attrib.string = tostring(value) + end + t_insert(parent, node) + end + local function defaultFor(var, value, placeholder) + if placeholder and placeholder[var] ~= nil then + return placeholder[var] + end + if self.defaultState[var] ~= nil then + return self.defaultState[var] + end + if type(value) == "number" then + return 0 + elseif type(value) == "boolean" then + return false + elseif type(value) == "string" then + return "" + end + return nil + end + local function writeInputs(parent, input, placeholder) + for k, v in pairs(input) do + if v ~= defaultFor(k, v, placeholder) then + writeValueNode(parent, "Input", k, v) + end + end + end + local function writePlaceholders(parent, placeholder) + for k, v in pairs(placeholder) do + writeValueNode(parent, "Placeholder", k, v) + end + end + local function writeCustomMods(parent, customModsList) + for _, block in ipairs(customModsList) do + t_insert(parent, { + elem = "CustomModifierBlock", + attrib = { + title = block.title or "Default", + enabled = tostring(block.enabled ~= false) + }, + [1] = block.text or "" + }) + end + end for _, configSetId in ipairs(self.configSetOrderList) do local configSet = self.configSets[configSetId] + self:EnsureActorConfig(configSet) local child = { elem = "ConfigSet", attrib = { id = tostring(configSetId), title = configSet.title } } + if configSet.mercenarySetId then + child.attrib.mercenarySetId = tostring(configSet.mercenarySetId) + end t_insert(xml, child) - for k, v in pairs(configSet.input) do - if v ~= self:GetDefaultState(k, type(v)) then - local node = { elem = "Input", attrib = { name = k } } - if type(v) == "number" then - node.attrib.number = tostring(v) - elseif type(v) == "boolean" then - node.attrib.boolean = tostring(v) - else - node.attrib.string = tostring(v) - end - t_insert(child, node) - end - end - for k, v in pairs(configSet.placeholder) do - local node = { elem = "Placeholder", attrib = { name = k } } - if type(v) == "number" then - node.attrib.number = tostring(v) - else - node.attrib.string = tostring(v) - end - t_insert(child, node) - end - if configSet.customModsList then - for _, block in ipairs(configSet.customModsList) do - local blockNode = { - elem = "CustomModifierBlock", - attrib = { - title = block.title or "Default", - enabled = tostring(block.enabled ~= false) - }, - [1] = block.text or "" - } - t_insert(child, blockNode) - end - end + -- Player and shared values keep the upstream layout so clients without + -- Mercenary support still read them. Only Mercenary-owned values go under + -- an Actor node, which those clients ignore. + writeInputs(child, configSet.input, configSet.placeholder) + writePlaceholders(child, configSet.placeholder) + writeCustomMods(child, configSet.customModsList) + local mercenary = configSet.actors.mercenary + local actorNode = { elem = "Actor", attrib = { id = "mercenary" } } + writeInputs(actorNode, mercenary.input, mercenary.placeholder) + writePlaceholders(actorNode, mercenary.placeholder) + writeCustomMods(actorNode, mercenary.customModsList) + t_insert(child, actorNode) end end +function ConfigTabClass:RefreshActorSelect() + if not MercenaryTools.tabVisible(self.build) and self:GetViewActor() == "mercenary" then + self.viewActor = "player" + end + self.controls.actorSelect:SetList(MercenaryTools.configActorList(self.build)) + self.controls.actorSelect:SelByValue(self:GetViewActor(), "id") +end + function ConfigTabClass:UpdateControls() + self:RefreshActorSelect() for var, control in pairs(self.varControls) do + local input, placeholder = self:GetVarTables(var) if control._className == "EditControl" or control._className == "ResizableEditControl" then - control:SetText(tostring(self.configSets[self.activeConfigSetId].input[var] or "")) - if self.configSets[self.activeConfigSetId].placeholder[var] then - control:SetPlaceholder(tostring(self.configSets[self.activeConfigSetId].placeholder[var])) + control:SetText(tostring(input[var] or "")) + if placeholder[var] then + control:SetPlaceholder(tostring(placeholder[var])) end elseif control._className == "CheckBoxControl" then - control.state = self.configSets[self.activeConfigSetId].input[var] + control.state = input[var] elseif control._className == "DropDownControl" then - control:SelByValue(self.configSets[self.activeConfigSetId].input[var] or self:GetDefaultState(var), "val") + control:SelByValue(input[var] or self:GetDefaultState(var), "val") end end self:UpdateCustomModsControls() @@ -1127,40 +1090,28 @@ function ConfigTabClass:UpdateLevel() end end -function ConfigTabClass:BuildModList() - local modList = new("ModList"):ModList() - self.modList = modList - local enemyModList = new("ModList"):ModList() - self.enemyModList = enemyModList - local input = self.configSets[self.activeConfigSetId].input - local placeholder = self.configSets[self.activeConfigSetId].placeholder - self:UpdateLevel() -- enemy level handled here because it's needed to correctly set boss stats - for _, varData in ipairs(varList) do - if varData.apply then - if varData.type == "check" then - if input[varData.var] then - varData.apply(true, modList, enemyModList, self.build) - end - elseif varData.type == "count" or varData.type == "integer" or varData.type == "countAllowZero" or varData.type == "float" then - if input[varData.var] and (input[varData.var] ~= 0 or varData.type == "countAllowZero") then - varData.apply(input[varData.var], modList, enemyModList, self.build) - elseif placeholder[varData.var] and (placeholder[varData.var] ~= 0 or varData.type == "countAllowZero") then - varData.apply(placeholder[varData.var], modList, enemyModList, self.build) - end - elseif varData.type == "list" then - if input[varData.var] then - varData.apply(input[varData.var], modList, enemyModList, self.build) - end - elseif varData.type == "text" then - if input[varData.var] then - varData.apply(input[varData.var], modList, enemyModList, self.build) - end - end +local function applyConfigVar(varData, input, placeholder, modList, enemyModList, build) + if not varData.apply or not varData.var then + return + end + if varData.type == "check" then + if input[varData.var] then + varData.apply(true, modList, enemyModList, build) + end + elseif varData.type == "count" or varData.type == "integer" or varData.type == "countAllowZero" or varData.type == "float" then + if input[varData.var] and (input[varData.var] ~= 0 or varData.type == "countAllowZero") then + varData.apply(input[varData.var], modList, enemyModList, build) + elseif placeholder[varData.var] and (placeholder[varData.var] ~= 0 or varData.type == "countAllowZero") then + varData.apply(placeholder[varData.var], modList, enemyModList, build) + end + elseif varData.type == "list" or varData.type == "text" then + if input[varData.var] then + varData.apply(input[varData.var], modList, enemyModList, build) end end +end - -- Apply Custom Modifier groups - local customModsList = self.configSets[self.activeConfigSetId].customModsList +local function applyCustomMods(customModsList, modList, fallbackText) local hasBlockText = false if customModsList then for _, block in ipairs(customModsList) do @@ -1174,8 +1125,7 @@ function ConfigTabClass:BuildModList() for i = 1, #mods do local mod = mods[i] if mod then - mod = modLib.setSource(mod, source) - modList:AddMod(mod) + modList:AddMod(modLib.setSource(mod, source)) end end end @@ -1183,18 +1133,15 @@ function ConfigTabClass:BuildModList() end end end - -- Fallback for tests/headless - if not hasBlockText and input.customMods and #input.customMods > 0 then - for line in input.customMods:gmatch("([^\n]*)\n?") do + if not hasBlockText and fallbackText and #fallbackText > 0 then + for line in fallbackText:gmatch("([^\n]*)\n?") do local strippedLine = StripEscapes(line):match("^%s*(.-)%s*$") local mods, extra = modLib.parseMod(strippedLine) if mods and not extra then - local source = "Custom" for i = 1, #mods do local mod = mods[i] if mod then - mod = modLib.setSource(mod, source) - modList:AddMod(mod) + modList:AddMod(modLib.setSource(mod, "Custom")) end end end @@ -1202,6 +1149,328 @@ function ConfigTabClass:BuildModList() end end +function ConfigTabClass:GetViewActor() + return self.viewActor or "player" +end + +function ConfigTabClass:ComparisonActorFor(viewActor) + return (viewActor or self:GetViewActor()) == "mercenary" and "MERCENARY" or nil +end + +function ConfigTabClass:ComparisonBase(playerBase, actorOutputs, viewActor) + local actor = self:ComparisonActorFor(viewActor) + if actor and actorOutputs then + return actorOutputs[actor], actor + end + return playerBase, actor +end + +function ConfigTabClass:GetComparisonCalculator(viewActor) + local calcFunc, playerBase, actorOutputs = self.build.calcsTab:GetMiscCalculator(self.build) + local calcBase, actor = self:ComparisonBase(playerBase, actorOutputs, viewActor) + return calcFunc, calcBase, actor +end + +function ConfigTabClass:RunComparisonCalc(calcFunc, actor) + return calcFunc(actor and { comparisonActor = actor } or nil) +end + +-- Preview toggling a check/list option against viewActor's output. +-- optionShown is the control's eligibility; hidden-but-set values are flagged invalid. +function ConfigTabClass:AddOptionStatComparison(tooltip, varData, value, viewActor, optionShown) + viewActor = viewActor or self:GetViewActor() + local inputs = select(1, self:GetVarTablesForActor(varData.var, viewActor)) + local cur = inputs[varData.var] + local def = self:GetDefaultState(varData.var, type(cur)) + if not optionShown and cur ~= nil and cur ~= def then + tooltip:AddLine(14, colorCodes.NEGATIVE.."This config option is conditional with missing source and is invalid.") + return + end + -- Number inputs apply as the user types, so a hover delta is meaningless. + if varData.type ~= "check" and varData.type ~= "list" then + return + end + local valueMapped + if varData.type == "check" then + valueMapped = not cur + else + valueMapped = type(value) == "table" and value.val or value + end + if valueMapped == cur then + return + end + local calcFunc, playerBase, actorOutputs = self.build.calcsTab:GetMiscCalculator(self.build) + if not calcFunc then + return + end + local calcBase, actor = self:ComparisonBase(playerBase, actorOutputs, viewActor) + if self.optionComparisonCacheRevision ~= self.build.outputRevision then + self.optionComparisonCache = { } + self.optionComparisonCacheRevision = self.build.outputRevision + end + self.optionComparisonCache = self.optionComparisonCache or { } + local key = string.format("%s:%s:%s:%s", varData.var, tostring(valueMapped), tostring(cur), tostring(actor or "PLAYER")) + if not self.optionComparisonCache[key] then + local buildFlag = self.build.buildFlag + inputs[varData.var] = valueMapped + self:BuildModList() + self.optionComparisonCache[key] = self:RunComparisonCalc(calcFunc, actor) + inputs[varData.var] = cur + self:BuildModList() + self.build.buildFlag = buildFlag + end + tooltip:AddSeparator(10) + local prefix = (varData.type == "check") and "^7Toggling this" or "^7Selecting this" + self.build:AddStatComparesToTooltip(tooltip, calcBase, self.optionComparisonCache[key], prefix .. " option will give you:", nil, actor) + if #tooltip.lines == 1 then + tooltip:Clear() + end +end + +function ConfigTabClass:SetViewActor(actor) + if actor ~= "mercenary" then + actor = "player" + end + self.viewActor = actor + if self.controls.actorSelect then + self.controls.actorSelect:SelByValue(actor, "id") + end + self:UpdateControls() + self:UpdateCustomModsControls() +end + +function ConfigTabClass:GetVarTablesForActor(var, actor) + local configSet = self.configSets[self.activeConfigSetId] + self:EnsureActorConfig(configSet) + -- Skill-option headers have a label and ifSkill but no var. Draw still + -- asks for their current value when deciding whether to highlight them. + if var and ConfigScope.forVar(var) == "actor" and actor == "mercenary" then + return configSet.actors.mercenary.input, configSet.actors.mercenary.placeholder + end + return configSet.input, configSet.placeholder +end + +function ConfigTabClass:GetVarTables(var) + return self:GetVarTablesForActor(var, self:GetViewActor()) +end + +function ConfigTabClass:GetConfigValue(var) + local input = self:GetVarTables(var) + return input[var] +end + +function ConfigTabClass:GetActorConfigInput(actor) + local configSet = self.configSets[self.activeConfigSetId] + self:EnsureActorConfig(configSet) + if actor ~= "mercenary" then + return configSet.input, configSet.placeholder + end + local sharedCache = self.mercenarySharedConfigCache + if not (sharedCache and sharedCache.configSet == configSet) then + local sharedInput, sharedPlaceholder = { }, { } + for k, v in pairs(configSet.input) do + if ConfigScope.tryForVar(k) == "shared" then + sharedInput[k] = v + end + end + for k, v in pairs(configSet.placeholder) do + if ConfigScope.tryForVar(k) == "shared" then + sharedPlaceholder[k] = v + end + end + sharedCache = { configSet = configSet, input = sharedInput, placeholder = sharedPlaceholder } + self.mercenarySharedConfigCache = sharedCache + end + -- Actor keys are live. Tests and the Config UI write mercenary.input + -- without always rebuilding the shared snapshot first. + -- Reuse the merge buffers; callers that persist the result must copy. + local input = wipeTable(self.mercenaryMergedInput) + local placeholder = wipeTable(self.mercenaryMergedPlaceholder) + self.mercenaryMergedInput = input + self.mercenaryMergedPlaceholder = placeholder + for k, v in pairs(sharedCache.input) do + input[k] = v + end + for k, v in pairs(sharedCache.placeholder) do + placeholder[k] = v + end + for k, v in pairs(configSet.actors.mercenary.input) do + input[k] = v + end + for k, v in pairs(configSet.actors.mercenary.placeholder) do + placeholder[k] = v + end + return input, placeholder +end + +function ConfigTabClass:SetConfigValue(var, value) + local input = self:GetVarTables(var) + input[var] = value +end + +function ConfigTabClass:SetConfigPlaceholder(var, value) + local _, placeholder = self:GetVarTables(var) + placeholder[var] = value +end + +function ConfigTabClass:GetActorCustomModsList(configSet) + configSet = configSet or self.configSets[self.activeConfigSetId] + self:EnsureActorConfig(configSet) + if self:GetViewActor() == "mercenary" then + return configSet.actors.mercenary.customModsList + end + return configSet.customModsList +end + +function ConfigTabClass:EnsureActorConfig(configSet) + if not configSet then + return + end + if not configSet.actors then + configSet.actors = { } + end + if not configSet.actors.player then + configSet.actors.player = { + customModsList = configSet.customModsList, + } + end + if configSet.customModsList then + configSet.actors.player.customModsList = configSet.customModsList + elseif not configSet.actors.player.customModsList then + configSet.actors.player.customModsList = { { title = "Default", enabled = true, text = "" } } + configSet.customModsList = configSet.actors.player.customModsList + end + if not configSet.actors.mercenary then + local mercenaryInput, mercenaryPlaceholder = { }, { } + for _, varData in ipairs(varList) do + if varData.var and ConfigScope.forVarData(varData) == "actor" then + mercenaryInput[varData.var] = varData.defaultState + mercenaryPlaceholder[varData.var] = varData.defaultPlaceholderState + if varData.defaultIndex then + mercenaryInput[varData.var] = varData.list[varData.defaultIndex].val + end + end + end + configSet.actors.mercenary = { + input = mercenaryInput, + placeholder = mercenaryPlaceholder, + customModsList = { { title = "Default", enabled = true, text = "" } }, + } + end +end + +local function reuseModList(list) + if list then + local multipliers = list.multipliers + local conditions = list.conditions + local actor = list.actor + wipeTable(list) + list.parent = false + list.actor = wipeTable(actor) + list.multipliers = wipeTable(multipliers) + list.conditions = wipeTable(conditions) + return list + end + return new("ModList"):ModList() +end + +local function idleModList(list) + if list then + return reuseModList(list) + end + return nil +end + +function ConfigTabClass:BuildModList() + local configSet = self.configSets[self.activeConfigSetId] + self:EnsureActorConfig(configSet) + self.mercenarySharedConfigCache = nil + local hired = MercenaryTools.isHired(self.build) + local playerModList = reuseModList(self.modList) + local enemyModList = reuseModList(self.enemyModList) + self.modList = playerModList + self.enemyModList = enemyModList + local mercenaryModList, playerEnemyModList, mercenaryEnemyModList, tempEnemy + if hired then + mercenaryModList = reuseModList(self.mercenaryModList) + playerEnemyModList = reuseModList(self.playerEnemyModList) + mercenaryEnemyModList = reuseModList(self.mercenaryEnemyModList) + tempEnemy = reuseModList(self.tempEnemyModList) + self.mercenaryModList = mercenaryModList + self.playerEnemyModList = playerEnemyModList + self.mercenaryEnemyModList = mercenaryEnemyModList + self.tempEnemyModList = tempEnemy + else + self.mercenaryModList = idleModList(self.mercenaryModList) + self.playerEnemyModList = idleModList(self.playerEnemyModList) + self.mercenaryEnemyModList = idleModList(self.mercenaryEnemyModList) + self.mercenaryEncounterModList = idleModList(self.mercenaryEncounterModList) + self.tempEnemyModList = idleModList(self.tempEnemyModList) + end + local input = configSet.input + local placeholder = configSet.placeholder + self:UpdateLevel() -- enemy level handled here because it's needed to correctly set boss stats + + local function applyPartitioned(varData, srcInput, srcPlaceholder, actorMods, sourceEnemy) + for i = #tempEnemy, 1, -1 do + tempEnemy[i] = nil + end + applyConfigVar(varData, srcInput, srcPlaceholder, actorMods, tempEnemy, self.build) + for _, mod in ipairs(tempEnemy) do + if ConfigScope.isSourceOwnedEnemyMod(mod) then + sourceEnemy:AddMod(mod) + else + enemyModList:AddMod(mod) + end + end + end + local sharedMods = reuseModList(self.sharedModsList) + self.sharedModsList = sharedMods + for _, varData in ipairs(varList) do + local scope = ConfigScope.forVarData(varData) + if scope == "shared" then + applyConfigVar(varData, input, placeholder, sharedMods, enemyModList, self.build) + elseif scope == "actor" or scope == "player" then + if hired and ConfigScope.enemyStateForVarData(varData) == "source" then + applyPartitioned(varData, input, placeholder, playerModList, playerEnemyModList) + else + applyConfigVar(varData, input, placeholder, playerModList, enemyModList, self.build) + end + end + end + playerModList:AddList(sharedMods) + if hired then + -- Copy so ModStore tag.div writes cannot leak between actors. + mercenaryModList:CopyList(sharedMods) + end + + local mercenary = configSet.actors.mercenary + if hired then + local mercenaryEnemyMods = reuseModList(self.mercenaryEncounterModList) + self.mercenaryEncounterModList = mercenaryEnemyMods + for _, varData in ipairs(varList) do + if ConfigScope.forVarData(varData) == "actor" then + if ConfigScope.enemyStateForVarData(varData) == "source" then + applyPartitioned(varData, mercenary.input, mercenary.placeholder, mercenaryModList, mercenaryEnemyModList) + else + applyConfigVar(varData, mercenary.input, mercenary.placeholder, mercenaryModList, mercenaryEnemyMods, self.build) + end + end + end + enemyModList:AddList(mercenaryEnemyMods) + applyCustomMods(mercenary.customModsList, mercenaryModList) + end + + applyCustomMods(configSet.customModsList, playerModList, input.customMods) + self.modListHasHiredMercenary = hired +end + +function ConfigTabClass:EnsureHiredMercenaryModList() + if self.modListHasHiredMercenary ~= MercenaryTools.isHired(self.build) then + self:BuildModList() + end +end + function ConfigTabClass:ImportCalcSettings() local input = self.configSets[self.activeConfigSetId].input local calcsInput = self.build.calcsTab.input @@ -1241,9 +1510,12 @@ end function ConfigTabClass:CreateUndoState() local configSet = self.configSets[self.activeConfigSetId] + self:EnsureActorConfig(configSet) return { input = copyTable(configSet.input), - customModsList = copyTable(configSet.customModsList) + placeholder = copyTable(configSet.placeholder), + customModsList = copyTable(configSet.customModsList), + actors = copyTable(configSet.actors), } end @@ -1254,9 +1526,15 @@ function ConfigTabClass:RestoreUndoState(state) for k, v in pairs(state.input) do configSet.input[k] = v end + if state.placeholder then + configSet.placeholder = copyTable(state.placeholder) + end if state.customModsList then configSet.customModsList = copyTable(state.customModsList) end + if state.actors then + configSet.actors = copyTable(state.actors) + end else wipeTable(configSet.input) for k, v in pairs(state) do @@ -1296,6 +1574,7 @@ function ConfigTabClass:NewConfigSet(configSetId, title) end end self.configSets[configSet.id] = configSet + self:EnsureActorConfig(configSet) return configSet end @@ -1307,11 +1586,17 @@ function ConfigTabClass:UpdateCustomModsControls() if not configSet then return end - if not configSet.customModsList then - configSet.customModsList = { } + local customModsList = self:GetActorCustomModsList(configSet) + if not customModsList then + customModsList = { } + if self:GetViewActor() == "mercenary" then + configSet.actors.mercenary.customModsList = customModsList + else + configSet.customModsList = customModsList + end end - if #configSet.customModsList == 0 then - t_insert(configSet.customModsList, { title = "Default", enabled = true, text = configSet.input and configSet.input.customMods or "" }) + if #customModsList == 0 then + t_insert(customModsList, { title = "Default", enabled = true, text = configSet.input and configSet.input.customMods or "" }) end if self.customModsBlockControls then @@ -1322,7 +1607,7 @@ function ConfigTabClass:UpdateCustomModsControls() self.customModsBlockControls = { } self.customSection.varControlList = { self.controls.customModsAddBlock } - for index, block in ipairs(configSet.customModsList) do + for index, block in ipairs(customModsList) do local blockControl = new("CustomModBlockControl"):CustomModBlockControl({"TOPLEFT", self.customSection, "TOPLEFT"}, {8, 0, 344, 120}, self, index, block) blockControl.shown = function() return not self:IsSectionCollapsed(self.customSection) @@ -1333,7 +1618,6 @@ function ConfigTabClass:UpdateCustomModsControls() end end --- Changes the active config set function ConfigTabClass:SetActiveConfigSet(configSetId, init) -- Initialize config sets if needed if not self.configSetOrderList[1] then diff --git a/src/Classes/ImportTab.lua b/src/Classes/ImportTab.lua index a44f91bc0aa..c4d190e5a36 100644 --- a/src/Classes/ImportTab.lua +++ b/src/Classes/ImportTab.lua @@ -10,8 +10,8 @@ local b_rshift = bit.rshift local band = bit.band local m_max = math.max local dkjson = require "dkjson" - - +local MercenaryImport = require("Modules.MercenaryImport") +local MercenaryTools = require("Modules.MercenaryTools") local influenceInfo = itemLib.influenceInfo.all @@ -91,7 +91,7 @@ local function addOAuthControls(self) self.controls.characterImportAnchor = new("Control"):Control({ "TOPLEFT", self.controls.sectionOauthCharImport, "TOPLEFT" }, { labelSpacing, 40, 200, 16 }) self.controls.sectionOauthCharImport.height = function() - return self.isAuthorized() and 200 or 60 + return self.isAuthorized() and 228 or 60 end -- realm select @@ -142,6 +142,7 @@ local function addOAuthControls(self) local function onResponse(body, err, timeNext) if not err then self.characterList[realm.realmCode] = body.characters + self.mercenaryRosterEmpty = { } setLeaguesFromCharList() self.oauthLoading = false self.oauthErrCode = nil @@ -198,6 +199,7 @@ local function addOAuthControls(self) self.controls.accountRealm = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.charSelectHeader, "BOTTOMLEFT" }, { 0, rowSpacing, 60, 20 }, realmList, function() + self:CancelMercenaryImport() setLeaguesFromCharList() end) self.controls.accountRealm:SelByValue(main.lastRealm or "PC", "id") @@ -216,6 +218,7 @@ local function addOAuthControls(self) -- league select --- @param newLeague string local function onLeagueChange(_, newLeague) + self:CancelMercenaryImport() local realm = self.controls.accountRealm:GetSelValue().realmCode if newLeague == "Any" then self:BuildCharacterList(realm, nil, self.characterList[realm], self.controls.charSelect) @@ -230,7 +233,7 @@ local function addOAuthControls(self) { labelSpacing, 0, 150, 18 }, nil, onLeagueChange) -- character select self.controls.charSelect = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.charSelectLeagueLabel, "BOTTOMLEFT" }, - { 0, rowSpacing, 400, 18 }, nil) + { 0, rowSpacing, 400, 18 }, nil, function() self:CancelMercenaryImport() end) self.controls.charSelect.enabled = function() return self.usingOauth and self.isAuthorized() end @@ -318,6 +321,25 @@ local function addOAuthControls(self) { 220, 0, 18 }, "Delete equipment:", nil, "Delete all equipped items when importing.", true) self.controls.charImportItemsIgnoreWeaponSwap = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.charImportItems, "RIGHT" }, { 380, 0, 18 }, "Ignore weapon swap:", nil, "Ignore items and skills in weapon swap.", false) + self.controls.charImportMercenaries = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.charImportItems, "BOTTOMLEFT" }, + { 0, rowSpacing, 210, 20 }, function() + return main.api:HasScope("account:league_accounts") and "Mercenaries..." or "Authorize Mercenary access" + end, function() self:DownloadMercenaries() end) + self.controls.charImportMercenaries.enabled = function() + return self.usingOauth and self.isAuthorized() and self.controls.charSelect:GetSelValue() + and not self.oauthLoading and not self.oauthTimer and not self.rateLimitEndTime + and not self:SelectedCharacterHasNoMercenaries() + end + self.controls.charImportMercenaries.shown = function() + return self.usingOauth and self.isAuthorized() + end + self.controls.cancelMercenaryImport = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.charImportMercenaries, "RIGHT" }, + { 6, 0, 90, 20 }, "Cancel", function() + self:CancelMercenaryImport() + end) + self.controls.cancelMercenaryImport.shown = function() + return self.mercenaryImportPending + end end local function addAccountNameControls(self) self.charImportMode = "GETACCOUNTNAME" @@ -481,7 +503,7 @@ function ImportTabClass:ImportTab(build) self.build = build if not main.api then - main.api = new("PoEAPI"):PoEAPI(main.lastToken, main.lastRefreshToken, main.tokenExpiry) + main.api = new("PoEAPI"):PoEAPI(main.lastToken, main.lastRefreshToken, main.tokenExpiry, main.grantedScopes) end @@ -1337,13 +1359,22 @@ local function applySocketGroupReimportState(socketGroup, state) end end +local function isAnimateGuardianGem(gem) + if not gem then + return false + end + local name = gem.nameSpec or (gem.gemData and gem.gemData.name) or (gem.grantedEffect and gem.grantedEffect.name) + return name == "Animate Guardian" +end + local GUARD_ITEM_SET = "Animate Guardian" --- Locates AG's item set from the import + function ImportTabClass:GetOrCreateGuardianItemSet() local itemsTab = self.build.itemsTab + local activeItemSetId = itemsTab.activeItemSetId for _, itemSetId in ipairs(itemsTab.itemSetOrderList) do local itemSet = itemsTab.itemSets[itemSetId] - if itemSet.title == GUARD_ITEM_SET then + if itemSet and itemSet.title == GUARD_ITEM_SET and itemSet.id ~= activeItemSetId then return itemSet end end @@ -1353,12 +1384,11 @@ function ImportTabClass:GetOrCreateGuardianItemSet() return itemSet end --- Allocates AG's item set for the AG skill gem. function ImportTabClass:AssignGuardianItemSet(itemSetId) local itemsTab = self.build.itemsTab for _, socketGroup in ipairs(self.build.skillsTab.socketGroupList) do for _, gem in ipairs(socketGroup.gemList) do - if gem.grantedEffect and gem.grantedEffect.name == "Animate Guardian" then + if isAnimateGuardianGem(gem) then for _, suffix in ipairs({ "", "Calcs" }) do local current = gem["skillMinionItemSet"..suffix] local currentSet = current and itemsTab.itemSets[current] @@ -1381,9 +1411,29 @@ end function ImportTabClass:ImportItemsAndSkills(charData, clearItems, clearSkills, ignoreWeaponSwap) charData = copyTable(charData) if clearItems then - for _, slot in pairs(self.build.itemsTab.slots) do - if slot.selItemId ~= 0 and not slot.nodeId then - self.build.itemsTab:DeleteItem(self.build.itemsTab.items[slot.selItemId]) + local itemsTab = self.build.itemsTab + local preservedItemIds = { } + for _, itemSetId in ipairs(itemsTab.itemSetOrderList) do + if itemSetId ~= itemsTab.activeItemSetId then + local itemSet = itemsTab.itemSets[itemSetId] + for _, slot in pairs(itemSet) do + if type(slot) == "table" and slot.selItemId and slot.selItemId ~= 0 then + preservedItemIds[slot.selItemId] = true + end + end + end + end + for _, slot in ipairs(itemsTab.orderedSlots) do + if not slot.nodeId then + local itemSlot = itemsTab.activeItemSet[slot.slotName] + local itemId = itemSlot and itemSlot.selItemId or 0 + if itemId ~= 0 then + if preservedItemIds[itemId] then + itemSlot.selItemId = 0 + else + itemsTab:DeleteItem(itemsTab.items[itemId]) + end + end end end end @@ -1415,8 +1465,10 @@ function ImportTabClass:ImportItemsAndSkills(charData, clearItems, clearSkills, for _, itemData in ipairs(charData.equipment) do self:ImportItem(itemData, nil, ignoreWeaponSwap) end + local guardianSetId if charData.guardian and charData.guardian[1] then local guardianSet = self:GetOrCreateGuardianItemSet() + guardianSetId = guardianSet.id for _, itemData in ipairs(charData.guardian) do self:ImportItem(itemData, nil, ignoreWeaponSwap, guardianSet.id) end @@ -1475,10 +1527,14 @@ function ImportTabClass:ImportItemsAndSkills(charData, clearItems, clearSkills, self.build.mainSocketGroup = restoredMainSocketGroup end end + if guardianSetId then + self:AssignGuardianItemSet(guardianSetId) + end if mainSkillEmpty then self.build.mainSocketGroup = self:GuessMainSocketGroup() end self.build.itemsTab:PopulateSlots() + self.build.itemsTab:SetViewItemSet(self.build.itemsTab.activeItemSetId, "PLAYER") self.build.itemsTab:AddUndoState() self.build.skillsTab:UpdateSocketGroups() self.build.skillsTab:AddUndoState() @@ -1494,7 +1550,7 @@ local rarityMap = { [0] = "NORMAL", "MAGIC", "RARE", "UNIQUE", [9] = "RELIC", [1 local slotMap = { ["Weapon"] = "Weapon 1", ["Offhand"] = "Weapon 2", ["Weapon2"] = "Weapon 1 Swap", ["Offhand2"] = "Weapon 2 Swap", ["Helm"] = "Helmet", ["BodyArmour"] = "Body Armour", ["Gloves"] = "Gloves", ["Boots"] = "Boots", ["Amulet"] = "Amulet", ["Ring"] = "Ring 1", ["Ring2"] = "Ring 2", ["Ring3"] = "Ring 3", ["Belt"] = "Belt", ["BrequelGrafts"] = "Graft 1", ["BrequelGrafts2"] = "Graft 2", } -function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSetId) +function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSetId, context) if not slotName then if itemData.inventoryId == "PassiveJewels" then slotName = "Jewel "..self.build.latestTree.jewelSlots[itemData.x + 1] @@ -1513,7 +1569,7 @@ function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSet -- Determine rarity, display name and base type of the item item.rarity = rarityMap[itemData.frameType] - if #itemData.name > 0 then + if #(itemData.name or "") > 0 then item.title = sanitiseText(itemData.name) item.baseName = sanitiseText(itemData.typeLine):gsub("Synthesised ", ""):gsub("^Vestigial ", "") item.name = item.title .. ", " .. item.baseName @@ -1581,7 +1637,7 @@ function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSet if itemData.tangled then item.tangle = true end - if itemData.ilvl > 0 then + if (itemData.ilvl or 0) > 0 then item.itemLevel = itemData.ilvl end if item.base.weapon or item.base.armour or item.base.flask or item.base.tincture then @@ -1647,7 +1703,7 @@ function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSet item.sockets = { } for i, socket in pairs(itemData.sockets) do if socket.sColour == "A" then - item.abyssalSocketCount = item.abyssalSocketCount or 0 + 1 + item.abyssalSocketCount = (item.abyssalSocketCount or 0) + 1 end item.sockets[i] = { group = socket.group, color = socket.sColour } end @@ -1656,7 +1712,7 @@ function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSet end end if itemData.socketedItems then - self:ImportSocketedItems(item, itemData.socketedItems, slotName) + self:ImportSocketedItems(item, itemData.socketedItems, slotName, itemSetId, context) end if itemData.requirements and (not itemData.socketedItems or not itemData.socketedItems[1]) then -- Requirements cannot be trusted if there are socketed gems, as they may override the item's natural requirements @@ -1794,6 +1850,17 @@ function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSet -- Add and equip the new item item:BuildAndParseRaw() + if context and context.staged then + if not item.base then + error("Unsupported item in " .. slotName) + end + if context.staged[slotName] then + error("Duplicate equipment slot: " .. slotName) + end + item:BuildModList() + context.staged[slotName] = item + return item + end --ConPrintf("%s", item.raw) if item.base then local repIndex, repItem @@ -1812,21 +1879,30 @@ function ImportTabClass:ImportItem(itemData, slotName, ignoreWeaponSwap, itemSet else self.build.itemsTab:AddItem(item, true) end - if itemSetId and itemSetId ~= self.build.itemsTab.activeItemSetId then - self.build.itemsTab.itemSets[itemSetId][slotName].selItemId = item.id + if itemSetId then + local itemSet = assert(self.build.itemsTab.itemSets[itemSetId], "Missing imported item set: "..tostring(itemSetId)) + local targetSlot = assert(itemSet[slotName], "Missing imported item slot: "..slotName) + targetSlot.selItemId = item.id else - self.build.itemsTab.slots[slotName]:SetSelItemId(item.id) + self.build.itemsTab.slots[slotName]:SetSelItemId(item.id, self.build.itemsTab.activeItemSet) end end end -function ImportTabClass:ImportSocketedItems(item, socketedItems, slotName) +function ImportTabClass:ImportSocketedItems(item, socketedItems, slotName, itemSetId, context) -- Build socket group list local itemSocketGroupList = { } local abyssalSocketId = 1 + local mercenaryOccupancy = context and context.actor == "MERCENARY" + if mercenaryOccupancy then + item.socketedGems = item.socketedGems or { } + end for _, socketedItem in ipairs(socketedItems) do if socketedItem.abyssJewel then - self:ImportItem(socketedItem, slotName .. " Abyssal Socket "..abyssalSocketId) + local imported = self:ImportItem(socketedItem, slotName .. " Abyssal Socket " .. abyssalSocketId, false, itemSetId, context) + if context and context.staged and not imported then + error("Unsupported Abyss jewel in " .. slotName) + end abyssalSocketId = abyssalSocketId + 1 else local normalizedBasename = sanitiseText(socketedItem.typeLine) @@ -1843,22 +1919,33 @@ function ImportTabClass:ImportSocketedItems(item, socketedItems, slotName) local gemInstance = { level = 20, quality = 0, enabled = true, enableGlobal1 = true, gemId = gemId } gemInstance.nameSpec = self.build.data.gems[gemId].name gemInstance.support = socketedItem.support - for _, property in pairs(socketedItem.properties) do + for _, property in pairs(socketedItem.properties or { }) do if property.name == "Level" then gemInstance.level = tonumber(property.values[1][1]:match("%d+")) elseif property.name == "Quality" then gemInstance.quality = tonumber(property.values[1][1]:match("%d+")) end end - local groupID = item.sockets[socketedItem.socket + 1].group - if not itemSocketGroupList[groupID] then - itemSocketGroupList[groupID] = { label = "", enabled = true, gemList = { }, slot = slotName } - end - local socketGroup = itemSocketGroupList[groupID] - t_insert(socketGroup.gemList, gemInstance) - if socketedItem.builtInSupport then - socketGroup.imbuedSupport = socketedItem.builtInSupport:gsub("Supported by Level 1 ", "") - self.build.skillsTab.controls.imbuedSupport.gemChangeFunc(data.gems[data.gemForBaseName[socketGroup.imbuedSupport:lower().." support"]], nil, nil, true, slotName) + if mercenaryOccupancy then + -- Preserve occupancy for socket-property item bonuses; do not create usable gem skills. + item.socketedGems[(socketedItem.socket or 0) + 1] = { + gemId = gemInstance.gemId, + nameSpec = gemInstance.nameSpec, + support = gemInstance.support, + level = gemInstance.level, + quality = gemInstance.quality, + } + else + local groupID = item.sockets[socketedItem.socket + 1].group + if not itemSocketGroupList[groupID] then + itemSocketGroupList[groupID] = { label = "", enabled = true, gemList = { }, slot = slotName } + end + local socketGroup = itemSocketGroupList[groupID] + t_insert(socketGroup.gemList, gemInstance) + if socketedItem.builtInSupport then + socketGroup.imbuedSupport = socketedItem.builtInSupport:gsub("Supported by Level 1 ", "") + self.build.skillsTab.controls.imbuedSupport.gemChangeFunc(data.gems[data.gemForBaseName[socketGroup.imbuedSupport:lower().." support"]], nil, nil, true, slotName) + end end end end @@ -1897,6 +1984,356 @@ function ImportTabClass:ImportSocketedItems(item, socketedItems, slotName) end end +function ImportTabClass:CancelMercenaryImport() + self.mercenaryImportGeneration = (self.mercenaryImportGeneration or 0) + 1 + if self.mercenaryImportPending then + self.oauthLoading = false + end + self.mercenaryImportPending = false +end + +function ImportTabClass:SelectedCharacterHasNoMercenaries() + local realm = self.controls.accountRealm:GetSelValue() + local selected = self.controls.charSelect:GetSelValue() + local league = selected and selected.char and selected.char.league + return realm and league and self.mercenaryRosterEmpty and self.mercenaryRosterEmpty[realm.realmCode .. "\0" .. league] +end + +function ImportTabClass:DownloadMercenaries() + local api = main.api + if not api:HasScope("account:league_accounts") then + self.oauthTimer = os.time() + api:FetchAuthToken(function(err) + if self.build.importTab ~= self then return end + self.oauthTimer = nil + self.oauthErrCode = err + if not err then + self.characterList = { } + self.controls.charSelect:SetList({ }) + self.controls.charSelectLeague:SetList({ }) + if not api:HasScope("account:league_accounts") then + self.oauthErrCode = "Mercenary access was not granted. Authorize again to retrieve Mercenaries." + end + end + end) + return + end + self:CancelMercenaryImport() + local generation = self.mercenaryImportGeneration + local authGeneration = api.authGeneration + local realm = self.controls.accountRealm:GetSelValue().realmCode + local character = self.controls.charSelect:GetSelValue() + if not character then + return + end + local spec, profile = self.build.spec, self.build.mercenaryTab.profile + local function current() + local valid = self.build.importTab == self and self.build.spec == spec and self.build.mercenaryTab.profile == profile + and main.api == api and api.authGeneration == authGeneration and api.authToken ~= nil + and self.mercenaryImportGeneration == generation and self.usingOauth + and self.controls.accountRealm:GetSelValue().realmCode == realm and self.controls.charSelect:GetSelValue() == character + if not valid and self.mercenaryImportGeneration == generation then + self:CancelMercenaryImport() + end + return valid + end + local function failure(err, timeNext) + self.mercenaryImportPending = false + self.oauthLoading = false + self.oauthErrCode = err + self.rateLimitEndTime = timeNext + end + self.mercenaryImportPending = true + self.oauthLoading = true + self.oauthErrCode = nil + api:DownloadCharacter(realm, character.label, function(body, err, timeNext) + if not current() then return end + local league = body and body.character and body.character.league + local activeIndex = body and body.character and body.character.active_mercenary_index + if err or not league then + failure(err or "Selected character has no league", timeNext) + return + end + -- Profile UUID is the account identity; character names and access tokens are not. + api:DownloadProfile(function(account, err, timeNext) + if not current() then return end + if err or not account or type(account.uuid) ~= "string" then + failure(err or "Could not identify the authorized account", timeNext) + return + end + api:DownloadLeagueAccount(realm, league, function(body, err, timeNext) + if not current() then return end + local roster = body and body.league_account + if err or type(roster) ~= "table" then + failure(err or "Missing league account response", timeNext) + return + end + roster.active_mercenary_index = activeIndex + if #(roster.mercenaries or { }) == 0 then + self.mercenaryRosterEmpty = self.mercenaryRosterEmpty or { } + self.mercenaryRosterEmpty[realm .. "\0" .. league] = true + failure("No Mercenaries found.") + return + end + if self.mercenaryRosterEmpty then + self.mercenaryRosterEmpty[realm .. "\0" .. league] = nil + end + failure(nil) + self:OpenMercenaryImportPopup(roster, { account = account.uuid, realm = realm, league = league }, current) + end) + end) + end) +end + +function ImportTabClass:OpenMercenaryImportPopup(account, source, current) + if #(account.mercenaries or { }) == 0 then + return + end + local tab = self.build.mercenaryTab + local data = tab:EnsureData() + local controls, hires = { }, { } + local status = "" + local activeIndex = MercenaryImport.activeIndex(account) + for index, hire in ipairs(account.mercenaries or { }) do + local mercBuild = data.builds[hire.build] + t_insert(hires, { + hire = hire, + label = string.format("%s - %s%s", hire.name or "Unknown", mercBuild and mercBuild.name or "Unsupported build", index == activeIndex and " (Active)" or ""), + }) + end + local function selectHire(_, selected) + status = "" + local destinations = { { id = 0, label = "Create new loadout: " .. selected.hire.name } } + local matches, selectedIndex = 0, 1 + for _, id in ipairs(tab.mercenarySetOrderList) do + local profile = tab.mercenarySets[id] + local matchesSource = MercenaryImport.matchesAssociation(profile.importAssociation, source.account, source.realm, source.league, selected.hire) + t_insert(destinations, { id = id, label = (profile.title or "Default") .. (matchesSource and " (Matches import)" or "") }) + if matchesSource then + matches = matches + 1 + selectedIndex = #destinations + end + end + if matches == 0 then + local unused = MercenaryImport.unusedEmptyId(tab.mercenarySets, tab.mercenarySetOrderList) + if unused then + for index, destination in ipairs(destinations) do + if destination.id == unused then + selectedIndex = index + break + end + end + end + end + controls.destination:SetList(destinations) + controls.destination.selIndex = selectedIndex + if matches > 1 then + controls.destination.selIndex = nil + status = "Multiple matching loadouts: select a destination." + end + end + controls.hire = new("DropDownControl"):DropDownControl(nil, { 0, 35, 690, 20 }, hires, selectHire) + controls.destinationLabel = new("LabelControl"):LabelControl(nil, { 0, 70, 0, 16 }, "Destination loadout (supplied skills, supports and equipment will be replaced):") + controls.destination = new("DropDownControl"):DropDownControl(nil, { 0, 95, 690, 20 }, { }) + controls.status = new("LabelControl"):LabelControl(nil, { 0, 133, 0, 16 }, function() + if status ~= "" then + return status + end + if #hires == 0 then + return "No Mercenaries found." + end + if not controls.hire:GetSelValue() then + return "Select a Mercenary" + end + return "" + end) + controls.import = new("ButtonControl"):ButtonControl(nil, { -45, 173, 80, 20 }, "Import", function() + if current and not current() then + status = "Import context changed. Close and fetch Mercenaries again." + return + end + local selected, destination = controls.hire:GetSelValue(), controls.destination:GetSelValue() + if not selected or not destination then + return + end + local imported, message = self:ImportMercenary(selected.hire, source, destination.id) + if imported then + main:ClosePopup() + main:OpenMessagePopup("Mercenary Import", message) + else + status = message + end + end) + controls.import.enabled = function() + return controls.hire:GetSelValue() and controls.destination:GetSelValue() + end + controls.cancel = new("ButtonControl"):ButtonControl(nil, { 45, 173, 80, 20 }, "Cancel", function() + self:CancelMercenaryImport() + main:ClosePopup() + end) + if activeIndex then + controls.hire:SetSel(activeIndex) + end + local selected = controls.hire:GetSelValue() + if selected then + selectHire(controls.hire.selIndex, selected) + end + main:OpenPopup(730, 215, "Import Mercenaries", controls, "import", "hire", "cancel") +end + +-- Parse the entire snapshot before assigning any build data. +function ImportTabClass:ImportMercenary(hire, source, destinationId) + local tab, itemsTab = self.build.mercenaryTab, self.build.itemsTab + local profile, err = MercenaryImport.profile(hire, tab:EnsureData()) + if not profile then + return nil, err + end + if type(hire.items) ~= "table" then + return nil, "Missing Mercenary equipment snapshot" + end + local association = MercenaryImport.association(source.account, source.realm, source.league, hire) + if destinationId == nil then + for _, id in ipairs(tab.mercenarySetOrderList) do + if MercenaryImport.matchesAssociation(tab.mercenarySets[id].importAssociation, source.account, source.realm, source.league, hire) then + if destinationId then + return nil, "Multiple matching loadouts: select a destination" + end + destinationId = id + end + end + if destinationId == nil then + destinationId = MercenaryImport.unusedEmptyId(tab.mercenarySets, tab.mercenarySetOrderList) + end + end + local previous = destinationId and destinationId ~= 0 and tab.mercenarySets[destinationId] + if destinationId and destinationId ~= 0 and not previous then + return nil, "Destination loadout no longer exists" + end + local context = { actor = "MERCENARY", staged = { } } + local ok, parseError = pcall(function() + for _, itemData in ipairs(hire.items) do + local slotName = slotMap[itemData.inventoryId] + if not slotName or not MercenaryTools.isSlotSupported(slotName) then + error("Unsupported equipment slot: " .. tostring(itemData.inventoryId), 0) + end + if not self:ImportItem(copyTable(itemData), slotName, false, nil, context) then + error("Unsupported item in " .. slotName .. ": " .. tostring(itemData.typeLine), 0) + end + end + end) + if not ok then + return nil, "Could not import equipment: " .. tostring(parseError) + end + local seenItems = { } + for slotName, item in pairs(context.staged) do + if not itemsTab.slots[slotName] then + return nil, "Unsupported equipment slot: " .. slotName + end + if item.uniqueID and seenItems[item.uniqueID] then + return nil, "Duplicate item identifier in equipment snapshot" + end + if item.uniqueID then + seenItems[item.uniqueID] = true + end + local parent, socket = slotName:match("^(.-) Abyssal Socket (%d+)$") + if parent and (not context.staged[parent] or (context.staged[parent].abyssalSocketCount or 0) < tonumber(socket)) then + return nil, "Missing parent Abyss socket for " .. slotName + end + end + for _, item in pairs(context.staged) do + if MercenaryTools.playerEquipsPhysicalItem(item, itemsTab.activeItemSet, itemsTab.items) then + return nil, "This item is still equipped by the player in PoB; refresh the character import or unequip it first." + end + end + + -- Replace the destination loadout's own equipment set. Fork only if that + -- would overwrite the player's currently equipped gear. + local previousSetId = previous and previous.itemSetId + local itemSet = previousSetId and itemsTab.itemSets[previousSetId] + itemsTab:AddUndoState() + if not itemSet or itemSet.id == itemsTab.activeItemSetId then + itemSet = itemsTab:NewItemSet() + itemSet.title = hire.name + t_insert(itemsTab.itemSetOrderList, itemSet.id) + end + local oldItems, referenced = { }, { } + for _, slot in pairs(itemSet) do + if type(slot) == "table" and slot.selItemId and slot.selItemId ~= 0 then + oldItems[slot.selItemId] = true + end + end + for id, other in pairs(itemsTab.itemSets) do + if id ~= itemSet.id then + for _, slot in pairs(other) do + if type(slot) == "table" and slot.selItemId then + referenced[slot.selItemId] = true + end + end + end + end + for _, spec in pairs(self.build.treeTab.specList) do + for _, id in pairs(spec.jewels) do + referenced[id] = true + end + end + local reusable = { } + for id in pairs(oldItems) do + local item = itemsTab.items[id] + if item and item.uniqueID and not referenced[id] then + reusable[item.uniqueID] = id + end + end + for _, slot in pairs(itemSet) do + if type(slot) == "table" and slot.selItemId then + slot.selItemId = 0 + end + end + local slotNames = { } + for name in pairs(context.staged) do + t_insert(slotNames, name) + end + table.sort(slotNames) + for _, name in ipairs(slotNames) do + local item = context.staged[name] + item.id = item.uniqueID and reusable[item.uniqueID] + itemsTab:AddItem(item, true) + itemSet[name].selItemId = item.id + oldItems[item.id] = nil + end + for id in pairs(oldItems) do + if not referenced[id] and itemsTab.items[id] then + itemsTab:DeleteItem(itemsTab.items[id], true) + end + end + if previous then + profile.id = previous.id + else + profile.id = tab:NewMercenarySet().id + t_insert(tab.mercenarySetOrderList, profile.id) + end + profile.importAssociation = association + profile.itemSetId = itemSet.id + tab.mercenarySets[profile.id] = profile + -- SetActiveMercenarySet stores the outgoing profile; replace its pointer first. + if tab.activeMercenarySetId == profile.id then + tab.profile = profile + end + -- Bind the active Config only when creating a hire or filling an unused empty + -- slot (including an explicit empty destination). Reimport, and explicit + -- overwrite of an occupied slot with a different hire, must not steal the + -- active loadout's binding. + local bindToLoadout = not previous or (not previous.buildId and not previous.importAssociation) + tab:SetActiveMercenarySet(profile.id, false, bindToLoadout) + tab:AddUndoState() + itemsTab:PopulateSlots() + itemsTab:AddUndoState() + local supports = 0 + for _, skill in ipairs(profile.skills) do + supports = supports + #skill.supports + end + return profile, string.format("Imported %d skills, %d supports, %d equipped items and %d Abyss jewels", #profile.skills, supports, #hire.items, #slotNames - #hire.items) +end + -- Return the index of the group with the most gems function ImportTabClass:GuessMainSocketGroup() local largestGroupSize = 0 diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua index 1618e93e018..fc4576257c0 100644 --- a/src/Classes/Item.lua +++ b/src/Classes/Item.lua @@ -484,6 +484,7 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) end self.checkSection = false self.sockets = { } + self.socketedGems = { } self.classRequirementModLines = { } self.buffModLines = { } ---@type ModLine[] @@ -687,6 +688,20 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) group = group + 1 end end + elseif specName == "Socketed Gem" then + local socketIndex, nameSpec, level, quality = specVal:match("^(%d+) (.+) (%d+)/(%d+)$") + if not socketIndex then + socketIndex, nameSpec = specVal:match("^(%d+) (.+)$") + end + if socketIndex and nameSpec then + local gemId = data.gemForBaseName and data.gemForBaseName[nameSpec:lower()] + self.socketedGems[tonumber(socketIndex)] = { + nameSpec = nameSpec, + gemId = gemId, + level = tonumber(level) or 20, + quality = tonumber(quality) or 0, + } + end elseif specName == "Radius" and self.type == "Jewel" then self.jewelRadiusLabel = specVal:match("^[%a ]+") if specVal:match("^[%a ]+") == "Variable" then @@ -1997,6 +2012,21 @@ function ItemClass:BuildRaw() end t_insert(rawLines, line) end + if self.socketedGems then + local indices = { } + for index in pairs(self.socketedGems) do + if type(index) == "number" then + t_insert(indices, index) + end + end + table.sort(indices) + for _, index in ipairs(indices) do + local gem = self.socketedGems[index] + if gem and gem.nameSpec then + t_insert(rawLines, "Socketed Gem: "..index.." "..gem.nameSpec.." "..(gem.level or 20).."/"..(gem.quality or 0)) + end + end + end if self.requirements and self.requirements.level then t_insert(rawLines, "LevelReq: " .. self.requirements.level) end diff --git a/src/Classes/ItemDBControl.lua b/src/Classes/ItemDBControl.lua index bc5c227bf3d..1ab916d6b4a 100644 --- a/src/Classes/ItemDBControl.lua +++ b/src/Classes/ItemDBControl.lua @@ -9,7 +9,6 @@ local t_insert = table.insert local m_max = math.max local m_floor = math.floor - ---@class ItemDBControl: ListControl local ItemDBClass = newClass("ItemDBControl", "ListControl") @@ -256,15 +255,28 @@ function ItemDBClass:ListBuilder() local useFullDPS = self.sortDetail.stat == "FullDPS" local start = GetTime() local calcFunc, calcBase = self.itemsTab.build.calcsTab:GetMiscCalculator(self.build) + local visibleItemSet = self.itemsTab:GetVisibleItemSet() + local visibleSlots = self.itemsTab.orderedSlots for itemIndex, item in ipairs(list) do item.measuredPower = -math.huge - for slotName, slot in pairs(self.itemsTab.slots) do - if self.itemsTab:IsItemValidForSlot(item, slotName) and not slot.inactive and (not slot.weaponSet or slot.weaponSet == (self.itemsTab.activeItemSet.useSecondWeaponSet and 2 or 1)) then - local output = calcFunc(item.base.flask and { toggleFlask = item } or item.base.tincture and { toggleTincture = item } or { repSlotName = slotName, repItem = item }, useFullDPS) + local function measureSlot(slotName, slot) + if self.itemsTab:IsItemValidForSlot(item, slotName, visibleItemSet) and not slot.inactive and slot:IsShown() and (not slot.weaponSet or slot.weaponSet == (visibleItemSet.useSecondWeaponSet and 2 or 1)) then + local override + if item.base.flask then + override = { toggleFlask = item } + elseif item.base.tincture then + override = { toggleTincture = item } + else + override = self.itemsTab:ItemCalculationOverride(slotName, item) + end + local output = calcFunc(override, useFullDPS) local measuredPower = data.powerStatList.GetFromOutput(output, self.sortDetail) item.measuredPower = m_max(item.measuredPower, measuredPower) end end + for _, slot in ipairs(visibleSlots) do + measureSlot(slot.slotName, slot) + end local now = GetTime() if now - start > 50 then self.defaultText = "^7Sorting... ("..m_floor(itemIndex/#list*100).."%)" @@ -356,19 +368,20 @@ function ItemDBClass:OnSelClick(index, item, doubleClick) -- Equip item if able local slotName = newItem:GetPrimarySlot() + local visibleItemSet = self.itemsTab:GetVisibleItemSet() if slotName and self.itemsTab.slots[slotName] then - if self.itemsTab.slots[slotName].weaponSet == 1 and self.itemsTab.activeItemSet.useSecondWeaponSet then + if self.itemsTab.slots[slotName].weaponSet == 1 and visibleItemSet.useSecondWeaponSet then -- Redirect to second weapon set slotName = slotName .. " Swap" end if IsKeyDown("SHIFT") then -- Redirect to second slot if possible local altSlot = slotName:gsub("1","2") - if self.itemsTab:IsItemValidForSlot(newItem, altSlot) then + if self.itemsTab:IsItemValidForSlot(newItem, altSlot, visibleItemSet) then slotName = altSlot end end - self.itemsTab.slots[slotName]:SetSelItemId(newItem.id) + self.itemsTab.slots[slotName]:SetSelItemId(newItem.id, visibleItemSet) end self.itemsTab:AddForbiddenJewelCounterpart(newItem) diff --git a/src/Classes/ItemListControl.lua b/src/Classes/ItemListControl.lua index a38fe5fbc5e..bbfdfa1c5ac 100644 --- a/src/Classes/ItemListControl.lua +++ b/src/Classes/ItemListControl.lua @@ -52,8 +52,13 @@ function ItemListClass:ItemListControl(anchor, rect, itemsTab, forceTooltip) end self.controls.deleteAll = new("ButtonControl"):ButtonControl({"LEFT",self.controls.deleteUnused,"RIGHT"}, {4, 0, 58, 18}, "Del All", function() main:OpenConfirmPopup("Delete All", "Are you sure you want to delete all items in this build?", "Delete", function() + for _, itemSet in pairs(itemsTab.itemSets) do + for _, itemSlot in pairs(itemSet) do + if type(itemSlot) == "table" and itemSlot.selItemId then itemSlot.selItemId = 0 end + end + end for _, slot in pairs(itemsTab.slots) do - slot:SetSelItemId(0) + if slot.nodeId then slot:SetSelItemId(0) end end for _, spec in pairs(itemsTab.build.treeTab.specList) do for nodeId, itemId in pairs(spec.jewels) do @@ -97,7 +102,8 @@ function ItemListClass:UpdateLoadoutList() end end if self.itemsTab.itemSetOrderList then - for _, itemSetId in ipairs(self.itemsTab.itemSetOrderList) do + local itemSetOrderList = self.itemsTab.itemSetOrderList + for _, itemSetId in ipairs(itemSetOrderList) do local itemSet = self.itemsTab.itemSets[itemSetId] local title = itemSet and (itemSet.title or "Default") if title and not listValues[title] then @@ -132,11 +138,12 @@ function ItemListClass:UpdateList() local filterItemSet local filterSpec if selFilter == 2 or filterVal == "Current Loadout" then - filterItemSet = self.itemsTab.activeItemSet + filterItemSet = self.itemsTab:GetVisibleItemSet() filterSpec = self.itemsTab.build.treeTab.specList[self.itemsTab.build.treeTab.activeSpec] elseif selFilter ~= 3 and filterVal ~= "Unused Items" then local filterTitle = filterVal:gsub("^%[[^%]]+%]%s*", "") - for _, itemSetId in ipairs(self.itemsTab.itemSetOrderList) do + local itemSetOrderList = self.itemsTab.itemSetOrderList + for _, itemSetId in ipairs(itemSetOrderList) do local itemSet = self.itemsTab.itemSets[itemSetId] if (itemSet.title or "Default") == filterTitle then filterItemSet = itemSet @@ -153,7 +160,7 @@ function ItemListClass:UpdateList() local linkId = filterVal:match("%{(%w+)%}") local itemLink = linkId and self.itemsTab.build.itemListSpecialLinks and self.itemsTab.build.itemListSpecialLinks[linkId] local treeLink = linkId and self.itemsTab.build.treeListSpecialLinks and self.itemsTab.build.treeListSpecialLinks[linkId] - filterItemSet = filterItemSet or #self.itemsTab.itemSetOrderList == 1 and self.itemsTab.itemSets[self.itemsTab.itemSetOrderList[1]] or itemLink and self.itemsTab.itemSets[itemLink.setId] + filterItemSet = filterItemSet or #itemSetOrderList == 1 and self.itemsTab.itemSets[itemSetOrderList[1]] or itemLink and self.itemsTab.itemSets[itemLink.setId] filterSpec = filterSpec or #treeTab.specList == 1 and treeTab.specList[1] or treeLink and treeTab.specList[treeLink.setId] end filterItemSet = filterItemSet or { } @@ -300,22 +307,23 @@ function ItemListClass:OnSelClick(index, itemId, doubleClick) local item = self.itemsTab.items[itemId] if IsKeyDown("CTRL") then local slotName = item:GetPrimarySlot() + local visibleItemSet = self.itemsTab:GetVisibleItemSet() if slotName and self.itemsTab.slots[slotName] then - if self.itemsTab.slots[slotName].weaponSet == 1 and self.itemsTab.activeItemSet.useSecondWeaponSet then + if self.itemsTab.slots[slotName].weaponSet == 1 and visibleItemSet.useSecondWeaponSet then -- Redirect to second weapon set slotName = slotName .. " Swap" end if IsKeyDown("SHIFT") then -- Redirect to second slot if possible local altSlot = slotName:gsub("1","2") - if self.itemsTab:IsItemValidForSlot(item, altSlot) then + if self.itemsTab:IsItemValidForSlot(item, altSlot, visibleItemSet) then slotName = altSlot end end if self.itemsTab.slots[slotName].selItemId == item.id then - self.itemsTab.slots[slotName]:SetSelItemId(0) + self.itemsTab.slots[slotName]:SetSelItemId(0, visibleItemSet) else - self.itemsTab.slots[slotName]:SetSelItemId(item.id) + self.itemsTab.slots[slotName]:SetSelItemId(item.id, visibleItemSet) end self.itemsTab:PopulateSlots() self.itemsTab:AddUndoState() @@ -385,4 +393,4 @@ function ItemListClass:OnHoverKeyUp(key) itemLib.wiki.openItem(item) end end -end \ No newline at end of file +end diff --git a/src/Classes/ItemSetListControl.lua b/src/Classes/ItemSetListControl.lua index 4448d74ae2b..cf8832d4e9c 100644 --- a/src/Classes/ItemSetListControl.lua +++ b/src/Classes/ItemSetListControl.lua @@ -5,8 +5,9 @@ -- local t_insert = table.insert local t_remove = table.remove +local ipairs = ipairs local m_max = math.max -local s_format = string.format +local MercenaryTools = require("Modules.MercenaryTools") ---@class ItemSetListControl: ListControl local ItemSetListClass = newClass("ItemSetListControl", "ListControl") @@ -30,7 +31,18 @@ function ItemSetListClass:ItemSetListControl(anchor, rect, itemsTab) self:OnSelDelete(self.selIndex, self.selValue) end) self.controls.delete.enabled = function() - return self.selValue ~= nil and #self.list > 1 + return self:CanDeleteItemSet(self.selValue) + end + self.controls.delete.tooltipText = function() + if not self.selValue then + return + end + if self.itemsTab:IsItemSetReferenced(self.selValue) then + return "This item set is assigned to a Mercenary, Animate Guardian, or skill loadout" + end + if #self.list <= 1 then + return "The last item set cannot be deleted" + end end self.controls.rename = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function() self:RenameSet(itemsTab.itemSets[self.selValue]) @@ -42,9 +54,37 @@ function ItemSetListClass:ItemSetListControl(anchor, rect, itemsTab) local newSet = itemsTab:NewItemSet() self:RenameSet(newSet, true) end) + self.controls.equipActorLabel = new("LabelControl"):LabelControl({"TOPLEFT", self, "BOTTOMLEFT"}, {0, 6, 0, 16}, "^7Assign to:") + self.controls.equipActor = new("DropDownControl"):DropDownControl({"LEFT", self.controls.equipActorLabel, "RIGHT"}, {6, 0, 120, 18}, self:EquipActorList()) + self.controls.equip = new("ButtonControl"):ButtonControl({"LEFT", self.controls.equipActor, "RIGHT"}, {4, 0, 90, 18}, "Equip", function() + local actor = self.controls.equipActor:GetSelValueByKey("id") + if self.selValue and actor then + itemsTab:SetActorItemSet(actor, self.selValue) + itemsTab:AddUndoState() + end + end) + self.controls.equip.enabled = function() + return self.selValue ~= nil + end return self end +function ItemSetListClass:EquipActorList() + local list = { { id = "PLAYER", label = "Player" } } + if MercenaryTools.tabVisible(self.itemsTab.build) then + t_insert(list, { id = "MERCENARY", label = "Mercenary" }) + end + return list +end + +function ItemSetListClass:CanDeleteItemSet(itemSetId) + local itemSet = self.itemsTab.itemSets[itemSetId] + if not itemSet or self.itemsTab:IsItemSetReferenced(itemSetId) then + return false + end + return #self.list > 1 +end + function ItemSetListClass:RenameSet(itemSet, addOnName) local controls = { } controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this item set:") @@ -76,7 +116,10 @@ end function ItemSetListClass:GetRowValue(column, index, itemSetId) local itemSet = self.itemsTab.itemSets[itemSetId] if column == 1 then - return (itemSet.title or "Default") .. (itemSetId == self.itemsTab.activeItemSetId and " ^9(Current)" or "") + local title = itemSet.title or "Default" + return title .. (itemSetId == self.itemsTab.viewItemSetId and " ^9(Visible)" or "") + .. (itemSetId == self.itemsTab.activeItemSetId and " ^9(Current player)" or "") + .. (itemSetId == self.itemsTab:GetActorItemSetId("MERCENARY") and " ^9(Current mercenary)" or "") end end @@ -98,11 +141,15 @@ function ItemSetListClass:ReceiveDrag(type, value, source) if type == "SharedItemList" then local itemSet = self.itemsTab:NewItemSet() itemSet.title = value.title - for slotName, item in pairs(value.slots) do - local newItem = new("Item"):Item(item.raw) - newItem:NormaliseQuality() - self.itemsTab:AddItem(newItem, true) - itemSet[slotName].selItemId = newItem.id + for _, slot in ipairs(self.itemsTab.orderedSlots) do + local slotName = slot.slotName + local item = value.slots[slotName] + if item then + local newItem = new("Item"):Item(item.raw) + newItem:NormaliseQuality() + self.itemsTab:AddItem(newItem, true) + itemSet[slotName].selItemId = newItem.id + end end t_insert(self.list, self.selDragIndex or #self.list + 1, itemSet.id) self.itemsTab:AddUndoState() @@ -114,22 +161,25 @@ function ItemSetListClass:OnOrderChange() end function ItemSetListClass:OnSelClick(index, itemSetId, doubleClick) - if doubleClick and itemSetId ~= self.itemsTab.activeItemSetId then - self.itemsTab:SetActiveItemSet(itemSetId) + if doubleClick and itemSetId ~= self.itemsTab.viewItemSetId then + self.itemsTab:SetViewItemSet(itemSetId) self.itemsTab:AddUndoState() end end function ItemSetListClass:OnSelDelete(index, itemSetId) local itemSet = self.itemsTab.itemSets[itemSetId] - if #self.list > 1 then + if self:CanDeleteItemSet(itemSetId) then main:OpenConfirmPopup("Delete Item Set", "Are you sure you want to delete '"..(itemSet.title or "Default").."'?\nThis will not delete any items used by the set.", "Delete", function() t_remove(self.list, index) self.itemsTab.itemSets[itemSetId] = nil self.selIndex = nil self.selValue = nil - if itemSetId == self.itemsTab.activeItemSetId then - self.itemsTab:SetActiveItemSet(self.list[m_max(1, index - 1)]) + local replacementItemSetId = self.list[m_max(1, index)] or self.list[index - 1] + if itemSetId == self.itemsTab.activeItemSetId then + self.itemsTab:SetActiveItemSet(replacementItemSetId) + elseif itemSetId == self.itemsTab.viewItemSetId then + self.itemsTab:SetViewItemSet(self.list[m_max(1, index - 1)]) end self.itemsTab:AddUndoState() self.itemsTab.build:SyncLoadouts() diff --git a/src/Classes/ItemSlotControl.lua b/src/Classes/ItemSlotControl.lua index a3f658a78e3..b570b53b9c1 100644 --- a/src/Classes/ItemSlotControl.lua +++ b/src/Classes/ItemSlotControl.lua @@ -21,7 +21,7 @@ local ItemSlotClass = newClass("ItemSlotControl", "DropDownControl") function ItemSlotClass:ItemSlotControl(anchor, x, y, itemsTab, slotName, slotLabel, nodeId) self:DropDownControl(anchor, { x, y, 310, 20 }, {}, function(index, value) if self.items[index] ~= self.selItemId then - self:SetSelItemId(self.items[index]) + self:SetSelItemId(self.items[index], itemsTab:GetVisibleItemSet()) itemsTab:PopulateSlots() itemsTab:AddUndoState() itemsTab.build.buildFlag = true @@ -42,7 +42,9 @@ function ItemSlotClass:ItemSlotControl(anchor, x, y, itemsTab, slotName, slotLab if slotName:match("Flask") then self.controls.activate = new("CheckBoxControl"):CheckBoxControl({"RIGHT",self,"LEFT"}, {-2, 0, 20}, nil, function(state) self.active = state - itemsTab.activeItemSet[self.slotName].active = state + local itemSet = itemsTab:GetVisibleItemSet() + local itemSlot = itemSet and itemSet[self.slotName] + if itemSlot then itemSlot.active = state end itemsTab:AddUndoState() itemsTab.build.buildFlag = true end) @@ -69,7 +71,7 @@ function ItemSlotClass:ItemSlotControl(anchor, x, y, itemsTab, slotName, slotLab return self end -function ItemSlotClass:SetSelItemId(selItemId) +function ItemSlotClass:SetSelItemId(selItemId, targetItemSet) if self.nodeId then if self.itemsTab.build.spec then self.itemsTab.build.spec.jewels[self.nodeId] = selItemId @@ -78,7 +80,9 @@ function ItemSlotClass:SetSelItemId(selItemId) end end else - self.itemsTab.activeItemSet[self.slotName].selItemId = selItemId + local itemSet = targetItemSet or self.itemsTab:GetVisibleItemSet() + local itemSlot = itemSet and itemSet[self.slotName] + if itemSlot then itemSlot.selItemId = selItemId end end self.selItemId = selItemId end @@ -86,6 +90,12 @@ end function ItemSlotClass:Populate() if self.nodeId and self.itemsTab.build.spec then self.selItemId = self.itemsTab.build.spec.jewels[self.nodeId] or 0 + elseif not self.nodeId then + local itemSet = self.itemsTab:GetVisibleItemSet() + local itemSlot = itemSet and itemSet[self.slotName] + self.selItemId = itemSlot and itemSlot.selItemId or 0 + self.active = itemSlot and itemSlot.active or false + if self.controls.activate then self.controls.activate.state = self.active end end wipeTable(self.items) @@ -94,7 +104,7 @@ function ItemSlotClass:Populate() self.list[1] = "None" self.selIndex = 1 for _, item in pairs(self.itemsTab.items) do - if self.itemsTab:IsItemValidForSlot(item, self.slotName) then + if self.itemsTab:IsItemValidForSlot(item, self.slotName, self.itemsTab:GetVisibleItemSet()) then t_insert(self.items, item.id) t_insert(self.list, colorCodes[item.rarity]..item.name) if item.id == self.selItemId then @@ -102,8 +112,27 @@ function ItemSlotClass:Populate() end end end - if not self.selItemId or not self.itemsTab.items[self.selItemId] or not self.itemsTab:IsItemValidForSlot(self.itemsTab.items[self.selItemId], self.slotName) then - self:SetSelItemId(0) + local selectedItem = self.itemsTab.items[self.selItemId] + if not self.selItemId or not selectedItem then + self:SetSelItemId(0, self.itemsTab:GetVisibleItemSet()) + elseif not self.itemsTab:IsItemValidForSlot(selectedItem, self.slotName, self.itemsTab:GetVisibleItemSet()) then + local inspectingOtherSet = self.itemsTab.viewItemSetId and self.itemsTab.viewItemSetId ~= self.itemsTab.activeItemSetId + if inspectingOtherSet then + local alreadyListed = false + for _, itemId in ipairs(self.items) do + if itemId == self.selItemId then + alreadyListed = true + break + end + end + if not alreadyListed then + t_insert(self.items, self.selItemId) + t_insert(self.list, colorCodes.NEGATIVE..selectedItem.name) + self.selIndex = #self.list + end + else + self:SetSelItemId(0, self.itemsTab:GetVisibleItemSet()) + end end -- Update Abyssal Sockets @@ -117,23 +146,23 @@ function ItemSlotClass:Populate() if abyssalSocket.inactive then -- this can be inconvenient, but otherwise it is possible to double -- equip jewels by moving the jewel while the socket is inactive - abyssalSocket:SetSelItemId(0) + abyssalSocket:SetSelItemId(0, self.itemsTab:GetVisibleItemSet()) end end end function ItemSlotClass:CanReceiveDrag(type, value) - return type == "Item" and self.itemsTab:IsItemValidForSlot(value, self.slotName) + return type == "Item" and self.itemsTab:IsItemValidForSlot(value, self.slotName, self.itemsTab:GetVisibleItemSet()) end function ItemSlotClass:ReceiveDrag(type, value, source) if value.id and self.itemsTab.items[value.id] then - self:SetSelItemId(value.id) + self:SetSelItemId(value.id, self.itemsTab:GetVisibleItemSet()) else local newItem = new("Item"):Item(value.raw) newItem:NormaliseQuality() self.itemsTab:AddItem(newItem, true) - self:SetSelItemId(newItem.id) + self:SetSelItemId(newItem.id, self.itemsTab:GetVisibleItemSet()) self.itemsTab:AddForbiddenJewelCounterpart(newItem) end self.itemsTab:PopulateSlots() @@ -183,4 +212,4 @@ function ItemSlotClass:OnHoverKeyUp(key) end end end -end \ No newline at end of file +end diff --git a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua index 0b3852aba58..81d4db03f71 100644 --- a/src/Classes/ItemsTab.lua +++ b/src/Classes/ItemsTab.lua @@ -18,6 +18,7 @@ local m_modf = math.modf local buySimilar = require("Classes.CompareBuySimilar") local addImplicit = require("Modules.AddImplicitPopup") local gemTooltip = require("Classes.GemTooltip") +local MercenaryTools = require("Modules.MercenaryTools") local rarityDropList = { { label = colorCodes.NORMAL.."Normal", rarity = "NORMAL" }, @@ -109,7 +110,7 @@ function ItemsTabClass:ItemsTab(build) -- Set selector self.controls.setSelect = new("DropDownControl"):DropDownControl({"TOPLEFT",self,"TOPLEFT"}, {96, 8, 216, 20}, nil, function(index, value) - self:SetActiveItemSet(self.itemSetOrderList[index]) + self:SetViewItemSet(self.itemSetOrderList[index]) self:AddUndoState() end) self.controls.setSelect.enableDroppedWidth = true @@ -122,7 +123,7 @@ function ItemsTabClass:ItemsTab(build) self:AddItemSetTooltip(tooltip, self.itemSets[self.itemSetOrderList[index]]) end end - self.controls.setLabel = new("LabelControl"):LabelControl({"RIGHT",self.controls.setSelect,"LEFT"}, {-2, 0, 0, 16}, "^7Item set:") + self.controls.setLabel = new("LabelControl"):LabelControl({"RIGHT",self.controls.setSelect,"LEFT"}, {-2, 0, 0, 16}, "^7View item set:") self.controls.setManage = new("ButtonControl"):ButtonControl({"LEFT",self.controls.setSelect,"RIGHT"}, {4, 0, 90, 20}, "Manage...", function() self:OpenItemSetManagePopup() end) @@ -157,13 +158,13 @@ function ItemsTabClass:ItemsTab(build) -- Add alternate weapon slot slot.weaponSet = 1 slot.shown = function() - return not self.activeItemSet.useSecondWeaponSet + return not self:VisibleUsesSecondWeaponSet() end local swapSlot = new("ItemSlotControl"):ItemSlotControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Swap", slotName) addSlot(swapSlot) swapSlot.weaponSet = 2 swapSlot.shown = function() - return self.activeItemSet.useSecondWeaponSet + return self:VisibleUsesSecondWeaponSet() end for i = 1, 6 do local abyssal = new("ItemSlotControl"):ItemSlotControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Swap Abyssal Socket "..i, "Abyssal #"..i) @@ -171,7 +172,7 @@ function ItemsTabClass:ItemsTab(build) abyssal.parentSlot = swapSlot abyssal.weaponSet = 2 abyssal.shown = function() - return not abyssal.inactive and self.activeItemSet.useSecondWeaponSet + return not abyssal.inactive and self:VisibleUsesSecondWeaponSet() end swapSlot.abyssalSocketList[i] = abyssal end @@ -193,7 +194,7 @@ function ItemsTabClass:ItemsTab(build) if slotName:match("Weapon") then abyssal.weaponSet = 1 abyssal.shown = function() - return not abyssal.inactive and not self.activeItemSet.useSecondWeaponSet + return not abyssal.inactive and not self:VisibleUsesSecondWeaponSet() end end slot.abyssalSocketList[i] = abyssal @@ -234,47 +235,29 @@ function ItemsTabClass:ItemsTab(build) end self.controls.slotHeader = new("LabelControl"):LabelControl({"BOTTOMLEFT",self.slotAnchor,"TOPLEFT"}, {0, -4, 0, 16}, "^7Equipped items:") self.controls.weaponSwap1 = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self.slotAnchor,"TOPRIGHT"}, {-20, -2, 18, 18}, "I", function() - if self.activeItemSet.useSecondWeaponSet then - self.activeItemSet.useSecondWeaponSet = false - self:AddUndoState() - self.build.buildFlag = true - local mainSocketGroup = self.build.skillsTab.socketGroupList[self.build.mainSocketGroup] - if mainSocketGroup and mainSocketGroup.slot and self.slots[mainSocketGroup.slot].weaponSet == 2 then - for index, socketGroup in ipairs(self.build.skillsTab.socketGroupList) do - if socketGroup.slot and self.slots[socketGroup.slot].weaponSet == 1 then - self.build.mainSocketGroup = index - break - end - end - end - end + self:SetVisibleWeaponSet(false) end) self.controls.weaponSwap1.overSizeText = 3 + self.controls.weaponSwap1.shown = function() + return self:ComparisonActorForItemSet() ~= "MERCENARY" + end self.controls.weaponSwap1.locked = function() - return not self.activeItemSet.useSecondWeaponSet + return not self:VisibleUsesSecondWeaponSet() end self.controls.weaponSwap2 = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self.slotAnchor,"TOPRIGHT"}, {0, -2, 18, 18}, "II", function() - if not self.activeItemSet.useSecondWeaponSet then - self.activeItemSet.useSecondWeaponSet = true - self:AddUndoState() - self.build.buildFlag = true - local mainSocketGroup = self.build.skillsTab.socketGroupList[self.build.mainSocketGroup] - if mainSocketGroup and mainSocketGroup.slot and self.slots[mainSocketGroup.slot].weaponSet == 1 then - for index, socketGroup in ipairs(self.build.skillsTab.socketGroupList) do - if socketGroup.slot and self.slots[socketGroup.slot].weaponSet == 2 then - self.build.mainSocketGroup = index - break - end - end - end - end + self:SetVisibleWeaponSet(true) end) self.controls.weaponSwap2.overSizeText = 3 + self.controls.weaponSwap2.shown = function() + return self:ComparisonActorForItemSet() ~= "MERCENARY" + end self.controls.weaponSwap2.locked = function() - return self.activeItemSet.useSecondWeaponSet + return self:VisibleUsesSecondWeaponSet() end self.controls.weaponSwapLabel = new("LabelControl"):LabelControl({"RIGHT",self.controls.weaponSwap1,"LEFT"}, {-4, 0, 0, 14}, "^7Weapon Set:") - + self.controls.weaponSwapLabel.shown = function() + return self:ComparisonActorForItemSet() ~= "MERCENARY" + end -- All items list if main.portraitMode then self.controls.itemList = new("ItemListControl"):ItemListControl({"TOPRIGHT",self.lastSlot,"BOTTOMRIGHT"}, {0, 0, 360, 308}, self, true) @@ -1205,6 +1188,7 @@ holding Shift will put it in the second.]]) -- Initialise item sets self.itemSets = { } self.itemSetOrderList = { 1 } + self.actorItemSetIds = { } self:NewItemSet(1) self:SetActiveItemSet(1) @@ -1215,8 +1199,12 @@ end function ItemsTabClass:Load(xml, dbFileName) self.activeItemSetId = 0 + self.viewItemSetId = nil + self.viewItemSet = nil + self.viewComparisonActor = nil self.itemSets = { } self.itemSetOrderList = { } + self.actorItemSetIds = { } self.tradeQuery.statSortSelectionList = { } for _, node in ipairs(xml) do if node.elem == "Item" then @@ -1284,10 +1272,11 @@ function ItemsTabClass:Load(xml, dbFileName) for _, child in ipairs(node) do if child.elem == "Slot" then local slotName = child.attrib.name or "" - if itemSet[slotName] then - itemSet[slotName].selItemId = tonumber(child.attrib.itemId) - itemSet[slotName].active = child.attrib.active == "true" - itemSet[slotName].pbURL = child.attrib.itemPbURL or "" + local itemSlot = itemSet[slotName] + if itemSlot then + itemSlot.selItemId = tonumber(child.attrib.itemId) or 0 + itemSlot.active = child.attrib.active == "true" + itemSlot.pbURL = child.attrib.itemPbURL or "" end elseif child.elem == "SocketIdURL" then local id = tonumber(child.attrib.nodeId) @@ -1295,6 +1284,12 @@ function ItemsTabClass:Load(xml, dbFileName) end end t_insert(self.itemSetOrderList, itemSet.id) + elseif node.elem == "ActorItemSet" then + local actor = node.attrib.actor + local itemSetId = tonumber(node.attrib.itemSetId) + if actor and actor ~= "PLAYER" and itemSetId then + self.actorItemSetIds[actor] = itemSetId + end elseif node.elem == "TradeSearchWeights" then for _, child in ipairs(node) do local statSort = { @@ -1314,12 +1309,29 @@ function ItemsTabClass:Load(xml, dbFileName) end end end + local savedActiveItemSetId = tonumber(xml.attrib.activeItemSet) if not self.itemSetOrderList[1] then - self.activeItemSet = self:NewItemSet(1) - self.activeItemSet.useSecondWeaponSet = xml.attrib.useSecondWeaponSet == "true" - self.itemSetOrderList[1] = 1 + local itemSet = self:NewItemSet(1) + itemSet.useSecondWeaponSet = xml.attrib.useSecondWeaponSet == "true" + -- Legacy values lived on the UI controls; copy them into the new set. + for _, slot in ipairs(self.orderedSlots) do + if not slot.nodeId then + itemSet[slot.slotName].selItemId = slot.selItemId or 0 + itemSet[slot.slotName].active = slot.active + end + end + t_insert(self.itemSetOrderList, itemSet.id) + end + local activeItemSetId = savedActiveItemSetId + if not self.itemSets[activeItemSetId] then + activeItemSetId = self.itemSetOrderList[1] + end + self:SetActiveItemSet(activeItemSetId) + for actor, itemSetId in pairs(self.actorItemSetIds) do + if not self.itemSets[itemSetId] then + self.actorItemSetIds[actor] = nil + end end - self:SetActiveItemSet(tonumber(xml.attrib.activeItemSet) or 1) if xml.attrib.showStatDifferences then self.showStatDifferences = xml.attrib.showStatDifferences == "true" end @@ -1384,17 +1396,34 @@ function ItemsTabClass:Save(xml) for _, itemSetId in ipairs(self.itemSetOrderList) do local itemSet = self.itemSets[itemSetId] local child = { elem = "ItemSet", attrib = { id = tostring(itemSetId), title = itemSet.title, useSecondWeaponSet = tostring(itemSet.useSecondWeaponSet) } } - for slotName, slot in pairs(self.slots) do + for _, slot in ipairs(self.orderedSlots) do if not slot.nodeId then - t_insert(child, { elem = "Slot", attrib = { name = slotName, itemId = tostring(itemSet[slotName].selItemId), itemPbURL = itemSet[slotName].pbURL or "", active = itemSet[slotName].active and "true" }}) - else - if self.build.spec.allocNodes[slot.nodeId] then - t_insert(child, { elem = "SocketIdURL", attrib = { name = slotName, nodeId = tostring(slot.nodeId), itemPbURL = itemSet[slot.nodeId] and itemSet[slot.nodeId].pbURL or ""}}) + local itemSlot = itemSet[slot.slotName] + if itemSlot then + t_insert(child, { elem = "Slot", attrib = { name = slot.slotName, itemId = tostring(itemSlot.selItemId), itemPbURL = itemSlot.pbURL or "", active = itemSlot.active and "true" }}) end end end + for _, slot in ipairs(self.orderedSlots) do + if slot.nodeId and self.build.spec.allocNodes[slot.nodeId] then + t_insert(child, { elem = "SocketIdURL", attrib = { name = slot.slotName, nodeId = tostring(slot.nodeId), itemPbURL = itemSet[slot.nodeId] and itemSet[slot.nodeId].pbURL or ""}}) + end + end t_insert(xml, child) end + local actors = { } + for actor in pairs(self.actorItemSetIds) do + if actor ~= "PLAYER" then + t_insert(actors, actor) + end + end + table.sort(actors) + for _, actor in ipairs(actors) do + local itemSetId = self.actorItemSetIds[actor] + if itemSetId and self.itemSets[itemSetId] then + t_insert(xml, { elem = "ActorItemSet", attrib = { actor = actor, itemSetId = tostring(itemSetId) } }) + end + end if self.tradeQuery.statSortSelectionList then local parent = { elem = "TradeSearchWeights" @@ -1515,8 +1544,9 @@ function ItemsTabClass:Draw(viewPort, inputEvents) local newItemList = { } for index, itemSetId in ipairs(self.itemSetOrderList) do local itemSet = self.itemSets[itemSetId] - t_insert(newItemList, itemSet.title or "Default") - if itemSetId == self.activeItemSetId then + local title = itemSet.title or "Default" + t_insert(newItemList, title) + if itemSetId == self.viewItemSetId then self.controls.setSelect.selIndex = index end end @@ -1569,6 +1599,134 @@ function ItemsTabClass:Draw(viewPort, inputEvents) self.controls.specSelect:SetList(self.build.treeTab:GetSpecList()) end +function ItemsTabClass:GetVisibleItemSet() + return self.viewItemSet +end + +function ItemsTabClass:VisibleUsesSecondWeaponSet(itemSet) + if self:ComparisonActorForItemSet() == "MERCENARY" then + return false + end + itemSet = itemSet or self:GetVisibleItemSet() + return itemSet and itemSet.useSecondWeaponSet or false +end + +function ItemsTabClass:NormalizeItemSetActor(actor) + if actor == "player" then + return "PLAYER" + end + if actor == "mercenary" then + return "MERCENARY" + end + return actor +end + +function ItemsTabClass:GetActorItemSetId(actor) + actor = self:NormalizeItemSetActor(actor) + if actor == "PLAYER" then + return self.activeItemSetId + end + return self.actorItemSetIds[actor] +end + +function ItemsTabClass:GetActorItemSet(actor) + local itemSetId = self:GetActorItemSetId(actor) + return itemSetId and self.itemSets[itemSetId] +end + +-- Assign an item set to an actor. PLAYER wraps SetActiveItemSet. +-- Pass changeView == false to assign without switching the Items tab's viewed set. +function ItemsTabClass:SetActorItemSet(actor, itemSetId, changeView) + actor = self:NormalizeItemSetActor(actor) + if actor == "PLAYER" then + return self:SetActiveItemSet(itemSetId, changeView) + end + if itemSetId then + local itemSet = self.itemSets[itemSetId] + if not itemSet then + return false + end + self.actorItemSetIds[actor] = itemSetId + if changeView ~= false then + self:SetViewItemSet(itemSetId, actor) + end + else + self.actorItemSetIds[actor] = nil + end + self.build.buildFlag = true + return true +end + +function ItemsTabClass:EnsureActorItemSet(actor, title) + actor = self:NormalizeItemSetActor(actor) + local itemSet = self:GetActorItemSet(actor) + if itemSet then + return itemSet + end + if actor == "PLAYER" then + return self.activeItemSet + end + itemSet = self:NewItemSet() + itemSet.title = title or (actor == "MERCENARY" and "Mercenary Equipment" or (actor.." Equipment")) + t_insert(self.itemSetOrderList, itemSet.id) + self:SetActorItemSet(actor, itemSet.id, false) + self:AddUndoState() + self.build.buildFlag = true + return itemSet +end + +-- Changes weapon set I/II on the currently viewed item set. +-- The player's selected main skill only follows this change when that set is actually equipped. +function ItemsTabClass:SetVisibleWeaponSet(useSecond) + if self:ComparisonActorForItemSet() == "MERCENARY" then + return + end + local visibleItemSet = self:GetVisibleItemSet() + if not visibleItemSet then + return + end + local wantSecond = useSecond and true or false + if (visibleItemSet.useSecondWeaponSet and true or false) == wantSecond then + return + end + visibleItemSet.useSecondWeaponSet = wantSecond + self:AddUndoState() + self.build.buildFlag = true + if visibleItemSet ~= self.activeItemSet then + return + end + local fromSet = useSecond and 1 or 2 + local toSet = useSecond and 2 or 1 + local mainSocketGroup = self.build.skillsTab.socketGroupList[self.build.mainSocketGroup] + local fromSlot = mainSocketGroup and mainSocketGroup.slot and self.slots[mainSocketGroup.slot] + if fromSlot and fromSlot.weaponSet == fromSet then + for index, socketGroup in ipairs(self.build.skillsTab.socketGroupList) do + local toSlot = socketGroup.slot and self.slots[socketGroup.slot] + if toSlot and toSlot.weaponSet == toSet then + self.build.mainSocketGroup = index + break + end + end + end +end + +function ItemsTabClass:IsItemSetReferenced(itemSetId) + for actor, assignedId in pairs(self.actorItemSetIds) do + if actor ~= "PLAYER" and assignedId == itemSetId then + return true + end + end + local mercenaryTab = self.build.mercenaryTab + if mercenaryTab then + for _, profile in pairs(mercenaryTab.mercenarySets) do + if profile.itemSetId == itemSetId then + return true + end + end + end + return self.build.skillsTab and self.build.skillsTab:UsesItemSet(itemSetId) or false +end + -- Creates a new item set function ItemsTabClass:NewItemSet(itemSetId) local itemSet = { id = itemSetId } @@ -1578,49 +1736,96 @@ function ItemsTabClass:NewItemSet(itemSetId) itemSet.id = itemSet.id + 1 end end - for slotName, slot in pairs(self.slots) do + for _, slot in ipairs(self.orderedSlots) do if not slot.nodeId then - itemSet[slotName] = { selItemId = 0 } + itemSet[slot.slotName] = { selItemId = 0 } end end self.itemSets[itemSet.id] = itemSet return itemSet end --- Changes the active item set -function ItemsTabClass:SetActiveItemSet(itemSetId) - local prevSet = self.activeItemSet - if not self.itemSets[itemSetId] then - itemSetId = self.itemSetOrderList[1] +local function isTreeJewelSlot(slotName) + return type(slotName) == "string" and slotName:match("^Jewel ") ~= nil +end + +function ItemsTabClass:ComparisonActorForItemSet(itemSetId) + itemSetId = itemSetId or self.viewItemSetId + if itemSetId and itemSetId == self.viewItemSetId and self.viewComparisonActor then + return self.viewComparisonActor + end + if self:GetActorItemSetId("MERCENARY") == itemSetId and self:GetActorItemSetId("PLAYER") ~= itemSetId then + return "MERCENARY" + end + return "PLAYER" +end + +function ItemsTabClass:ComparisonActorForSlot(slotName, itemSetId) + if isTreeJewelSlot(slotName) then + return "PLAYER" + end + if MercenaryTools.baseItemSlotName(slotName) then + return "MERCENARY" + end + return self:ComparisonActorForItemSet(itemSetId) +end + +function ItemsTabClass:ItemCalculationOverride(slotName, item, itemSetId) + itemSetId = itemSetId or self.viewItemSetId + local isTreeJewel = isTreeJewelSlot(slotName) + return { + itemSetId = (not isTreeJewel) and itemSetId or nil, + comparisonActor = self:ComparisonActorForSlot(slotName, itemSetId), + repSlotName = slotName, + repItem = item, + } +end + +function ItemsTabClass:SetViewItemSet(itemSetId, comparisonActor) + local itemSet = self.itemSets[itemSetId] + if not itemSet then + return false + end + self.viewItemSetId = itemSet.id + self.viewItemSet = itemSet + if comparisonActor == "MERCENARY" or comparisonActor == "PLAYER" then + self.viewComparisonActor = comparisonActor + else + self.viewComparisonActor = nil + end + self.build.buildFlag = true + self:PopulateSlots() + self:UpdateSockets() + return true +end + +-- Changes the active player item set. Missing IDs are rejected. +-- Pass changeView == false to equip without switching the Items tab's viewed set. +function ItemsTabClass:SetActiveItemSet(itemSetId, changeView) + local itemSet = self.itemSets[itemSetId] + if not itemSet then + return false end self.activeItemSetId = itemSetId - self.activeItemSet = self.itemSets[itemSetId] - local curSet = self.activeItemSet - for slotName, slot in pairs(self.slots) do - if not slot.nodeId then - if prevSet then - -- Update the previous set - prevSet[slotName].selItemId = slot.selItemId - prevSet[slotName].active = slot.active - end - -- Equip the incoming set's item - slot.selItemId = curSet[slotName].selItemId - slot.active = curSet[slotName].active - if slot.controls.activate then - slot.controls.activate.state = slot.active - end - end + self.activeItemSet = itemSet + if changeView ~= false then + self.viewItemSetId = itemSetId + self.viewItemSet = itemSet + self.viewComparisonActor = nil end self.build.buildFlag = true self:PopulateSlots() + self:UpdateSockets() self.build:SyncLoadouts() + return true end -- Equips the given item in the given item set function ItemsTabClass:EquipItemInSet(item, itemSetId) local itemSet = self.itemSets[itemSetId] local slotName = item:GetPrimarySlot() - if self.slots[slotName].weaponSet == 1 and itemSet.useSecondWeaponSet then + local slot = self.slots[slotName] + if slot and slot.weaponSet == 1 and itemSet.useSecondWeaponSet and self:ComparisonActorForItemSet(itemSetId) ~= "MERCENARY" then -- Redirect to second weapon set slotName = slotName .. " Swap" end @@ -1635,12 +1840,14 @@ function ItemsTabClass:EquipItemInSet(item, itemSetId) slotName = altSlot end end - if itemSet == self.activeItemSet then - self.slots[slotName]:SetSelItemId(item.id) + if itemSet == self:GetVisibleItemSet() and self.slots[slotName] then + self.slots[slotName]:SetSelItemId(item.id, itemSet) else - itemSet[slotName].selItemId = item.id - if itemSet[altSlot].selItemId ~= 0 and not self:IsItemValidForSlot(self.items[itemSet[altSlot].selItemId], altSlot, itemSet) then - itemSet[altSlot].selItemId = 0 + local itemSlot = itemSet[slotName] + if itemSlot then itemSlot.selItemId = item.id end + local altItemSlot = itemSet[altSlot] + if altItemSlot and altItemSlot.selItemId ~= 0 and not self:IsItemValidForSlot(self.items[altItemSlot.selItemId], altSlot, itemSet) then + altItemSlot.selItemId = 0 end end self:PopulateSlots() @@ -1657,6 +1864,8 @@ end -- Updates the status and position of the socket controls function ItemsTabClass:UpdateSockets() + self.lastSlot = self.slots[baseSlots[#baseSlots]] + if not self.build.spec then return end -- Build a list of active sockets local activeSocketList = { } for nodeId, slot in pairs(self.sockets) do @@ -1670,7 +1879,6 @@ function ItemsTabClass:UpdateSockets() table.sort(activeSocketList) -- Update the state of the active socket controls - self.lastSlot = self.slots[baseSlots[#baseSlots]] for index, nodeId in ipairs(activeSocketList) do self.sockets[nodeId].label = "Socket #"..index self.lastSlot = self.sockets[nodeId] @@ -1700,9 +1908,10 @@ function ItemsTabClass:AddItem(item, noAutoEquip, index) if not noAutoEquip then -- Autoequip it + local visibleItemSet = self:GetVisibleItemSet() for _, slot in ipairs(self.orderedSlots) do - if not slot.nodeId and slot.selItemId == 0 and slot:IsShown() and self:IsItemValidForSlot(item, slot.slotName) then - slot:SetSelItemId(item.id) + if not slot.nodeId and slot.selItemId == 0 and slot:IsShown() and self:IsItemValidForSlot(item, slot.slotName, visibleItemSet) then + slot:SetSelItemId(item.id, visibleItemSet) break end end @@ -1857,13 +2066,14 @@ end function ItemsTabClass:DeleteItem(item, deferUndoState) for slotName, slot in pairs(self.slots) do if slot.selItemId == item.id then - slot:SetSelItemId(0) + slot.selItemId = 0 self.build.buildFlag = true end if not slot.nodeId then for _, itemSet in pairs(self.itemSets) do - if itemSet[slotName].selItemId == item.id then - itemSet[slotName].selItemId = 0 + local itemSlot = itemSet[slotName] + if itemSlot and itemSlot.selItemId == item.id then + itemSlot.selItemId = 0 self.build.buildFlag = true end end @@ -1905,12 +2115,15 @@ end function ItemsTabClass:CopyAnointsAndEldritchImplicits(newItem, copyEldritchImplicits, overwrite, sourceSlotName) local newItemType = sourceSlotName or (newItem.base.weapon and "Weapon 1" or newItem.base.type) - if self.activeItemSet[newItemType] then - local currentItem = self.activeItemSet[newItemType].selItemId and self.items[self.activeItemSet[newItemType].selItemId] + local itemSet = self:GetVisibleItemSet() + local itemSetSlotName = newItemType + local itemSetSlot = itemSet and itemSet[itemSetSlotName] + if itemSetSlot then + local currentItem = itemSetSlot.selItemId and self.items[itemSetSlot.selItemId] -- if you don't have an equipped item that matches the type of the newItem, no need to do anything if currentItem then -- if the new item is anointable and does not have an anoint and your current respective item does, apply that anoint to the new item - if isAnointable(newItem) and (#newItem.enchantModLines == 0 or overwrite) and self.activeItemSet[newItemType].selItemId > 0 then + if isAnointable(newItem) and (#newItem.enchantModLines == 0 or overwrite) and itemSetSlot.selItemId > 0 then local currentAnoint = currentItem.enchantModLines if currentAnoint and #currentAnoint == 1 then -- skip if amulet has more than one anoint e.g. Stranglegasp newItem.enchantModLines = currentAnoint @@ -1935,7 +2148,7 @@ function ItemsTabClass:CopyAnointsAndEldritchImplicits(newItem, copyEldritchImpl end -- harvest and heist enchantments on modifiable body armour or weapons - if (newItem.base.weapon or newItem.base.type == "Body Armour") and (#newItem.enchantModLines == 0 or overwrite) and self.activeItemSet[newItemType].selItemId > 0 and modifiableItem and currentItem.enchantModLines then + if (newItem.base.weapon or newItem.base.type == "Body Armour") and (#newItem.enchantModLines == 0 or overwrite) and itemSetSlot.selItemId > 0 and modifiableItem and currentItem.enchantModLines then newItem.enchantModLines = currentItem.enchantModLines end @@ -2349,7 +2562,7 @@ function ItemsTabClass:UpdateAffixControl(control, item, affixType, outputTable, end testSubject:BuildAndParseRaw() power = data.powerStatList.GetFromOutput( - calcFunc({ repSlotName = slotName, repItem = testSubject }), + calcFunc(self:ItemCalculationOverride(slotName, testSubject)), sortOption ) testSubject = new("Item"):Item(originalItem) @@ -2366,7 +2579,7 @@ function ItemsTabClass:UpdateAffixControl(control, item, affixType, outputTable, testSubject:BuildModList() power = data.powerStatList.GetFromOutput( - calcFunc({ repSlotName = slotName, repItem = testSubject }), + calcFunc(self:ItemCalculationOverride(slotName, testSubject)), sortOption ) for _ = 1, modCount do @@ -2519,22 +2732,37 @@ function ItemsTabClass:AddModComparisonTooltip(tooltip, mod, replaceImplicits) newItem:BuildAndParseRaw() local calcFunc = self.build.calcsTab:GetMiscCalculator() - local outputBase = calcFunc({ repSlotName = slotName, repItem = self.displayItem }) - local outputNew = calcFunc({ repSlotName = slotName, repItem = newItem }) + local outputBase = calcFunc(self:ItemCalculationOverride(slotName, self.displayItem)) + local outputNew = calcFunc(self:ItemCalculationOverride(slotName, newItem)) self.build:AddStatComparesToTooltip(tooltip, outputBase, outputNew, "\nAdding this mod will give: ") end --- Returns the first slot in which the given item is equipped +-- Returns the first slot in which the given item is equipped. +-- Actively worn equipment returns (slot) with no item set; other sets return (slot, itemSet). function ItemsTabClass:GetEquippedSlotForItem(item) for _, slot in ipairs(self.orderedSlots) do if not slot.inactive then - if slot.selItemId == item.id then - return slot + if slot.nodeId then + if slot.selItemId == item.id then + return slot + end + else + local activeSlot = self.activeItemSet and self.activeItemSet[slot.slotName] + if activeSlot and activeSlot.selItemId == item.id then + return slot + end end + end + end + for _, slot in ipairs(self.orderedSlots) do + if not slot.inactive and not slot.nodeId then for _, itemSetId in ipairs(self.itemSetOrderList) do - local itemSet = self.itemSets[itemSetId] - if itemSetId ~= self.activeItemSetId and itemSet[slot.slotName] and itemSet[slot.slotName].selItemId == item.id then - return slot, itemSet + if itemSetId ~= self.activeItemSetId then + local itemSet = self.itemSets[itemSetId] + local itemSlot = itemSet and itemSet[slot.slotName] + if itemSlot and itemSlot.selItemId == item.id then + return slot, itemSet + end end end end @@ -2557,7 +2785,8 @@ function ItemsTabClass:GetComparisonSlotNameForItem(item) end -- Check if the given item could be equipped in the given slot, taking into account possible conflicts with currently equipped items -- For example, a shield is not valid for Weapon 2 if Weapon 1 is a staff, and a wand is not valid for Weapon 2 if Weapon 1 is a dagger -function ItemsTabClass:IsItemValidForSlot(item, slotName, itemSet) +-- equippedLookup(slotName), when provided, resolves counterpart slots (preview replacements) instead of itemSet. +function ItemsTabClass:IsItemValidForSlot(item, slotName, itemSet, equippedLookup) itemSet = itemSet or self.activeItemSet local slotType, slotId = slotName:match("^([%a ]+) (%d+)$") if not slotType then @@ -2593,8 +2822,16 @@ function ItemsTabClass:IsItemValidForSlot(item, slotName, itemSet) elseif slotName == "Weapon 1" or slotName == "Weapon 1 Swap" or slotName == "Weapon" then return item.base.weapon ~= nil elseif slotName == "Weapon 2" or slotName == "Weapon 2 Swap" then - local weapon1Sel = itemSet[slotName == "Weapon 2" and "Weapon 1" or "Weapon 1 Swap"].selItemId or 0 - local weapon1Type = self.items[weapon1Sel] and self.items[weapon1Sel].base.type or "None" + local weapon1SlotName = slotName == "Weapon 2" and "Weapon 1" or "Weapon 1 Swap" + local weapon1Item + if equippedLookup then + weapon1Item = equippedLookup(weapon1SlotName) + else + local weapon1Slot = itemSet and itemSet[weapon1SlotName] + local weapon1Sel = weapon1Slot and weapon1Slot.selItemId or 0 + weapon1Item = self.items[weapon1Sel] + end + local weapon1Type = weapon1Item and weapon1Item.base.type or "None" if weapon1Type == "None" then return item.type == "Shield" or (self.build.data.weaponTypeInfo[item.type] and self.build.data.weaponTypeInfo[item.type].oneHand) elseif weapon1Type == "Bow" then @@ -2612,10 +2849,10 @@ function ItemsTabClass:OpenItemSetManagePopup() controls.sharedList = new("SharedItemSetListControl"):SharedItemSetListControl(nil, {155, 50, 300, 200}, self) controls.setList.dragTargetList = { controls.sharedList } controls.sharedList.dragTargetList = { controls.setList } - controls.close = new("ButtonControl"):ButtonControl(nil, {0, 260, 90, 20}, "Done", function() + controls.close = new("ButtonControl"):ButtonControl(nil, {0, 290, 90, 20}, "Done", function() main:ClosePopup() end) - main:OpenPopup(630, 290, "Manage Item Sets", controls) + main:OpenPopup(630, 320, "Manage Item Sets", controls) end -- Opens the item crafting popup @@ -2875,7 +3112,7 @@ function ItemsTabClass:EnchantDisplayItem(enchantSlot) t_insert(item.enchantModLines, self.enchantSlot, { crafted = true, line = line }) end item:BuildAndParseRaw() - local output = calcFunc({ repSlotName = slotName, repItem = item }, useFullDPS) + local output = calcFunc(self:ItemCalculationOverride(slotName, item), useFullDPS) local value = data.powerStatList.GetFromOutput(output, sortStats[stat]) entry.sortValues[stat] = value return value @@ -3057,8 +3294,8 @@ function ItemsTabClass:AppendAnointTooltip(tooltip, node, actionText) end local calcFunc = self.build.calcsTab:GetMiscCalculator() local repSlotName = self.displayItem.base and self.displayItem.base.type or "Amulet" - local outputBase = calcFunc({ repSlotName = repSlotName, repItem = self.displayItem }) - local outputNew = calcFunc({ repSlotName = repSlotName, repItem = self:anointItem(node) }) + local outputBase = calcFunc(self:ItemCalculationOverride(repSlotName, self.displayItem)) + local outputNew = calcFunc(self:ItemCalculationOverride(repSlotName, self:anointItem(node))) local numChanges = self.build:AddStatComparesToTooltip(tooltip, outputBase, outputNew, header) if node and numChanges == 0 then tooltip:AddLine(14, "^7"..actionText.." "..node.dn.." changes nothing.") @@ -3236,7 +3473,7 @@ function ItemsTabClass:CorruptDisplayItem() end end item:BuildAndParseRaw() - local output = calcFunc({ repSlotName = slotName, repItem = item }, useFullDPS) + local output = calcFunc(self:ItemCalculationOverride(slotName, item), useFullDPS) local value = data.powerStatList.GetFromOutput(output, sortStats[stat]) entry.sortValues[stat] = value return value @@ -3536,7 +3773,7 @@ function ItemsTabClass:AddCustomModifierToDisplayItem() t_insert(item.explicitModLines, { line = checkLineForAllocates(line, self.build.spec.nodes), modTags = listMod.mod.modTags, [listMod.type] = true }) end item:BuildAndParseRaw() - local output = calcFunc({ repSlotName = slotName, repItem = item }, useFullDPS) + local output = calcFunc(self:ItemCalculationOverride(slotName, item), useFullDPS) local value = data.powerStatList.GetFromOutput(output, sortStats[stat]) listMod.sortValues[stat] = value return value @@ -3978,11 +4215,11 @@ function ItemsTabClass:AddCrucibleModifierToDisplayItem() main:OpenPopup(710, 185, "Add Crucible Modifier to Item", controls, "save") end - function ItemsTabClass:AddItemSetTooltip(tooltip, itemSet) for _, slot in ipairs(self.orderedSlots) do if not slot.nodeId then - local item = self.items[itemSet[slot.slotName].selItemId] + local itemSlot = itemSet[slot.slotName] + local item = itemSlot and self.items[itemSlot.selItemId] if item then tooltip:AddLine(16, s_format("^7%s: %s%s", slot.label, colorCodes[item.rarity], item.name)) end @@ -4662,7 +4899,7 @@ end ---@param item Item ---@param base any function ItemsTabClass:AddItemStatDifferences(tooltip, item, base, slot) - local calcFunc, calcBase = self.build.calcsTab:GetMiscCalculator() + local calcFunc, calcBase, calcBaseByActor = self.build.calcsTab:GetMiscCalculator() if base.flask then -- Special handling for flasks local stats = {} @@ -4910,16 +5147,17 @@ function ItemsTabClass:AddItemStatDifferences(tooltip, item, base, slot) else self:UpdateSockets() -- Build sorted list of slots to compare with - local compareSlots = {} + local compareSlots = { } + local visibleItemSet = self:GetVisibleItemSet() for slotName, slot in pairs(self.slots) do - if self:IsItemValidForSlot(item, slotName) and not slot.inactive and (not slot.weaponSet or slot.weaponSet == (self.activeItemSet.useSecondWeaponSet and 2 or 1)) and slot.shown() then + if self:IsItemValidForSlot(item, slotName, visibleItemSet) and not slot.inactive and (not slot.weaponSet or slot.weaponSet == (self:VisibleUsesSecondWeaponSet(visibleItemSet) and 2 or 1)) and slot.shown() then t_insert(compareSlots, slot) end end local function getReplacedItemAndOutput(compareSlot) local selItem = self.items[compareSlot.selItemId] - local override = { repSlotName = compareSlot.slotName, repItem = item ~= selItem and item or nil } + local override = self:ItemCalculationOverride(compareSlot.slotName, item ~= selItem and item or nil) if compareSlot.nodeId and (itemChangesPassiveTree(selItem) or itemChangesPassiveTree(item)) then override.spec = buildSpecForJewelComparison(self, compareSlot, override.repItem) end @@ -4936,7 +5174,19 @@ function ItemsTabClass:AddItemStatDifferences(tooltip, item, base, slot) else header = string.format("^7Equipping this item in %s will give you:%s", compareSlot.label or compareSlot.slotName, selItem and "\n(replacing " .. colorCodes[selItem.rarity] .. selItem.name .. "^7)" or "") end - self.build:AddStatComparesToTooltip(tooltip, calcBase, output, header) + local comparisonActor = self:ComparisonActorForSlot(compareSlot.slotName) + if comparisonActor == "PLAYER" then + comparisonActor = nil + end + local compareBase = comparisonActor and calcBaseByActor.MERCENARY or calcBase + if comparisonActor and not MercenaryTools.mercenaryOutputAvailable(compareBase) then + tooltip:AddLine(16, colorCodes.WARNING.."Mercenary comparison unavailable") + return + end + if not output then + return + end + self.build:AddStatComparesToTooltip(tooltip, compareBase, output, header, nil, comparisonActor) end -- if we have a specific slot to compare to, and the user has "Show @@ -5021,6 +5271,9 @@ end function ItemsTabClass:CreateUndoState() local state = { } state.activeItemSetId = self.activeItemSetId + state.actorItemSetIds = copyTable(self.actorItemSetIds) + state.viewItemSetId = self.viewItemSetId + state.viewComparisonActor = self.viewComparisonActor state.items = { } for k, v in pairs(self.items) do state.items[k] = copyTableSafe(self.items[k], true, true) @@ -5041,15 +5294,24 @@ function ItemsTabClass:RestoreUndoState(state) for k, v in pairs(state.itemOrderList) do self.itemOrderList[k] = v end - for slotName, selItemId in pairs(state.slotSelItemId) do - self.slots[slotName]:SetSelItemId(selItemId) - end self.itemSets = state.itemSets wipeTable(self.itemSetOrderList) for k, v in pairs(state.itemSetOrderList) do self.itemSetOrderList[k] = v end + self.actorItemSetIds = copyTable(state.actorItemSetIds) self.activeItemSetId = state.activeItemSetId self.activeItemSet = self.itemSets[self.activeItemSetId] + local viewItemSetId = state.viewItemSetId + if not self.itemSets[viewItemSetId] then + viewItemSetId = self.activeItemSetId + end + self.viewItemSetId = viewItemSetId + self.viewItemSet = self.itemSets[self.viewItemSetId] + self.viewComparisonActor = state.viewComparisonActor + for slotName, selItemId in pairs(state.slotSelItemId) do + local slot = self.slots[slotName] + if slot and slot.nodeId then slot:SetSelItemId(selItemId) end + end self:PopulateSlots() end diff --git a/src/Classes/MercenarySetListControl.lua b/src/Classes/MercenarySetListControl.lua new file mode 100644 index 00000000000..c5016893244 --- /dev/null +++ b/src/Classes/MercenarySetListControl.lua @@ -0,0 +1,135 @@ +-- Path of Building +-- +-- Class: Mercenary Set List +-- Mercenary loadout list control. +-- +local t_insert = table.insert +local t_remove = table.remove +local m_max = math.max + +---@class MercenarySetListControl: ListControl +local MercenarySetListClass = newClass("MercenarySetListControl", "ListControl") + +function MercenarySetListClass:MercenarySetListControl(anchor, rect, mercenaryTab) + self:ListControl(anchor, rect, 16, "VERTICAL", true, mercenaryTab.mercenarySetOrderList) + self.mercenaryTab = mercenaryTab + self.controls.copy = new("ButtonControl"):ButtonControl({"BOTTOMLEFT", self, "TOP"}, {2, -4, 60, 18}, "Copy", function() + local set = mercenaryTab.mercenarySets[self.selValue] + local newSet = copyTable(set) + newSet.importAssociation = nil + newSet.id = 1 + while mercenaryTab.mercenarySets[newSet.id] do + newSet.id = newSet.id + 1 + end + mercenaryTab.mercenarySets[newSet.id] = newSet + self:RenameSet(newSet, true) + end) + self.controls.copy.enabled = function() + return self.selValue ~= nil + end + self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT", self.controls.copy, "RIGHT"}, {4, 0, 60, 18}, "Delete", function() + self:OnSelDelete(self.selIndex, self.selValue) + end) + self.controls.delete.enabled = function() + return self.selValue ~= nil and #self.list > 1 + end + self.controls.rename = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT", self, "TOP"}, {-2, -4, 60, 18}, "Rename", function() + self:RenameSet(mercenaryTab.mercenarySets[self.selValue]) + end) + self.controls.rename.enabled = function() + return self.selValue ~= nil + end + self.controls.new = new("ButtonControl"):ButtonControl({"RIGHT", self.controls.rename, "LEFT"}, {-4, 0, 60, 18}, "New", function() + self:RenameSet(mercenaryTab:NewMercenarySet(), true) + end) + return self +end + +function MercenarySetListClass:RenameSet(set, addOnName) + local controls = { } + controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this Mercenary loadout:") + controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, set.title, nil, nil, 100, function(buf) + controls.save.enabled = buf:match("%S") + end) + controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function() + set.title = controls.edit.buf + self.mercenaryTab.modFlag = true + if addOnName then + local itemsTab = self.mercenaryTab.build.itemsTab + local source = set.itemSetId and itemsTab.itemSets[set.itemSetId] + if source then + local cloned = copyTable(source) + cloned.id = 1 + while itemsTab.itemSets[cloned.id] do + cloned.id = cloned.id + 1 + end + cloned.title = set.title + itemsTab.itemSets[cloned.id] = cloned + t_insert(itemsTab.itemSetOrderList, cloned.id) + set.itemSetId = cloned.id + itemsTab:AddUndoState() + end + t_insert(self.list, set.id) + self.selIndex = #self.list + self.selValue = set.id + end + self.mercenaryTab:RefreshControls() + self.mercenaryTab:AddUndoState() + self.mercenaryTab.build:SyncLoadouts() + main:ClosePopup() + end) + controls.save.enabled = false + controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function() + if addOnName then + self.mercenaryTab.mercenarySets[set.id] = nil + end + main:ClosePopup() + end) + main:OpenPopup(370, 100, set.title and "Rename" or "Set Name", controls, "save", "edit", "cancel") +end + +function MercenarySetListClass:GetRowValue(column, _, setId) + local set = self.mercenaryTab.mercenarySets[setId] + if column == 1 then + return (set.title or "Default") .. (setId == self.mercenaryTab.activeMercenarySetId and " ^9(Current)" or "") + end +end + +function MercenarySetListClass:OnOrderChange() + self.mercenaryTab.modFlag = true + self.mercenaryTab:AddUndoState() +end + +function MercenarySetListClass:OnSelClick(_, setId, doubleClick) + if doubleClick and setId ~= self.mercenaryTab.activeMercenarySetId then + self.mercenaryTab:SetActiveMercenarySet(setId, false, true) + self.mercenaryTab:AddUndoState() + end +end + +function MercenarySetListClass:OnSelDelete(index, setId) + local set = self.mercenaryTab.mercenarySets[setId] + if #self.list > 1 then + main:OpenConfirmPopup("Delete Mercenary Loadout", "Are you sure you want to delete '"..(set.title or "Default").."'?", "Delete", function() + self.mercenaryTab:ClearConfigBindings(setId) + t_remove(self.list, index) + self.mercenaryTab.mercenarySets[setId] = nil + self.selIndex = nil + self.selValue = nil + if setId == self.mercenaryTab.activeMercenarySetId then + self.mercenaryTab:SetActiveMercenarySet(self.list[m_max(1, index - 1)], false, false) + else + self.mercenaryTab:RefreshControls() + self.mercenaryTab.build:SyncLoadouts() + end + self.mercenaryTab:AddUndoState() + self.mercenaryTab.modFlag = true + end) + end +end + +function MercenarySetListClass:OnSelKeyDown(_, setId, key) + if key == "F2" then + self:RenameSet(self.mercenaryTab.mercenarySets[setId]) + end +end diff --git a/src/Classes/MercenaryTab.lua b/src/Classes/MercenaryTab.lua new file mode 100644 index 00000000000..c7250269543 --- /dev/null +++ b/src/Classes/MercenaryTab.lua @@ -0,0 +1,1305 @@ +-- Path of Building +-- +-- Class: Mercenary Tab +-- Permanent Mercenary configuration, persistence, import, and equipment validation. +-- +local MercenaryTools = require("Modules.MercenaryTools") +local skillOptions = require("Modules.SkillOptions") +local gemTooltip = LoadModule("Classes/GemTooltip") + +local t_insert = table.insert +local t_remove = table.remove +local t_sort = table.sort +local m_floor = math.floor +local m_min = math.min +local m_max = math.max + +local function gemColorLabel(color) + if not color then return "" end + return (data.skillColorMap[color] or colorCodes.NORMAL) +end + +local function supportLabel(support) + return gemColorLabel(support and support.color)..(support and support.name or "?").." (Tier "..(support and support.variant or "?")..")" +end + +local function mercenaryLevel(build, foundAreaLevel) + local currentAreaLevel = build.configTab and build.configTab.enemyLevel + return MercenaryTools.effectiveLevel(foundAreaLevel, currentAreaLevel) +end + +local function forEachConfigSet(mercenaryTab, fn) + local configTab = mercenaryTab.build.configTab + if not configTab then + return + end + for configSetId, configSet in pairs(configTab.configSets) do + fn(configTab, configSetId, configSet) + end +end + +local function itemSetOwnedByMercenary(mercenaryTab, itemSetId, excludeActive) + if not itemSetId then + return false + end + for setId, profile in pairs(mercenaryTab.mercenarySets) do + if profile.itemSetId == itemSetId and (not excludeActive or setId ~= mercenaryTab.activeMercenarySetId) then + return true + end + end + return false +end + +---@class MercenarySkillListControl: ListControl +local MercenarySkillListClass = newClass("MercenarySkillListControl", "ListControl") + +function MercenarySkillListClass:MercenarySkillListControl(anchor, rect, mercenaryTab) + self:ListControl(anchor, rect, 16, "VERTICAL", true, mercenaryTab.profile.skills) + self.mercenaryTab = mercenaryTab + self.label = "^7Skill Groups:" + self.controls.delete = new("ButtonControl"):ButtonControl({ "BOTTOMRIGHT", self, "TOPRIGHT" }, { 0, -2, 60, 18 }, "Delete", function() + self:OnSelDelete(self.selIndex) + end) + self.controls.delete.enabled = function() + return self.selValue ~= nil + end + self.controls.new = new("ButtonControl"):ButtonControl({ "RIGHT", self.controls.delete, "LEFT" }, { -4, 0, 60, 18 }, "New", function() + mercenaryTab:AddSkill() + end) + self.controls.new.enabled = function() + return MercenaryTools.firstLegalSkillId(mercenaryTab.profile, mercenaryTab.data) ~= nil + end + return self +end + +function MercenarySkillListClass:GetRowValue(_, _, skill) + local skillData = self.mercenaryTab.data.skills[skill.id] + local skillEffect = self.mercenaryTab.build.data.skills[skill.id] + local label = gemColorLabel(skillEffect and skillEffect.color)..(skillData and skillData.name or skill.id or "?") + if skill.enabled == false then label = colorCodes.NEGATIVE..label.." (Disabled)" end + if skill.includeInFullDPS then label = label..colorCodes.CUSTOM.." (FullDPS)" end + if #(skill.supports or { }) > 0 then label = label.." ^7+ "..#skill.supports.." support"..(#skill.supports == 1 and "" or "s") end + return label +end + +function MercenarySkillListClass:OnHoverKeyUp(key) + local skill = self.ListControl:GetHoverValue() + if not skill then return end + local skillData = self.mercenaryTab.data.skills[skill.id] + if itemLib.wiki.matchesKey(key) then + if skillData then itemLib.wiki.openGem(skillData.name) end + elseif key == "RIGHTBUTTON" and IsKeyDown("CTRL") then + skill.includeInFullDPS = not skill.includeInFullDPS + self.mercenaryTab:Changed() + elseif key == "LEFTBUTTON" and IsKeyDown("CTRL") then + self.mercenaryTab:SetSkillEnabled(skill, skill.enabled == false) + end +end + +function MercenarySkillListClass:OnSelect(index) + self.mercenaryTab.selectedSkillIndex = index + self.mercenaryTab:RefreshControls() +end + +function MercenarySkillListClass:AddValueTooltip(tooltip, _, skill) + local tab = self.mercenaryTab + if tooltip:CheckForUpdate(skill, tab.build.outputRevision, mercenaryLevel(tab.build, tab.profile.foundAreaLevel)) then + tooltip:Clear() + tab:AddSkillTooltip(tooltip, skill, false) + end +end + +function MercenarySkillListClass:OnSelDelete(index) + if index then self.mercenaryTab:SetSkill(index, nil) end +end + +function MercenarySkillListClass:OnOrderChange(_, newIndex) + self.mercenaryTab.selectedSkillIndex = newIndex + self.mercenaryTab:Changed() +end + +---@class MercenaryTab: UndoHandler, ControlHost, Control +local MercenaryTabClass = newClass("MercenaryTab", "UndoHandler", "ControlHost", "Control") + +function MercenaryTabClass:MercenaryTab(build) + self:UndoHandler() + self:ControlHost() + self:Control() + self.build = build + self.data = nil + self.classGroups, self.classGroupsByClassId = { }, { } + self.mercenarySets = { } + self.mercenarySetOrderList = { 1 } + self:NewMercenarySet(1) + self.activeMercenarySetId = 1 + self.profile = self.mercenarySets[1] + self.sortGemsByDPS = true + self.sortGemsByDPSField = "CombinedDPS" + self.supportSortRevision = 0 + self.supportSortCache = { } + self.supportSortCoroutine = nil + self.supportSortStatus = "" + self.selectedSkillIndex = 1 + self.controls.classLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self, "TOPLEFT" }, { 12, 12, 0, 16 }, "^7Mercenary class:") + self.controls.class = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.classLabel, "RIGHT" }, { 8, 0, 240, 20 }, { }, function(_, value) + local classGroup = value + self.profile.importedWarrant = nil + self.profile.classId = classGroup and classGroup.classIds[1] + self.profile.buildId = nil + self.profile.skills = { } + self.profile.mainSkillId = nil + self.selectedSkillIndex = 1 + self:Changed() + end) + self.controls.class:SetList(self.classGroups) + self.controls.setLabel = new("LabelControl"):LabelControl({ "LEFT", self.controls.class, "RIGHT" }, { 20, 0, 0, 16 }, "^7Mercenary set:") + self.controls.setSelect = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.setLabel, "RIGHT" }, { 8, 0, 210, 20 }, { }, function(_, value) + if not value then + return + end + local configTab = self.build.configTab + local configSet = configTab and configTab.configSets[configTab.activeConfigSetId] + local alreadyBound = configSet and configSet.mercenarySetId == value.id + if value.id == self.activeMercenarySetId and alreadyBound then + return + end + self:SetActiveMercenarySet(value.id, false, true) + self:AddUndoState() + end) + self.controls.setSelect.enableDroppedWidth = true + self.controls.setSelect.enabled = function() + return #self.mercenarySetOrderList > 1 + end + self.controls.setManage = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.setSelect, "RIGHT" }, { 4, 0, 90, 20 }, "Manage...", function() + self:OpenMercenarySetManagePopup() + end) + self.controls.buildLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.classLabel, "BOTTOMLEFT" }, { 0, 12, 0, 16 }, "^7Class and build:") + self.controls.build = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.buildLabel, "RIGHT" }, { 8, 0, 300, 20 }, { }, function(_, value) + self.profile.importedWarrant = nil + self.profile.buildId = value and value.id + self.profile.classId = value and value.classId or self.profile.classId + self.profile.skills = { } + self.profile.mainSkillId = nil + self.selectedSkillIndex = 1 + self:Changed() + end) + self.controls.levelLabel = new("LabelControl"):LabelControl({ "LEFT", self.controls.build, "RIGHT" }, { 20, 0, 0, 16 }, "^7Mercenary level:") + self.controls.level = new("EditControl"):EditControl({ "LEFT", self.controls.levelLabel, "RIGHT" }, { 6, 0, 55, 20 }, "68", nil, "%D", 3, function(buf) + self.profile.foundAreaLevel = m_min(m_max(tonumber(buf) or 1, 1), 100) + self:Changed() + end) + + self.controls.editEquipment = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.buildLabel, "BOTTOMLEFT" }, { 0, 14, 150, 20 }, "Edit Equipment", function() + local itemsTab = build.itemsTab + local itemSet = itemsTab:GetActorItemSet("MERCENARY") or self:GetItemSet(true) + itemsTab:SetViewItemSet(itemSet.id, "MERCENARY") + build.viewMode = "ITEMS" + end) + self.controls.reset = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.editEquipment, "RIGHT" }, { 8, 0, 80, 20 }, "Reset", function() + self:Reset() + end) + self.controls.importWarrant = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.reset, "RIGHT" }, { 8, 0, 120, 20 }, "Import Warrant...", function() + self:OpenWarrantImportPopup() + end) + self.controls.lifeComparisonLabel = new("LabelControl"):LabelControl({ "LEFT", self.controls.importWarrant, "RIGHT" }, { 20, 0, 0, 16 }, "^7Loyal Bodyguard:") + self.controls.lifeComparison = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.lifeComparisonLabel, "RIGHT" }, { 6, 0, 170, 20 }, { + { label = "Automatic Life comparison", id = "AUTO" }, + { label = "Mercenary has higher Life", id = "MERCENARY" }, + { label = "Player has higher Life", id = "PLAYER" }, + }, function(_, value) + self.profile.lifeComparison = value.id + self:Changed() + end) + self.controls.skillList = new("MercenarySkillListControl"):MercenarySkillListControl({ "TOPLEFT", self.controls.editEquipment, "BOTTOMLEFT" }, { 0, 32, 360, 300 }, self) + self.controls.skillTip = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillList, "BOTTOMLEFT" }, { 0, 8, 0, 14 }, [[ +^7Usage Tips: +- Ctrl + Click to enable/disable skill groups. +- Ctrl + Right click to include/exclude in Full DPS calculations. +]]) + self.controls.optionSection = new("SectionControl"):SectionControl({ "TOPLEFT", self.controls.skillList, "BOTTOMLEFT" }, { 0, 60, 360, 70 }, "Gem Options") + self.controls.sortGemsByDPS = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", self.controls.optionSection, "TOPLEFT" }, { 170, 20, 20 }, "Sort gems by DPS:", function(state) + self.sortGemsByDPS = state + self:InvalidateSupportSort() + self:RefreshSupportLists() + end, nil, true) + self.controls.sortGemsByDPSFieldControl = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.sortGemsByDPS, "RIGHT" }, { 10, 0, 140, 20 }, skillOptions.sortGemTypeList, function(_, value) + self.sortGemsByDPSField = value.type + self:InvalidateSupportSort() + self:RefreshSupportLists() + end) + self.controls.sortGemsByDPSFieldControl:SelByValue(self.sortGemsByDPSField, "type") + self.controls.skillDetailAnchor = new("Control"):Control({ "TOPLEFT", self.controls.skillList, "TOPRIGHT" }, { 20, 0, 0, 0 }) + self.controls.skillDetailAnchor.shown = function() + return self.profile.skills[self.selectedSkillIndex] ~= nil + end + self.controls.skillLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 0, 2, 0, 16 }, "^7Skill:") + self.controls.skill = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 85, 0, 380, 20 }, { }, function(_, value) + self:SetSkill(self.selectedSkillIndex, value and value.id) + end) + self.controls.skill.tooltipFunc = function(tooltip, mode, index, value) + if tooltip:CheckForUpdate(mode, index, value, self.build.outputRevision, mercenaryLevel(self.build, self.profile.foundAreaLevel), self.selectedSkillIndex) then + tooltip:Clear() + if value and value.id then + self:AddSkillTooltip(tooltip, value, mode == "HOVER") + end + end + end + self.controls.skillEnabledLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 0, 32, 0, 16 }, "^7Enabled:") + self.controls.skillEnabled = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 68, 30, 20 }, nil, function(state) + self:SetSkillEnabled(self.profile.skills[self.selectedSkillIndex], state) + end) + self.controls.skillFullDPSLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 108, 32, 0, 16 }, "^7Include in Full DPS:") + self.controls.skillFullDPS = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 247, 30, 20 }, nil, function(state) + local skill = self.profile.skills[self.selectedSkillIndex] + if skill then skill.includeInFullDPS = state end + self:Changed() + end, "Mercenary Full DPS assumes every selected skill's damage is simultaneously sustainable.\nIt does not simulate the Mercenary's skill priority or rotation.") + self.controls.skillCountLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 287, 32, 0, 16 }, "^7Count:") + self.controls.skillCount = new("EditControl"):EditControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 335, 30, 50, 20 }, "1", nil, "%D", 2, function(buf) + local skill = self.profile.skills[self.selectedSkillIndex] + if skill then skill.count = m_min(m_max(tonumber(buf) or 1, 1), 99) end + self:Changed() + end) + self.controls.skillPartLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 0, 64, 0, 16 }, "^7Skill part:") + self.controls.skillPart = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 85, 62, 180, 20 }, { }, function(_, value) + local selected = self.profile.skills[self.selectedSkillIndex] + if selected and value then selected.skillPart = value.index end + self:Changed() + end) + self.controls.skillMinionSkillLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 285, 64, 0, 16 }, "^7Minion skill:") + self.controls.skillMinionSkill = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 375, 62, 230, 20 }, { }, function(_, value) + local selected = self.profile.skills[self.selectedSkillIndex] + if selected and value then selected.skillMinionSkill = value.index end + self:Changed() + end) + + self.controls.supportsHeader = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 0, 102, 0, 16 }, function() + local skill = self.profile.skills[self.selectedSkillIndex] + return "^7Supports for "..(skill and self.data.skills[skill.id] and self.data.skills[skill.id].name or "selected skill")..":" + end) + self.controls.supportSortStatus = new("LabelControl"):LabelControl({ "LEFT", self.controls.supportsHeader, "RIGHT" }, { 8, 0, 0, 16 }, function() + return self.supportSortCoroutine and "^7Sorting "..self.supportSortStatus or "" + end) + self.supportControls = { } + self.skipEnsureData = true + self:RefreshControls() + self.skipEnsureData = nil + self:ResetUndo() + return self +end + +function MercenaryTabClass:CreateSupportControls() + local function createSupportRow(index) + local y = 124 + (index - 1) * 22 + local clear = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.skillDetailAnchor, "TOPLEFT" }, { 0, y, 20, 20 }, "x", function() + self:SetSupport(index, nil) + end) + clear.enabled = function() + local skill = self.profile.skills[self.selectedSkillIndex] + return skill and skill.supports[index] ~= nil + end + local control = new("DropDownControl"):DropDownControl({ "LEFT", clear, "RIGHT" }, { 2, 0, 380, 20 }, { }, function(_, value) + self:SetSupport(index, value and value.id) + end) + clear.shown = false + control.shown = false + control.tooltipFunc = function(tooltip, mode, _, value) + if tooltip:CheckForUpdate(mode, value, self.build.outputRevision, self.supportSortRevision, mercenaryLevel(self.build, self.profile.foundAreaLevel), self.selectedSkillIndex) then + tooltip:Clear() + local support = value and value.id and self.data.supports[value.id] + self:AddSupportTooltip(tooltip, support, index, mode == "HOVER") + end + end + local onKeyDown = control.OnKeyDown + control.OnKeyDown = function(dropdown, key) + if not dropdown.dropped and (key == "LEFTBUTTON" or key == "RIGHTBUTTON" or key == "DOWN") then + self:QueueSupportSort(index) + end + return onKeyDown(dropdown, key) + end + control.supportIndex = index + self.controls["support"..index.."Clear"] = clear + self.controls["support"..index] = control + return control + end + for index = 1, MercenaryTools.maxSupportLimit(self.data) do + self.supportControls[index] = createSupportRow(index) + end +end + +local function makeMercenarySkillGem(build, skillData, actorLevel) + local grantedEffect = build.data.skills[skillData.id] + if not grantedEffect or not grantedEffect.levels then return end + local sourceGem = build.data.gemForSkill and build.data.gems[build.data.gemForSkill[grantedEffect]] + local effect = copyTable(grantedEffect, true) + effect.name = skillData.name or effect.name + effect.description = skillData.description or effect.description + if skillData.icon and skillData.icon ~= "" then effect.icon = skillData.icon end + effect.stats = effect.stats or { } + effect.constantStats = effect.constantStats or { } + local secondary = skillData.secondarySkillId and build.data.skills[skillData.secondarySkillId] + if secondary then + secondary = copyTable(secondary, true) + end + local level = MercenaryTools.skillLevel(effect, actorLevel) + return { + level = level, + actorLevel = actorLevel, + color = data.skillColorMap[effect.color] or colorCodes.NORMAL, + quality = 0, + gemData = { + name = effect.name, + grantedEffect = effect, + secondaryGrantedEffect = secondary, + tags = sourceGem and copyTable(sourceGem.tags or { }, true) or { }, + tagString = sourceGem and sourceGem.tagString or "Mercenary Skill", + naturalMaxLevel = #effect.levels, + reqStr = 0, + reqDex = 0, + reqInt = 0, + }, + } +end + +local function makeMercenarySupportGem(build, support) + if not support then return end + build.data.ensureMercenaries() + local grantedEffect = build.data.mercenarySupportGrantedEffect(support.id) + if not grantedEffect then return end + local effect = copyTable(grantedEffect, true) + effect.icon = support.icon + return { + level = 1, + quality = 0, + gemData = { + name = support.name, + grantedEffect = effect, + tags = { }, + tagString = "Mercenary Support, Tier "..tostring(support.variant), + naturalMaxLevel = 1, + reqStr = 0, + reqDex = 0, + reqInt = 0, + }, + } +end + +local function calcMercenaryPreview(tab, skillId, calcFunc, useFullDPS) + if not calcFunc then return nil end + return MercenaryTools.withMainSkill(tab.profile, skillId, function() + return calcFunc({ comparisonActor = "MERCENARY" }, useFullDPS) + end) +end + +local function addMercenaryComparison(tab, tooltip, preview, header) + if not preview then return end + local calcTab = tab.build.calcsTab + local calcFunc, _, baseOutputs = calcTab:GetMiscCalculator() + local baseOutput = baseOutputs and baseOutputs.MERCENARY + if not calcFunc or not calcTab.mainEnv then return end + if not baseOutput then + tooltip:AddLine(16, colorCodes.WARNING.."Mercenary comparison unavailable") + return + end + local output = calcFunc({ comparisonActor = "MERCENARY" }, tab.sortGemsByDPSField == "FullDPS") + if not output then + tooltip:AddLine(16, colorCodes.WARNING.."Mercenary comparison unavailable") + return + end + tab.build:AddStatComparesToTooltip(tooltip, baseOutput, output, header, nil, "MERCENARY") +end + +function MercenaryTabClass:AddSkillTooltip(tooltip, value, preview) + local skillData = value and self.data.skills[value.id] + local actorLevel = mercenaryLevel(self.build, self.profile.foundAreaLevel) + local gemInstance = skillData and makeMercenarySkillGem(self.build, skillData, actorLevel) + if not gemInstance then + tooltip:AddLine(16, colorCodes.WARNING.."No exported Mercenary skill data") + return + end + gemTooltip.AddGemTooltip(tooltip, self.build, gemInstance, { skipRequirements = true }) + if preview then + local selected = self.profile.skills[self.selectedSkillIndex] + if selected then + local previewSkill = { + id = value.id, + supports = { }, + enabled = true, + includeInFullDPS = false, + count = 1, + skillPart = self.build.data.mercenaryStatData.defaultSkillParts[value.id] or 1, + } + MercenaryTools.withMainSkill(self.profile, value.id, function() + MercenaryTools.withReplacedSkill(self.profile, self.selectedSkillIndex, previewSkill, function() + addMercenaryComparison(self, tooltip, true, "^7Selecting this skill will give you:") + end) + end) + end + end +end + +function MercenaryTabClass:AddSupportTooltip(tooltip, support, index, preview) + local gemInstance = support and makeMercenarySupportGem(self.build, support) + if not gemInstance then + if index then tooltip:AddLine(16, "^7Remove this support") end + return + end + gemTooltip.AddGemTooltip(tooltip, self.build, gemInstance, { skipRequirements = true }) + if preview then + local selected = self.profile.skills[self.selectedSkillIndex] + local selectedData = selected and self.data.skills[selected.id] + if selected and selectedData and selectedData.possibleSupportIds then + local calcTab = self.build.calcsTab + local calcFunc = calcTab:GetMiscCalculator() + if not calcFunc or not calcTab.mainEnv then return end + local useFullDPS = self.sortGemsByDPSField == "FullDPS" + local header = "^7Selecting this support will give you:" + local baseOutput = calcMercenaryPreview(self, selected.id, calcFunc, useFullDPS) + if not MercenaryTools.mercenaryOutputAvailable(baseOutput) then + tooltip:AddLine(16, colorCodes.WARNING.."Mercenary comparison unavailable") + return + end + MercenaryTools.withEditedSupports(selected, index, { id = support.id, tier = support.variant }, function() + local output = calcMercenaryPreview(self, selected.id, calcFunc, useFullDPS) + if not output then + tooltip:AddLine(16, colorCodes.WARNING.."Mercenary comparison unavailable") + return + end + self.build:AddStatComparesToTooltip(tooltip, baseOutput, output, header, nil, "MERCENARY") + end) + end + end +end + +function MercenaryTabClass:Changed() + self.modFlag = true + self.build.buildFlag = true + self.build.configTab:EnsureHiredMercenaryModList() + self:InvalidateSupportSort() + self:RefreshControls() + self:AddUndoState() +end + +function MercenaryTabClass:ItemSetOwnedByAnyMercenary(itemSetId) + return itemSetOwnedByMercenary(self, itemSetId, false) +end + +function MercenaryTabClass:ItemSetOwnedByOtherLoadout(itemSetId) + return itemSetOwnedByMercenary(self, itemSetId, true) +end + +function MercenaryTabClass:ClearConfigBindings(setId) + if not setId then + return + end + forEachConfigSet(self, function(configTab, _, configSet) + if configSet.mercenarySetId == setId then + configSet.mercenarySetId = nil + configTab.modFlag = true + end + end) +end + +function MercenaryTabClass:DropInvalidConfigBindings(markDirty) + forEachConfigSet(self, function(configTab, _, configSet) + if configSet.mercenarySetId and not self.mercenarySets[configSet.mercenarySetId] then + configSet.mercenarySetId = nil + if markDirty then + configTab.modFlag = true + end + end + end) +end + +function MercenaryTabClass:GetConfigMercenaryBindings() + local bindings = { } + forEachConfigSet(self, function(_, configSetId, configSet) + -- false records "unbound" so Restore can tell it apart from a Config + -- that did not exist when this snapshot was taken. + bindings[configSetId] = configSet.mercenarySetId or false + end) + return bindings +end + +function MercenaryTabClass:StoreActiveMercenaryItemSet() + local itemsTab = self.build.itemsTab + if not itemsTab or not self.profile then + return + end + local itemSetId = itemsTab:GetActorItemSetId("MERCENARY") + if itemSetId then + self.profile.itemSetId = itemSetId + end +end + +function MercenaryTabClass:ApplyActiveMercenaryItemSet() + local itemsTab = self.build.itemsTab + if not itemsTab or not self.profile then + return + end + local itemSetId = self.profile.itemSetId + if itemSetId and not itemsTab.itemSets[itemSetId] then + self.profile.itemSetId = nil + itemSetId = nil + end + itemsTab:SetActorItemSet("MERCENARY", itemSetId, false) + if itemsTab.viewComparisonActor == "MERCENARY" then + if itemSetId then + itemsTab:SetViewItemSet(itemSetId, "MERCENARY") + else + itemsTab:SetViewItemSet(itemsTab.activeItemSetId, "PLAYER") + end + end +end + +function MercenaryTabClass:GetItemSet(create) + local itemsTab = self.build.itemsTab + local itemSetId = self.profile and self.profile.itemSetId + if itemSetId and itemsTab.itemSets[itemSetId] then + return itemsTab.itemSets[itemSetId] + end + if self.profile then + self.profile.itemSetId = nil + end + local actorSet = itemsTab:GetActorItemSet("MERCENARY") + if actorSet and not self:ItemSetOwnedByOtherLoadout(actorSet.id) then + if self.profile then + self.profile.itemSetId = actorSet.id + end + return actorSet + end + if create == true then + local itemSet = itemsTab:NewItemSet() + itemSet.title = (self.profile and self.profile.title) or "Mercenary Equipment" + t_insert(itemsTab.itemSetOrderList, itemSet.id) + if self.profile then + self.profile.itemSetId = itemSet.id + end + itemsTab:SetActorItemSet("MERCENARY", itemSet.id, false) + itemsTab:AddUndoState() + self.build.buildFlag = true + return itemSet + end +end + +function MercenaryTabClass:InvalidateSupportSort() + self.supportSortRevision = self.supportSortRevision + 1 + self.supportSortCache = { } + self.supportSortCoroutine = nil + self.supportSortStatus = "" +end + +function MercenaryTabClass:BuildSupportList(selectedData, supportIndex) + local supportList = { { label = "", id = nil } } + local selected = self.profile.skills[self.selectedSkillIndex] + for _, supportId in ipairs(selectedData and selectedData.possibleSupportIds or { }) do + local support = self.data.supports[supportId] + local err = selected and MercenaryTools.supportCandidateError(self.profile, self.data, self.selectedSkillIndex, supportIndex, supportId) + if support and (not err or (selected.supports[supportIndex] and selected.supports[supportIndex].id == supportId)) then + t_insert(supportList, { id = supportId, tier = support.variant, label = supportLabel(support) }) + end + end + return supportList +end + +function MercenaryTabClass:RefreshSupportLists() + local selected = self.profile.skills[self.selectedSkillIndex] + local selectedData = selected and self.data and self.data.skills[selected.id] + local maxSupports = MercenaryTools.supportLimit(self.data, selectedData) + local missingPolicy = selectedData and maxSupports == nil + for index, control in ipairs(self.supportControls) do + control:SetList(self:BuildSupportList(selectedData, index)) + control:SelByValue(selected and selected.supports[index] and selected.supports[index].id, "id") + if missingPolicy then + control.shown = true + control.enabled = false + else + control.shown = maxSupports ~= nil and index <= maxSupports + control.enabled = selected ~= nil and control.shown + end + self.controls["support"..index.."Clear"].shown = control.shown + self.controls["support"..index.."Clear"].enabled = function() + return selected and selected.supports[index] ~= nil and not missingPolicy + end + end +end + +local function copySupportSortList(list) + local copy = { } + for i, entry in ipairs(list or { }) do + copy[i] = copyTable(entry, true) + end + return copy +end + +local function supportDPS(output, field) + if not output then return 0 end + if field == "FullDPS" and output.FullDPS ~= nil then + return output.FullDPS + end + local actor = output.Minion or output + if actor[field] ~= nil then + return actor[field] + end + if output[field] ~= nil then + return output[field] + end + return 0 +end + +function MercenaryTabClass:ApplySupportSort(index, list) + local control = self.supportControls[index] + if not control then return end + control:SetList(copySupportSortList(list)) + local selected = self.profile.skills[self.selectedSkillIndex] + control:SelByValue(selected and selected.supports[index] and selected.supports[index].id, "id") +end + +function MercenaryTabClass:QueueSupportSort(index) + if not self.sortGemsByDPS then return end + local control = self.supportControls[index] + local selected = self.profile.skills[self.selectedSkillIndex] + if not control or not selected or not control.list or #control.list < 2 then return end + local key = table.concat({ self.supportSortRevision, self.build.outputRevision or 0, selected.id, index, self.sortGemsByDPSField }, ":") + local cached = self.supportSortCache[index] + if cached and cached.key == key then + self:ApplySupportSort(index, cached.list) + return + end + local originalList = copySupportSortList(control.list) + local revision = self.supportSortRevision + local skillIndex = self.selectedSkillIndex + self.supportSortStatus = "0%" + self.supportSortCoroutine = coroutine.create(function() + local calcFunc = select(1, self.build.calcsTab:GetMiscCalculator()) + if not calcFunc then return end + local useFullDPS = self.sortGemsByDPSField == "FullDPS" + local startTime = GetTime() + for entryIndex, entry in ipairs(originalList) do + entry.dps = MercenaryTools.withEditedSupports(selected, index, entry.id and { id = entry.id, tier = entry.tier } or nil, function() + return supportDPS(calcMercenaryPreview(self, selected.id, calcFunc, useFullDPS), self.sortGemsByDPSField) + end) + self.supportSortStatus = ("%d%%"):format(m_floor(entryIndex / #originalList * 100)) + if GetTime() - startTime > 50 then + coroutine.yield() + startTime = GetTime() + end + end + t_sort(originalList, function(a, b) + if a.dps ~= b.dps then return a.dps > b.dps end + local aLabel, bLabel = StripEscapes(a.label or ""), StripEscapes(b.label or "") + return aLabel == bLabel and tostring(a.id or "") < tostring(b.id or "") or aLabel < bLabel + end) + self.supportSortStatus = "" + if self.supportSortRevision == revision and self.selectedSkillIndex == skillIndex then + self:ApplySupportSort(index, originalList) + self.supportSortCache[index] = { key = key, list = originalList } + end + end) +end + +function MercenaryTabClass:ProcessSupportSort() + if not self.supportSortCoroutine then return end + local ok, err = coroutine.resume(self.supportSortCoroutine) + if not ok then + self.supportSortCoroutine = nil + self.supportSortStatus = "Error" + if launch and launch.devMode then + error(err) + end + ConPrintf("Mercenary support sort failed: %s", tostring(err)) + return + end + if coroutine.status(self.supportSortCoroutine) == "dead" then + self.supportSortCoroutine = nil + self.supportSortStatus = "" + end +end + +function MercenaryTabClass:EnsureData() + if self.data then + return self.data + end + self.data = self.build.data.ensureMercenaries() + self:CreateSupportControls() + self.classGroups, self.classGroupsByClassId = MercenaryTools.classGroups(self.data) + if self.controls.class then + self.controls.class:SetList(self.classGroups) + end + return self.data +end + +function MercenaryTabClass:anySetHasBuildId() + if self.profile and self.profile.buildId then + return true + end + for _, setId in ipairs(self.mercenarySetOrderList or { }) do + local profile = self.mercenarySets[setId] + if profile and profile.buildId then + return true + end + end + return false +end + +function MercenaryTabClass:RefreshControls() + if not self.skipEnsureData and not self.data and self:anySetHasBuildId() then + self:EnsureData() + end + local setList = { } + for _, setId in ipairs(self.mercenarySetOrderList) do + local set = self.mercenarySets[setId] + if set then + t_insert(setList, { id = setId, label = set.title or "Default" }) + end + end + self.controls.setSelect:SetList(setList) + self.controls.setSelect:SelByValue(self.activeMercenarySetId, "id") + + local classGroup = self.classGroupsByClassId[self.profile.classId] + if not classGroup then + classGroup = self.classGroups[self.controls.class.selIndex] or self.classGroups[1] + end + self.controls.class:SelByValue(classGroup and classGroup.id, "id") + + local builds = { } + for _, buildId in ipairs(classGroup and classGroup.buildIds or { }) do + local mercBuild = self.data and self.data.builds[buildId] + t_insert(builds, { id = buildId, classId = mercBuild.classId, label = mercBuild.name }) + end + self.controls.build:SetList(builds) + self.controls.build:SelByValue(self.profile.buildId, "id") + self.controls.level:SetText(tostring(self.profile.foundAreaLevel or 0), false) + self.controls.lifeComparison:SelByValue(self.profile.lifeComparison or "AUTO", "id") + self.controls.skillList.list = self.profile.skills + if #self.profile.skills > 0 then + self.selectedSkillIndex = m_min(m_max(self.selectedSkillIndex or 1, 1), #self.profile.skills) + else + self.selectedSkillIndex = 1 + end + local selected = self.profile.skills[self.selectedSkillIndex] + self.controls.skillList.selIndex = selected and self.selectedSkillIndex or nil + self.controls.skillList.selValue = selected + + local skillList = { { label = "", id = nil } } + local mercBuild = self.data and self.data.builds[self.profile.buildId] + local currentSkillId = selected and selected.id + for _, skillId in ipairs(mercBuild and mercBuild.skillIds or { }) do + local skill = self.data.skills[skillId] + local skillEffect = self.build.data.skills[skillId] + local err = MercenaryTools.skillCandidateError(self.profile, self.data, self.selectedSkillIndex, skillId) + if skill and (not err or skillId == currentSkillId) then + t_insert(skillList, { id = skillId, label = gemColorLabel(skillEffect and skillEffect.color)..skill.name }) + end + end + self.skillOptions = skillList + self.controls.skill:SetList(skillList) + self.controls.skill:SelByValue(selected and selected.id, "id") + self.controls.skillEnabled.state = selected and (selected.enabled ~= false) or false + self.controls.skillFullDPS.state = selected and selected.includeInFullDPS or false + self.controls.skillCount:SetText(tostring(selected and selected.count or 1), false) + local selectedData = selected and self.data and self.data.skills[selected.id] + local selectedEffect = selected and self.build.data.skills[selected.id] + local partList = { } + for index, part in ipairs(selectedEffect and selectedEffect.parts or { }) do + t_insert(partList, { index = index, label = part.name or "Part "..index }) + end + if #partList == 0 then partList[1] = { index = 1, label = "Default" } end + self.controls.skillPart:SetList(partList) + local defaultSkillParts = self.build.data.mercenaryStatData and self.build.data.mercenaryStatData.defaultSkillParts + self.controls.skillPart:SelByValue(selected and selected.skillPart or (defaultSkillParts and defaultSkillParts[selected and selected.id]) or 1, "index") + self.controls.skillPart.enabled = #partList > 1 + local minionSkillList = { } + local minionId = selected and self.data and self.data.summonedMinions and self.data.summonedMinions[selected.id] + local minion = minionId and self.build.data.minions[minionId] + for _, skillId in ipairs(minion and minion.skillList or { }) do + local minionSkill = self.build.data.skills[skillId] + if minionSkill then t_insert(minionSkillList, { index = #minionSkillList + 1, label = minionSkill.name }) end + end + self.controls.skillMinionSkill:SetList(minionSkillList) + self.controls.skillMinionSkill:SelByValue(selected and selected.skillMinionSkill or 1, "index") + self.controls.skillMinionSkill.enabled = #minionSkillList > 1 + self.controls.skillMinionSkill.shown = #minionSkillList > 0 + self.controls.skillMinionSkillLabel.shown = #minionSkillList > 0 + self.controls.sortGemsByDPS.state = self.sortGemsByDPS + self.controls.sortGemsByDPSFieldControl:SelByValue(self.sortGemsByDPSField, "type") + self:RefreshSupportLists() +end + +function MercenaryTabClass:AddSkill() + local skillId = MercenaryTools.firstLegalSkillId(self.profile, self.data) + if skillId then + self:SetSkill(#self.profile.skills + 1, skillId) + end +end + +function MercenaryTabClass:NewMercenarySet(setId, title) + local set = { + id = setId, + title = title, + foundAreaLevel = 68, + skills = { }, + lifeComparison = "AUTO", + } + if not set.id then + set.id = 1 + while self.mercenarySets[set.id] do + set.id = set.id + 1 + end + end + self.mercenarySets[set.id] = set + return set +end + +-- bindToLoadout defaults false so a forgotten caller cannot rewrite Config.mercenarySetId. +-- Pass true from the Mercenary dropdown and manage-list double-click. +-- Callers that are user actions (dropdown, double-click, import, delete) push undo; +-- loadout switch does not, matching ItemsTab/SkillsTab/ConfigTab SetActive. +function MercenaryTabClass:SetActiveMercenarySet(setId, init, bindToLoadout) + if not self.mercenarySetOrderList[1] then + self.mercenarySetOrderList[1] = 1 + self:NewMercenarySet(1) + end + + if self.activeMercenarySetId and self.profile and self.mercenarySets[self.activeMercenarySetId] then + self.profile.id = self.activeMercenarySetId + self.mercenarySets[self.activeMercenarySetId] = self.profile + if not init and self.activeMercenarySetId ~= setId then + self:StoreActiveMercenaryItemSet() + end + end + if not setId or not self.mercenarySets[setId] then + setId = self.mercenarySetOrderList[1] + end + local switched = self.activeMercenarySetId ~= setId + if switched then self:InvalidateSupportSort() end + + self.activeMercenarySetId = setId + self.profile = self.mercenarySets[setId] + if not init then + self:ApplyActiveMercenaryItemSet() + if bindToLoadout then + local configTab = self.build.configTab + local configSet = configTab and configTab.configSets[configTab.activeConfigSetId] + if configSet then + configSet.mercenarySetId = setId + configTab.modFlag = true + end + end + end + if switched then + self.selectedSkillIndex = 1 + end + self.build.buildFlag = true + if not init then + self.build.configTab:EnsureHiredMercenaryModList() + end + if self.controls.skillList then + self:RefreshControls() + end + if not init then + self.build:SyncLoadouts() + end +end + +function MercenaryTabClass:OpenMercenarySetManagePopup() + main:OpenPopup(370, 290, "Manage Mercenary Loadouts", { + new("MercenarySetListControl"):MercenarySetListControl(nil, {0, 50, 350, 200}, self), + new("ButtonControl"):ButtonControl(nil, {0, 260, 90, 20}, "Done", function() + main:ClosePopup() + end), + }) +end + +function MercenaryTabClass:SetSkillEnabled(skill, enabled) + if not skill then return end + skill.enabled = enabled and true or false + if skill.enabled == false and self.profile.mainSkillId == skill.id then + self.profile.mainSkillId = MercenaryTools.firstEnabledSkillId(self.profile) + elseif skill.enabled and not self.profile.mainSkillId then + self.profile.mainSkillId = skill.id + end + self:Changed() +end + +function MercenaryTabClass:SetSkill(index, skillId) + if skillId then + self:EnsureData() + local err = MercenaryTools.skillCandidateError(self.profile, self.data, index, skillId) + if err then + if self.controls.skillList then self:RefreshControls() end + return nil, err + end + end + self.profile.importedWarrant = nil + self.selectedSkillIndex = index + local existing = self.profile.skills[index] + local wasMainSkill = existing and self.profile.mainSkillId == existing.id + if not skillId then + table.remove(self.profile.skills, index) + if wasMainSkill then self.profile.mainSkillId = MercenaryTools.firstEnabledSkillId(self.profile) end + self.selectedSkillIndex = m_min(index, m_max(#self.profile.skills, 1)) + else + self.profile.skills[index] = existing and existing.id == skillId and existing or { + id = skillId, + enabled = true, + includeInFullDPS = false, + count = 1, + supports = { }, + } + if wasMainSkill or not self.profile.mainSkillId then self.profile.mainSkillId = skillId end + end + self:Changed() + return true +end + +function MercenaryTabClass:SetSupport(index, supportId) + local skill = self.profile.skills[self.selectedSkillIndex] + if not skill then return nil, "No selected Mercenary skill" end + if supportId then + self:EnsureData() + local err = MercenaryTools.supportCandidateError(self.profile, self.data, self.selectedSkillIndex, m_min(index, #skill.supports + 1), supportId) + if err then + if self.controls.skillList then self:RefreshControls() end + return nil, err + end + local support = self.data.supports[supportId] + MercenaryTools.setSkillSupport(skill.supports, index, { id = supportId, tier = support.variant }) + else + MercenaryTools.setSkillSupport(skill.supports, index, nil) + end + self:Changed() + return true +end + +function MercenaryTabClass:ImportWarrant(text) + local imported, err = MercenaryTools.importWarrant(text, self.data) + if not imported then return nil, err end + self.profile.classId = imported.classId + self.profile.buildId = imported.buildId + self.profile.foundAreaLevel = imported.foundAreaLevel + self.profile.importedWarrant = true + self.profile.mainSkillId = imported.mainSkillId + self.profile.skills = imported.skills + self.selectedSkillIndex = 1 + self:Changed() + return true +end + +function MercenaryTabClass:OpenWarrantImportPopup() + self:EnsureData() + local controls = { } + local importError + controls.edit = new("EditControl"):EditControl(nil, { 0, 40, 600, 420 }, "", nil, "^%C\t\n", nil, nil, 14) + controls.edit.font = "FIXED" + controls.edit.pasteFilter = sanitiseText + controls.error = new("LabelControl"):LabelControl({ "TOPLEFT", controls.edit, "BOTTOMLEFT" }, { 0, 8, 600, 16 }, function() + return importError and colorCodes.NEGATIVE..importError or "" + end) + controls.import = new("ButtonControl"):ButtonControl(nil, { -45, 510, 80, 20 }, "Import", function() + local ok, err = self:ImportWarrant(controls.edit.buf) + if not ok then + importError = err + return + end + main:ClosePopup() + end, nil, true) + controls.cancel = new("ButtonControl"):ButtonControl(nil, { 45, 510, 80, 20 }, "Cancel", function() + main:ClosePopup() + end) + main:OpenPopup(620, 550, "Import Mercenary Warrant", controls, "import", "edit", "cancel") +end + +function MercenaryTabClass:Reset() + self.profile = self:NewMercenarySet(self.activeMercenarySetId, self.profile.title) + self.selectedSkillIndex = 1 + self:Changed() +end + +function MercenaryTabClass:IsSlotSupported(slotName) + return MercenaryTools.isSlotSupported(slotName) +end + +-- Mercenary permissions are granted by parsed modifiers, so they are read from the +-- modifier database built by the last calculation rather than from tree node names. +function MercenaryTabClass:PlayerFlag(flagName) + local mainEnv = self.build.calcsTab and self.build.calcsTab.mainEnv + if not (mainEnv and mainEnv.modDB) then + return nil + end + return mainEnv.modDB:Flag(nil, flagName) and true or false +end + +function MercenaryTabClass:GetErrors() + local errors = { } + local seen = { } + local function addError(errorText) + if seen[errorText] then return end + seen[errorText] = true + t_insert(errors, errorText) + end + local canHire = self:PlayerFlag("CanHirePermanentMercenary") + if canHire == false then + addError("Permanently hiring a Mercenary requires Noble Blood, from the Scion's Luminary ascendancy") + end + if self.profile.buildId then + self:EnsureData() + end + for _, errorText in ipairs(MercenaryTools.validateProfile(self.profile, self.data)) do + addError(errorText) + end + if (self.profile.foundAreaLevel or 0) >= self.build.characterLevel + 20 then + addError("Character level is at least 20 below the Mercenary level") + end + local mercBuild = self.data and self.data.builds[self.profile.buildId] + if mercBuild and #mercBuild.weaponTypes == 0 then + addError("Selected build has no exported wieldable-type data") + end + local itemsTab = self.build.itemsTab + local itemSet = itemsTab:GetActorItemSet("MERCENARY") + if itemSet and self.data then + for _, errorText in ipairs(MercenaryTools.equipmentErrors({ + profile = self.profile, + mercenaryData = self.data, + itemSet = itemSet, + playerItemSet = itemsTab.activeItemSet, + items = itemsTab.items, + playerHasFlag = function(flagName) return self:PlayerFlag(flagName) end, + isItemValidForSlot = function(item, slotName, set, equippedLookup) + return itemsTab:IsItemValidForSlot(item, slotName, set, equippedLookup) + end, + })) do + addError(errorText) + end + end + -- Construction-time failures only. Profile and current-loadout equipment + -- errors are produced above; do not echo them from mercenaryCalculationErrors. + local mainEnv = self.build.calcsTab and self.build.calcsTab.mainEnv + for _, calculationError in ipairs(mainEnv and mainEnv.mercenaryCalculationErrors or { }) do + addError(calculationError) + end + return errors +end + +function MercenaryTabClass:Load(xml) + local function loadSkill(node, profile) + local skill = { + id = node.attrib.id, + enabled = node.attrib.enabled ~= "false", + includeInFullDPS = node.attrib.includeInFullDPS == "true", + count = tonumber(node.attrib.count) or 1, + skillPart = tonumber(node.attrib.skillPart), + skillStageCount = tonumber(node.attrib.skillStageCount), + skillMineCount = tonumber(node.attrib.skillMineCount), + skillMinionSkill = tonumber(node.attrib.skillMinionSkill), + skillMinionSkillCalcs = tonumber(node.attrib.skillMinionSkillCalcs), + supports = { }, + } + for _, supportNode in ipairs(node) do + if supportNode.elem == "Support" then + t_insert(skill.supports, { id = supportNode.attrib.id, tier = tonumber(supportNode.attrib.tier) }) + end + end + t_insert(profile.skills, skill) + end + local function loadProfile(node, profile) + profile.importAssociation = node.attrib.importAssociation + profile.buildId = node.attrib.buildId + profile.foundAreaLevel = tonumber(node.attrib.foundAreaLevel) + profile.importedWarrant = node.attrib.importedWarrant == "true" + profile.mainSkillId = node.attrib.mainSkillId + profile.lifeComparison = node.attrib.lifeComparison or "AUTO" + profile.classId = node.attrib.classId + profile.itemSetId = tonumber(node.attrib.itemSetId) + if profile.buildId then + self:EnsureData() + local mercBuild = self.data.builds[profile.buildId] + if mercBuild then + profile.classId = mercBuild.classId + end + end + for _, child in ipairs(node) do + if child.elem == "Skill" then loadSkill(child, profile) end + end + end + + self.activeMercenarySetId = nil + self.profile = nil + self.mercenarySets = { } + self.mercenarySetOrderList = { } + if xml.attrib.sortGemsByDPS then + self.sortGemsByDPS = xml.attrib.sortGemsByDPS ~= "false" + end + self.controls.sortGemsByDPS.state = self.sortGemsByDPS + self.controls.sortGemsByDPSFieldControl:SelByValue(xml.attrib.sortGemsByDPSField or "CombinedDPS", "type") + self.sortGemsByDPSField = self.controls.sortGemsByDPSFieldControl:GetSelValueByKey("type") + local activeMercenarySetId = tonumber(xml.attrib.activeMercenarySet) or 1 + for _, child in ipairs(xml) do + if child.elem == "MercenarySet" then + local setId = tonumber(child.attrib.id) or 1 + while self.mercenarySets[setId] do setId = setId + 1 end + local profile = self:NewMercenarySet(setId, child.attrib.title) + loadProfile(child, profile) + t_insert(self.mercenarySetOrderList, setId) + end + end + self:SetActiveMercenarySet(activeMercenarySetId, true) + self.modFlag = false + self:RefreshControls() + self:ResetUndo() +end + +function MercenaryTabClass:PostLoad() + self:DropInvalidConfigBindings(false) + local itemsTab = self.build.itemsTab + if itemsTab then + for _, profile in pairs(self.mercenarySets) do + if profile.itemSetId and not itemsTab.itemSets[profile.itemSetId] then + profile.itemSetId = nil + end + end + if self.profile and not self.profile.itemSetId then + local fallback = itemsTab:GetActorItemSetId("MERCENARY") + if fallback and itemsTab.itemSets[fallback] then + self.profile.itemSetId = fallback + end + end + local previous = itemsTab:GetActorItemSetId("MERCENARY") + self:ApplyActiveMercenaryItemSet() + if itemsTab:GetActorItemSetId("MERCENARY") ~= previous then + -- ItemsTab:Load already ResetUndo before this migration. + itemsTab:ResetUndo() + end + end + self:RefreshControls() + self.modFlag = false +end + +function MercenaryTabClass:Save(xml) + xml.attrib = { + activeMercenarySet = tostring(self.activeMercenarySetId), + sortGemsByDPS = tostring(self.sortGemsByDPS), + sortGemsByDPSField = self.sortGemsByDPSField, + } + if self.activeMercenarySetId and self.profile then + self.profile.id = self.activeMercenarySetId + self.mercenarySets[self.activeMercenarySetId] = self.profile + self:StoreActiveMercenaryItemSet() + end + for _, setId in ipairs(self.mercenarySetOrderList) do + local profile = self.mercenarySets[setId] + if profile then + local setNode = { elem = "MercenarySet", attrib = { + id = tostring(setId), + title = profile.title, + importAssociation = profile.importAssociation, + buildId = profile.buildId, + classId = profile.classId, + foundAreaLevel = profile.foundAreaLevel and tostring(profile.foundAreaLevel), + importedWarrant = tostring(profile.importedWarrant == true), + mainSkillId = profile.mainSkillId, + lifeComparison = profile.lifeComparison, + itemSetId = profile.itemSetId and tostring(profile.itemSetId), + } } + for _, skill in ipairs(profile.skills or { }) do + local child = { elem = "Skill", attrib = { + id = skill.id, + enabled = tostring(skill.enabled ~= false), + includeInFullDPS = tostring(skill.includeInFullDPS == true), + count = tostring(skill.count or 1), + skillPart = skill.skillPart and tostring(skill.skillPart), + skillStageCount = skill.skillStageCount and tostring(skill.skillStageCount), + skillMineCount = skill.skillMineCount and tostring(skill.skillMineCount), + skillMinionSkill = skill.skillMinionSkill and tostring(skill.skillMinionSkill), + skillMinionSkillCalcs = skill.skillMinionSkillCalcs and tostring(skill.skillMinionSkillCalcs), + } } + for _, support in ipairs(skill.supports or { }) do + t_insert(child, { elem = "Support", attrib = { id = support.id, tier = tostring(support.tier) } }) + end + t_insert(setNode, child) + end + t_insert(xml, setNode) + end + end + self.modFlag = false +end + +function MercenaryTabClass:CreateUndoState() + if self.activeMercenarySetId and self.profile then + self.profile.id = self.activeMercenarySetId + self.mercenarySets[self.activeMercenarySetId] = self.profile + self:StoreActiveMercenaryItemSet() + end + return { + activeMercenarySetId = self.activeMercenarySetId, + mercenarySets = copyTable(self.mercenarySets), + mercenarySetOrderList = copyTable(self.mercenarySetOrderList), + selectedSkillIndex = self.selectedSkillIndex, + sortGemsByDPS = self.sortGemsByDPS, + sortGemsByDPSField = self.sortGemsByDPSField, + configMercenarySetIds = self:GetConfigMercenaryBindings(), + } +end + +function MercenaryTabClass:RestoreUndoState(state) + local previousActive = self.activeMercenarySetId + self.mercenarySets = copyTable(state.mercenarySets) + wipeTable(self.mercenarySetOrderList) + for index, setId in ipairs(state.mercenarySetOrderList) do + self.mercenarySetOrderList[index] = setId + end + self.activeMercenarySetId = state.activeMercenarySetId + self.profile = self.mercenarySets[self.activeMercenarySetId] + self.selectedSkillIndex = state.selectedSkillIndex or 1 + self.sortGemsByDPS = state.sortGemsByDPS + self.sortGemsByDPSField = state.sortGemsByDPSField + self:InvalidateSupportSort() + if previousActive ~= self.activeMercenarySetId then + self:ApplyActiveMercenaryItemSet() + end + if state.configMercenarySetIds and self.build.configTab then + local configTab = self.build.configTab + for configSetId, configSet in pairs(configTab.configSets) do + local restoredId = state.configMercenarySetIds[configSetId] + -- Missing key: Config was created after this snapshot; leave it. + -- false: was unbound. number: restore that hire. + if restoredId ~= nil then + local setId = restoredId or nil + if configSet.mercenarySetId ~= setId then + configSet.mercenarySetId = setId + configTab.modFlag = true + end + end + end + end + if self.build.configTab then + self.build.configTab:EnsureHiredMercenaryModList() + end + self:RefreshControls() + self.build.buildFlag = true + self.build:SyncLoadouts() +end + +function MercenaryTabClass:Draw(viewPort, inputEvents) + local firstView = not self.data + self:EnsureData() + if firstView then + self:RefreshControls() + end + self.x, self.y, self.width, self.height = viewPort.x, viewPort.y, viewPort.width, viewPort.height + self:ProcessSupportSort() + for _, event in ipairs(inputEvents) do + if event.type == "KeyDown" then + if event.key == "z" and IsKeyDown("CTRL") then + self:Undo() + self.build.buildFlag = true + elseif event.key == "y" and IsKeyDown("CTRL") then + self:Redo() + self.build.buildFlag = true + end + end + end + self:ProcessControlsInput(inputEvents, viewPort) + main:DrawBackground(viewPort) + self:DrawControls(viewPort) +end diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index 0dd30e41d66..b71dfea18ee 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -53,6 +53,27 @@ local function getActor(self, actorType) end end +local function sourceOwnedDB(self, tag) + -- No overlay means a single actor: shared enemy is origin behaviour. + if tag.sourceOwned ~= true then + return nil + end + return (tag.sourceActor and tag.sourceActor.enemySourceDB) + or (self.actor and self.actor.enemySourceDB) + or nil +end + +local function actorModDB(self, actorType, tag) + if actorType == "enemy" and ((self.actor and self.actor.enemySourceDB) or (tag.sourceActor and tag.sourceActor.enemySourceDB)) then + local sourceDB = sourceOwnedDB(self, tag) + if sourceDB then + return sourceDB + end + end + local actor = getActor(self, actorType) + return actor and actor.modDB +end + function ModStoreClass:ScaleAddMod(mod, scale, replace) local unscalable = false for _, effects in ipairs(mod) do @@ -365,27 +386,24 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) local GetStat = self.GetStat local GetMultiplier = self.GetMultiplier local GetCondition = self.GetCondition + local hasOverlay = self.actor and self.actor.enemySourceDB for _, tag in ipairs(mod) do if tag.type == "Multiplier" then - local target = self + local target = (hasOverlay or tag.sourceActor) and (sourceOwnedDB(self, tag) or self) or self local limitTarget = self -- Allow limiting a self multiplier on a parent multiplier (eg. Agony Crawler on player virulence) -- This explicit target is necessary because even though the GetMultiplier method does call self.parent.GetMultiplier, it does so with noMod = true, -- disabling the summation (3rd part): (not noMod and self:Sum("BASE", cfg, multiplierName[var]) or 0) if tag.limitActor then - local limitActor = getActor(self, tag.limitActor) - if limitActor then - limitTarget = limitActor.modDB - else + limitTarget = actorModDB(self, tag.limitActor, tag) + if not limitTarget then return end end if tag.actor then - local actor = getActor(self, tag.actor) - if actor then - target = actor.modDB - else + target = actorModDB(self, tag.actor, tag) + if not target then return end end @@ -448,21 +466,17 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) end end elseif tag.type == "MultiplierThreshold" then - local target = self + local target = (hasOverlay or tag.sourceActor) and (sourceOwnedDB(self, tag) or self) or self local thresholdTarget = self if tag.thresholdActor then - local thresholdActor = getActor(self, tag.thresholdActor) - if thresholdActor then - thresholdTarget = thresholdActor.modDB - else + thresholdTarget = actorModDB(self, tag.thresholdActor, tag) + if not thresholdTarget then return end end if tag.actor then - local actor = getActor(self, tag.actor) - if actor then - target = actor.modDB - else + target = actorModDB(self, tag.actor, tag) + if not target then return end end @@ -483,9 +497,9 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) local target = self -- This functions similar to the above tagTypes in regard to which actor to use, but for PerStat -- if the actor is 'parent', we don't want to return if we're already using 'parent', just keep using 'self' - local actor = getActor(self, tag.actor) - if actor then - target = actor.modDB + local perStatDB = actorModDB(self, tag.actor, tag) + if perStatDB then + target = perStatDB end if tag.statList then base = 0 @@ -499,6 +513,9 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) tag.div = GetMultiplier(self, tag.divVar, cfg) end local mult = m_floor(base / (tag.div or 1) + 0.0001) + if tag.subtract then + mult = m_max(mult - tag.subtract, 0) + end local limitTotal if tag.limit or tag.limitVar then local limit = tag.limit or GetMultiplier(self, tag.limitVar, cfg) @@ -532,9 +549,9 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) local target = self -- This functions similar to the above tagTypes in regard to which actor to use, but for PercentStat -- if the actor is 'parent', we don't want to return if we're already using 'parent', just keep using 'self' - local actor = getActor(self, tag.actor) - if actor then - target = actor.modDB + local percentStatDB = actorModDB(self, tag.actor, tag) + if percentStatDB then + target = percentStatDB end if tag.statList then base = 0 @@ -632,7 +649,8 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) value = m_min(value, tag.limit or self:GetMultiplier(tag.limitVar, cfg)) elseif tag.type == "Condition" then local match = false - local allOneH = ((self.actor.weaponData1 and self.actor.weaponData1.countsAsAll1H) and self.actor.weaponData1) or ((self.actor.weaponData2 and self.actor.weaponData2.countsAsAll1H) and self.actor.weaponData2) + local condStore = (hasOverlay or tag.sourceActor) and (sourceOwnedDB(self, tag) or self) or self + local allOneH = ((condStore.actor.weaponData1 and condStore.actor.weaponData1.countsAsAll1H) and condStore.actor.weaponData1) or ((condStore.actor.weaponData2 and condStore.actor.weaponData2.countsAsAll1H) and condStore.actor.weaponData2) if tag.varList then for _, var in pairs(tag.varList) do if tag.neg and allOneH and allOneH["Added"..var] ~= nil then @@ -641,7 +659,7 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) if not allOneH["Added"..var] then return end - elseif GetCondition(self, var, cfg) or (cfg and cfg.skillCond and cfg.skillCond[var]) then + elseif GetCondition(condStore, var, cfg) or (cfg and cfg.skillCond and cfg.skillCond[var]) then match = true break end @@ -652,7 +670,7 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) return end else - match = GetCondition(self, tag.var, cfg) or (cfg and cfg.skillCond and cfg.skillCond[tag.var]) + match = GetCondition(condStore, tag.var, cfg) or (cfg and cfg.skillCond and cfg.skillCond[tag.var]) end end if tag.neg then @@ -665,8 +683,7 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) local match = false local target = self if tag.actor then - local actor = getActor(self, tag.actor) - target = actor and actor.modDB + target = actorModDB(self, tag.actor, tag) end if target and (tag.var or tag.varList) then if tag.varList then diff --git a/src/Classes/NotableDBControl.lua b/src/Classes/NotableDBControl.lua index 8253f4a471f..650b9e30db9 100644 --- a/src/Classes/NotableDBControl.lua +++ b/src/Classes/NotableDBControl.lua @@ -134,12 +134,12 @@ function NotableDBClass:ListBuilder() local start = GetTime() local calcFunc = self.itemsTab.build.calcsTab:GetMiscCalculator() local itemType = self.itemsTab.displayItem.base.type - local calcBase = calcFunc({ repSlotName = itemType, repItem = self.itemsTab:anointItem(nil) }) + local calcBase = calcFunc(self.itemsTab:ItemCalculationOverride(itemType, self.itemsTab:anointItem(nil))) self.sortMaxPower = 0 for nodeIndex, node in ipairs(list) do node.measuredPower = 0 if node.modKey ~= "" then - local output = calcFunc({ repSlotName = itemType, repItem = self.itemsTab:anointItem(node) }) + local output = calcFunc(self.itemsTab:ItemCalculationOverride(itemType, self.itemsTab:anointItem(node))) node.measuredPower = self:CalculatePowerStat(self.sortDetail, output, calcBase) if node.measuredPower == m_huge then t_insert(infinites, node) diff --git a/src/Classes/PoEAPI.lua b/src/Classes/PoEAPI.lua index 7a9031df059..66563a38469 100644 --- a/src/Classes/PoEAPI.lua +++ b/src/Classes/PoEAPI.lua @@ -6,19 +6,49 @@ local scopesOAuth = { "account:profile", "account:leagues", "account:characters", + "account:league_accounts", "account:trade" } local filename = "poe_api_response.json" +local function identifyingHeader() + return "User-Agent: OAuth pob/" .. tostring(launch.versionNumber) .. " (contact: https://github.com/PathOfBuildingCommunity/PathOfBuilding/issues)" +end + +local function validTokenResponse(response) + return type(response) == "table" and type(response.access_token) == "string" + and type(response.refresh_token) == "string" and type(response.expires_in) == "number" +end + +local function randomBytes(count) + local ffi = require("ffi") + if ffi.os == "Windows" then + ffi.cdef[[long __stdcall BCryptGenRandom(void*, unsigned char*, unsigned long, unsigned long);]] + local buffer = ffi.new("unsigned char[?]", count) + if ffi.load("bcrypt").BCryptGenRandom(nil, buffer, count, 2) ~= 0 then + error("Could not generate OAuth verifier") + end + return ffi.string(buffer, count) + end + local file = assert(io.open("/dev/urandom", "rb"), "Could not open OS random source") + local bytes = file:read(count) + file:close() + assert(bytes and #bytes == count, "Could not generate OAuth verifier") + return bytes +end + ---@class PoEAPI local PoEAPIClass = newClass("PoEAPI") -function PoEAPIClass:PoEAPI(authToken, refreshToken, tokenExpiry) +function PoEAPIClass:PoEAPI(authToken, refreshToken, tokenExpiry, grantedScopes) self.retries = 0 self.authToken = authToken self.refreshToken = refreshToken self.tokenExpiry = tokenExpiry or 0 + self.grantedScopes = grantedScopes + self.authGeneration = 0 + self.policyAliases = { } self.baseUrl = "https://api.pathofexile.com" self.rateLimiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter() self.tokenHasBeenValidated = false @@ -32,6 +62,7 @@ end -- will be reset. --- @param callback fun(valid: boolean, errMsg: string?) function PoEAPIClass:ValidateAuth(callback) + local generation = self.authGeneration if self.authToken and self.refreshToken and self.tokenExpiry then ConPrintf("Validating auth token") if self.tokenExpiry < os.time() then @@ -39,6 +70,7 @@ function PoEAPIClass:ValidateAuth(callback) -- here recreate the token with the refresh_token local formText = "client_id=pob&grant_type=refresh_token&refresh_token=" .. self.refreshToken launch:DownloadPage("https://www.pathofexile.com/oauth/token", function(response, errMsg) + if generation ~= self.authGeneration then callback(false, "Authorization changed") return end ConPrintf("Recreating auth token") if errMsg then ConPrintf("Failed to recreate auth token: %s", errMsg) @@ -46,20 +78,20 @@ function PoEAPIClass:ValidateAuth(callback) callback(false, errMsg) return end - local responseLua = dkjson.decode(response.body) - if not responseLua then + local responseLua = response and response.body and dkjson.decode(response.body) + if not validTokenResponse(responseLua) then self:ResetDetails() callback(false, "Malformed response") else self.authToken = responseLua.access_token self.refreshToken = responseLua.refresh_token self.tokenExpiry = os.time() + responseLua.expires_in + self.grantedScopes = responseLua.scope or self.grantedScopes self:UpdateMain() - self.retries = 0 callback(true) end - end, { body = formText }) + end, { body = formText, header = identifyingHeader() }) else callback(true) end @@ -70,14 +102,16 @@ end --- @param secret string local function base64_encode(secret) - return base64.encode(secret):gsub("+", "-"):gsub("/", "_"):gsub("=$", "") + return base64.encode(secret):gsub("+", "-"):gsub("/", "_"):gsub("=+$", "") end --- resets current authorization details function PoEAPIClass:ResetDetails() + self.authGeneration = self.authGeneration + 1 self.authToken = nil self.refreshToken = nil self.tokenExpiry = nil + self.grantedScopes = nil self:UpdateMain() end @@ -86,20 +120,30 @@ function PoEAPIClass:UpdateMain() main.lastToken = self.authToken main.lastRefreshToken = self.refreshToken main.tokenExpiry = self.tokenExpiry + main.grantedScopes = self.grantedScopes main:SaveSettings() end +function PoEAPIClass:HasScope(scope) + for granted in (self.grantedScopes or ""):gmatch("%S+") do + if granted == scope then + return true + end + end + return false +end + --- @param callback fun(errCode: string?) function PoEAPIClass:FetchAuthToken(callback) - math.randomseed(os.time()) - local secret = math.random(2 ^ 32 - 1) - local code_verifier = base64_encode(tostring(secret)) + local generation = self.authGeneration + local ok, secret = pcall(randomBytes, 48) + if not ok then + callback("Could not generate secure OAuth verifier") + return + end + local code_verifier = base64_encode(secret:sub(1, 32)) local code_challenge = base64_encode(sha.hex_to_bin(sha.sha256(code_verifier))) - - -- 16 character hex string - local initialState = string.gsub('xxxxxxxxxxxxxxxx', 'x', function() - return string.format('%x', math.random(0, 0xf)) - end) + local initialState = base64_encode(secret:sub(33)) local authUrl = string.format( "https://www.pathofexile.com/oauth/authorize?client_id=pob&response_type=code&scope=%s&state=%s&code_challenge=%s&code_challenge_method=S256" @@ -115,16 +159,15 @@ function PoEAPIClass:FetchAuthToken(callback) launch.subScripts[id] = { type = "DOWNLOAD", callback = function(code, errMsg, state, port) + if generation ~= self.authGeneration then return end if not code then ConPrintf("Failed to get code from server: %s", errMsg) - self:ResetDetails() callback(errMsg or self.ERROR_NO_AUTH) return end if initialState ~= state then ConPrintf("OAuth state mismatch during authentication") - self:ResetDetails() callback("OAuth state mismatch") return end @@ -133,30 +176,40 @@ function PoEAPIClass:FetchAuthToken(callback) "&redirect_uri=http://localhost:" .. port .. "&scope=" .. table.concat(scopesOAuth, " ") .. "&code_verifier=" .. code_verifier launch:DownloadPage("https://www.pathofexile.com/oauth/token", function(response, errMsg) + if generation ~= self.authGeneration then return end if errMsg then ConPrintf("Failed to get token from server: " .. errMsg) - self:ResetDetails() callback(errMsg) return end - local responseLua = dkjson.decode(response.body) + local responseLua = response and response.body and dkjson.decode(response.body) + if not validTokenResponse(responseLua) then + callback("Malformed authorization response") + return + end self.authToken = responseLua.access_token self.refreshToken = responseLua.refresh_token self.tokenExpiry = os.time() + responseLua.expires_in + self.grantedScopes = responseLua.scope or table.concat(scopesOAuth, " ") + self.authGeneration = self.authGeneration + 1 self:UpdateMain() self.retries = 0 SetForeground() callback() - end, { body = formText }) + end, { body = formText, header = identifyingHeader() }) end } + else + callback("Could not start authorization callback server") end end --- @param endpoint string --- @param callback fun(response: table?, errorMsg: string) function PoEAPIClass:DownloadWithRefresh(endpoint, callback) + local generation = self.authGeneration self:ValidateAuth(function(valid, validationErrMsg) + if generation ~= self.authGeneration then callback(nil, validationErrMsg or "Authorization changed") return end if not valid then -- Clean info about token and refresh token self:ResetDetails() @@ -165,6 +218,7 @@ function PoEAPIClass:DownloadWithRefresh(endpoint, callback) end launch:DownloadPage(self.baseUrl .. endpoint, function(response, errMsg) + if generation ~= self.authGeneration then callback(nil, "Authorization changed") return end if errMsg and errMsg:match("401") and self.retries < 1 then -- try once again with refresh token self.retries = 1 @@ -174,7 +228,7 @@ function PoEAPIClass:DownloadWithRefresh(endpoint, callback) self.retries = 0 if errMsg then ConPrintf("Failed to download %s: %s", endpoint, errMsg) - elseif response and response.body and launch.devMode then + elseif response and response.body and launch.devMode and not endpoint:match("^/league%-account") and endpoint ~= "/profile" then -- create the file and log the name file local file = io.open(filename, "w") if file then @@ -185,7 +239,7 @@ function PoEAPIClass:DownloadWithRefresh(endpoint, callback) end callback(response, errMsg) end - end, { header = "Authorization: Bearer " .. self.authToken }) + end, { header = "Authorization: Bearer " .. self.authToken .. "\r\n" .. identifyingHeader() }) end) end @@ -194,6 +248,8 @@ end --- @param url string --- @param callback DownloadCallback function PoEAPIClass:DownloadWithRateLimit(policy, url, callback) + local requestedPolicy = policy + policy = self.policyAliases[policy] or policy local now = os.time() local timeNext = self.rateLimiter:NextRequestTime(policy, now) if now >= timeNext then @@ -202,16 +258,22 @@ function PoEAPIClass:DownloadWithRateLimit(policy, url, callback) self.rateLimiter:FinishRequest(policy, requestId) local header = response and response.header or "" self.rateLimiter:UpdateFromHeader(header, policy) + local reportedPolicy = self.rateLimiter:ParseHeader(header)["x-rate-limit-policy"] or policy + self.policyAliases[requestedPolicy] = reportedPolicy + if header:match("HTTP/[%d%.]+ (%d+)") == "429" or (errMsg and errMsg:match("429")) then + timeNext = self.rateLimiter:NextRequestTime(reportedPolicy, os.time()) + callback(nil, "Response code: 429", timeNext) + return + end if errMsg then callback(response, errMsg, nil) return end - if header:match("HTTP/[%d%.]+ (%d+)") == "429" then - timeNext = self.rateLimiter:NextRequestTime(policy, now) - callback(nil, "Response code: 429", timeNext) + local responseLua = response and response.body and dkjson.decode(response.body) + if type(responseLua) ~= "table" then + callback(nil, "Malformed API response") return end - local responseLua = dkjson.decode(response.body) callback(responseLua, errMsg, nil) end self:DownloadWithRefresh(url, onComplete) @@ -236,3 +298,30 @@ function PoEAPIClass:DownloadCharacter(realm, name, callback) self:DownloadWithRateLimit("character-request-limit", "/character" .. (realm == "pc" and "" or "/" .. realm) .. "/" .. name, callback) end + +---Fetches league-account data from PoE's OAuth api +---@param realm string Realm to fetch the league account from +---@param league string League name +---@param callback DownloadCallback +function PoEAPIClass:DownloadLeagueAccount(realm, league, callback) + if not self:HasScope("account:league_accounts") then + callback(nil, "Authorize Mercenary access") + return + end + if realm ~= "pc" and realm ~= "xbox" and realm ~= "sony" then + callback(nil, "Unsupported realm") + return + end + if type(league) ~= "string" or league == "" then + callback(nil, "Character has no league") + return + end + self:DownloadWithRateLimit("league-account-request-limit", + "/league-account" .. (realm == "pc" and "" or "/" .. realm) .. "/" .. urlEncode(league), callback) +end + +---Fetches the authorized account profile +---@param callback DownloadCallback +function PoEAPIClass:DownloadProfile(callback) + self:DownloadWithRateLimit("profile-request-limit", "/profile", callback) +end diff --git a/src/Classes/SharedItemSetListControl.lua b/src/Classes/SharedItemSetListControl.lua index ba604874c77..2bf231a3a64 100644 --- a/src/Classes/SharedItemSetListControl.lua +++ b/src/Classes/SharedItemSetListControl.lua @@ -78,12 +78,13 @@ end function SharedItemSetListClass:ReceiveDrag(type, value, source) if type == "ItemList" then local sharedItemList = { title = value.title, slots = { } } - for slotName, slot in pairs(self.itemsTab.slots) do + for _, slot in ipairs(self.itemsTab.orderedSlots) do if not slot.nodeId then - if value ~= self.itemsTab.activeItemSet then + local slotName = slot.slotName + if value ~= self.itemsTab:GetVisibleItemSet() then slot = value[slotName] end - if slot.selItemId ~= 0 then + if slot and slot.selItemId ~= 0 then local item = self.itemsTab.items[slot.selItemId] local rawItem = { raw = item:BuildRaw() } local newItem = new("Item"):Item(rawItem.raw) @@ -110,4 +111,4 @@ function SharedItemSetListClass:OnSelKeyDown(index, sharedItemSet, key) if key == "F2" then self:RenameSet(sharedItemSet) end -end \ No newline at end of file +end diff --git a/src/Classes/SkillsTab.lua b/src/Classes/SkillsTab.lua index f1326ddc980..af8559a902e 100644 --- a/src/Classes/SkillsTab.lua +++ b/src/Classes/SkillsTab.lua @@ -10,6 +10,8 @@ local t_remove = table.remove local m_min = math.min local m_max = math.max +local skillOptions = require("Modules.SkillOptions") + local groupSlotDropList = { { label = "None" }, { label = "Weapon 1", slotName = "Weapon 1" }, @@ -27,6 +29,11 @@ local groupSlotDropList = { { label = "Belt", slotName = "Belt" }, } +local function getActiveItemForSlot(itemsTab, slotName) + local itemSlot = itemsTab.activeItemSet and itemsTab.activeItemSet[slotName] + return itemSlot and itemsTab.items[itemSlot.selItemId] +end + local defaultGemLevelList = { { label = "Normal Maximum", @@ -63,18 +70,6 @@ local showSupportGemTypeList = { { label = "Exceptional", show = "EXCEPTIONAL" }, } -local sortGemTypeList = { - { label = "Full DPS", type = "FullDPS" }, - { label = "Combined DPS", type = "CombinedDPS" }, - { label = "Hit DPS", type = "TotalDPS" }, - { label = "Average Hit", type = "AverageDamage" }, - { label = "DoT DPS", type = "TotalDot" }, - { label = "Bleed DPS", type = "BleedDPS" }, - { label = "Ignite DPS", type = "IgniteDPS" }, - { label = "Poison DPS", type = "TotalPoisonDPS" }, - { label = "Effective Hit Pool", type = "TotalEHP" }, -} - ---@class SkillsTab: UndoHandler, ControlHost, Control local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Control") @@ -128,7 +123,7 @@ function SkillsTabClass:SkillsTab(build) self.controls.sortGemsByDPS = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 70, 20 }, "Sort gems by DPS:", function(state) self.sortGemsByDPS = state end, nil, true) - self.controls.sortGemsByDPSFieldControl = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.sortGemsByDPS, "RIGHT" }, { 10, 0, 140, 20 }, sortGemTypeList, function(index, value) + self.controls.sortGemsByDPSFieldControl = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.sortGemsByDPS, "RIGHT" }, { 10, 0, 140, 20 }, skillOptions.sortGemTypeList, function(index, value) self.sortGemsByDPSField = value.type end) self.controls.defaultLevel = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 94, 170, 20 }, defaultGemLevelList, function(index, value) @@ -193,7 +188,7 @@ function SkillsTabClass:SkillsTab(build) tooltip:AddLine(16, "This will allow the skill to benefit from modifiers on the item that affect socketed gems.") else local slot = self.build.itemsTab.slots[value.slotName] - local ttItem = self.build.itemsTab.items[slot.selItemId] + local ttItem = getActiveItemForSlot(self.build.itemsTab, value.slotName) if ttItem then self.build.itemsTab:AddItemTooltip(tooltip, ttItem, slot) else @@ -219,12 +214,9 @@ function SkillsTabClass:SkillsTab(build) local item local groupSlot = self.controls.groupSlot:GetSelValue() if groupSlot and groupSlot.slotName then - local slot = self.build.itemsTab.slots[groupSlot.slotName] - if slot then - item = self.build.itemsTab.items[slot.selItemId] - if not item then - return - end + item = getActiveItemForSlot(self.build.itemsTab, groupSlot.slotName) + if not item then + return end end return item, groupSlot @@ -1254,7 +1246,7 @@ function SkillsTabClass:UpdateSocketGroups() local colours = { "R", "G", "B" } local gemIdx = gemOffset + i if slot then - local item = self.build.itemsTab.items[slot.selItemId] + local item = getActiveItemForSlot(self.build.itemsTab, socketGroup.slot) if item and item.sockets then -- e.g. dialla's malefaction if item.sockets.colourAlwaysMatches then @@ -1474,6 +1466,19 @@ function SkillsTabClass:RebuildImbuedSupportBySlot() end end +function SkillsTabClass:UsesItemSet(itemSetId) + for _, skillSet in pairs(self.skillSets) do + for _, group in ipairs(skillSet.socketGroupList) do + for _, gem in ipairs(group.gemList or { }) do + if gem.skillMinionItemSet == itemSetId or gem.skillMinionItemSetCalcs == itemSetId then + return true + end + end + end + end + return false +end + -- Changes the active skill set function SkillsTabClass:SetActiveSkillSet(skillSetId) -- Initialize skill sets if needed diff --git a/src/Classes/TradeHelpers.lua b/src/Classes/TradeHelpers.lua index 444834a7974..000c7a1e94c 100644 --- a/src/Classes/TradeHelpers.lua +++ b/src/Classes/TradeHelpers.lua @@ -4,6 +4,7 @@ -- Stateless trade mod lookup/matching and item display helper functions -- local m_floor = math.floor +local MercenaryTools = require("Modules.MercenaryTools") -- The stat description data is big and is only needed once a trade lookup actually runs, -- so it and its precalculated patterns are built lazily @@ -350,6 +351,7 @@ end --- @param item table function M.getTradeCategory(slotName, item) if not slotName then return nil, nil end + slotName = MercenaryTools.baseItemSlotName(slotName) or slotName local itemType = item and (item.type or (item.base and item.base.type)) if slotName:find("^Weapon %d") then if not itemType then return "weapon.one", "1HWeapon" end diff --git a/src/Classes/TradeQuery.lua b/src/Classes/TradeQuery.lua index 66ad1fc1ff9..d1141746698 100644 --- a/src/Classes/TradeQuery.lua +++ b/src/Classes/TradeQuery.lua @@ -7,11 +7,11 @@ local dkjson = require "dkjson" local itemSlotHelper = require("Modules.ItemSlotHelper") +local MercenaryTools = require("Modules.MercenaryTools") local get_time = os.time local t_insert = table.insert local t_remove = table.remove -local t_sort = table.sort local m_max = math.max local m_min = math.min local m_ceil = math.ceil @@ -63,7 +63,7 @@ function TradeQueryClass:TradeQuery(itemsTab) self.tradeQueryRequests = new("TradeQueryRequests"):TradeQueryRequests() if not main.api then - main.api = new("PoEAPI"):PoEAPI(main.lastToken, main.lastRefreshToken, main.tokenExpiry) + main.api = new("PoEAPI"):PoEAPI(main.lastToken, main.lastRefreshToken, main.tokenExpiry, main.grantedScopes) end self.hostName = "https://www.pathofexile.com/" @@ -288,6 +288,7 @@ function TradeQueryClass:PriceItem() local top_pane_alignment_ref = nil local pane_margins_horizontal = 16 local pane_margins_vertical = 16 + local initialItemSetId = self.itemsTab.viewItemSetId or self.itemsTab.activeItemSetId local newItemList = { } for index, itemSetId in ipairs(self.itemsTab.itemSetOrderList) do @@ -295,9 +296,16 @@ function TradeQueryClass:PriceItem() t_insert(newItemList, itemSet.title or "Default") end self.controls.setSelect = new("DropDownControl"):DropDownControl({"TOPLEFT", nil, "TOPLEFT"}, {pane_margins_horizontal, pane_margins_vertical, 188, row_height}, newItemList, function(index, value) - self.itemsTab:SetActiveItemSet(self.itemsTab.itemSetOrderList[index]) + local itemSetId = self.itemsTab.itemSetOrderList[index] + local itemSetChanged = itemSetId ~= initialItemSetId + self.itemsTab:SetViewItemSet(itemSetId, self.itemsTab.viewComparisonActor) self.itemsTab:AddUndoState() + if itemSetChanged then + main:ClosePopup() + self:PriceItem() + end end) + self.controls.setSelect.selIndex = isValueInArray(self.itemsTab.itemSetOrderList, self.itemsTab.viewItemSetId or self.itemsTab.activeItemSetId) or 1 self.controls.setSelect.enableDroppedWidth = true self.controls.setSelect.enabled = function() return #self.itemsTab.itemSetOrderList > 1 @@ -517,21 +525,6 @@ Highest Weight - Displays the order retrieved from trade]] self:UpdateRealms() end - local activeAbyssalSockets = { - ["Weapon 1"] = { }, ["Weapon 2"] = { }, ["Helmet"] = { }, ["Body Armour"] = { }, ["Gloves"] = { }, ["Boots"] = { }, ["Belt"] = { }, - } - -- loop all slots, set any active abyssal sockets - for index, slot in pairs(self.itemsTab.slots) do - if index:find("Abyssal") and slot.shown() then - t_insert(activeAbyssalSockets[slot.parentSlot.slotName], slot) - end - end - for _, abyssal in pairs(activeAbyssalSockets) do -- sort Abyssal #1 > Abyssal #2 etc - t_sort(abyssal, function(a, b) - return a.label < b.label - end) - end - -- Individual slot rows ---@class TradeQuerySlotTable ---@field slotName string Display name of the row, also the slot name for regular slots @@ -544,14 +537,29 @@ Highest Weight - Displays the order retrieved from trade]] ---@type TradeQuerySlotTable[] local slotTables = {} - for _, slotName in ipairs(baseSlots) do - if self.itemsTab.slots[slotName].shown() then - t_insert(slotTables, { slotName = slotName }) + local visibleSlots = self.itemsTab.orderedSlots + local visibleItemSet = self.itemsTab:GetVisibleItemSet() + local visibleItemSetId = visibleItemSet and visibleItemSet.id + local function isSlotShown(slot) + if slot.shown == nil then return true end + if type(slot.shown) == "function" then + return slot.shown() end - -- add abyssal sockets to slotTables if exist for this slot - if activeAbyssalSockets[slotName] then - for _, abyssalSocket in pairs(activeAbyssalSockets[slotName]) do - t_insert(slotTables, { slotName = abyssalSocket.label, fullName = abyssalSocket.slotName }) -- actual slotName doesn't fit/excessive in slotName on popup but is needed for exact matching later + return slot.shown + end + for _, slot in ipairs(visibleSlots) do + if isSlotShown(slot) then + if not slot.nodeId and not slot.slotName:find("Abyssal") then + t_insert(slotTables, { + slotName = slot.slotName, + itemSetId = visibleItemSetId, + }) + elseif slot.slotName:find("Abyssal") then + t_insert(slotTables, { + slotName = slot.label, + fullName = slot.slotName, + itemSetId = visibleItemSetId, + }) end end end @@ -820,8 +828,22 @@ end -- Method to evaluate a result by getting it's output and weight function TradeQueryClass:GetResultEvaluation(row_idx, result_index, calcFunc, baseOutput) local result = self.resultTbl[row_idx][result_index] + local slotTbl = self.slotTables[row_idx] + local jewelNodeId = slotTbl.nodeId or slotTbl.selectedJewelNodeId + local slotName = jewelNodeId and "Jewel " .. tostring(jewelNodeId) or slotTbl.fullName or slotTbl.slotName + local comparisonActor = self.itemsTab:ComparisonActorForSlot(slotName, slotTbl.itemSetId) if not calcFunc then -- Always evaluate when calcFunc is given - calcFunc, baseOutput = self.itemsTab.build.calcsTab:GetMiscCalculator() + local actorOutputs + calcFunc, baseOutput, actorOutputs = self.itemsTab.build.calcsTab:GetMiscCalculator() + if slotTbl.itemSetId then + baseOutput = calcFunc({ itemSetId = slotTbl.itemSetId, comparisonActor = comparisonActor }) + else + baseOutput = MercenaryTools.comparisonBaseOutput(baseOutput, actorOutputs, comparisonActor) + end + if comparisonActor == "MERCENARY" and not MercenaryTools.mercenaryOutputAvailable(baseOutput) then + result.evaluation = { } + return result.evaluation + end local onlyWeightedBaseOutput = self:ReduceOutput(baseOutput) if not self.onlyWeightedBaseOutput[row_idx] then self.onlyWeightedBaseOutput[row_idx] = { } @@ -836,8 +858,6 @@ function TradeQueryClass:GetResultEvaluation(row_idx, result_index, calcFunc, ba self.onlyWeightedBaseOutput[row_idx][result_index] = onlyWeightedBaseOutput self.lastComparedWeightList[row_idx][result_index] = self.statSortSelectionList end - local slotTbl = self.slotTables[row_idx] - local jewelNodeId = slotTbl.nodeId or slotTbl.selectedJewelNodeId if slotTbl.slotName == "Megalomaniac" then local addedNodes = {} for nodeName in (result.item_string.."\r\n"):gmatch("1 Added Passive Skill is (.-)\r?\n") do @@ -872,7 +892,7 @@ function TradeQueryClass:GetResultEvaluation(row_idx, result_index, calcFunc, ba local slotName = jewelNodeId and "Jewel " .. tostring(jewelNodeId) or slotTbl.selectedSlotName or slotTbl.slotName local item = new("Item"):Item(result.item_string) - local output = self:ReduceOutput(calcFunc({ repSlotName = slotName, repItem = item })) + local output = self:ReduceOutput(calcFunc(self.itemsTab:ItemCalculationOverride(slotName, item, slotTbl.itemSetId))) local weight = self.tradeQueryGenerator.WeightedRatioOutputs(baseOutput, output, self.statSortSelectionList) result.evaluation = {{ output = output, weight = weight }} end @@ -1029,7 +1049,7 @@ function TradeQueryClass:FilterToSafeItems(itemEntries, slotName) local itemsSafe = {} for _, entry in ipairs(itemEntries) do local item = new("Item"):Item(entry.item_string) - if item.base and ((not slotName) or self.itemsTab:IsItemValidForSlot(item, slotName)) then + if item.base and ((not slotName) or self.itemsTab:IsItemValidForSlot(item, slotName, self.itemsTab:GetVisibleItemSet())) then t_insert(itemsSafe, entry) end end @@ -1039,7 +1059,9 @@ end function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, row_vertical_padding, row_height) local controls = self.controls local slotTbl = self.slotTables[row_idx] - local activeSlotRef = slotTbl.nodeId and self.itemsTab.activeItemSet[slotTbl.nodeId] or self.itemsTab.activeItemSet[slotTbl.slotName] + local function getVisibleItemSet() + return self.itemsTab:GetVisibleItemSet() + end local nodeId = slotTbl.nodeId or slotTbl.selectedJewelNodeId local activeSlot = nodeId and self.itemsTab.sockets[nodeId] or slotTbl.slotName and (self.itemsTab.slots[slotTbl.slotName] or @@ -1050,7 +1072,7 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro return selectedNodeId and self.itemsTab.sockets[selectedNodeId] or activeSlot end local nameColor = slotTbl.unique and colorCodes.UNIQUE or "^7" - controls["name" .. row_idx] = new("LabelControl"):LabelControl(top_pane_alignment_ref, { 0, row_idx * (row_height + row_vertical_padding), 135, row_height - 4 }, nameColor .. slotTbl.slotName) + controls["name" .. row_idx] = new("LabelControl"):LabelControl(top_pane_alignment_ref, { 0, row_idx * (row_height + row_vertical_padding), 135, row_height - 4 }, nameColor .. (slotTbl.displayName or slotTbl.slotName)) controls["bestButton" .. row_idx] = new("ButtonControl"):ButtonControl({ "LEFT", controls["name" .. row_idx], "LEFT" }, { 135 + 8, 0, 80, row_height }, "Find best", function() self.tradeQueryGenerator:RequestQuery(activeSlot, { slotTbl = slotTbl, controls = controls, row_idx = row_idx }, self.statSortSelectionList, function(context, query, errMsg) if errMsg then @@ -1142,9 +1164,10 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite elseif buf == "" then pbURL = "" end - if not activeSlotRef and slotTbl.nodeId then - self.itemsTab.activeItemSet[slotTbl.nodeId] = { pbURL = "" } - activeSlotRef = self.itemsTab.activeItemSet[slotTbl.nodeId] + local currentItemSet = getVisibleItemSet() + local currentSlotRef = slotTbl.nodeId and currentItemSet[slotTbl.nodeId] or currentItemSet[slotTbl.fullName or slotTbl.slotName] + if not currentSlotRef and slotTbl.nodeId then + currentItemSet[slotTbl.nodeId] = { pbURL = "" } end end, nil) controls["uri"..row_idx]:SetPlaceholder("Paste trade URL here...") @@ -1252,9 +1275,10 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite self.itemsTab:AddDisplayItem(true) -- Autoequip it local jewelNodeId = slotTbl.nodeId or slotTbl.selectedJewelNodeId - local slot = jewelNodeId and self.itemsTab.sockets[jewelNodeId] or self.itemsTab.slots[slotTbl.slotName] - if slot and (jewelNodeId or slotTbl.slotName == slot.label) and slot:IsShown() and self.itemsTab:IsItemValidForSlot(item, slot.slotName) then - slot:SetSelItemId(item.id) + local slotName = slotTbl.fullName or slotTbl.slotName + local slot = jewelNodeId and self.itemsTab.sockets[jewelNodeId] or self.itemsTab.slots[slotName] + if slot and slot:IsShown() and self.itemsTab:IsItemValidForSlot(item, slot.slotName, getVisibleItemSet()) then + slot:SetSelItemId(item.id, getVisibleItemSet()) self.itemsTab:PopulateSlots() self.itemsTab:AddUndoState() self.itemsTab.build.buildFlag = true diff --git a/src/Classes/TradeQueryGenerator.lua b/src/Classes/TradeQueryGenerator.lua index 826cb34a086..343a4bbd19f 100644 --- a/src/Classes/TradeQueryGenerator.lua +++ b/src/Classes/TradeQueryGenerator.lua @@ -11,6 +11,7 @@ local s_format = string.format local t_insert = table.insert local tradeHelpers = require("Classes.TradeHelpers") local utils = require("Modules.Utils") +local MercenaryTools = require("Modules.MercenaryTools") -- a table which tells us what subtypes each category we can search for -- contains. the commented out lines are type-subtype combinations which don't @@ -592,7 +593,11 @@ function TradeQueryGeneratorClass:GenerateModWeights(modsToTest) logToFile("Failed to test %s mod: %s", self.calcContext.itemCategory, modLine) end - local output = self.calcContext.calcFunc({ repSlotName = self.calcContext.slot.slotName, repItem = self.calcContext.testItem }) + local output = self.calcContext.calcFunc(self.itemsTab:ItemCalculationOverride( + self.calcContext.slot.slotName, + self.calcContext.testItem, + self.calcContext.itemSetId + )) local meanStatDiff = TradeQueryGeneratorClass.WeightedRatioOutputs(self.calcContext.baseOutput, output, self.calcContext.options.statWeights) * 1000 - (self.calcContext.baseStatValue or 0) if meanStatDiff > 0.01 then t_insert(self.modWeights, { tradeModId = entry.tradeMod.id, weight = meanStatDiff / modValue, meanStatDiff = meanStatDiff, invert = entry.sign == "-" and true or false }) @@ -764,8 +769,23 @@ function TradeQueryGeneratorClass:StartQuery(slot, options) local testItem = new("Item"):Item(itemRawStr) -- Calculate base output with a blank item - local calcFunc, baseOutput = self.itemsTab.build.calcsTab:GetMiscCalculator() - local baseItemOutput = slot and calcFunc({ repSlotName = slot.slotName, repItem = testItem }) or baseOutput + local calcFunc, baseOutput, actorOutputs = self.itemsTab.build.calcsTab:GetMiscCalculator() + local itemSetId = options.itemSetId or self.itemsTab.viewItemSetId + local slotName = slot and slot.slotName + local comparisonActor = self.itemsTab:ComparisonActorForSlot(slotName, itemSetId) + if itemSetId then + baseOutput = calcFunc({ itemSetId = itemSetId, comparisonActor = comparisonActor }) + else + baseOutput = MercenaryTools.comparisonBaseOutput(baseOutput, actorOutputs, comparisonActor) + end + if comparisonActor == "MERCENARY" and not MercenaryTools.mercenaryOutputAvailable(baseOutput) then + if self.requesterCallback then + self.requesterCallback(self.requesterContext, nil, "Mercenary calculation unavailable") + main:ClosePopup() + end + return + end + local baseItemOutput = slot and calcFunc(self.itemsTab:ItemCalculationOverride(slotName, testItem, itemSetId)) or baseOutput -- make weights more human readable local compStatValue = TradeQueryGeneratorClass.WeightedRatioOutputs(baseOutput, baseItemOutput, options.statWeights) * 1000 @@ -781,6 +801,7 @@ function TradeQueryGeneratorClass:StartQuery(slot, options) baseOutput = baseOutput, baseStatValue = compStatValue, calcFunc = calcFunc, + itemSetId = itemSetId, options = options, slot = slot, requiredMods = options.requiredMods, @@ -927,7 +948,11 @@ function TradeQueryGeneratorClass:FinishQuery() end self.calcContext.testItem:BuildAndParseRaw() - local originalOutput = originalItem and self.calcContext.calcFunc({ repSlotName = self.calcContext.slot.slotName, repItem = self.calcContext.testItem }) or self.calcContext.baseOutput + local originalOutput = originalItem and self.calcContext.calcFunc(self.itemsTab:ItemCalculationOverride( + self.calcContext.slot.slotName, + self.calcContext.testItem, + self.calcContext.itemSetId + )) or self.calcContext.baseOutput local currentStatDiff = TradeQueryGeneratorClass.WeightedRatioOutputs(self.calcContext.baseOutput, originalOutput, self.calcContext.options.statWeights) * 1000 - (self.calcContext.baseStatValue or 0) if self.calcContext.options.includeAllWEMods then @@ -1174,12 +1199,13 @@ function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callb local popupHeight = 110 local popupWidth = 480 - local isJewelSlot = slot and slot.slotName:find("Jewel") ~= nil - local isAbyssalJewelSlot = slot and slot.slotName:find("Abyssal") ~= nil - local isAmuletSlot = slot and slot.slotName == "Amulet" - local isBeltSlot = slot and slot.slotName == "Belt" - local isWeaponSlot = slot and (slot.slotName == "Weapon 1" or slot.slotName == "Weapon 2") - local isEldritchModSlot = slot and eldritchModSlots[slot.slotName] == true + local slotName = slot and (MercenaryTools.baseItemSlotName(slot.slotName) or slot.slotName) + local isJewelSlot = slotName and slotName:find("Jewel") ~= nil + local isAbyssalJewelSlot = slotName and slotName:find("Abyssal") ~= nil + local isAmuletSlot = slotName == "Amulet" + local isBeltSlot = slotName == "Belt" + local isWeaponSlot = slotName == "Weapon 1" or slotName == "Weapon 2" + local isEldritchModSlot = eldritchModSlots[slotName] == true local lastItemAnchor local function updateLastAnchor(anchor, height) @@ -1424,6 +1450,7 @@ Remove: %s will be removed from the search results.]], term, term, term) options.blockedMods = copyTable(notMods) end options.statWeights = statWeights + options.itemSetId = context.slotTbl.itemSetId if controls.jewelSlot then slot = controls.jewelSlot:GetSelValue() -- pass node id back to table so evaluation can use the correct socket instead of the unique pseudo slot diff --git a/src/Classes/TradeQueryRateLimiter.lua b/src/Classes/TradeQueryRateLimiter.lua index f98c59f669f..093385a2c53 100644 --- a/src/Classes/TradeQueryRateLimiter.lua +++ b/src/Classes/TradeQueryRateLimiter.lua @@ -56,7 +56,9 @@ function TradeQueryRateLimiterClass:TradeQueryRateLimiter() ["trade-search-request-limit"] = {}, ["trade-fetch-request-limit"] = {}, ["character-list-request-limit"] = {}, - ["character-request-limit"] = {} + ["character-request-limit"] = {}, + ["league-account-request-limit"] = {}, + ["profile-request-limit"] = {}, } return self end @@ -118,6 +120,7 @@ function TradeQueryRateLimiterClass:UpdateFromHeader(headerString, policy) return end for policyKey, policyValue in pairs(newPolicies) do + self.pendingRequests[policyKey] = self.pendingRequests[policyKey] or { } if self.requestHistory[policyKey] == nil then self.requestHistory[policyKey] = { timestamps = {} } end @@ -225,6 +228,7 @@ function TradeQueryRateLimiterClass:InsertRequest(policy, timestamp, time) end local requestId = self.requestId self.requestId = self.requestId + 1 + self.pendingRequests[policy] = self.pendingRequests[policy] or { } table.insert(self.pendingRequests[policy], requestId) return requestId end diff --git a/src/Data/Mercenaries.lua b/src/Data/Mercenaries.lua new file mode 100644 index 00000000000..8e3f5cfc5a0 --- /dev/null +++ b/src/Data/Mercenaries.lua @@ -0,0 +1,34787 @@ +-- This file is automatically generated, do not edit! +-- Mercenary data (c) Grinding Gear Games + +return { + baseStats={ + accuracyPerLevel=3, + disableDefaultMonsterStats=true, + lifePerLevel=18, + manaPerLevel=9 + }, + buildOrder={ + [1]="AurasMinionsTemplarSmite", + [2]="AurasMinionsTemplarSmiteNoble", + [3]="AurasMinionsTemplarSmiteRuckusNoble", + [4]="AurasMinionsTemplarSpectres", + [5]="AurasMinionsTemplarSpectresNoble", + [6]="AurasMinionsTemplarStaff", + [7]="AurasMinionsTemplarStaffNoble", + [8]="ChaosMinionWitchChaosHit", + [9]="ChaosMinionWitchChaosHitNoble", + [10]="ChaosMinionWitchDot", + [11]="ChaosMinionWitchDotNoble", + [12]="ChaosMinionWitchInstability", + [13]="ChaosMinionWitchInstabilityNoble", + [14]="Crit1HShadowPhysSpell", + [15]="Crit1HShadowPhysSpellNoble", + [16]="Crit1HShadowPoison", + [17]="Crit1HShadowPoisonNoble", + [18]="Crit1HShadowSpectral", + [19]="DivingDuelist", + [20]="DivingDuelistNoble", + [21]="EleBowRangerClones", + [22]="EleBowRangerClonesNoble", + [23]="EleBowRangerFire", + [24]="EleBowRangerFireNoble", + [25]="EleBowRangerLightning", + [26]="ElementalWitchCold", + [27]="ElementalWitchColdNoble", + [28]="ElementalWitchFire", + [29]="ElementalWitchLightning", + [30]="ElementalWitchLightningNoble", + [31]="MeleeAOEMarauderFireSlam", + [32]="MeleeAOEMarauderFireSlamNoble", + [33]="MeleeAOEMarauderNonSlam", + [34]="MeleeAOEMarauderNonSlamNoble", + [35]="MeleeAOEMarauderPhysSlam", + [36]="MeleeAOEMarauderPhysSlamNoble", + [37]="MeleeAOEStrikeDuelistCyclone", + [38]="MeleeAOEStrikeDuelistCycloneNoble", + [39]="MeleeAOEStrikeDuelistRangeStrikes", + [40]="MeleeAOEStrikeDuelistRangeStrikesNoble", + [41]="MeleeStrikesMaraduerPhys", + [42]="MeleeStrikesMaraduerPhysNoble", + [43]="MeleeStrikesMarauderFire", + [44]="MiscScionPhysDot", + [45]="MiscScionPhysDotNoble", + [46]="MiscScionWandAttacks", + [47]="MiscScionWandAttacksNoble", + [48]="NonEleBowRangerChaos", + [49]="NonEleBowRangerChaosNoble", + [50]="NonEleBowRangerPhys", + [51]="NonEleBowRangerPhysNoble", + [52]="PhysConvertTemplarCold", + [53]="PhysConvertTemplarFire", + [54]="PhysConvertTemplarLightning", + [55]="PhysConvertTemplarLightningNoble", + [56]="PhysicalDuelistBleed", + [57]="PhysicalDuelistBleedNoble", + [58]="PhysicalDuelistShields", + [59]="PhysicalDuelistShieldsNoble", + [60]="PhysicalDuelistSteel", + [61]="TrapsMinesShadowAttack", + [62]="TrapsMinesShadowAttackNoble", + [63]="TrapsMinesShadowCold", + [64]="TrapsMinesShadowLightning", + [65]="TrapsMinesShadowLightningNoble" + }, + builds={ + AurasMinionsTemplarSmite={ + classId="AurasMinionsTemplar", + hash=30019, + id="AurasMinionsTemplarSmite", + infamous=false, + name="Warpriest", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [13]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Attack Speed", + id="minion_attack_speed", + statId="minion_attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [14]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Critical Strike Chance", + id="minion_crit_chance", + statId="minion_critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have +%s%% to Critical Strike Multiplier", + id="minion_crit_damage", + statId="minion_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [16]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_damage_applies_to_you", + line="Increases and Reductions to Minion Damage also affect you", + statId="minion_damage_increases_and_reductions_also_affects_you", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [17]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_high", + statId="minion_damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="Minions have %s%% increased maximum Life", + id="minion_life", + statId="minion_maximum_life_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Minions Regenerate %s%% of Life per second", + id="minion_life_regen", + statId="minion_life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [20]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [21]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [22]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="DominatingBlowMercenary", + [2]="DoryanisTouchMercenary", + [3]="FlameDashMercenary", + [4]="HeraldOfPurityMercenary", + [5]="PhysicalBeaconMercenary", + [6]="PurityOfLightningMercenary", + [7]="SSMHolySpectresMercenary", + [8]="SmiteMercenary", + [9]="SummonHolyRelicMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="SmiteMercenary", + [2]="SummonHolyRelicMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="DominatingBlowMercenary", + [2]="DoryanisTouchMercenary", + [3]="PhysicalBeaconMercenary", + [4]="SSMHolySpectresMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="HeraldOfPurityMercenary", + [3]="PurityOfLightningMercenary" + } + } + }, + tags={ + [1]="mercenary_aura_templar", + [2]="mercenary_aura_templar_smite" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Mace", + [2]="Sceptre" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="One Handed Mace", + [2]="Sceptre", + [3]="Shield" + } + }, + AurasMinionsTemplarSmiteNoble={ + classId="AurasMinionsTemplar", + hash=54254, + id="AurasMinionsTemplarSmiteNoble", + infamous=true, + name="Infamous Warpriest", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [13]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Attack Speed", + id="minion_attack_speed", + statId="minion_attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [14]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Critical Strike Chance", + id="minion_crit_chance", + statId="minion_critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have +%s%% to Critical Strike Multiplier", + id="minion_crit_damage", + statId="minion_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [16]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_damage_applies_to_you", + line="Increases and Reductions to Minion Damage also affect you", + statId="minion_damage_increases_and_reductions_also_affects_you", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [17]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_high", + statId="minion_damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="Minions have %s%% increased maximum Life", + id="minion_life", + statId="minion_maximum_life_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Minions Regenerate %s%% of Life per second", + id="minion_life_regen", + statId="minion_life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [20]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [21]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [22]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="DominatingBlowMercenary", + [2]="DoryanisTouchMercenary", + [3]="FlameDashMercenary", + [4]="HeraldOfPurityMercenary", + [5]="PhysicalBeaconMercenary", + [6]="PurityOfLightningMercenary", + [7]="SSMHolySpectresMercenary", + [8]="SmiteMercenary", + [9]="SummonHolyRelicMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="SmiteMercenary", + [2]="SummonHolyRelicMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="DominatingBlowMercenary", + [2]="DoryanisTouchMercenary", + [3]="PhysicalBeaconMercenary", + [4]="SSMHolySpectresMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="HeraldOfPurityMercenary", + [3]="PurityOfLightningMercenary" + } + } + }, + tags={ + [1]="mercenary_aura_templar", + [2]="mercenary_aura_templar_smite", + [3]="mercenary_aura_templar_smite_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Mace", + [2]="Sceptre" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="One Handed Mace", + [2]="Sceptre", + [3]="Shield" + } + }, + AurasMinionsTemplarSmiteRuckusNoble={ + classId="AurasMinionsTemplar", + hash=8619, + id="AurasMinionsTemplarSmiteRuckusNoble", + infamous=true, + name="Infamous Warpriest of the Ruckus", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [13]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Attack Speed", + id="minion_attack_speed", + statId="minion_attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [14]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Critical Strike Chance", + id="minion_crit_chance", + statId="minion_critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have +%s%% to Critical Strike Multiplier", + id="minion_crit_damage", + statId="minion_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [16]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_damage_applies_to_you", + line="Increases and Reductions to Minion Damage also affect you", + statId="minion_damage_increases_and_reductions_also_affects_you", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [17]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_high", + statId="minion_damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="Minions have %s%% increased maximum Life", + id="minion_life", + statId="minion_maximum_life_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Minions Regenerate %s%% of Life per second", + id="minion_life_regen", + statId="minion_life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [20]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [21]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [22]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="DominatingBlowMercenary", + [2]="DoryanisTouchMercenary", + [3]="FlameDashMercenary", + [4]="HeraldOfPurityMercenary", + [5]="PhysicalBeaconMercenary", + [6]="PurityOfLightningMercenary", + [7]="SSMHolySpectresMercenary", + [8]="SmiteMercenary", + [9]="SummonHolyRelicMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="SmiteMercenary", + [2]="SummonHolyRelicMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="DominatingBlowMercenary", + [2]="DoryanisTouchMercenary", + [3]="PhysicalBeaconMercenary", + [4]="SSMHolySpectresMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="HeraldOfPurityMercenary", + [3]="PurityOfLightningMercenary" + } + } + }, + tags={ + [1]="mercenary_aura_templar", + [2]="mercenary_aura_templar_smite", + [3]="mercenary_aura_templar_smite_noble", + [4]="mercenary_aura_templar_spectre_ruckus_noble", + [5]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Mace", + [2]="Sceptre" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="One Handed Mace", + [2]="Sceptre", + [3]="Shield" + } + }, + AurasMinionsTemplarSpectres={ + classId="AurasMinionsTemplar", + hash=41496, + id="AurasMinionsTemplarSpectres", + infamous=false, + name="Fallen Reverend", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour30", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_low", + statId="base_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield70", + statId="maximum_energy_shield_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge70", + statId="energy_shield_delay_-%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int70", + statId="base_intelligence", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life30", + statId="maximum_life_+%", + values={ + [1]=49, + [2]=98, + [3]=130 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen30", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=18, + [2]=27, + [3]=36 + } + }, + [12]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Cast Speed", + id="minion_cast_speed", + statId="minion_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [13]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Critical Strike Chance", + id="minion_crit_chance", + statId="minion_critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [14]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have +%s%% to Critical Strike Multiplier", + id="minion_crit_damage", + statId="minion_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_damage_applies_to_you", + line="Increases and Reductions to Minion Damage also affect you", + statId="minion_damage_increases_and_reductions_also_affects_you", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [16]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_high", + statId="minion_damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="Minions have %s%% increased maximum Life", + id="minion_life", + statId="minion_maximum_life_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Minions Regenerate %s%% of Life per second", + id="minion_life_regen", + statId="minion_life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate70", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [20]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [21]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str30", + statId="base_strength", + values={ + [1]=22, + [2]=77, + [3]=154 + } + } + }, + skillIds={ + [1]="AbsolutionMercenary", + [2]="BattlemagesCryMercenary", + [3]="DesecrateMercenary", + [4]="FlameDashMercenary", + [5]="FrostblinkMercenary", + [6]="RaiseSpectreAltMercenary", + [7]="SSMPaganBishopMercenary", + [8]="SSMSkeletalBossMercenary", + [9]="SSMVollMercenary", + [10]="WrathMercenary", + [11]="ZealotryMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="AbsolutionMercenary", + [2]="DesecrateMercenary", + [3]="RaiseSpectreAltMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="SSMPaganBishopMercenary", + [2]="SSMSkeletalBossMercenary", + [3]="SSMVollMercenary" + } + }, + [3]={ + skillIds={ + [1]="BattlemagesCryMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="WrathMercenary", + [5]="ZealotryMercenary" + } + } + }, + tags={ + [1]="mercenary_aura_templar", + [2]="mercenary_aura_templar_spectre" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Sceptre", + [2]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Sceptre", + [2]="Shield", + [3]="Wand" + } + }, + weaponTypes={ + [1]="Sceptre", + [2]="Shield", + [3]="Wand" + } + }, + AurasMinionsTemplarSpectresNoble={ + classId="AurasMinionsTemplar", + hash=26531, + id="AurasMinionsTemplarSpectresNoble", + infamous=true, + name="Infamous Fallen Reverend", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour30", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_low", + statId="base_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield70", + statId="maximum_energy_shield_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge70", + statId="energy_shield_delay_-%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int70", + statId="base_intelligence", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life30", + statId="maximum_life_+%", + values={ + [1]=49, + [2]=98, + [3]=130 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen30", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=18, + [2]=27, + [3]=36 + } + }, + [12]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Cast Speed", + id="minion_cast_speed", + statId="minion_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [13]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Critical Strike Chance", + id="minion_crit_chance", + statId="minion_critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [14]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have +%s%% to Critical Strike Multiplier", + id="minion_crit_damage", + statId="minion_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_damage_applies_to_you", + line="Increases and Reductions to Minion Damage also affect you", + statId="minion_damage_increases_and_reductions_also_affects_you", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [16]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_medium", + statId="minion_damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="Minions have %s%% increased maximum Life", + id="minion_life", + statId="minion_maximum_life_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Minions Regenerate %s%% of Life per second", + id="minion_life_regen", + statId="minion_life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate70", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [20]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [21]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str30", + statId="base_strength", + values={ + [1]=22, + [2]=77, + [3]=154 + } + } + }, + skillIds={ + [1]="AbsolutionMercenary", + [2]="BattlemagesCryMercenary", + [3]="DesecrateMercenary", + [4]="FlameDashMercenary", + [5]="FrostblinkMercenary", + [6]="RaiseSpectreAltMercenary", + [7]="SSMPaganBishopMercenary", + [8]="SSMSkeletalBossMercenary", + [9]="SSMVollMercenary", + [10]="WrathMercenary", + [11]="ZealotryMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="AbsolutionMercenary", + [2]="DesecrateMercenary", + [3]="RaiseSpectreAltMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="SSMPaganBishopMercenary", + [2]="SSMSkeletalBossMercenary", + [3]="SSMVollMercenary" + } + }, + [3]={ + skillIds={ + [1]="BattlemagesCryMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="WrathMercenary", + [5]="ZealotryMercenary" + } + } + }, + tags={ + [1]="mercenary_aura_templar", + [2]="mercenary_aura_templar_spectre", + [3]="mercenary_aura_templar_spectre_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Sceptre", + [2]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Sceptre", + [2]="Shield", + [3]="Wand" + } + }, + weaponTypes={ + [1]="Sceptre", + [2]="Shield", + [3]="Wand" + } + }, + AurasMinionsTemplarStaff={ + classId="AurasMinionsTemplar", + hash=36751, + id="AurasMinionsTemplarStaff", + infamous=false, + name="Cardinal", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_low", + statId="accuracy_rating_+%", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour60", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Spell Damage", + id="block_spell_high", + statId="base_spell_block_%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life60", + statId="maximum_life_+%", + values={ + [1]=60, + [2]=120, + [3]=160 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen60", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=36, + [2]=54, + [3]=72 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_medium", + statId="minion_damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str60", + statId="base_strength", + values={ + [1]=37, + [2]=133, + [3]=267 + } + } + }, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="FlameDashMercenary", + [3]="HeraldOfPurityMercenary", + [4]="HolyHammersMercenary", + [5]="HolyStrikeMercenary", + [6]="MoltenStrikeHolyMercenary", + [7]="PurityOfLightningMercenary", + [8]="SweepMercenary", + [9]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="HolyHammersMercenary", + [2]="HolyStrikeMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="MoltenStrikeHolyMercenary", + [3]="SweepMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="HeraldOfPurityMercenary", + [3]="PurityOfLightningMercenary", + [4]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_aura_templar", + [2]="mercenary_aura_templar_staff" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + AurasMinionsTemplarStaffNoble={ + classId="AurasMinionsTemplar", + hash=62547, + id="AurasMinionsTemplarStaffNoble", + infamous=true, + name="Infamous Cardinal", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_low", + statId="accuracy_rating_+%", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour60", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Spell Damage", + id="block_spell_high", + statId="base_spell_block_%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life60", + statId="maximum_life_+%", + values={ + [1]=60, + [2]=120, + [3]=160 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen60", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=36, + [2]=54, + [3]=72 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_medium", + statId="minion_damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str60", + statId="base_strength", + values={ + [1]=37, + [2]=133, + [3]=267 + } + } + }, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="FlameDashMercenary", + [3]="HeraldOfPurityMercenary", + [4]="HolyHammersMercenary", + [5]="HolyStrikeMercenary", + [6]="MoltenStrikeHolyMercenary", + [7]="PurityOfLightningMercenary", + [8]="SweepMercenary", + [9]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="HolyHammersMercenary", + [2]="HolyStrikeMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="MoltenStrikeHolyMercenary", + [3]="SweepMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="HeraldOfPurityMercenary", + [3]="PurityOfLightningMercenary", + [4]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_aura_templar", + [2]="mercenary_aura_templar_staff", + [3]="mercenary_aura_templar_staff_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + ChaosMinionWitchChaosHit={ + classId="ChaosMinionWitch", + hash=51598, + id="ChaosMinionWitchChaosHit", + infamous=false, + name="Cruel Mistress", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_high", + statId="critical_strike_chance_+%", + values={ + [1]=75, + [2]=150, + [3]=250 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_high", + statId="base_critical_strike_multiplier_+", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="ChaosGlacialCascadeMercenary", + [2]="DarkPactMercenary", + [3]="DespairMercenary", + [4]="EnvyMercenary", + [5]="FlameDashMercenary", + [6]="ForbiddenRiteTotemMercenary", + [7]="FrostblinkMercenary", + [8]="LightningWarpMercenary", + [9]="SSMMercenarySoulrendOrb", + [10]="SoulrendAltMercenary", + [11]="VoidSphereMercenary", + [12]="VoltaxicBurstMercenary", + [13]="ZealotryMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="DespairMercenary", + [2]="VoidSphereMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ChaosGlacialCascadeMercenary", + [2]="DarkPactMercenary", + [3]="ForbiddenRiteTotemMercenary", + [4]="SSMMercenarySoulrendOrb", + [5]="SoulrendAltMercenary", + [6]="VoltaxicBurstMercenary" + } + }, + [3]={ + skillIds={ + [1]="EnvyMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="ZealotryMercenary" + } + } + }, + tags={ + [1]="mercenary_chaos_witch", + [2]="mercenary_chaos_witch_chaos_hit" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + ChaosMinionWitchChaosHitNoble={ + classId="ChaosMinionWitch", + hash=16025, + id="ChaosMinionWitchChaosHitNoble", + infamous=true, + name="Infamous Cruel Mistress", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_high", + statId="critical_strike_chance_+%", + values={ + [1]=75, + [2]=150, + [3]=250 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_high", + statId="base_critical_strike_multiplier_+", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="ChaosGlacialCascadeMercenary", + [2]="DarkPactMercenary", + [3]="DespairMercenary", + [4]="EnvyMercenary", + [5]="FlameDashMercenary", + [6]="ForbiddenRiteTotemMercenary", + [7]="FrostblinkMercenary", + [8]="LightningWarpMercenary", + [9]="SSMMercenarySoulrendOrb", + [10]="SoulrendAltMercenary", + [11]="VoidSphereMercenary", + [12]="VoltaxicBurstMercenary", + [13]="ZealotryMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="DespairMercenary", + [2]="VoidSphereMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ChaosGlacialCascadeMercenary", + [2]="DarkPactMercenary", + [3]="ForbiddenRiteTotemMercenary", + [4]="SSMMercenarySoulrendOrb", + [5]="SoulrendAltMercenary", + [6]="VoltaxicBurstMercenary" + } + }, + [3]={ + skillIds={ + [1]="EnvyMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="ZealotryMercenary" + } + } + }, + tags={ + [1]="mercenary_chaos_witch", + [2]="mercenary_chaos_witch_chaos_hit", + [3]="mercenary_chaos_witch_chaos_hit_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + ChaosMinionWitchDot={ + classId="ChaosMinionWitch", + hash=2894, + id="ChaosMinionWitchDot", + infamous=false, + name="Withertouch", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_low", + statId="base_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_veryhigh", + statId="damage_+%", + values={ + [1]=140, + [2]=280, + [3]=350 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="BaneMercenary", + [2]="BlightMercenary", + [3]="ClarityMercenary", + [4]="EssenceDrainAltMercenary", + [5]="FlameDashMercenary", + [6]="FrostblinkMercenary", + [7]="GigaSoulrendMercenary", + [8]="LightningWarpMercenary", + [9]="MalevolenceMercenary", + [10]="OfferingOfJudgementChaosMercenary", + [11]="SandstormChaosMercenary", + [12]="TemporalChainsMercenary", + [13]="WitherTotemMercenary", + [14]="WitheringStepMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="BaneMercenary", + [2]="TemporalChainsMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BlightMercenary", + [2]="EssenceDrainAltMercenary", + [3]="GigaSoulrendMercenary", + [4]="OfferingOfJudgementChaosMercenary", + [5]="SandstormChaosMercenary" + } + }, + [3]={ + skillIds={ + [1]="ClarityMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="MalevolenceMercenary", + [6]="WitherTotemMercenary", + [7]="WitheringStepMercenary" + } + } + }, + tags={ + [1]="mercenary_chaos_witch", + [2]="mercenary_chaos_witch_dot" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + ChaosMinionWitchDotNoble={ + classId="ChaosMinionWitch", + hash=31247, + id="ChaosMinionWitchDotNoble", + infamous=true, + name="Infamous Withertouch", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_low", + statId="base_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_veryhigh", + statId="damage_+%", + values={ + [1]=140, + [2]=280, + [3]=350 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="BaneMercenary", + [2]="BlightMercenary", + [3]="ClarityMercenary", + [4]="EssenceDrainAltMercenary", + [5]="FlameDashMercenary", + [6]="FrostblinkMercenary", + [7]="GigaSoulrendMercenary", + [8]="LightningWarpMercenary", + [9]="MalevolenceMercenary", + [10]="OfferingOfJudgementChaosMercenary", + [11]="SandstormChaosMercenary", + [12]="TemporalChainsMercenary", + [13]="WitherTotemMercenary", + [14]="WitheringStepMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="BaneMercenary", + [2]="TemporalChainsMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BlightMercenary", + [2]="EssenceDrainAltMercenary", + [3]="GigaSoulrendMercenary", + [4]="OfferingOfJudgementChaosMercenary", + [5]="SandstormChaosMercenary" + } + }, + [3]={ + skillIds={ + [1]="ClarityMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="MalevolenceMercenary", + [6]="WitherTotemMercenary", + [7]="WitheringStepMercenary" + } + } + }, + tags={ + [1]="mercenary_chaos_witch", + [2]="mercenary_chaos_witch_dot", + [3]="mercenary_chaos_witch_dot_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + ChaosMinionWitchInstability={ + classId="ChaosMinionWitch", + hash=7452, + id="ChaosMinionWitchInstability", + infamous=false, + name="Reanimator", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour10", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life10", + statId="maximum_life_+%", + values={ + [1]=41, + [2]=83, + [3]=110 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen10", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=6, + [2]=9, + [3]=12 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Attack Speed", + id="minion_attack_speed", + statId="minion_attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [11]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_damage_applies_to_you", + line="Increases and Reductions to Minion Damage also affect you", + statId="minion_damage_increases_and_reductions_also_affects_you", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [12]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_high", + statId="minion_damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [13]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_instability", + line="Minion Instability", + statId="keystone_minion_instability", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="Minions have %s%% increased maximum Life", + id="minion_life", + statId="minion_maximum_life_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Minions Regenerate %s%% of Life per second", + id="minion_life_regen", + statId="minion_life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str10", + statId="base_strength", + values={ + [1]=11, + [2]=40, + [3]=79 + } + } + }, + skillIds={ + [1]="BoneOfferingMercenary", + [2]="DesecrateMercenary", + [3]="EnfeebleMercenary", + [4]="FlameDashMercenary", + [5]="FleshOfferingMercenary", + [6]="FrostblinkMercenary", + [7]="GigaRaiseZombieMercenary", + [8]="LightningWarpMercenary", + [9]="RaiseZombieAltMercenary", + [10]="SSMMercenaryRelic", + [11]="SummonRagingSpiritMercenary", + [12]="SummonSkeletonsMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="DesecrateMercenary", + [2]="GigaRaiseZombieMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BoneOfferingMercenary", + [2]="FleshOfferingMercenary", + [3]="RaiseZombieAltMercenary", + [4]="SummonRagingSpiritMercenary", + [5]="SummonSkeletonsMercenary" + } + }, + [3]={ + skillIds={ + [1]="EnfeebleMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="SSMMercenaryRelic" + } + } + }, + tags={ + [1]="mercenary_chaos_witch", + [2]="mercenary_chaos_witch_instability" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + ChaosMinionWitchInstabilityNoble={ + classId="ChaosMinionWitch", + hash=3604, + id="ChaosMinionWitchInstabilityNoble", + infamous=true, + name="Infamous Reanimator", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour10", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life10", + statId="maximum_life_+%", + values={ + [1]=41, + [2]=83, + [3]=110 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen10", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=6, + [2]=9, + [3]=12 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions have %s%% increased Attack Speed", + id="minion_attack_speed", + statId="minion_attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [11]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_damage_applies_to_you", + line="Increases and Reductions to Minion Damage also affect you", + statId="minion_damage_increases_and_reductions_also_affects_you", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [12]={ + categoryId="Offensive", + categoryName="Offensive", + format="Minions deal %s%% increased Damage", + id="minion_damage_high", + statId="minion_damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [13]={ + categoryId="Offensive", + categoryName="Offensive", + id="minion_instability", + line="Minion Instability", + statId="keystone_minion_instability", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="Minions have %s%% increased maximum Life", + id="minion_life", + statId="minion_maximum_life_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Minions Regenerate %s%% of Life per second", + id="minion_life_regen", + statId="minion_life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str10", + statId="base_strength", + values={ + [1]=11, + [2]=40, + [3]=79 + } + } + }, + skillIds={ + [1]="BoneOfferingMercenary", + [2]="DesecrateMercenary", + [3]="EnfeebleMercenary", + [4]="FlameDashMercenary", + [5]="FleshOfferingMercenary", + [6]="FrostblinkMercenary", + [7]="GigaRaiseZombieMercenary", + [8]="LightningWarpMercenary", + [9]="RaiseZombieAltMercenary", + [10]="SSMMercenaryRelic", + [11]="SummonRagingSpiritMercenary", + [12]="SummonSkeletonsMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="DesecrateMercenary", + [2]="GigaRaiseZombieMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BoneOfferingMercenary", + [2]="FleshOfferingMercenary", + [3]="RaiseZombieAltMercenary", + [4]="SummonRagingSpiritMercenary", + [5]="SummonSkeletonsMercenary" + } + }, + [3]={ + skillIds={ + [1]="EnfeebleMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="SSMMercenaryRelic" + } + } + }, + tags={ + [1]="mercenary_chaos_witch", + [2]="mercenary_chaos_witch_instability", + [3]="mercenary_chaos_witch_instability_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + Crit1HShadowPhysSpell={ + classId="Crit1HShadow", + hash=18440, + id="Crit1HShadowPhysSpell", + infamous=false, + name="Bladecaster", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_high", + statId="critical_strike_chance_+%", + values={ + [1]=75, + [2]=150, + [3]=250 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_high", + statId="base_critical_strike_multiplier_+", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex50", + statId="base_dexterity", + values={ + [1]=32, + [2]=115, + [3]=229 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield50", + statId="maximum_energy_shield_+%", + values={ + [1]=13, + [2]=25, + [3]=38 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion50", + statId="evasion_rating_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge50", + statId="energy_shield_delay_-%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int50", + statId="base_intelligence", + values={ + [1]=32, + [2]=115, + [3]=229 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate50", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=13, + [2]=25, + [3]=38 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression50", + statId="base_spell_suppression_chance_%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="AspectOfTheSpiderMercenary", + [2]="BladeVortexMercenary", + [3]="BladefallAltMercenary", + [4]="BladefallMercenary", + [5]="DashMercenary", + [6]="DonutCircleMercenary", + [7]="EtherealKnivesMercenary", + [8]="FlameDashMercenary", + [9]="FrostShieldMercenary", + [10]="GraceMercenary", + [11]="LightningWarpPhysMercenary", + [12]="TemporalAnomalyMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="LightningWarpPhysMercenary", + [2]="TemporalAnomalyMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BladeVortexMercenary", + [2]="BladefallAltMercenary", + [3]="BladefallMercenary", + [4]="DonutCircleMercenary", + [5]="EtherealKnivesMercenary" + } + }, + [3]={ + skillIds={ + [1]="AspectOfTheSpiderMercenary", + [2]="DashMercenary", + [3]="FlameDashMercenary", + [4]="FrostShieldMercenary", + [5]="GraceMercenary" + } + } + }, + tags={ + [1]="mercenary_crit_shadow", + [2]="mercenary_crit_shadow_phys_spell" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Shield", + [3]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Shield", + [3]="Wand" + } + }, + Crit1HShadowPhysSpellNoble={ + classId="Crit1HShadow", + hash=39356, + id="Crit1HShadowPhysSpellNoble", + infamous=true, + name="Infamous Bladecaster", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_high", + statId="critical_strike_chance_+%", + values={ + [1]=75, + [2]=150, + [3]=250 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_high", + statId="base_critical_strike_multiplier_+", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex50", + statId="base_dexterity", + values={ + [1]=32, + [2]=115, + [3]=229 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield50", + statId="maximum_energy_shield_+%", + values={ + [1]=13, + [2]=25, + [3]=38 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion50", + statId="evasion_rating_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge50", + statId="energy_shield_delay_-%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int50", + statId="base_intelligence", + values={ + [1]=32, + [2]=115, + [3]=229 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate50", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=13, + [2]=25, + [3]=38 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression50", + statId="base_spell_suppression_chance_%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="AspectOfTheSpiderMercenary", + [2]="BladeVortexMercenary", + [3]="BladefallAltMercenary", + [4]="BladefallMercenary", + [5]="DashMercenary", + [6]="DonutCircleMercenary", + [7]="EtherealKnivesMercenary", + [8]="FlameDashMercenary", + [9]="FrostShieldMercenary", + [10]="GraceMercenary", + [11]="LightningWarpPhysMercenary", + [12]="TemporalAnomalyMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="LightningWarpPhysMercenary", + [2]="TemporalAnomalyMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BladeVortexMercenary", + [2]="BladefallAltMercenary", + [3]="BladefallMercenary", + [4]="DonutCircleMercenary", + [5]="EtherealKnivesMercenary" + } + }, + [3]={ + skillIds={ + [1]="AspectOfTheSpiderMercenary", + [2]="DashMercenary", + [3]="FlameDashMercenary", + [4]="FrostShieldMercenary", + [5]="GraceMercenary" + } + } + }, + tags={ + [1]="mercenary_crit_shadow", + [2]="mercenary_crit_shadow_phys_spell", + [3]="mercenary_crit_shadow_phys_spell_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Shield", + [3]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Shield", + [3]="Wand" + } + }, + Crit1HShadowPoison={ + classId="Crit1HShadow", + hash=23200, + id="Crit1HShadowPoison", + infamous=false, + name="Bladebitter", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex70", + statId="base_dexterity", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [8]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_med", + statId="dot_multiplier_+", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield30", + statId="maximum_energy_shield_+%", + values={ + [1]=8, + [2]=15, + [3]=23 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion70", + statId="evasion_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge30", + statId="energy_shield_delay_-%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int30", + statId="base_intelligence", + values={ + [1]=22, + [2]=77, + [3]=154 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Poison on Hit", + id="poison_chance", + statId="base_chance_to_poison_on_hit_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [16]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Poison Duration", + id="poison_duration", + statId="base_poison_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate30", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=8, + [2]=15, + [3]=23 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression70", + statId="base_spell_suppression_chance_%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="AbyssalCryMercenary", + [2]="CobraLashMercenary", + [3]="DashMercenary", + [4]="GraceMercenary", + [5]="MalevolenceMercenary", + [6]="MoltenStrikePoisonMercenary", + [7]="PestilentStrikeMercenary", + [8]="VenomGyreMercenary", + [9]="ViperStrikeMercenary", + [10]="WhirlingBladesMercenary", + [11]="WitheringStepMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="AbyssalCryMercenary", + [2]="ViperStrikeMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="CobraLashMercenary", + [2]="MoltenStrikePoisonMercenary", + [3]="PestilentStrikeMercenary", + [4]="VenomGyreMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="GraceMercenary", + [3]="MalevolenceMercenary", + [4]="WhirlingBladesMercenary", + [5]="WitheringStepMercenary" + } + } + }, + tags={ + [1]="mercenary_crit_shadow", + [2]="mercenary_crit_shadow_poison" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + Crit1HShadowPoisonNoble={ + classId="Crit1HShadow", + hash=43290, + id="Crit1HShadowPoisonNoble", + infamous=true, + name="Infamous Bladebitter", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex70", + statId="base_dexterity", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [8]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_med", + statId="dot_multiplier_+", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield30", + statId="maximum_energy_shield_+%", + values={ + [1]=8, + [2]=15, + [3]=23 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion70", + statId="evasion_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge30", + statId="energy_shield_delay_-%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int30", + statId="base_intelligence", + values={ + [1]=22, + [2]=77, + [3]=154 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Poison on Hit", + id="poison_chance", + statId="base_chance_to_poison_on_hit_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [16]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Poison Duration", + id="poison_duration", + statId="base_poison_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate30", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=8, + [2]=15, + [3]=23 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression70", + statId="base_spell_suppression_chance_%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="AbyssalCryMercenary", + [2]="CobraLashMercenary", + [3]="DashMercenary", + [4]="GraceMercenary", + [5]="MalevolenceMercenary", + [6]="MoltenStrikePoisonMercenary", + [7]="PestilentStrikeMercenary", + [8]="VenomGyreMercenary", + [9]="ViperStrikeMercenary", + [10]="WhirlingBladesMercenary", + [11]="WitheringStepMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="AbyssalCryMercenary", + [2]="ViperStrikeMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="CobraLashMercenary", + [2]="MoltenStrikePoisonMercenary", + [3]="PestilentStrikeMercenary", + [4]="VenomGyreMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="GraceMercenary", + [3]="MalevolenceMercenary", + [4]="WhirlingBladesMercenary", + [5]="WitheringStepMercenary" + } + } + }, + tags={ + [1]="mercenary_crit_shadow", + [2]="mercenary_crit_shadow_poison", + [3]="mercenary_crit_shadow_poison_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + Crit1HShadowSpectral={ + classId="Crit1HShadow", + hash=1556, + id="Crit1HShadowSpectral", + infamous=false, + name="Bladereach", + passiveStats={ + }, + skillIds={ + [1]="DoLiterallyNothing" + }, + skillPools={ + [1]={ + countMax=0, + skillIds={ + [1]="DoLiterallyNothing" + } + }, + [2]={ + countMax=0, + skillIds={ + } + }, + [3]={ + skillIds={ + } + } + }, + tags={ + [1]="mercenary_crit_shadow", + [2]="mercenary_crit_shadow_spectral" + }, + weaponConfiguration={ + mainHandTypes={ + }, + offHandRequired=false, + offHandTypes={ + } + }, + weaponTypes={ + } + }, + DivingDuelist={ + classId="MeleeAOEStrikeDuelist", + hash=64848, + id="DivingDuelist", + infamous=false, + name="Mysterious Diver", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour30", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_high", + statId="attack_speed_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex70", + statId="base_dexterity", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion70", + statId="evasion_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life30", + statId="maximum_life_+%", + values={ + [1]=49, + [2]=98, + [3]=130 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen30", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=18, + [2]=27, + [3]=36 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression70", + statId="base_spell_suppression_chance_%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str30", + statId="base_strength", + values={ + [1]=22, + [2]=77, + [3]=154 + } + } + }, + skillIds={ + [1]="DashMercenary", + [2]="ElementalHitColdOnlyMercenary", + [3]="FrostBladesMercenary", + [4]="FrostBombMercenary", + [5]="FrostblinkMercenary", + [6]="HatredMercenary", + [7]="HeraldOfIceMercenary", + [8]="PurityOfIceMercenary", + [9]="WildStrikeMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ElementalHitColdOnlyMercenary", + [2]="FrostBombMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="FrostBladesMercenary", + [2]="HeraldOfIceMercenary", + [3]="WildStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="FrostblinkMercenary", + [3]="HatredMercenary", + [4]="PurityOfIceMercenary" + } + } + }, + tags={ + [1]="mercenary_diving_duelist", + [2]="mercenary_melee_aoe_strike_duelist" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + DivingDuelistNoble={ + classId="MeleeAOEStrikeDuelist", + hash=33084, + id="DivingDuelistNoble", + infamous=true, + name="Infamous Mysterious Diver", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour30", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_high", + statId="attack_speed_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex70", + statId="base_dexterity", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion70", + statId="evasion_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life30", + statId="maximum_life_+%", + values={ + [1]=49, + [2]=98, + [3]=130 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen30", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=18, + [2]=27, + [3]=36 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression70", + statId="base_spell_suppression_chance_%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str30", + statId="base_strength", + values={ + [1]=22, + [2]=77, + [3]=154 + } + } + }, + skillIds={ + [1]="DashMercenary", + [2]="ElementalHitColdOnlyMercenary", + [3]="FrostBladesMercenary", + [4]="FrostBombMercenary", + [5]="FrostblinkMercenary", + [6]="HatredMercenary", + [7]="HeraldOfIceMercenary", + [8]="PurityOfIceMercenary", + [9]="WildStrikeMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ElementalHitColdOnlyMercenary", + [2]="FrostBombMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="FrostBladesMercenary", + [2]="HeraldOfIceMercenary", + [3]="WildStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="FrostblinkMercenary", + [3]="HatredMercenary", + [4]="PurityOfIceMercenary" + } + } + }, + tags={ + [1]="mercenary_diving_duelist", + [2]="mercenary_diving_duelist_noble", + [3]="mercenary_melee_aoe_strike_duelist", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + EleBowRangerClones={ + classId="EleBowRanger", + hash=61428, + id="EleBowRangerClones", + infamous=false, + name="Manyshot", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_high", + statId="attack_speed_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Chill", + id="chill_effect", + statId="chill_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex90", + statId="base_dexterity", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield10", + statId="maximum_energy_shield_+%", + values={ + [1]=3, + [2]=5, + [3]=8 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion90", + statId="evasion_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge10", + statId="energy_shield_delay_-%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [12]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Freeze", + id="freeze_chance", + statId="base_chance_to_freeze_%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int10", + statId="base_intelligence", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate10", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=3, + [2]=5, + [3]=8 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression90", + statId="base_spell_suppression_chance_%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="BlastRainColdMercenary", + [2]="BlinkArrowMercenary", + [3]="DashMercenary", + [4]="FrostBombMercenary", + [5]="GraceMercenary", + [6]="HatredMercenary", + [7]="HydraForkArrowMercenary", + [8]="IceShotMercenary", + [9]="MirrorArrowMercenary", + [10]="VaalGraceMercenary", + [11]="VaalIceShotMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="IceShotMercenary", + [2]="VaalGraceMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BlastRainColdMercenary", + [2]="HydraForkArrowMercenary", + [3]="MirrorArrowMercenary", + [4]="VaalIceShotMercenary" + } + }, + [3]={ + skillIds={ + [1]="BlinkArrowMercenary", + [2]="DashMercenary", + [3]="FrostBombMercenary", + [4]="GraceMercenary", + [5]="HatredMercenary" + } + } + }, + tags={ + [1]="mercenary_ele_ranger", + [2]="mercenary_ele_ranger_clones" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + EleBowRangerClonesNoble={ + classId="EleBowRanger", + hash=4124, + id="EleBowRangerClonesNoble", + infamous=true, + name="Infamous Manyshot", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_high", + statId="attack_speed_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Chill", + id="chill_effect", + statId="chill_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex90", + statId="base_dexterity", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield10", + statId="maximum_energy_shield_+%", + values={ + [1]=3, + [2]=5, + [3]=8 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion90", + statId="evasion_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge10", + statId="energy_shield_delay_-%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [12]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Freeze", + id="freeze_chance", + statId="base_chance_to_freeze_%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int10", + statId="base_intelligence", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate10", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=3, + [2]=5, + [3]=8 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression90", + statId="base_spell_suppression_chance_%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="BlastRainColdMercenary", + [2]="BlinkArrowMercenary", + [3]="DashMercenary", + [4]="FrostBombMercenary", + [5]="GraceMercenary", + [6]="HatredMercenary", + [7]="HydraForkArrowMercenary", + [8]="IceShotMercenary", + [9]="MirrorArrowMercenary", + [10]="VaalGraceMercenary", + [11]="VaalIceShotMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="IceShotMercenary", + [2]="VaalGraceMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BlastRainColdMercenary", + [2]="HydraForkArrowMercenary", + [3]="MirrorArrowMercenary", + [4]="VaalIceShotMercenary" + } + }, + [3]={ + skillIds={ + [1]="BlinkArrowMercenary", + [2]="DashMercenary", + [3]="FrostBombMercenary", + [4]="GraceMercenary", + [5]="HatredMercenary" + } + } + }, + tags={ + [1]="mercenary_ele_ranger", + [2]="mercenary_ele_ranger_clones", + [3]="mercenary_ele_ranger_clones_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + EleBowRangerFire={ + classId="EleBowRanger", + hash=1967, + id="EleBowRangerFire", + infamous=false, + name="Flamequiver", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour10", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex90", + statId="base_dexterity", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_med", + statId="dot_multiplier_+", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion90", + statId="evasion_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [10]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Ignite", + id="ignite_chance", + statId="base_chance_to_ignite_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [11]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Ignite Duration", + id="ignite_duration", + statId="ignite_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life10", + statId="maximum_life_+%", + values={ + [1]=41, + [2]=83, + [3]=110 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen10", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=6, + [2]=9, + [3]=12 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression90", + statId="base_spell_suppression_chance_%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str10", + statId="base_strength", + values={ + [1]=11, + [2]=40, + [3]=79 + } + } + }, + skillIds={ + [1]="AlchemistsMarkMercenary", + [2]="ArtilleryBallistaMercenary", + [3]="BlastRainAltMercenary", + [4]="BlinkArrowMercenary", + [5]="BurningArrowMercenary", + [6]="ConflagrationMercenary", + [7]="DashMercenary", + [8]="DropArrowMercenary", + [9]="ExplosiveArrowBarrageMercenary", + [10]="FlammabilityBlasphemyMercenary", + [11]="GraceMercenary", + [12]="VaalBurningArrowMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="AlchemistsMarkMercenary", + [2]="BurningArrowMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ArtilleryBallistaMercenary", + [2]="BlastRainAltMercenary", + [3]="ConflagrationMercenary", + [4]="DropArrowMercenary", + [5]="ExplosiveArrowBarrageMercenary", + [6]="VaalBurningArrowMercenary" + } + }, + [3]={ + skillIds={ + [1]="BlinkArrowMercenary", + [2]="DashMercenary", + [3]="FlammabilityBlasphemyMercenary", + [4]="GraceMercenary" + } + } + }, + tags={ + [1]="mercenary_ele_ranger", + [2]="mercenary_ele_ranger_fire" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + EleBowRangerFireNoble={ + classId="EleBowRanger", + hash=51585, + id="EleBowRangerFireNoble", + infamous=true, + name="Infamous Flamequiver", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour10", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex90", + statId="base_dexterity", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_med", + statId="dot_multiplier_+", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion90", + statId="evasion_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [10]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Ignite", + id="ignite_chance", + statId="base_chance_to_ignite_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [11]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Ignite Duration", + id="ignite_duration", + statId="ignite_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life10", + statId="maximum_life_+%", + values={ + [1]=41, + [2]=83, + [3]=110 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen10", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=6, + [2]=9, + [3]=12 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression90", + statId="base_spell_suppression_chance_%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str10", + statId="base_strength", + values={ + [1]=11, + [2]=40, + [3]=79 + } + } + }, + skillIds={ + [1]="AlchemistsMarkMercenary", + [2]="ArtilleryBallistaMercenary", + [3]="BlastRainAltMercenary", + [4]="BlinkArrowMercenary", + [5]="BurningArrowMercenary", + [6]="ConflagrationMercenary", + [7]="DashMercenary", + [8]="DropArrowMercenary", + [9]="ExplosiveArrowBarrageMercenary", + [10]="FlammabilityBlasphemyMercenary", + [11]="GraceMercenary", + [12]="VaalBurningArrowMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="AlchemistsMarkMercenary", + [2]="BurningArrowMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ArtilleryBallistaMercenary", + [2]="BlastRainAltMercenary", + [3]="ConflagrationMercenary", + [4]="DropArrowMercenary", + [5]="ExplosiveArrowBarrageMercenary", + [6]="VaalBurningArrowMercenary" + } + }, + [3]={ + skillIds={ + [1]="BlinkArrowMercenary", + [2]="DashMercenary", + [3]="FlammabilityBlasphemyMercenary", + [4]="GraceMercenary" + } + } + }, + tags={ + [1]="mercenary_ele_ranger", + [2]="mercenary_ele_ranger_fire", + [3]="mercenary_ele_ranger_fire_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + EleBowRangerLightning={ + classId="EleBowRanger", + hash=51927, + id="EleBowRangerLightning", + infamous=false, + name="Thunderquiver", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_high", + statId="attack_speed_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex90", + statId="base_dexterity", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield10", + statId="maximum_energy_shield_+%", + values={ + [1]=3, + [2]=5, + [3]=8 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion90", + statId="evasion_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge10", + statId="energy_shield_delay_-%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int10", + statId="base_intelligence", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate10", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=3, + [2]=5, + [3]=8 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Shock", + id="shock_chance", + statId="base_chance_to_shock_%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Shock", + id="shock_effect", + statId="shock_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression90", + statId="base_spell_suppression_chance_%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="AssassinsMarkMercenary", + [3]="BlinkArrowMercenary", + [4]="DashMercenary", + [5]="GalvanicArrowMercenary", + [6]="GigaLightningArrowMercenary", + [7]="LightningArrowMercenary", + [8]="PrecisionMercenary", + [9]="StormRainMercenary", + [10]="VaalLightningArrowMercenary", + [11]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="AssassinsMarkMercenary", + [2]="LightningArrowMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="GalvanicArrowMercenary", + [2]="GigaLightningArrowMercenary", + [3]="StormRainMercenary", + [4]="VaalLightningArrowMercenary" + } + }, + [3]={ + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BlinkArrowMercenary", + [3]="DashMercenary", + [4]="PrecisionMercenary", + [5]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_ele_ranger", + [2]="mercenary_ele_ranger_lightning" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + ElementalWitchCold={ + classId="ElementalWitch", + hash=34653, + id="ElementalWitchCold", + infamous=false, + name="Frosthand", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Chill", + id="chill_effect", + statId="chill_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [8]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_low", + statId="dot_multiplier_+", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [12]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Freeze", + id="freeze_chance", + statId="base_chance_to_freeze_%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="DisciplineMercenary", + [2]="EyeOfWinterMercenary", + [3]="FlameDashMercenary", + [4]="FrostBombMercenary", + [5]="FrostWallMercenary", + [6]="FrostbiteMercenary", + [7]="FrostblinkMercenary", + [8]="FrostboltMercenary", + [9]="IceNovaMercenary", + [10]="IceNovaProjectedMercenary", + [11]="IcestormMercenary", + [12]="LightningWarpMercenary", + [13]="PurityOfIceMercenary", + [14]="VortexMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="FrostBombMercenary", + [2]="FrostbiteMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="EyeOfWinterMercenary", + [2]="FrostWallMercenary", + [3]="FrostboltMercenary", + [4]="IceNovaMercenary", + [5]="IceNovaProjectedMercenary", + [6]="IcestormMercenary", + [7]="VortexMercenary" + } + }, + [3]={ + skillIds={ + [1]="DisciplineMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="PurityOfIceMercenary" + } + } + }, + tags={ + [1]="mercenary_elemental_witch", + [2]="mercenary_elemental_witch_cold" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + ElementalWitchColdNoble={ + classId="ElementalWitch", + hash=64793, + id="ElementalWitchColdNoble", + infamous=true, + name="Infamous Frosthand", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Chill", + id="chill_effect", + statId="chill_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [8]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_low", + statId="dot_multiplier_+", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [12]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Freeze", + id="freeze_chance", + statId="base_chance_to_freeze_%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="DisciplineMercenary", + [2]="EyeOfWinterMercenary", + [3]="FlameDashMercenary", + [4]="FrostBombMercenary", + [5]="FrostWallMercenary", + [6]="FrostbiteMercenary", + [7]="FrostblinkMercenary", + [8]="FrostboltMercenary", + [9]="IceNovaMercenary", + [10]="IceNovaProjectedMercenary", + [11]="IcestormMercenary", + [12]="LightningWarpMercenary", + [13]="PurityOfIceMercenary", + [14]="VortexMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="FrostBombMercenary", + [2]="FrostbiteMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="EyeOfWinterMercenary", + [2]="FrostWallMercenary", + [3]="FrostboltMercenary", + [4]="IceNovaMercenary", + [5]="IceNovaProjectedMercenary", + [6]="IcestormMercenary", + [7]="VortexMercenary" + } + }, + [3]={ + skillIds={ + [1]="DisciplineMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="PurityOfIceMercenary" + } + } + }, + tags={ + [1]="mercenary_elemental_witch", + [2]="mercenary_elemental_witch_cold", + [3]="mercenary_elemental_witch_cold_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + ElementalWitchFire={ + classId="ElementalWitch", + hash=52411, + id="ElementalWitchFire", + infamous=false, + name="Flamehand", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour10", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_med", + statId="dot_multiplier_+", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield90", + statId="maximum_energy_shield_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge90", + statId="energy_shield_delay_-%", + values={ + [1]=18, + [2]=36, + [3]=54 + } + }, + [9]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Ignite", + id="ignite_chance", + statId="base_chance_to_ignite_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Ignite Duration", + id="ignite_duration", + statId="ignite_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int90", + statId="base_intelligence", + values={ + [1]=53, + [2]=190, + [3]=379 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life10", + statId="maximum_life_+%", + values={ + [1]=41, + [2]=83, + [3]=110 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen10", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=6, + [2]=9, + [3]=12 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate90", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=23, + [2]=45, + [3]=68 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str10", + statId="base_strength", + values={ + [1]=11, + [2]=40, + [3]=79 + } + } + }, + skillIds={ + [1]="AngerMercenary", + [2]="FireAegisMercenary", + [3]="FireballAltMercenary", + [4]="FireballMercenary", + [5]="FlameSurgeMercenary", + [6]="FlameWallMercenary", + [7]="FlameblastMercenary", + [8]="FlammabilityMercenary", + [9]="FrostblinkMercenary", + [10]="GigaFlameDashMercenary", + [11]="LightningWarpMercenary", + [12]="PurityOfFireMercenary", + [13]="RollingMagmaMercenary", + [14]="VaalFlameblastMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="FlameWallMercenary", + [2]="FlammabilityMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="FireballAltMercenary", + [2]="FireballMercenary", + [3]="FlameSurgeMercenary", + [4]="FlameblastMercenary", + [5]="GigaFlameDashMercenary", + [6]="RollingMagmaMercenary", + [7]="VaalFlameblastMercenary" + } + }, + [3]={ + skillIds={ + [1]="AngerMercenary", + [2]="FireAegisMercenary", + [3]="FrostblinkMercenary", + [4]="LightningWarpMercenary", + [5]="PurityOfFireMercenary" + } + } + }, + tags={ + [1]="mercenary_elemental_witch", + [2]="mercenary_elemental_witch_fire" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + ElementalWitchLightning={ + classId="ElementalWitch", + hash=26688, + id="ElementalWitchLightning", + infamous=false, + name="Stormhand", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_high", + statId="base_cast_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield100", + statId="maximum_energy_shield_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge100", + statId="energy_shield_delay_-%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int100", + statId="base_intelligence", + values={ + [1]=58, + [2]=208, + [3]=417 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate100", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [14]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Shock", + id="shock_chance", + statId="base_chance_to_shock_%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Shock", + id="shock_effect", + statId="shock_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="ArcAltMercenary", + [2]="ArcMercenary", + [3]="BallLightningAltMercenary", + [4]="ConductivityMercenary", + [5]="FlameDashMercenary", + [6]="FrostblinkMercenary", + [7]="GigaShockNovaMercenary", + [8]="GigaStormCallMercenary", + [9]="LightningWarpMercenary", + [10]="OrbOfStormsMercenary", + [11]="ProximityShieldMercenary", + [12]="PurityOfLightningMercenary", + [13]="SigilOfPowerMercenary", + [14]="SparkMercenary", + [15]="StormCallMercenary", + [16]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ConductivityMercenary", + [2]="SigilOfPowerMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ArcAltMercenary", + [2]="ArcMercenary", + [3]="BallLightningAltMercenary", + [4]="GigaShockNovaMercenary", + [5]="GigaStormCallMercenary", + [6]="OrbOfStormsMercenary", + [7]="SparkMercenary", + [8]="StormCallMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="FrostblinkMercenary", + [3]="LightningWarpMercenary", + [4]="ProximityShieldMercenary", + [5]="PurityOfLightningMercenary", + [6]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_elemental_witch", + [2]="mercenary_elemental_witch_lightning" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + ElementalWitchLightningNoble={ + classId="ElementalWitch", + hash=45712, + id="ElementalWitchLightningNoble", + infamous=true, + name="Infamous Stormhand", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_high", + statId="base_cast_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield100", + statId="maximum_energy_shield_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge100", + statId="energy_shield_delay_-%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int100", + statId="base_intelligence", + values={ + [1]=58, + [2]=208, + [3]=417 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate100", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [14]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Shock", + id="shock_chance", + statId="base_chance_to_shock_%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Shock", + id="shock_effect", + statId="shock_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="ArcAltMercenary", + [2]="ArcMercenary", + [3]="BallLightningAltMercenary", + [4]="ConductivityMercenary", + [5]="FlameDashMercenary", + [6]="FrostblinkMercenary", + [7]="GigaShockNovaMercenary", + [8]="GigaStormCallMercenary", + [9]="LightningWarpMercenary", + [10]="OrbOfStormsMercenary", + [11]="ProximityShieldMercenary", + [12]="PurityOfLightningMercenary", + [13]="SigilOfPowerMercenary", + [14]="SparkMercenary", + [15]="StormCallMercenary", + [16]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ConductivityMercenary", + [2]="SigilOfPowerMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ArcAltMercenary", + [2]="ArcMercenary", + [3]="BallLightningAltMercenary", + [4]="GigaShockNovaMercenary", + [5]="GigaStormCallMercenary", + [6]="OrbOfStormsMercenary", + [7]="SparkMercenary", + [8]="StormCallMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="FrostblinkMercenary", + [3]="LightningWarpMercenary", + [4]="ProximityShieldMercenary", + [5]="PurityOfLightningMercenary", + [6]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_elemental_witch", + [2]="mercenary_elemental_witch_lightning", + [3]="mercenary_elemental_witch_lightning_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + MeleeAOEMarauderFireSlam={ + classId="MeleeAOEMarauder", + hash=17483, + id="MeleeAOEMarauderFireSlam", + infamous=false, + name="Eruptor", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour100", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=50, + [2]=100, + [3]=150 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_veryhigh", + statId="damage_+%", + values={ + [1]=140, + [2]=280, + [3]=350 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life100", + statId="maximum_life_+%", + values={ + [1]=75, + [2]=150, + [3]=200 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen100", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=60, + [2]=90, + [3]=120 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str100", + statId="base_strength", + values={ + [1]=58, + [2]=208, + [3]=417 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% reduced Enemy Stun Threshold", + id="stun_chance", + statId="base_stun_threshold_reduction_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Stun Duration on Enemies", + id="stun_duration", + statId="base_stun_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + } + }, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="DeterminationMercenary", + [3]="FissureSlamMercenary", + [4]="FlameLinkMercenary", + [5]="HeraldOfAshMercenary", + [6]="InfernalCryMercenary", + [7]="LeapSlamMercenary", + [8]="MoltenShellMercenary", + [9]="PurityOfFireMercenary", + [10]="TectonicSlamFireMercenary", + [11]="TriggeredFireSlamMercenary", + [12]="VolcanicFissureAltMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="InfernalCryMercenary", + [2]="LeapSlamMercenary", + [3]="TriggeredFireSlamMercenary" + } + }, + [2]={ + countMax=1, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="FissureSlamMercenary", + [3]="TectonicSlamFireMercenary", + [4]="VolcanicFissureAltMercenary" + } + }, + [3]={ + skillIds={ + [1]="DeterminationMercenary", + [2]="FlameLinkMercenary", + [3]="HeraldOfAshMercenary", + [4]="MoltenShellMercenary", + [5]="PurityOfFireMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_marauder", + [2]="mercenary_melee_aoe_marauder_fire" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + }, + offHandRequired=false, + offHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + weaponTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + MeleeAOEMarauderFireSlamNoble={ + classId="MeleeAOEMarauder", + hash=16147, + id="MeleeAOEMarauderFireSlamNoble", + infamous=true, + name="Infamous Eruptor", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour100", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=50, + [2]=100, + [3]=150 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_veryhigh", + statId="damage_+%", + values={ + [1]=140, + [2]=280, + [3]=350 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life100", + statId="maximum_life_+%", + values={ + [1]=75, + [2]=150, + [3]=200 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen100", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=60, + [2]=90, + [3]=120 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str100", + statId="base_strength", + values={ + [1]=58, + [2]=208, + [3]=417 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% reduced Enemy Stun Threshold", + id="stun_chance", + statId="base_stun_threshold_reduction_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Stun Duration on Enemies", + id="stun_duration", + statId="base_stun_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + } + }, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="DeterminationMercenary", + [3]="FissureSlamMercenary", + [4]="FlameLinkMercenary", + [5]="HeraldOfAshMercenary", + [6]="InfernalCryMercenary", + [7]="LeapSlamMercenary", + [8]="MoltenShellMercenary", + [9]="PurityOfFireMercenary", + [10]="TectonicSlamFireMercenary", + [11]="TriggeredFireSlamMercenary", + [12]="VolcanicFissureAltMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="InfernalCryMercenary", + [2]="LeapSlamMercenary", + [3]="TriggeredFireSlamMercenary" + } + }, + [2]={ + countMax=1, + skillIds={ + [1]="ConsecratedPathMercenary", + [2]="FissureSlamMercenary", + [3]="TectonicSlamFireMercenary", + [4]="VolcanicFissureAltMercenary" + } + }, + [3]={ + skillIds={ + [1]="DeterminationMercenary", + [2]="FlameLinkMercenary", + [3]="HeraldOfAshMercenary", + [4]="MoltenShellMercenary", + [5]="PurityOfFireMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_marauder", + [2]="mercenary_melee_aoe_marauder_fire", + [3]="mercenary_melee_aoe_marauder_fire_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + }, + offHandRequired=false, + offHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + weaponTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + MeleeAOEMarauderNonSlam={ + classId="MeleeAOEMarauder", + hash=57617, + id="MeleeAOEMarauderNonSlam", + infamous=false, + name="Ripper", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [3]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour100", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=50, + [2]=100, + [3]=150 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life100", + statId="maximum_life_+%", + values={ + [1]=75, + [2]=150, + [3]=200 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen100", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=60, + [2]=90, + [3]=120 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str100", + statId="base_strength", + values={ + [1]=58, + [2]=208, + [3]=417 + } + } + }, + skillIds={ + [1]="ChainHookAltMercenary", + [2]="CleaveMercenary", + [3]="DeterminationMercenary", + [4]="EnrageMercenary", + [5]="LeapSlamMercenary", + [6]="LeapSlamMercenaryAlt", + [7]="MoltenShellMercenary", + [8]="RemoteSlamMercenary", + [9]="VaalCleaveMercenary", + [10]="VitalityMercenary", + [11]="WindSlashMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="EnrageMercenary", + [2]="RemoteSlamMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ChainHookAltMercenary", + [2]="CleaveMercenary", + [3]="LeapSlamMercenaryAlt", + [4]="VaalCleaveMercenary", + [5]="WindSlashMercenary" + } + }, + [3]={ + skillIds={ + [1]="DeterminationMercenary", + [2]="LeapSlamMercenary", + [3]="MoltenShellMercenary", + [4]="VitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_marauder", + [2]="mercenary_melee_aoe_marauder_non_slam" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + MeleeAOEMarauderNonSlamNoble={ + classId="MeleeAOEMarauder", + hash=17136, + id="MeleeAOEMarauderNonSlamNoble", + infamous=true, + name="Infamous Ripper", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [3]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour100", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=50, + [2]=100, + [3]=150 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life100", + statId="maximum_life_+%", + values={ + [1]=75, + [2]=150, + [3]=200 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen100", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=60, + [2]=90, + [3]=120 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str100", + statId="base_strength", + values={ + [1]=58, + [2]=208, + [3]=417 + } + } + }, + skillIds={ + [1]="ChainHookAltMercenary", + [2]="CleaveMercenary", + [3]="DeterminationMercenary", + [4]="EnrageMercenary", + [5]="LeapSlamMercenary", + [6]="LeapSlamMercenaryAlt", + [7]="MoltenShellMercenary", + [8]="RemoteSlamMercenary", + [9]="VaalCleaveMercenary", + [10]="VitalityMercenary", + [11]="WindSlashMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="EnrageMercenary", + [2]="RemoteSlamMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ChainHookAltMercenary", + [2]="CleaveMercenary", + [3]="LeapSlamMercenaryAlt", + [4]="VaalCleaveMercenary", + [5]="WindSlashMercenary" + } + }, + [3]={ + skillIds={ + [1]="DeterminationMercenary", + [2]="LeapSlamMercenary", + [3]="MoltenShellMercenary", + [4]="VitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_marauder", + [2]="mercenary_melee_aoe_marauder_non_slam", + [3]="mercenary_melee_aoe_marauder_non_slam_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + MeleeAOEMarauderPhysSlam={ + classId="MeleeAOEMarauder", + hash=32159, + id="MeleeAOEMarauderPhysSlam", + infamous=false, + name="Earthshaker", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour100", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=50, + [2]=100, + [3]=150 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_veryhigh", + statId="damage_+%", + values={ + [1]=140, + [2]=280, + [3]=350 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life100", + statId="maximum_life_+%", + values={ + [1]=75, + [2]=150, + [3]=200 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen100", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=60, + [2]=90, + [3]=120 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str100", + statId="base_strength", + values={ + [1]=58, + [2]=208, + [3]=417 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% reduced Enemy Stun Threshold", + id="stun_chance", + statId="base_stun_threshold_reduction_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Stun Duration on Enemies", + id="stun_duration", + statId="base_stun_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + } + }, + skillIds={ + [1]="BurrowMercenary", + [2]="DeterminationMercenary", + [3]="EarthquakeAltMercenary", + [4]="GroundSlamMercenary", + [5]="IntimidatingCryMercenary", + [6]="LeapSlamMercenary", + [7]="MassEnduranceMercenary", + [8]="MoltenShellMercenary", + [9]="SunderAltMercenary", + [10]="TectonicSlamPhysMercenary", + [11]="VaalGroundSlamMercenary", + [12]="VaalVitalityMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="IntimidatingCryMercenary", + [2]="LeapSlamMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="EarthquakeAltMercenary", + [2]="GroundSlamMercenary", + [3]="SunderAltMercenary", + [4]="TectonicSlamPhysMercenary", + [5]="VaalGroundSlamMercenary" + } + }, + [3]={ + skillIds={ + [1]="BurrowMercenary", + [2]="DeterminationMercenary", + [3]="MassEnduranceMercenary", + [4]="MoltenShellMercenary", + [5]="VaalVitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_marauder", + [2]="mercenary_melee_aoe_marauder_phys" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + }, + offHandRequired=false, + offHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + weaponTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + MeleeAOEMarauderPhysSlamNoble={ + classId="MeleeAOEMarauder", + hash=52392, + id="MeleeAOEMarauderPhysSlamNoble", + infamous=true, + name="Infamous Earthshaker", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour100", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=50, + [2]=100, + [3]=150 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_veryhigh", + statId="damage_+%", + values={ + [1]=140, + [2]=280, + [3]=350 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life100", + statId="maximum_life_+%", + values={ + [1]=75, + [2]=150, + [3]=200 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen100", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=60, + [2]=90, + [3]=120 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str100", + statId="base_strength", + values={ + [1]=58, + [2]=208, + [3]=417 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% reduced Enemy Stun Threshold", + id="stun_chance", + statId="base_stun_threshold_reduction_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Stun Duration on Enemies", + id="stun_duration", + statId="base_stun_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + } + }, + skillIds={ + [1]="BurrowMercenary", + [2]="DeterminationMercenary", + [3]="EarthquakeAltMercenary", + [4]="GroundSlamMercenary", + [5]="IntimidatingCryMercenary", + [6]="LeapSlamMercenary", + [7]="MassEnduranceMercenary", + [8]="MoltenShellMercenary", + [9]="SunderAltMercenary", + [10]="TectonicSlamPhysMercenary", + [11]="VaalGroundSlamMercenary", + [12]="VaalVitalityMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="IntimidatingCryMercenary", + [2]="LeapSlamMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="EarthquakeAltMercenary", + [2]="GroundSlamMercenary", + [3]="SunderAltMercenary", + [4]="TectonicSlamPhysMercenary", + [5]="VaalGroundSlamMercenary" + } + }, + [3]={ + skillIds={ + [1]="BurrowMercenary", + [2]="DeterminationMercenary", + [3]="MassEnduranceMercenary", + [4]="MoltenShellMercenary", + [5]="VaalVitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_marauder", + [2]="mercenary_melee_aoe_marauder_phys", + [3]="mercenary_melee_aoe_marauder_phys_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + }, + offHandRequired=false, + offHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + weaponTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Mace" + } + }, + MeleeAOEStrikeDuelistCyclone={ + classId="MeleeAOEStrikeDuelist", + hash=57213, + id="MeleeAOEStrikeDuelistCyclone", + infamous=false, + name="Swiftblade", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour50", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex50", + statId="base_dexterity", + values={ + [1]=32, + [2]=115, + [3]=229 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion50", + statId="evasion_rating_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life50", + statId="maximum_life_+%", + values={ + [1]=56, + [2]=113, + [3]=150 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen50", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=45, + [3]=60 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression50", + statId="base_spell_suppression_chance_%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str50", + statId="base_strength", + values={ + [1]=32, + [2]=115, + [3]=229 + } + } + }, + skillIds={ + [1]="CycloneReverseKnockbackMercenary", + [2]="DashMercenary", + [3]="DonutBladesMercenary", + [4]="FlickerStrikeMercenary", + [5]="LeapSlamMercenary", + [6]="MassFrenzyMercenary", + [7]="PrideMercenary", + [8]="QuickGuardAllyMercenary", + [9]="RallyingCryMercenary", + [10]="VaalDoubleStrikeMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="CycloneReverseKnockbackMercenary", + [2]="DonutBladesMercenary", + [3]="RallyingCryMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="FlickerStrikeMercenary", + [2]="VaalDoubleStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="LeapSlamMercenary", + [3]="MassFrenzyMercenary", + [4]="PrideMercenary", + [5]="QuickGuardAllyMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_strike_duelist", + [2]="mercenary_melee_aoe_strike_duelist_cyclone" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Sword" + } + }, + weaponTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Sword" + } + }, + MeleeAOEStrikeDuelistCycloneNoble={ + classId="MeleeAOEStrikeDuelist", + hash=59945, + id="MeleeAOEStrikeDuelistCycloneNoble", + infamous=true, + name="Infamous Swiftblade", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour50", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex50", + statId="base_dexterity", + values={ + [1]=32, + [2]=115, + [3]=229 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion50", + statId="evasion_rating_+%", + values={ + [1]=25, + [2]=50, + [3]=75 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life50", + statId="maximum_life_+%", + values={ + [1]=56, + [2]=113, + [3]=150 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen50", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=30, + [2]=45, + [3]=60 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression50", + statId="base_spell_suppression_chance_%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str50", + statId="base_strength", + values={ + [1]=32, + [2]=115, + [3]=229 + } + } + }, + skillIds={ + [1]="CycloneReverseKnockbackMercenary", + [2]="DashMercenary", + [3]="DonutBladesMercenary", + [4]="FlickerStrikeMercenary", + [5]="LeapSlamMercenary", + [6]="MassFrenzyMercenary", + [7]="PrideMercenary", + [8]="QuickGuardAllyMercenary", + [9]="RallyingCryMercenary", + [10]="VaalDoubleStrikeMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="CycloneReverseKnockbackMercenary", + [2]="DonutBladesMercenary", + [3]="RallyingCryMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="FlickerStrikeMercenary", + [2]="VaalDoubleStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="LeapSlamMercenary", + [3]="MassFrenzyMercenary", + [4]="PrideMercenary", + [5]="QuickGuardAllyMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_strike_duelist", + [2]="mercenary_melee_aoe_strike_duelist_cyclone", + [3]="mercenary_melee_aoe_strike_duelist_cyclone_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Sword" + } + }, + weaponTypes={ + [1]="Two Handed Axe", + [2]="Two Handed Sword" + } + }, + MeleeAOEStrikeDuelistRangeStrikes={ + classId="MeleeAOEStrikeDuelist", + hash=28843, + id="MeleeAOEStrikeDuelistRangeStrikes", + infamous=false, + name="Combatant", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour30", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_high", + statId="attack_speed_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex70", + statId="base_dexterity", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion70", + statId="evasion_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life30", + statId="maximum_life_+%", + values={ + [1]=49, + [2]=98, + [3]=130 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen30", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=18, + [2]=27, + [3]=36 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression70", + statId="base_spell_suppression_chance_%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str30", + statId="base_strength", + values={ + [1]=22, + [2]=77, + [3]=154 + } + } + }, + skillIds={ + [1]="DashMercenary", + [2]="FrostBladesMercenary", + [3]="FrostblinkMercenary", + [4]="HeraldOfIceMercenary", + [5]="InspiringCryMercenary", + [6]="PurityOfIceMercenary", + [7]="SpectralHelixMercenary", + [8]="StaticStrikeMercenary", + [9]="WildStrikeMercenary", + [10]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="HeraldOfIceMercenary", + [2]="InspiringCryMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="FrostBladesMercenary", + [2]="SpectralHelixMercenary", + [3]="StaticStrikeMercenary", + [4]="WildStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="FrostblinkMercenary", + [3]="PurityOfIceMercenary", + [4]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_strike_duelist", + [2]="mercenary_melee_aoe_strike_duelist_range_strikes" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + MeleeAOEStrikeDuelistRangeStrikesNoble={ + classId="MeleeAOEStrikeDuelist", + hash=4167, + id="MeleeAOEStrikeDuelistRangeStrikesNoble", + infamous=true, + name="Infamous Combatant", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour30", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_high", + statId="attack_speed_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex70", + statId="base_dexterity", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion70", + statId="evasion_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life30", + statId="maximum_life_+%", + values={ + [1]=49, + [2]=98, + [3]=130 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen30", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=18, + [2]=27, + [3]=36 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression70", + statId="base_spell_suppression_chance_%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str30", + statId="base_strength", + values={ + [1]=22, + [2]=77, + [3]=154 + } + } + }, + skillIds={ + [1]="DashMercenary", + [2]="FrostBladesMercenary", + [3]="FrostblinkMercenary", + [4]="HeraldOfIceMercenary", + [5]="InspiringCryMercenary", + [6]="PurityOfIceMercenary", + [7]="SpectralHelixMercenary", + [8]="StaticStrikeMercenary", + [9]="WildStrikeMercenary", + [10]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="HeraldOfIceMercenary", + [2]="InspiringCryMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="FrostBladesMercenary", + [2]="SpectralHelixMercenary", + [3]="StaticStrikeMercenary", + [4]="WildStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DashMercenary", + [2]="FrostblinkMercenary", + [3]="PurityOfIceMercenary", + [4]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_melee_aoe_strike_duelist", + [2]="mercenary_melee_aoe_strike_duelist_range_strikes", + [3]="mercenary_melee_aoe_strike_duelist_range_strikes_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="One Handed Axe", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + MeleeStrikesMaraduerPhys={ + classId="MeleeStrikesMarauder", + hash=23889, + id="MeleeStrikesMaraduerPhys", + infamous=false, + name="Striker", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour90", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life90", + statId="maximum_life_+%", + values={ + [1]=71, + [2]=143, + [3]=190 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen90", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=54, + [2]=81, + [3]=108 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str90", + statId="base_strength", + values={ + [1]=53, + [2]=190, + [3]=379 + } + } + }, + skillIds={ + [1]="BoneshatterMercenary", + [2]="DecoyTotemMercenary", + [3]="DeterminationMercenary", + [4]="DualStrikeMercenary", + [5]="EnduringCryMercenary", + [6]="HeavyStrikeMercenary", + [7]="LeapSlamMercenary", + [8]="MoltenShellMercenary", + [9]="PhysicalAegisMercenary", + [10]="VaalAncestralWarchiefMercenary", + [11]="VigilantStrikeMercenary", + [12]="VitalityMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="EnduringCryMercenary", + [2]="PhysicalAegisMercenary", + [3]="VigilantStrikeMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BoneshatterMercenary", + [2]="DualStrikeMercenary", + [3]="HeavyStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DecoyTotemMercenary", + [2]="DeterminationMercenary", + [3]="LeapSlamMercenary", + [4]="MoltenShellMercenary", + [5]="VaalAncestralWarchiefMercenary", + [6]="VitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_strikes_marauder", + [2]="mercenary_strikes_marauder_phys" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace" + } + }, + MeleeStrikesMaraduerPhysNoble={ + classId="MeleeStrikesMarauder", + hash=21915, + id="MeleeStrikesMaraduerPhysNoble", + infamous=true, + name="Infamous Striker", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour90", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life90", + statId="maximum_life_+%", + values={ + [1]=71, + [2]=143, + [3]=190 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen90", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=54, + [2]=81, + [3]=108 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str90", + statId="base_strength", + values={ + [1]=53, + [2]=190, + [3]=379 + } + } + }, + skillIds={ + [1]="BoneshatterMercenary", + [2]="DecoyTotemMercenary", + [3]="DeterminationMercenary", + [4]="DualStrikeMercenary", + [5]="EnduringCryMercenary", + [6]="HeavyStrikeMercenary", + [7]="LeapSlamMercenary", + [8]="MoltenShellMercenary", + [9]="PhysicalAegisMercenary", + [10]="VaalAncestralWarchiefMercenary", + [11]="VigilantStrikeMercenary", + [12]="VitalityMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="EnduringCryMercenary", + [2]="PhysicalAegisMercenary", + [3]="VigilantStrikeMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BoneshatterMercenary", + [2]="DualStrikeMercenary", + [3]="HeavyStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="DecoyTotemMercenary", + [2]="DeterminationMercenary", + [3]="LeapSlamMercenary", + [4]="MoltenShellMercenary", + [5]="VaalAncestralWarchiefMercenary", + [6]="VitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_strikes_marauder", + [3]="mercenary_strikes_marauder_phys", + [4]="mercenary_strikes_marauder_phys_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace" + } + }, + MeleeStrikesMarauderFire={ + classId="MeleeStrikesMarauder", + hash=54140, + id="MeleeStrikesMarauderFire", + infamous=false, + name="Smoulderstrike", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour90", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=45, + [2]=90, + [3]=135 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex10", + statId="base_dexterity", + values={ + [1]=11, + [2]=40, + [3]=79 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_low", + statId="dot_multiplier_+", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion10", + statId="evasion_rating_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [10]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Ignite", + id="ignite_chance", + statId="base_chance_to_ignite_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [11]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Ignite Duration", + id="ignite_duration", + statId="ignite_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life90", + statId="maximum_life_+%", + values={ + [1]=71, + [2]=143, + [3]=190 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen90", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=54, + [2]=81, + [3]=108 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression10", + statId="base_spell_suppression_chance_%", + values={ + [1]=2, + [2]=4, + [3]=6 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str90", + statId="base_strength", + values={ + [1]=53, + [2]=190, + [3]=379 + } + } + }, + skillIds={ + [1]="AngerMercenary", + [2]="FireAegisMercenary", + [3]="FireEnrageMercenary", + [4]="InfernalBlowAltMercenary", + [5]="InfernalCryMercenary", + [6]="LeapSlamMercenary", + [7]="LightningStrikeFireMercenary", + [8]="MoltenShellMercenary", + [9]="MoltenStrikeMercenary", + [10]="PunishmentMercenary", + [11]="VaalMoltenStrikeMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="FireEnrageMercenary", + [2]="PunishmentMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="InfernalBlowAltMercenary", + [2]="LightningStrikeFireMercenary", + [3]="MoltenStrikeMercenary", + [4]="VaalMoltenStrikeMercenary" + } + }, + [3]={ + skillIds={ + [1]="AngerMercenary", + [2]="FireAegisMercenary", + [3]="InfernalCryMercenary", + [4]="LeapSlamMercenary", + [5]="MoltenShellMercenary" + } + } + }, + tags={ + [1]="mercenary_strikes_marauder", + [2]="mercenary_strikes_marauder_fire" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace", + [3]="One Handed Sword", + [4]="Shield", + [5]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace", + [3]="One Handed Sword", + [4]="Shield", + [5]="Thrusting One Handed Sword" + } + }, + MiscScionPhysDot={ + classId="MiscScion", + hash=35686, + id="MiscScionPhysDot", + infamous=false, + name="Sanguimancer", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_low", + statId="base_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex20", + statId="base_dexterity", + values={ + [1]=16, + [2]=58, + [3]=117 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion20", + statId="evasion_rating_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression20", + statId="base_spell_suppression_chance_%", + values={ + [1]=4, + [2]=8, + [3]=12 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="BladeVortexAltMercenary", + [2]="BodyswapMercenary", + [3]="CGEBloodGroundMercenary", + [4]="ExsanguinateMercenary", + [5]="FlameDashMercenary", + [6]="LightningWarpMercenary", + [7]="PrideMercenary", + [8]="ProximityShieldMercenary", + [9]="ReapMercenary", + [10]="StormCallAltMercenary", + [11]="VaalReapMercenary", + [12]="VaalVitalityMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="BodyswapMercenary", + [2]="CGEBloodGroundMercenary", + [3]="StormCallAltMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BladeVortexAltMercenary", + [2]="ExsanguinateMercenary", + [3]="ReapMercenary", + [4]="VaalReapMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="LightningWarpMercenary", + [3]="PrideMercenary", + [4]="ProximityShieldMercenary", + [5]="VaalVitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_misc_scion", + [2]="mercenary_misc_scion_phys_dot" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Wand" + } + }, + MiscScionPhysDotNoble={ + classId="MiscScion", + hash=36701, + id="MiscScionPhysDotNoble", + infamous=true, + name="Infamous Sanguimancer", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_low", + statId="base_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex20", + statId="base_dexterity", + values={ + [1]=16, + [2]=58, + [3]=117 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion20", + statId="evasion_rating_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression20", + statId="base_spell_suppression_chance_%", + values={ + [1]=4, + [2]=8, + [3]=12 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="BladeVortexAltMercenary", + [2]="BodyswapMercenary", + [3]="CGEBloodGroundMercenary", + [4]="ExsanguinateMercenary", + [5]="FlameDashMercenary", + [6]="LightningWarpMercenary", + [7]="PrideMercenary", + [8]="ProximityShieldMercenary", + [9]="ReapMercenary", + [10]="StormCallAltMercenary", + [11]="VaalReapMercenary", + [12]="VaalVitalityMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="BodyswapMercenary", + [2]="CGEBloodGroundMercenary", + [3]="StormCallAltMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BladeVortexAltMercenary", + [2]="ExsanguinateMercenary", + [3]="ReapMercenary", + [4]="VaalReapMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="LightningWarpMercenary", + [3]="PrideMercenary", + [4]="ProximityShieldMercenary", + [5]="VaalVitalityMercenary" + } + } + }, + tags={ + [1]="mercenary_misc_scion", + [2]="mercenary_misc_scion_phys_dot", + [3]="mercenary_misc_scion_phys_dot_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Wand" + } + }, + MiscScionWandAttacks={ + classId="MiscScion", + hash=45992, + id="MiscScionWandAttacks", + infamous=false, + name="Kineticist", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex40", + statId="base_dexterity", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion40", + statId="evasion_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression40", + statId="base_spell_suppression_chance_%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="BarrageMercenary", + [2]="ElementalWeaknessMercenary", + [3]="FlameDashMercenary", + [4]="FlameWallMercenary", + [5]="FrostblinkMercenary", + [6]="GigaKineticBlastMercenary", + [7]="HasteMercenary", + [8]="InspiringCryMercenary", + [9]="KineticBlastAltMercenary", + [10]="KineticBoltMercenary", + [11]="KineticRainAltXMercenary", + [12]="PowerSiphonMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ElementalWeaknessMercenary", + [2]="FlameWallMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BarrageMercenary", + [2]="GigaKineticBlastMercenary", + [3]="KineticBlastAltMercenary", + [4]="KineticBoltMercenary", + [5]="KineticRainAltXMercenary", + [6]="PowerSiphonMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="FrostblinkMercenary", + [3]="HasteMercenary", + [4]="InspiringCryMercenary" + } + } + }, + tags={ + [1]="mercenary_misc_scion", + [2]="mercenary_misc_scion_wand_attack" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Wand" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="Shield", + [2]="Wand" + } + }, + MiscScionWandAttacksNoble={ + classId="MiscScion", + hash=54383, + id="MiscScionWandAttacksNoble", + infamous=true, + name="Infamous Kineticist", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex40", + statId="base_dexterity", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion40", + statId="evasion_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression40", + statId="base_spell_suppression_chance_%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="BarrageMercenary", + [2]="ElementalWeaknessMercenary", + [3]="FlameDashMercenary", + [4]="FlameWallMercenary", + [5]="FrostblinkMercenary", + [6]="GigaKineticBlastMercenary", + [7]="HasteMercenary", + [8]="InspiringCryMercenary", + [9]="KineticBlastAltMercenary", + [10]="KineticBoltMercenary", + [11]="KineticRainAltXMercenary", + [12]="PowerSiphonMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ElementalWeaknessMercenary", + [2]="FlameWallMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BarrageMercenary", + [2]="GigaKineticBlastMercenary", + [3]="KineticBlastAltMercenary", + [4]="KineticBoltMercenary", + [5]="KineticRainAltXMercenary", + [6]="PowerSiphonMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="FrostblinkMercenary", + [3]="HasteMercenary", + [4]="InspiringCryMercenary" + } + } + }, + tags={ + [1]="mercenary_misc_scion", + [2]="mercenary_misc_scion_wand_attack", + [3]="mercenary_misc_scion_wand_attack_noble", + [4]="mercenary_noble_born" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Wand" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="Shield", + [2]="Wand" + } + }, + NonEleBowRangerChaos={ + classId="NonEleBowRanger", + hash=27959, + id="NonEleBowRangerChaos", + infamous=false, + name="Toxicologist", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex80", + statId="base_dexterity", + values={ + [1]=48, + [2]=171, + [3]=342 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield20", + statId="maximum_energy_shield_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion80", + statId="evasion_rating_+%", + values={ + [1]=40, + [2]=80, + [3]=120 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge20", + statId="energy_shield_delay_-%", + values={ + [1]=4, + [2]=8, + [3]=12 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int20", + statId="base_intelligence", + values={ + [1]=16, + [2]=58, + [3]=117 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate20", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression80", + statId="base_spell_suppression_chance_%", + values={ + [1]=16, + [2]=32, + [3]=48 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BlinkArrowMercenary", + [3]="CausticArrowMercenary", + [4]="DashMercenary", + [5]="DeceleratingProjectileMercenary", + [6]="DeceleratingProjectileMercenaryExplode", + [7]="GraceMercenary", + [8]="MalevolenceMercenary", + [9]="ScourgeArrowAltMercenary", + [10]="ToxicRainMercenary", + [11]="VaalCausticArrowMercenary", + [12]="WitheringStepMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="DeceleratingProjectileMercenary", + [2]="DeceleratingProjectileMercenaryExplode", + [3]="WitheringStepMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="CausticArrowMercenary", + [2]="ScourgeArrowAltMercenary", + [3]="ToxicRainMercenary", + [4]="VaalCausticArrowMercenary" + } + }, + [3]={ + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BlinkArrowMercenary", + [3]="DashMercenary", + [4]="GraceMercenary", + [5]="MalevolenceMercenary" + } + } + }, + tags={ + [1]="mercenary_non_ele_ranger", + [2]="mercenary_non_ele_ranger_chaos" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + NonEleBowRangerChaosNoble={ + classId="NonEleBowRanger", + hash=18312, + id="NonEleBowRangerChaosNoble", + infamous=true, + name="Infamous Toxicologist", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex80", + statId="base_dexterity", + values={ + [1]=48, + [2]=171, + [3]=342 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield20", + statId="maximum_energy_shield_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion80", + statId="evasion_rating_+%", + values={ + [1]=40, + [2]=80, + [3]=120 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge20", + statId="energy_shield_delay_-%", + values={ + [1]=4, + [2]=8, + [3]=12 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int20", + statId="base_intelligence", + values={ + [1]=16, + [2]=58, + [3]=117 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate20", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=5, + [2]=10, + [3]=15 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression80", + statId="base_spell_suppression_chance_%", + values={ + [1]=16, + [2]=32, + [3]=48 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + } + }, + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BlinkArrowMercenary", + [3]="CausticArrowMercenary", + [4]="DashMercenary", + [5]="DeceleratingProjectileMercenary", + [6]="DeceleratingProjectileMercenaryExplode", + [7]="GraceMercenary", + [8]="MalevolenceMercenary", + [9]="ScourgeArrowAltMercenary", + [10]="ToxicRainMercenary", + [11]="VaalCausticArrowMercenary", + [12]="WitheringStepMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="DeceleratingProjectileMercenary", + [2]="DeceleratingProjectileMercenaryExplode", + [3]="WitheringStepMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="CausticArrowMercenary", + [2]="ScourgeArrowAltMercenary", + [3]="ToxicRainMercenary", + [4]="VaalCausticArrowMercenary" + } + }, + [3]={ + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BlinkArrowMercenary", + [3]="DashMercenary", + [4]="GraceMercenary", + [5]="MalevolenceMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_non_ele_ranger", + [3]="mercenary_non_ele_ranger_chaos", + [4]="mercenary_non_ele_ranger_chaos_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + NonEleBowRangerPhys={ + classId="NonEleBowRanger", + hash=44391, + id="NonEleBowRangerPhys", + infamous=false, + name="Sniper", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour20", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to cause Bleeding", + id="bleed_chance", + statId="bleed_on_hit_with_attacks_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [5]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Bleed Duration", + id="bleed_duration", + statId="base_bleed_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [8]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex80", + statId="base_dexterity", + values={ + [1]=48, + [2]=171, + [3]=342 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_low", + statId="dot_multiplier_+", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion80", + statId="evasion_rating_+%", + values={ + [1]=40, + [2]=80, + [3]=120 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life20", + statId="maximum_life_+%", + values={ + [1]=45, + [2]=90, + [3]=120 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen20", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=12, + [2]=18, + [3]=24 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression80", + statId="base_spell_suppression_chance_%", + values={ + [1]=16, + [2]=32, + [3]=48 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str20", + statId="base_strength", + values={ + [1]=16, + [2]=58, + [3]=117 + } + } + }, + skillIds={ + [1]="BarrageAltMercenary", + [2]="BlinkArrowMercenary", + [3]="DashMercenary", + [4]="EnsnaringArrowMercenary", + [5]="FrenzyMercenary", + [6]="GraceMercenary", + [7]="HasteMercenary", + [8]="PoachersMarkMercenary", + [9]="PunctureMercenary", + [10]="RainOfArrowsAltMercenary", + [11]="ShrapnelBallistaMercenary", + [12]="SiegeBallistaAltMercenary", + [13]="SplitArrowMercenary", + [14]="TornadoShotMercenary", + [15]="VaalSplitArrowMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="EnsnaringArrowMercenary", + [2]="PoachersMarkMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BarrageAltMercenary", + [2]="PunctureMercenary", + [3]="RainOfArrowsAltMercenary", + [4]="ShrapnelBallistaMercenary", + [5]="SiegeBallistaAltMercenary", + [6]="SplitArrowMercenary", + [7]="TornadoShotMercenary", + [8]="VaalSplitArrowMercenary" + } + }, + [3]={ + skillIds={ + [1]="BlinkArrowMercenary", + [2]="DashMercenary", + [3]="FrenzyMercenary", + [4]="GraceMercenary", + [5]="HasteMercenary" + } + } + }, + tags={ + [1]="mercenary_non_ele_ranger", + [2]="mercenary_non_ele_ranger_phys" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + NonEleBowRangerPhysNoble={ + classId="NonEleBowRanger", + hash=1570, + id="NonEleBowRangerPhysNoble", + infamous=true, + name="Infamous Sniper", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_high", + statId="accuracy_rating_+%", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour20", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to cause Bleeding", + id="bleed_chance", + statId="bleed_on_hit_with_attacks_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [5]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Bleed Duration", + id="bleed_duration", + statId="base_bleed_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [8]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex80", + statId="base_dexterity", + values={ + [1]=48, + [2]=171, + [3]=342 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_low", + statId="dot_multiplier_+", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion80", + statId="evasion_rating_+%", + values={ + [1]=40, + [2]=80, + [3]=120 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life20", + statId="maximum_life_+%", + values={ + [1]=45, + [2]=90, + [3]=120 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen20", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=12, + [2]=18, + [3]=24 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression80", + statId="base_spell_suppression_chance_%", + values={ + [1]=16, + [2]=32, + [3]=48 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str20", + statId="base_strength", + values={ + [1]=16, + [2]=58, + [3]=117 + } + } + }, + skillIds={ + [1]="BarrageAltMercenary", + [2]="BlinkArrowMercenary", + [3]="DashMercenary", + [4]="EnsnaringArrowMercenary", + [5]="FrenzyMercenary", + [6]="GraceMercenary", + [7]="HasteMercenary", + [8]="PoachersMarkMercenary", + [9]="PunctureMercenary", + [10]="RainOfArrowsAltMercenary", + [11]="ShrapnelBallistaMercenary", + [12]="SiegeBallistaAltMercenary", + [13]="SplitArrowMercenary", + [14]="TornadoShotMercenary", + [15]="VaalSplitArrowMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="EnsnaringArrowMercenary", + [2]="PoachersMarkMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BarrageAltMercenary", + [2]="PunctureMercenary", + [3]="RainOfArrowsAltMercenary", + [4]="ShrapnelBallistaMercenary", + [5]="SiegeBallistaAltMercenary", + [6]="SplitArrowMercenary", + [7]="TornadoShotMercenary", + [8]="VaalSplitArrowMercenary" + } + }, + [3]={ + skillIds={ + [1]="BlinkArrowMercenary", + [2]="DashMercenary", + [3]="FrenzyMercenary", + [4]="GraceMercenary", + [5]="HasteMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_non_ele_ranger", + [3]="mercenary_non_ele_ranger_phys", + [4]="mercenary_non_ele_ranger_phys_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Bow" + }, + offHandRequired=true, + offHandTypes={ + [1]="Quiver" + } + }, + weaponTypes={ + [1]="Bow", + [2]="Quiver" + } + }, + PhysConvertTemplarCold={ + classId="PhysConvertTemplar", + hash=60686, + id="PhysConvertTemplarCold", + infamous=false, + name="Winter Deacon", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_low", + statId="accuracy_rating_+%", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Other", + categoryName="Other", + id="base_phasing_without_visual", + line="Phasing", + statId="base_phasing_without_visual", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Spell Damage", + id="block_spell_high", + statId="base_spell_block_%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [7]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Effect of Chill", + id="chill_effect", + statId="chill_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [8]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [9]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex20", + statId="base_dexterity", + values={ + [1]=16, + [2]=58, + [3]=117 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion20", + statId="evasion_rating_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [15]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Freeze", + id="freeze_chance", + statId="base_chance_to_freeze_%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [20]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression20", + statId="base_spell_suppression_chance_%", + values={ + [1]=4, + [2]=8, + [3]=12 + } + }, + [21]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="ArcticArmourMercenary", + [2]="EarthquakeColdMercenary", + [3]="FrostBombMercenary", + [4]="FrostShieldMercenary", + [5]="FrostblinkMercenary", + [6]="GlacialHammerMercenary", + [7]="HatredMercenary", + [8]="HeavyStrikeAltMercenary", + [9]="IceCrashMercenary", + [10]="PurityOfIceMercenary", + [11]="VaalGlacialHammerMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="FrostShieldMercenary", + [2]="VaalGlacialHammerMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="EarthquakeColdMercenary", + [2]="GlacialHammerMercenary", + [3]="HeavyStrikeAltMercenary", + [4]="IceCrashMercenary" + } + }, + [3]={ + skillIds={ + [1]="ArcticArmourMercenary", + [2]="FrostBombMercenary", + [3]="FrostblinkMercenary", + [4]="HatredMercenary", + [5]="PurityOfIceMercenary" + } + } + }, + tags={ + [1]="mercenary_phys_convert_templar", + [2]="mercenary_phys_convert_templar_cold" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff", + [2]="Two Handed Mace" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff", + [2]="Two Handed Mace" + } + }, + weaponTypes={ + [1]="Staff", + [2]="Two Handed Mace" + } + }, + PhysConvertTemplarFire={ + classId="PhysConvertTemplar", + hash=39466, + id="PhysConvertTemplarFire", + infamous=false, + name="Flaming Charlatan", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour60", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_low", + statId="base_cast_speed_+%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_low", + statId="dot_multiplier_+", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life60", + statId="maximum_life_+%", + values={ + [1]=60, + [2]=120, + [3]=160 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen60", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=36, + [2]=54, + [3]=72 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str60", + statId="base_strength", + values={ + [1]=37, + [2]=133, + [3]=267 + } + } + }, + skillIds={ + [1]="AngerMercenary", + [2]="FlameDashMercenary", + [3]="HeraldOfAshMercenary", + [4]="HolyFireMortarMercenary", + [5]="HolyFlameTotemMercenary", + [6]="LightningWarpMercenary", + [7]="MeteorUpheavalMercenary", + [8]="PurifyingFlameMercenary", + [9]="ScorchingRayTotemMercenary", + [10]="WaveOfConvictionAltMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="HolyFlameTotemMercenary", + [2]="PurifyingFlameMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="HolyFireMortarMercenary", + [2]="MeteorUpheavalMercenary", + [3]="ScorchingRayTotemMercenary", + [4]="WaveOfConvictionAltMercenary" + } + }, + [3]={ + skillIds={ + [1]="AngerMercenary", + [2]="FlameDashMercenary", + [3]="HeraldOfAshMercenary", + [4]="LightningWarpMercenary" + } + } + }, + tags={ + [1]="mercenary_phys_convert_templar", + [2]="mercenary_phys_convert_templar_fire" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Sceptre", + [2]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Sceptre", + [2]="Wand" + } + }, + weaponTypes={ + [1]="Sceptre", + [2]="Wand" + } + }, + PhysConvertTemplarLightning={ + classId="PhysConvertTemplar", + hash=37789, + id="PhysConvertTemplarLightning", + infamous=false, + name="Storming Zealot", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Spell Damage", + id="block_spell_high", + statId="base_spell_block_%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="ChargedDashSpellScalingMercenary", + [2]="DivineIreMercenary", + [3]="DivineRetributionMercenary", + [4]="FlameDashMercenary", + [5]="LightningWarpMercenary", + [6]="MercenaryLightningDelayedBlast", + [7]="ShockwaveTotemMercenary", + [8]="TornadoAltMercenary", + [9]="WaveOfConvictionLightningMercenary", + [10]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="MercenaryLightningDelayedBlast", + [2]="WaveOfConvictionLightningMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="DivineIreMercenary", + [2]="DivineRetributionMercenary", + [3]="ShockwaveTotemMercenary", + [4]="TornadoAltMercenary" + } + }, + [3]={ + skillIds={ + [1]="ChargedDashSpellScalingMercenary", + [2]="FlameDashMercenary", + [3]="LightningWarpMercenary", + [4]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_phys_convert_templar", + [2]="mercenary_phys_convert_templar_lightning" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + PhysConvertTemplarLightningNoble={ + classId="PhysConvertTemplar", + hash=49599, + id="PhysConvertTemplarLightningNoble", + infamous=true, + name="Infamous Storming Zealot", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [3]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Spell Damage", + id="block_spell_high", + statId="base_spell_block_%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Cast Speed", + id="cast_speed_med", + statId="base_cast_speed_+%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex0", + statId="base_dexterity", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion0", + statId="evasion_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression0", + statId="base_spell_suppression_chance_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="ChargedDashSpellScalingMercenary", + [2]="DivineIreMercenary", + [3]="DivineRetributionMercenary", + [4]="FlameDashMercenary", + [5]="LightningWarpMercenary", + [6]="MercenaryLightningDelayedBlast", + [7]="ShockwaveTotemMercenary", + [8]="TornadoAltMercenary", + [9]="WaveOfConvictionLightningMercenary", + [10]="WrathMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="MercenaryLightningDelayedBlast", + [2]="WaveOfConvictionLightningMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="DivineIreMercenary", + [2]="DivineRetributionMercenary", + [3]="ShockwaveTotemMercenary", + [4]="TornadoAltMercenary" + } + }, + [3]={ + skillIds={ + [1]="ChargedDashSpellScalingMercenary", + [2]="FlameDashMercenary", + [3]="LightningWarpMercenary", + [4]="WrathMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_phys_convert_templar", + [3]="mercenary_phys_convert_templar_lightning", + [4]="mercenary_phys_convert_templar_lightning_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Staff" + }, + offHandRequired=false, + offHandTypes={ + [1]="Staff" + } + }, + weaponTypes={ + [1]="Staff" + } + }, + PhysicalDuelistBleed={ + classId="PhysicalDuelist", + hash=37584, + id="PhysicalDuelistBleed", + infamous=false, + name="Bloodletter", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour70", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to cause Bleeding", + id="bleed_chance", + statId="bleed_on_hit_with_attacks_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [5]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Bleed Duration", + id="bleed_duration", + statId="base_bleed_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex30", + statId="base_dexterity", + values={ + [1]=22, + [2]=77, + [3]=154 + } + }, + [9]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion30", + statId="evasion_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life70", + statId="maximum_life_+%", + values={ + [1]=64, + [2]=128, + [3]=170 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen70", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=42, + [2]=63, + [3]=84 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression30", + statId="base_spell_suppression_chance_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str70", + statId="base_strength", + values={ + [1]=43, + [2]=152, + [3]=304 + } + } + }, + skillIds={ + [1]="ABTTPhysEnrageMercenary", + [2]="BladestormMercenary", + [3]="BloodMortarMercenary", + [4]="CGEOilGroundSlowMercenary", + [5]="DashMercenary", + [6]="DeterminationMercenary", + [7]="LacerateMercenary", + [8]="LeapSlamMercenary", + [9]="PerforateMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="ABTTPhysEnrageMercenary", + [2]="BloodMortarMercenary", + [3]="LacerateMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BladestormMercenary", + [2]="PerforateMercenary" + } + }, + [3]={ + skillIds={ + [1]="CGEOilGroundSlowMercenary", + [2]="DashMercenary", + [3]="DeterminationMercenary", + [4]="LeapSlamMercenary" + } + } + }, + tags={ + [1]="mercenary_phys_duelist", + [2]="mercenary_phys_duelist_bleed" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + PhysicalDuelistBleedNoble={ + classId="PhysicalDuelist", + hash=57872, + id="PhysicalDuelistBleedNoble", + infamous=true, + name="Infamous Bloodletter", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour70", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=35, + [2]=70, + [3]=105 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to cause Bleeding", + id="bleed_chance", + statId="bleed_on_hit_with_attacks_%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [5]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Bleed Duration", + id="bleed_duration", + statId="base_bleed_duration_+%", + values={ + [1]=10, + [2]=20, + [3]=25 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex30", + statId="base_dexterity", + values={ + [1]=22, + [2]=77, + [3]=154 + } + }, + [9]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_high", + statId="dot_multiplier_+", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion30", + statId="evasion_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life70", + statId="maximum_life_+%", + values={ + [1]=64, + [2]=128, + [3]=170 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen70", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=42, + [2]=63, + [3]=84 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression30", + statId="base_spell_suppression_chance_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str70", + statId="base_strength", + values={ + [1]=43, + [2]=152, + [3]=304 + } + } + }, + skillIds={ + [1]="ABTTPhysEnrageMercenary", + [2]="BladestormMercenary", + [3]="BloodMortarMercenary", + [4]="CGEOilGroundSlowMercenary", + [5]="DashMercenary", + [6]="DeterminationMercenary", + [7]="LacerateMercenary", + [8]="LeapSlamMercenary", + [9]="PerforateMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="ABTTPhysEnrageMercenary", + [2]="BloodMortarMercenary", + [3]="LacerateMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BladestormMercenary", + [2]="PerforateMercenary" + } + }, + [3]={ + skillIds={ + [1]="CGEOilGroundSlowMercenary", + [2]="DashMercenary", + [3]="DeterminationMercenary", + [4]="LeapSlamMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_phys_duelist", + [3]="mercenary_phys_duelist_bleed", + [4]="mercenary_phys_duelist_bleed_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + PhysicalDuelistShields={ + classId="PhysicalDuelist", + hash=17404, + id="PhysicalDuelistShields", + infamous=false, + name="Bastion", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour60", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_high", + statId="monster_base_block_%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Spell Damage", + id="block_spell_low", + statId="base_spell_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex40", + statId="base_dexterity", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion40", + statId="evasion_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life60", + statId="maximum_life_+%", + values={ + [1]=60, + [2]=120, + [3]=160 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen60", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=36, + [2]=54, + [3]=72 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression40", + statId="base_spell_suppression_chance_%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str60", + statId="base_strength", + values={ + [1]=37, + [2]=133, + [3]=267 + } + } + }, + skillIds={ + [1]="ABTTArmourEleMercenary", + [2]="ABTTInvulnBubbleMercenary", + [3]="DashMercenary", + [4]="DeterminationMercenary", + [5]="IntimidatingCryMercenary", + [6]="PhysicalAegisMercenary", + [7]="ShieldChargeMercenary", + [8]="ShieldCrushMercenary", + [9]="SpectralShieldThrowAltMercenary", + [10]="TempestShieldMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ShieldChargeMercenary", + [2]="ShieldCrushMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ABTTArmourEleMercenary", + [2]="SpectralShieldThrowAltMercenary", + [3]="TempestShieldMercenary" + } + }, + [3]={ + skillIds={ + [1]="ABTTInvulnBubbleMercenary", + [2]="DashMercenary", + [3]="DeterminationMercenary", + [4]="IntimidatingCryMercenary", + [5]="PhysicalAegisMercenary" + } + } + }, + tags={ + [1]="mercenary_phys_duelist", + [2]="mercenary_phys_duelist_shields" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace", + [3]="One Handed Sword", + [4]="Shield", + [5]="Thrusting One Handed Sword" + } + }, + PhysicalDuelistShieldsNoble={ + classId="PhysicalDuelist", + hash=46351, + id="PhysicalDuelistShieldsNoble", + infamous=true, + name="Infamous Bastion", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + id="accuracy_resolute_technique", + line="Resolute Technique", + statId="resolute_technique", + values={ + [1]=1, + [2]=1, + [3]=1 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour60", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_low", + statId="attack_speed_+%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_high", + statId="monster_base_block_%", + values={ + [1]=9, + [2]=18, + [3]=27 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Spell Damage", + id="block_spell_low", + statId="base_spell_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_high", + statId="damage_+%", + values={ + [1]=120, + [2]=240, + [3]=300 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex40", + statId="base_dexterity", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion40", + statId="evasion_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [11]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life60", + statId="maximum_life_+%", + values={ + [1]=60, + [2]=120, + [3]=160 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen60", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=36, + [2]=54, + [3]=72 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression40", + statId="base_spell_suppression_chance_%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str60", + statId="base_strength", + values={ + [1]=37, + [2]=133, + [3]=267 + } + } + }, + skillIds={ + [1]="ABTTArmourEleMercenary", + [2]="ABTTInvulnBubbleMercenary", + [3]="DashMercenary", + [4]="DeterminationMercenary", + [5]="IntimidatingCryMercenary", + [6]="PhysicalAegisMercenary", + [7]="ShieldChargeMercenary", + [8]="ShieldCrushMercenary", + [9]="SpectralShieldThrowAltMercenary", + [10]="TempestShieldMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ShieldChargeMercenary", + [2]="ShieldCrushMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="ABTTArmourEleMercenary", + [2]="SpectralShieldThrowAltMercenary", + [3]="TempestShieldMercenary" + } + }, + [3]={ + skillIds={ + [1]="ABTTInvulnBubbleMercenary", + [2]="DashMercenary", + [3]="DeterminationMercenary", + [4]="IntimidatingCryMercenary", + [5]="PhysicalAegisMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_phys_duelist", + [3]="mercenary_phys_duelist_shields", + [4]="mercenary_phys_duelist_shields_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Mace", + [3]="One Handed Sword", + [4]="Shield", + [5]="Thrusting One Handed Sword" + } + }, + PhysicalDuelistSteel={ + classId="PhysicalDuelist", + hash=40900, + id="PhysicalDuelistSteel", + infamous=false, + name="Shattersword", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour40", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Attack Speed", + id="attack_speed_med", + statId="attack_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [4]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% Chance to Block Attack Damage", + id="block_attack_low", + statId="monster_base_block_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_low", + statId="critical_strike_chance_+%", + values={ + [1]=25, + [2]=50, + [3]=80 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_low", + statId="base_critical_strike_multiplier_+", + values={ + [1]=15, + [2]=35, + [3]=50 + } + }, + [7]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex60", + statId="base_dexterity", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield0", + statId="maximum_energy_shield_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion60", + statId="evasion_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge0", + statId="energy_shield_delay_-%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [12]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [13]={ + categoryId="Other", + categoryName="Other", + format="%s%% chance to Impale Enemies on Hit with Attacks", + id="impale_chance", + statId="attacks_impale_on_hit_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [14]={ + categoryId="Other", + categoryName="Other", + format="%s%% increased Impale Effect", + id="impale_effect", + statId="impale_debuff_effect_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int0", + statId="base_intelligence", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life40", + statId="maximum_life_+%", + values={ + [1]=53, + [2]=105, + [3]=140 + } + }, + [17]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen40", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=24, + [2]=36, + [3]=48 + } + }, + [18]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate0", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [19]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression60", + statId="base_spell_suppression_chance_%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [20]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str40", + statId="base_strength", + values={ + [1]=27, + [2]=96, + [3]=192 + } + } + }, + skillIds={ + [1]="ABTTExtraImpaleMercenary", + [2]="CallOfSteelMercenary", + [3]="DashMercenary", + [4]="DonutBladesMercenary", + [5]="GraceMercenary", + [6]="LancingSteelMercenary", + [7]="RallyingCryMercenary", + [8]="ShatteringSteelMercenary", + [9]="SplittingSteelMercenary", + [10]="WhirlingBladesMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="CallOfSteelMercenary", + [2]="DonutBladesMercenary", + [3]="RallyingCryMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="LancingSteelMercenary", + [2]="ShatteringSteelMercenary", + [3]="SplittingSteelMercenary" + } + }, + [3]={ + skillIds={ + [1]="ABTTExtraImpaleMercenary", + [2]="DashMercenary", + [3]="GraceMercenary", + [4]="WhirlingBladesMercenary" + } + } + }, + tags={ + [1]="mercenary_phys_duelist", + [2]="mercenary_phys_duelist_steel" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="One Handed Axe", + [2]="One Handed Sword", + [3]="Thrusting One Handed Sword" + } + }, + TrapsMinesShadowAttack={ + classId="TrapsMinesShadow", + hash=33100, + id="TrapsMinesShadowAttack", + infamous=false, + name="Blade Ambusher", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex60", + statId="base_dexterity", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion60", + statId="evasion_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression60", + statId="base_spell_suppression_chance_%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [17]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Trap Throwing Speed", + id="trap_throw_speed", + statId="trap_throwing_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + } + }, + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BearTrapMercenary", + [3]="BladeTrapMercenary", + [4]="FlameDashMercenary", + [5]="GraceMercenary", + [6]="SmokeMineMercenary", + [7]="SpectralHelixAltMercenary", + [8]="SpectralThrowAltMercenary", + [9]="SummonSkitterbotsMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BladeTrapMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="SpectralHelixAltMercenary", + [2]="SpectralThrowAltMercenary" + } + }, + [3]={ + skillIds={ + [1]="BearTrapMercenary", + [2]="FlameDashMercenary", + [3]="GraceMercenary", + [4]="SmokeMineMercenary", + [5]="SummonSkitterbotsMercenary" + } + } + }, + tags={ + [1]="mercenary_traps_mines_shadow", + [2]="mercenary_traps_mines_shadow_attack" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + TrapsMinesShadowAttackNoble={ + classId="TrapsMinesShadow", + hash=57984, + id="TrapsMinesShadowAttackNoble", + infamous=true, + name="Infamous Blade Ambusher", + passiveStats={ + [1]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Accuracy Rating", + id="accuracy_med", + statId="accuracy_rating_+%", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [2]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [5]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex60", + statId="base_dexterity", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield40", + statId="maximum_energy_shield_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion60", + statId="evasion_rating_+%", + values={ + [1]=30, + [2]=60, + [3]=90 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge40", + statId="energy_shield_delay_-%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [10]={ + categoryId="Offensive", + categoryName="Offensive", + format="Hits have %s%% chance to ignore Enemy Physical Damage Reduction", + id="ignore_phys_reduction", + statId="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int40", + statId="base_intelligence", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate40", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression60", + statId="base_spell_suppression_chance_%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [16]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [17]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Trap Throwing Speed", + id="trap_throw_speed", + statId="trap_throwing_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + } + }, + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BearTrapMercenary", + [3]="BladeTrapMercenary", + [4]="FlameDashMercenary", + [5]="GraceMercenary", + [6]="SmokeMineMercenary", + [7]="SpectralHelixAltMercenary", + [8]="SpectralThrowAltMercenary", + [9]="SummonSkitterbotsMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BladeTrapMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="SpectralHelixAltMercenary", + [2]="SpectralThrowAltMercenary" + } + }, + [3]={ + skillIds={ + [1]="BearTrapMercenary", + [2]="FlameDashMercenary", + [3]="GraceMercenary", + [4]="SmokeMineMercenary", + [5]="SummonSkitterbotsMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_traps_mines_shadow", + [3]="mercenary_traps_mines_shadow_attack", + [4]="mercenary_traps_mines_shadow_attack_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + }, + offHandRequired=false, + offHandTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + weaponTypes={ + [1]="Claw", + [2]="Dagger", + [3]="One Handed Sword", + [4]="Thrusting One Handed Sword" + } + }, + TrapsMinesShadowCold={ + classId="TrapsMinesShadow", + hash=14950, + id="TrapsMinesShadowCold", + infamous=false, + name="Frost Ambusher", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_med", + statId="critical_strike_chance_+%", + values={ + [1]=50, + [2]=100, + [3]=160 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_med", + statId="base_critical_strike_multiplier_+", + values={ + [1]=25, + [2]=60, + [3]=90 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_medium", + statId="damage_+%", + values={ + [1]=100, + [2]=200, + [3]=250 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex40", + statId="base_dexterity", + values={ + [1]=27, + [2]=96, + [3]=192 + } + }, + [6]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Damage over Time Multiplier", + id="dot_multi_low", + statId="dot_multiplier_+", + values={ + [1]=10, + [2]=20, + [3]=30 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield60", + statId="maximum_energy_shield_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion40", + statId="evasion_rating_+%", + values={ + [1]=20, + [2]=40, + [3]=60 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge60", + statId="energy_shield_delay_-%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int60", + statId="base_intelligence", + values={ + [1]=37, + [2]=133, + [3]=267 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate60", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression40", + statId="base_spell_suppression_chance_%", + values={ + [1]=8, + [2]=16, + [3]=24 + } + }, + [15]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [16]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Trap Throwing Speed", + id="trap_throw_speed", + statId="trap_throwing_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + } + }, + skillIds={ + [1]="ArcticArmourMercenary", + [2]="CreepingFrostTrapMercenary", + [3]="FlameDashMercenary", + [4]="FrostShieldMercenary", + [5]="FrostblinkMercenary", + [6]="GigaVortexTrapMercenary", + [7]="GraceMercenary", + [8]="IceTrapMercenary", + [9]="SummonSkitterbotsMercenary", + [10]="VaalArcticArmourMercenary" + }, + skillPools={ + [1]={ + countMax=1, + skillIds={ + [1]="FrostShieldMercenary", + [2]="GigaVortexTrapMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="CreepingFrostTrapMercenary", + [2]="IceTrapMercenary" + } + }, + [3]={ + skillIds={ + [1]="ArcticArmourMercenary", + [2]="FlameDashMercenary", + [3]="FrostblinkMercenary", + [4]="GraceMercenary", + [5]="SummonSkitterbotsMercenary", + [6]="VaalArcticArmourMercenary" + } + } + }, + tags={ + [1]="mercenary_traps_mines_shadow", + [2]="mercenary_traps_mines_shadow_cold" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=true, + offHandTypes={ + [1]="Shield" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Shield", + [4]="Wand" + } + }, + TrapsMinesShadowLightning={ + classId="TrapsMinesShadow", + hash=5145, + id="TrapsMinesShadowLightning", + infamous=false, + name="Shock Ambusher", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_high", + statId="critical_strike_chance_+%", + values={ + [1]=75, + [2]=150, + [3]=250 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_high", + statId="base_critical_strike_multiplier_+", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex30", + statId="base_dexterity", + values={ + [1]=22, + [2]=77, + [3]=154 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield70", + statId="maximum_energy_shield_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion30", + statId="evasion_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge70", + statId="energy_shield_delay_-%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int70", + statId="base_intelligence", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate70", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression30", + statId="base_spell_suppression_chance_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Trap Throwing Speed", + id="trap_throw_speed", + statId="trap_throwing_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + } + }, + skillIds={ + [1]="BallLightningAltTrapMercenary", + [2]="ConductivityMercenary", + [3]="FlameDashMercenary", + [4]="FrostblinkMercenary", + [5]="LightningSpireTrapMercenary", + [6]="LightningTrapMercenary", + [7]="LightningWarpTrapsMercenary", + [8]="SmokeMineMercenary", + [9]="SummonSkitterbotsMercenary", + [10]="VaalLightningTrapMercenary", + [11]="ZealotryMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ConductivityMercenary", + [2]="VaalLightningTrapMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BallLightningAltTrapMercenary", + [2]="LightningSpireTrapMercenary", + [3]="LightningTrapMercenary", + [4]="LightningWarpTrapsMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="FrostblinkMercenary", + [3]="SmokeMineMercenary", + [4]="SummonSkitterbotsMercenary", + [5]="ZealotryMercenary" + } + } + }, + tags={ + [1]="mercenary_traps_mines_shadow", + [2]="mercenary_traps_mines_shadow_lightning" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + } + }, + TrapsMinesShadowLightningNoble={ + classId="TrapsMinesShadow", + hash=36090, + id="TrapsMinesShadowLightningNoble", + infamous=true, + name="Infamous Shock Ambusher", + passiveStats={ + [1]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Armour", + id="armour0", + statId="physical_damage_reduction_rating_+%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [2]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Critical Strike Chance", + id="crit_chance_high", + statId="critical_strike_chance_+%", + values={ + [1]=75, + [2]=150, + [3]=250 + } + }, + [3]={ + categoryId="Offensive", + categoryName="Offensive", + format="+%s%% to Critical Strike Multiplier", + id="crit_multi_high", + statId="base_critical_strike_multiplier_+", + values={ + [1]=40, + [2]=100, + [3]=150 + } + }, + [4]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Damage", + id="damage_low", + statId="damage_+%", + values={ + [1]=80, + [2]=160, + [3]=200 + } + }, + [5]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Dexterity", + id="dex30", + statId="base_dexterity", + values={ + [1]=22, + [2]=77, + [3]=154 + } + }, + [6]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Energy Shield", + id="energyshield70", + statId="maximum_energy_shield_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [7]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Evasion Rating", + id="evasion30", + statId="evasion_rating_+%", + values={ + [1]=15, + [2]=30, + [3]=45 + } + }, + [8]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% faster start of Energy Shield Recharge", + id="fasterrecharge70", + statId="energy_shield_delay_-%", + values={ + [1]=14, + [2]=28, + [3]=42 + } + }, + [9]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Intelligence", + id="int70", + statId="base_intelligence", + values={ + [1]=43, + [2]=152, + [3]=304 + } + }, + [10]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased maximum Life", + id="life0", + statId="maximum_life_+%", + values={ + [1]=38, + [2]=75, + [3]=100 + } + }, + [11]={ + categoryId="Defensive", + categoryName="Defensive", + divisor=60, + format="Regenerate %s%% of Life per second", + id="liferegen0", + statId="life_regeneration_rate_per_minute_%", + values={ + [1]=0, + [2]=0, + [3]=0 + } + }, + [12]={ + categoryId="Defensive", + categoryName="Defensive", + format="%s%% increased Energy Shield Recharge Rate", + id="rechargerate70", + statId="energy_shield_recharge_rate_+%", + values={ + [1]=18, + [2]=35, + [3]=53 + } + }, + [13]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s%% chance to Suppress Spell Damage", + id="spellsuppression30", + statId="base_spell_suppression_chance_%", + values={ + [1]=6, + [2]=12, + [3]=18 + } + }, + [14]={ + categoryId="Defensive", + categoryName="Defensive", + format="+%s to Strength", + id="str0", + statId="base_strength", + values={ + [1]=6, + [2]=21, + [3]=42 + } + }, + [15]={ + categoryId="Offensive", + categoryName="Offensive", + format="%s%% increased Trap Throwing Speed", + id="trap_throw_speed", + statId="trap_throwing_speed_+%", + values={ + [1]=12, + [2]=24, + [3]=36 + } + } + }, + skillIds={ + [1]="BallLightningAltTrapMercenary", + [2]="ConductivityMercenary", + [3]="FlameDashMercenary", + [4]="FrostblinkMercenary", + [5]="LightningSpireTrapMercenary", + [6]="LightningTrapMercenary", + [7]="LightningWarpTrapsMercenary", + [8]="SmokeMineMercenary", + [9]="SummonSkitterbotsMercenary", + [10]="VaalLightningTrapMercenary", + [11]="ZealotryMercenary" + }, + skillPools={ + [1]={ + countMax=2, + skillIds={ + [1]="ConductivityMercenary", + [2]="VaalLightningTrapMercenary" + } + }, + [2]={ + countMax=2, + skillIds={ + [1]="BallLightningAltTrapMercenary", + [2]="LightningSpireTrapMercenary", + [3]="LightningTrapMercenary", + [4]="LightningWarpTrapsMercenary" + } + }, + [3]={ + skillIds={ + [1]="FlameDashMercenary", + [2]="FrostblinkMercenary", + [3]="SmokeMineMercenary", + [4]="SummonSkitterbotsMercenary", + [5]="ZealotryMercenary" + } + } + }, + tags={ + [1]="mercenary_noble_born", + [2]="mercenary_traps_mines_shadow", + [3]="mercenary_traps_mines_shadow_lightning", + [4]="mercenary_traps_mines_shadow_lightning_noble" + }, + weaponConfiguration={ + mainHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + }, + offHandRequired=false, + offHandTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + } + }, + weaponTypes={ + [1]="Dagger", + [2]="Sceptre", + [3]="Wand" + } + } + }, + classOrder={ + [1]="AurasMinionsTemplar", + [2]="ChaosMinionWitch", + [3]="Crit1HShadow", + [4]="EleBowRanger", + [5]="ElementalWitch", + [6]="MeleeAOEMarauder", + [7]="MeleeAOEStrikeDuelist", + [8]="MeleeStrikesMarauder", + [9]="MiscScion", + [10]="NonEleBowRanger", + [11]="PhysConvertTemplar", + [12]="PhysicalDuelist", + [13]="TrapsMinesShadow" + }, + classes={ + AurasMinionsTemplar={ + attributeId="StrInt", + attributeName="Str / Int", + attributeTags={ + [1]="int_armour", + [2]="str_armour", + [3]="str_int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconKeita", + buildIds={ + [1]="AurasMinionsTemplarSmite", + [2]="AurasMinionsTemplarSmiteNoble", + [3]="AurasMinionsTemplarSmiteRuckusNoble", + [4]="AurasMinionsTemplarSpectres", + [5]="AurasMinionsTemplarSpectresNoble", + [6]="AurasMinionsTemplarStaff", + [7]="AurasMinionsTemplarStaffNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseKeita", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconTemplar", + id="AurasMinionsTemplar", + monster={ + accuracy=1, + armour=0, + attackRange=10, + attackTime=1.245, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryTemplar2Allied__", + life=0.32, + lightningResist=0, + name="[DNT] Merc Templar 2", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="number_of_additional_totems_allowed", + source="Metadata/Monsters/Mercenaries/MercenaryTemplar/MercenaryTemplar2", + value=1 + }, + [18]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [20]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [22]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [23]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [25]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [26]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [29]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [31]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [33]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [35]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [38]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [41]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [42]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [43]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Templar 2", + skillIds={ + [1]="AbsolutionMercenary", + [2]="BattlemagesCryMercenary", + [3]="ConsecratedPathMercenary", + [4]="DesecrateMercenary", + [5]="DominatingBlowMercenary", + [6]="DoryanisTouchMercenary", + [7]="FlameDashMercenary", + [8]="FrostblinkMercenary", + [9]="HeraldOfPurityMercenary", + [10]="HolyHammersMercenary", + [11]="HolyStrikeMercenary", + [12]="MoltenStrikeHolyMercenary", + [13]="PhysicalBeaconMercenary", + [14]="PurityOfLightningMercenary", + [15]="RaiseSpectreAltMercenary", + [16]="SSMHolySpectresMercenary", + [17]="SSMPaganBishopMercenary", + [18]="SSMSkeletalBossMercenary", + [19]="SSMVollMercenary", + [20]="SmiteMercenary", + [21]="SummonHolyRelicMercenary", + [22]="SweepMercenary", + [23]="WrathMercenary", + [24]="ZealotryMercenary" + } + }, + ChaosMinionWitch={ + attributeId="Int", + attributeName="Int", + attributeTags={ + [1]="dex_int_armour", + [2]="int_armour", + [3]="str_int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconCyaxan", + buildIds={ + [1]="ChaosMinionWitchChaosHit", + [2]="ChaosMinionWitchChaosHitNoble", + [3]="ChaosMinionWitchDot", + [4]="ChaosMinionWitchDotNoble", + [5]="ChaosMinionWitchInstability", + [6]="ChaosMinionWitchInstabilityNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseCyaxan", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconWitch", + id="ChaosMinionWitch", + monster={ + accuracy=1, + armour=0, + attackRange=40, + attackTime=1.005, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryWitch2Allied", + life=0.22, + lightningResist=0, + name="[DNT] Witch Merc 2", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="keystone_minion_instability", + source="Metadata/Monsters/Mercenaries/MercenaryWitch/MercenaryWitch2", + value=1 + }, + [8]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [9]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [10]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [11]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [12]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [13]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [14]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [15]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [16]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [17]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [18]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [20]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [22]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [23]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [25]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [26]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [29]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [31]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [33]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [35]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [38]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [41]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [42]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [43]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Witch Merc 2", + skillIds={ + [1]="BaneMercenary", + [2]="BlightMercenary", + [3]="BoneOfferingMercenary", + [4]="ChaosGlacialCascadeMercenary", + [5]="ClarityMercenary", + [6]="DarkPactMercenary", + [7]="DesecrateMercenary", + [8]="DespairMercenary", + [9]="EnfeebleMercenary", + [10]="EnvyMercenary", + [11]="EssenceDrainAltMercenary", + [12]="FlameDashMercenary", + [13]="FleshOfferingMercenary", + [14]="ForbiddenRiteTotemMercenary", + [15]="FrostblinkMercenary", + [16]="GigaRaiseZombieMercenary", + [17]="GigaSoulrendMercenary", + [18]="LightningWarpMercenary", + [19]="MalevolenceMercenary", + [20]="OfferingOfJudgementChaosMercenary", + [21]="RaiseZombieAltMercenary", + [22]="SSMMercenaryRelic", + [23]="SSMMercenarySoulrendOrb", + [24]="SandstormChaosMercenary", + [25]="SoulrendAltMercenary", + [26]="SummonRagingSpiritMercenary", + [27]="SummonSkeletonsMercenary", + [28]="TemporalChainsMercenary", + [29]="VoidSphereMercenary", + [30]="VoltaxicBurstMercenary", + [31]="WitherTotemMercenary", + [32]="WitheringStepMercenary", + [33]="ZealotryMercenary" + } + }, + Crit1HShadow={ + attributeId="DexInt", + attributeName="Dex / Int", + attributeTags={ + [1]="dex_armour", + [2]="dex_int_armour", + [3]="int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconAzadi", + buildIds={ + [1]="Crit1HShadowPhysSpell", + [2]="Crit1HShadowPhysSpellNoble", + [3]="Crit1HShadowPoison", + [4]="Crit1HShadowPoisonNoble", + [5]="Crit1HShadowSpectral" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseAzadi", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconShadow", + id="Crit1HShadow", + monster={ + accuracy=1, + armour=0, + attackRange=40, + attackTime=1.305, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryShadow2Allied", + life=0.27, + lightningResist=0, + name="[DNT] Merc Shadow 2", + skillIds={ + [1]="DetonateMinesMercenary", + [2]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="base_number_of_remote_mines_allowed", + source="Metadata/Monsters/Mercenaries/MercenaryShadow/MercenaryShadow2", + value=20 + }, + [2]={ + id="base_number_of_traps_allowed", + source="Metadata/Monsters/Mercenaries/MercenaryShadow/MercenaryShadow2", + value=20 + }, + [3]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [8]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [9]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [10]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [11]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [12]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [13]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [14]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [15]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [16]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [17]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [18]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [19]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [20]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [23]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [24]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [25]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [26]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [27]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [28]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [29]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [30]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [31]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [32]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [33]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [34]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [35]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [36]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [38]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [39]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [41]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [42]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [43]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [44]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Shadow 2", + skillIds={ + [1]="AbyssalCryMercenary", + [2]="AspectOfTheSpiderMercenary", + [3]="BladeVortexMercenary", + [4]="BladefallAltMercenary", + [5]="BladefallMercenary", + [6]="CobraLashMercenary", + [7]="DashMercenary", + [8]="DoLiterallyNothing", + [9]="DonutCircleMercenary", + [10]="EtherealKnivesMercenary", + [11]="FlameDashMercenary", + [12]="FrostShieldMercenary", + [13]="GraceMercenary", + [14]="LightningWarpPhysMercenary", + [15]="MalevolenceMercenary", + [16]="MoltenStrikePoisonMercenary", + [17]="PestilentStrikeMercenary", + [18]="TemporalAnomalyMercenary", + [19]="VenomGyreMercenary", + [20]="ViperStrikeMercenary", + [21]="WhirlingBladesMercenary", + [22]="WitheringStepMercenary" + } + }, + EleBowRanger={ + attributeId="Dex", + attributeName="Dex", + attributeTags={ + [1]="dex_armour", + [2]="dex_int_armour", + [3]="str_dex_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconCyaxan", + buildIds={ + [1]="EleBowRangerClones", + [2]="EleBowRangerClonesNoble", + [3]="EleBowRangerFire", + [4]="EleBowRangerFireNoble", + [5]="EleBowRangerLightning" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseCyaxan", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconRanger", + id="EleBowRanger", + monster={ + accuracy=1, + armour=0, + attackRange=40, + attackTime=1.605, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryRanger2Allied", + life=0.24, + lightningResist=0, + name="[DNT] Merc Ranger 2", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Ranger 2", + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="AlchemistsMarkMercenary", + [3]="ArtilleryBallistaMercenary", + [4]="AssassinsMarkMercenary", + [5]="BlastRainAltMercenary", + [6]="BlastRainColdMercenary", + [7]="BlinkArrowMercenary", + [8]="BurningArrowMercenary", + [9]="ConflagrationMercenary", + [10]="DashMercenary", + [11]="DropArrowMercenary", + [12]="ExplosiveArrowBarrageMercenary", + [13]="FlammabilityBlasphemyMercenary", + [14]="FrostBombMercenary", + [15]="GalvanicArrowMercenary", + [16]="GigaLightningArrowMercenary", + [17]="GraceMercenary", + [18]="HatredMercenary", + [19]="HydraForkArrowMercenary", + [20]="IceShotMercenary", + [21]="LightningArrowMercenary", + [22]="MirrorArrowMercenary", + [23]="PrecisionMercenary", + [24]="StormRainMercenary", + [25]="VaalBurningArrowMercenary", + [26]="VaalGraceMercenary", + [27]="VaalIceShotMercenary", + [28]="VaalLightningArrowMercenary", + [29]="WrathMercenary" + } + }, + ElementalWitch={ + attributeId="Int", + attributeName="Int", + attributeTags={ + [1]="dex_int_armour", + [2]="int_armour", + [3]="str_int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconCyaxan", + buildIds={ + [1]="ElementalWitchCold", + [2]="ElementalWitchColdNoble", + [3]="ElementalWitchFire", + [4]="ElementalWitchLightning", + [5]="ElementalWitchLightningNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseCyaxan", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconWitch", + id="ElementalWitch", + monster={ + accuracy=1, + armour=0, + attackRange=40, + attackTime=1.005, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryWitch1Allied", + life=0.22, + lightningResist=0, + name="[DNT] Witch Merc 1", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="base_mana_regeneration_rate_per_minute", + source="Metadata/Monsters/Mercenaries/MercenaryWitch/MercenaryWitch1", + value=10000 + }, + [2]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [8]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [9]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [10]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [11]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [12]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [13]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [14]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [15]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [16]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [17]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [18]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [20]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [22]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [23]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [25]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [26]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [29]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [31]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [33]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [35]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [38]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [41]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [42]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [43]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Witch Merc 1", + skillIds={ + [1]="AngerMercenary", + [2]="ArcAltMercenary", + [3]="ArcMercenary", + [4]="BallLightningAltMercenary", + [5]="ConductivityMercenary", + [6]="DisciplineMercenary", + [7]="EyeOfWinterMercenary", + [8]="FireAegisMercenary", + [9]="FireballAltMercenary", + [10]="FireballMercenary", + [11]="FlameDashMercenary", + [12]="FlameSurgeMercenary", + [13]="FlameWallMercenary", + [14]="FlameblastMercenary", + [15]="FlammabilityMercenary", + [16]="FrostBombMercenary", + [17]="FrostWallMercenary", + [18]="FrostbiteMercenary", + [19]="FrostblinkMercenary", + [20]="FrostboltMercenary", + [21]="GigaFlameDashMercenary", + [22]="GigaShockNovaMercenary", + [23]="GigaStormCallMercenary", + [24]="IceNovaMercenary", + [25]="IceNovaProjectedMercenary", + [26]="IcestormMercenary", + [27]="LightningWarpMercenary", + [28]="OrbOfStormsMercenary", + [29]="ProximityShieldMercenary", + [30]="PurityOfFireMercenary", + [31]="PurityOfIceMercenary", + [32]="PurityOfLightningMercenary", + [33]="RollingMagmaMercenary", + [34]="SigilOfPowerMercenary", + [35]="SparkMercenary", + [36]="StormCallMercenary", + [37]="VaalFlameblastMercenary", + [38]="VortexMercenary", + [39]="WrathMercenary" + } + }, + MeleeAOEMarauder={ + attributeId="Str", + attributeName="Str", + attributeTags={ + [1]="str_armour", + [2]="str_dex_armour", + [3]="str_int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconKeita", + buildIds={ + [1]="MeleeAOEMarauderFireSlam", + [2]="MeleeAOEMarauderFireSlamNoble", + [3]="MeleeAOEMarauderNonSlam", + [4]="MeleeAOEMarauderNonSlamNoble", + [5]="MeleeAOEMarauderPhysSlam", + [6]="MeleeAOEMarauderPhysSlamNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseKeita", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconMarauder", + id="MeleeAOEMarauder", + monster={ + accuracy=1, + armour=0, + attackRange=10, + attackTime=1.305, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryMarauder1Allied", + life=0.46, + lightningResist=0, + name="[DNT] Merc Marauder 1", + skillIds={ + [1]="EASMercenaryPortalOut", + [2]="MeleeAtAnimationSpeed" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Marauder 1", + skillIds={ + [1]="BurrowMercenary", + [2]="ChainHookAltMercenary", + [3]="CleaveMercenary", + [4]="ConsecratedPathMercenary", + [5]="DeterminationMercenary", + [6]="EarthquakeAltMercenary", + [7]="EnrageMercenary", + [8]="FissureSlamMercenary", + [9]="FlameLinkMercenary", + [10]="GroundSlamMercenary", + [11]="HeraldOfAshMercenary", + [12]="InfernalCryMercenary", + [13]="IntimidatingCryMercenary", + [14]="LeapSlamMercenary", + [15]="LeapSlamMercenaryAlt", + [16]="MassEnduranceMercenary", + [17]="MoltenShellMercenary", + [18]="PurityOfFireMercenary", + [19]="RemoteSlamMercenary", + [20]="SunderAltMercenary", + [21]="TectonicSlamFireMercenary", + [22]="TectonicSlamPhysMercenary", + [23]="TriggeredFireSlamMercenary", + [24]="VaalCleaveMercenary", + [25]="VaalGroundSlamMercenary", + [26]="VaalVitalityMercenary", + [27]="VitalityMercenary", + [28]="VolcanicFissureAltMercenary", + [29]="WindSlashMercenary" + } + }, + MeleeAOEStrikeDuelist={ + attributeId="StrDex", + attributeName="Str / Dex", + attributeTags={ + [1]="dex_armour", + [2]="str_armour", + [3]="str_dex_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconAzadi", + buildIds={ + [1]="DivingDuelist", + [2]="DivingDuelistNoble", + [3]="MeleeAOEStrikeDuelistCyclone", + [4]="MeleeAOEStrikeDuelistCycloneNoble", + [5]="MeleeAOEStrikeDuelistRangeStrikes", + [6]="MeleeAOEStrikeDuelistRangeStrikesNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseAzadi", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconDuelist", + id="MeleeAOEStrikeDuelist", + monster={ + accuracy=1, + armour=0, + attackRange=10, + attackTime=1.65, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryDuelist2Allied", + life=0.37, + lightningResist=0, + name="[DNT] Merc Duelist 2", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Duelist 2", + skillIds={ + [1]="CycloneReverseKnockbackMercenary", + [2]="DashMercenary", + [3]="DonutBladesMercenary", + [4]="ElementalHitColdOnlyMercenary", + [5]="FlickerStrikeMercenary", + [6]="FrostBladesMercenary", + [7]="FrostBombMercenary", + [8]="FrostblinkMercenary", + [9]="HatredMercenary", + [10]="HeraldOfIceMercenary", + [11]="InspiringCryMercenary", + [12]="LeapSlamMercenary", + [13]="MassFrenzyMercenary", + [14]="PrideMercenary", + [15]="PurityOfIceMercenary", + [16]="QuickGuardAllyMercenary", + [17]="RallyingCryMercenary", + [18]="SpectralHelixMercenary", + [19]="StaticStrikeMercenary", + [20]="VaalDoubleStrikeMercenary", + [21]="WildStrikeMercenary", + [22]="WrathMercenary" + } + }, + MeleeStrikesMarauder={ + attributeId="Str", + attributeName="Str", + attributeTags={ + [1]="str_armour", + [2]="str_dex_armour", + [3]="str_int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconKeita", + buildIds={ + [1]="MeleeStrikesMaraduerPhys", + [2]="MeleeStrikesMaraduerPhysNoble", + [3]="MeleeStrikesMarauderFire" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseKeita", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconMarauder", + id="MeleeStrikesMarauder", + monster={ + accuracy=1, + armour=0, + attackRange=10, + attackTime=1.305, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryMarauder2Allied", + life=0.46, + lightningResist=0, + name="[DNT] Merc Marauder 2", + skillIds={ + [1]="EASMercenaryPortalOut", + [2]="MeleeAtAnimationSpeed" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Marauder 2", + skillIds={ + [1]="AngerMercenary", + [2]="BoneshatterMercenary", + [3]="DecoyTotemMercenary", + [4]="DeterminationMercenary", + [5]="DualStrikeMercenary", + [6]="EnduringCryMercenary", + [7]="FireAegisMercenary", + [8]="FireEnrageMercenary", + [9]="HeavyStrikeMercenary", + [10]="InfernalBlowAltMercenary", + [11]="InfernalCryMercenary", + [12]="LeapSlamMercenary", + [13]="LightningStrikeFireMercenary", + [14]="MoltenShellMercenary", + [15]="MoltenStrikeMercenary", + [16]="PhysicalAegisMercenary", + [17]="PunishmentMercenary", + [18]="VaalAncestralWarchiefMercenary", + [19]="VaalMoltenStrikeMercenary", + [20]="VigilantStrikeMercenary", + [21]="VitalityMercenary" + } + }, + MiscScion={ + attributeId="StrDexInt", + attributeName="Str / Dex / Int", + attributeTags={ + [1]="dex_armour", + [2]="dex_int_armour", + [3]="int_armour", + [4]="str_armour", + [5]="str_dex_armour", + [6]="str_dex_int_armour", + [7]="str_int_armour", + [8]="ward_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconBardiya", + buildIds={ + [1]="MiscScionPhysDot", + [2]="MiscScionPhysDotNoble", + [3]="MiscScionWandAttacks", + [4]="MiscScionWandAttacksNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBardiya", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconScion", + id="MiscScion", + monster={ + accuracy=1, + armour=0, + attackRange=40, + attackTime=1.005, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryScion1Allied", + life=0.35, + lightningResist=0, + name="[DNT] Merc Scion 1", + skillIds={ + [1]="EASMercenaryPortalOut", + [2]="SummonSacredWisp" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Scion 1", + skillIds={ + [1]="BarrageMercenary", + [2]="BladeVortexAltMercenary", + [3]="BodyswapMercenary", + [4]="CGEBloodGroundMercenary", + [5]="ElementalWeaknessMercenary", + [6]="ExsanguinateMercenary", + [7]="FlameDashMercenary", + [8]="FlameWallMercenary", + [9]="FrostblinkMercenary", + [10]="GigaKineticBlastMercenary", + [11]="HasteMercenary", + [12]="InspiringCryMercenary", + [13]="KineticBlastAltMercenary", + [14]="KineticBoltMercenary", + [15]="KineticRainAltXMercenary", + [16]="LightningWarpMercenary", + [17]="PowerSiphonMercenary", + [18]="PrideMercenary", + [19]="ProximityShieldMercenary", + [20]="ReapMercenary", + [21]="StormCallAltMercenary", + [22]="VaalReapMercenary", + [23]="VaalVitalityMercenary" + } + }, + NonEleBowRanger={ + attributeId="Dex", + attributeName="Dex", + attributeTags={ + [1]="dex_armour", + [2]="dex_int_armour", + [3]="str_dex_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconCyaxan", + buildIds={ + [1]="NonEleBowRangerChaos", + [2]="NonEleBowRangerChaosNoble", + [3]="NonEleBowRangerPhys", + [4]="NonEleBowRangerPhysNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseCyaxan", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconRanger", + id="NonEleBowRanger", + monster={ + accuracy=1, + armour=0, + attackRange=40, + attackTime=1.605, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryRanger1Allied", + life=0.24, + lightningResist=0, + name="[DNT] Merc Ranger 1", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Ranger 1", + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="BarrageAltMercenary", + [3]="BlinkArrowMercenary", + [4]="CausticArrowMercenary", + [5]="DashMercenary", + [6]="DeceleratingProjectileMercenary", + [7]="DeceleratingProjectileMercenaryExplode", + [8]="EnsnaringArrowMercenary", + [9]="FrenzyMercenary", + [10]="GraceMercenary", + [11]="HasteMercenary", + [12]="MalevolenceMercenary", + [13]="PoachersMarkMercenary", + [14]="PunctureMercenary", + [15]="RainOfArrowsAltMercenary", + [16]="ScourgeArrowAltMercenary", + [17]="ShrapnelBallistaMercenary", + [18]="SiegeBallistaAltMercenary", + [19]="SplitArrowMercenary", + [20]="TornadoShotMercenary", + [21]="ToxicRainMercenary", + [22]="VaalCausticArrowMercenary", + [23]="VaalSplitArrowMercenary", + [24]="WitheringStepMercenary" + } + }, + PhysConvertTemplar={ + attributeId="StrInt", + attributeName="Str / Int", + attributeTags={ + [1]="int_armour", + [2]="str_armour", + [3]="str_int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconKeita", + buildIds={ + [1]="PhysConvertTemplarCold", + [2]="PhysConvertTemplarFire", + [3]="PhysConvertTemplarLightning", + [4]="PhysConvertTemplarLightningNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseKeita", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconTemplar", + id="PhysConvertTemplar", + monster={ + accuracy=1, + armour=0, + attackRange=10, + attackTime=1.245, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryTemplar1Allied", + life=0.32, + lightningResist=0, + name="[DNT] Merc Templar 1", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Templar 1", + skillIds={ + [1]="AngerMercenary", + [2]="ArcticArmourMercenary", + [3]="ChargedDashSpellScalingMercenary", + [4]="DivineIreMercenary", + [5]="DivineRetributionMercenary", + [6]="EarthquakeColdMercenary", + [7]="FlameDashMercenary", + [8]="FrostBombMercenary", + [9]="FrostShieldMercenary", + [10]="FrostblinkMercenary", + [11]="GlacialHammerMercenary", + [12]="HatredMercenary", + [13]="HeavyStrikeAltMercenary", + [14]="HeraldOfAshMercenary", + [15]="HolyFireMortarMercenary", + [16]="HolyFlameTotemMercenary", + [17]="IceCrashMercenary", + [18]="LightningWarpMercenary", + [19]="MercenaryLightningDelayedBlast", + [20]="MeteorUpheavalMercenary", + [21]="PurifyingFlameMercenary", + [22]="PurityOfIceMercenary", + [23]="ScorchingRayTotemMercenary", + [24]="ShockwaveTotemMercenary", + [25]="TornadoAltMercenary", + [26]="VaalGlacialHammerMercenary", + [27]="WaveOfConvictionAltMercenary", + [28]="WaveOfConvictionLightningMercenary", + [29]="WrathMercenary" + } + }, + PhysicalDuelist={ + attributeId="StrDex", + attributeName="Str / Dex", + attributeTags={ + [1]="dex_armour", + [2]="str_armour", + [3]="str_dex_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconAzadi", + buildIds={ + [1]="PhysicalDuelistBleed", + [2]="PhysicalDuelistBleedNoble", + [3]="PhysicalDuelistShields", + [4]="PhysicalDuelistShieldsNoble", + [5]="PhysicalDuelistSteel" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseAzadi", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconDuelist", + id="PhysicalDuelist", + monster={ + accuracy=1, + armour=0, + attackRange=10, + attackTime=1.005, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryDuelist1Allied_", + life=0.37, + lightningResist=0, + name="[DNT] Merc Duelist 1", + skillIds={ + [1]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [2]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [8]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [9]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [10]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [11]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [12]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [13]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [14]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [15]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [16]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [17]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [18]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [19]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [20]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [23]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [24]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [25]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [26]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [27]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [28]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [29]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [30]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [31]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [32]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [33]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [34]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [35]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [36]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [38]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [39]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [41]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [42]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Duelist 1", + skillIds={ + [1]="ABTTArmourEleMercenary", + [2]="ABTTExtraImpaleMercenary", + [3]="ABTTInvulnBubbleMercenary", + [4]="ABTTPhysEnrageMercenary", + [5]="BladestormMercenary", + [6]="BloodMortarMercenary", + [7]="CGEOilGroundSlowMercenary", + [8]="CallOfSteelMercenary", + [9]="DashMercenary", + [10]="DeterminationMercenary", + [11]="DonutBladesMercenary", + [12]="GraceMercenary", + [13]="IntimidatingCryMercenary", + [14]="LacerateMercenary", + [15]="LancingSteelMercenary", + [16]="LeapSlamMercenary", + [17]="PerforateMercenary", + [18]="PhysicalAegisMercenary", + [19]="RallyingCryMercenary", + [20]="ShatteringSteelMercenary", + [21]="ShieldChargeMercenary", + [22]="ShieldCrushMercenary", + [23]="SpectralShieldThrowAltMercenary", + [24]="SplittingSteelMercenary", + [25]="TempestShieldMercenary", + [26]="WhirlingBladesMercenary" + } + }, + TrapsMinesShadow={ + attributeId="DexInt", + attributeName="Dex / Int", + attributeTags={ + [1]="dex_armour", + [2]="dex_int_armour", + [3]="int_armour" + }, + buffIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseBuffIconAzadi", + buildIds={ + [1]="TrapsMinesShadowAttack", + [2]="TrapsMinesShadowAttackNoble", + [3]="TrapsMinesShadowCold", + [4]="TrapsMinesShadowLightning", + [5]="TrapsMinesShadowLightningNoble" + }, + houseIcon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/HouseAzadi", + icon="Art/2DArt/UIImages/InGame/MercenariesofTrarthus/MercClassIconShadow", + id="TrapsMinesShadow", + monster={ + accuracy=1, + armour=0, + attackRange=40, + attackTime=1.305, + baseDamageIgnoresAttackSpeed=true, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryShadow1Allied", + life=0.27, + lightningResist=0, + name="[DNT] Merc Shadow 1", + skillIds={ + [1]="DetonateMinesMercenary", + [2]="EASMercenaryPortalOut" + }, + stats={ + [1]={ + id="base_number_of_remote_mines_allowed", + source="Metadata/Monsters/Mercenaries/MercenaryShadow/MercenaryShadow1", + value=20 + }, + [2]={ + id="base_number_of_traps_allowed", + source="Metadata/Monsters/Mercenaries/MercenaryShadow/MercenaryShadow1", + value=20 + }, + [3]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [4]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [8]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [9]={ + id="kill_traps_mines_and_totems_on_death", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [10]={ + id="life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1200 + }, + [11]={ + id="map_related_item_drop_chance_+%_final_from_league", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [12]={ + id="max_steel_ammo", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=12 + }, + [13]={ + id="maximum_rage", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=30 + }, + [14]={ + id="mines_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [15]={ + id="monster_no_additional_player_scaling", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [16]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [17]={ + id="monster_rarity_attack_cast_speed_+%_and_damage_-%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-33 + }, + [18]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-70 + }, + [19]={ + id="rage_loss_delay_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + }, + [20]={ + id="set_base_attack_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [21]={ + id="set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [22]={ + id="set_base_cast_speed_+%_per_frenzy_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [23]={ + id="set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [24]={ + id="set_base_mana_cost_-%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=100 + }, + [25]={ + id="set_critical_strike_chance_+%_per_power_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=50 + }, + [26]={ + id="set_critical_strike_chance_+%_per_power_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [27]={ + id="set_damage_taken_from_labyrinth_traps_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [28]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [29]={ + id="set_elemental_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [30]={ + id="set_ignore_skill_weapon_restrictions", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [31]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [32]={ + id="set_labyrinth_trap_degen_effect_on_self_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [33]={ + id="set_minion_damage_taken_+%", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=-90 + }, + [34]={ + id="set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [35]={ + id="set_movement_velocity_cap", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [36]={ + id="set_physical_damage_%_to_add_as_cold_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [37]={ + id="set_physical_damage_%_to_add_as_lightning_per_brine_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [38]={ + id="set_physical_damage_reduction_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=4 + }, + [39]={ + id="set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [40]={ + id="set_resist_all_elements_%_per_endurance_charge", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [41]={ + id="set_resist_all_elements_%_per_endurance_charge_if_not_player_minion", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=0 + }, + [42]={ + id="set_totem_life_+%_final", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1000 + }, + [43]={ + id="traps_explode_on_timeout", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=1 + }, + [44]={ + id="traps_invulnerable_for_duration_ms", + source="Metadata/Monsters/Mercenaries/Mercenary", + value=2000 + } + } + }, + name="[DNT] Merc Shadow 1", + skillIds={ + [1]="ActionSpeedAuraMercenary", + [2]="ArcticArmourMercenary", + [3]="BallLightningAltTrapMercenary", + [4]="BearTrapMercenary", + [5]="BladeTrapMercenary", + [6]="ConductivityMercenary", + [7]="CreepingFrostTrapMercenary", + [8]="FlameDashMercenary", + [9]="FrostShieldMercenary", + [10]="FrostblinkMercenary", + [11]="GigaVortexTrapMercenary", + [12]="GraceMercenary", + [13]="IceTrapMercenary", + [14]="LightningSpireTrapMercenary", + [15]="LightningTrapMercenary", + [16]="LightningWarpTrapsMercenary", + [17]="SmokeMineMercenary", + [18]="SpectralHelixAltMercenary", + [19]="SpectralThrowAltMercenary", + [20]="SummonSkitterbotsMercenary", + [21]="VaalArcticArmourMercenary", + [22]="VaalLightningTrapMercenary", + [23]="ZealotryMercenary" + } + } + }, + minions={ + ["Metadata/Monsters/HolyFireElemental/HolyFireElementalSolarisBeam"]={ + accuracy=1, + armour=0.25, + attackRange=9, + attackTime=1.5, + chaosResist=0, + coldResist=0, + damage=1.12, + damageSpread=0.2, + energyShield=0.1, + evasion=0, + fireResist=75, + id="Metadata/Monsters/HolyFireElemental/HolyFireElementalSolarisBeam", + life=1.98, + lightningResist=0, + name="Solar Guard", + skillIds={ + [1]="HolyFireElementalFireball", + [2]="SpecialBeamCannon" + }, + stats={ + [1]={ + id="physical_damage_%_to_add_as_fire", + source="MonsterPhysicalAddedAsFireHolyFireElemental", + value=60 + } + } + }, + ["Metadata/Monsters/Mercenaries/MercenarySoulrendOrb"]={ + accuracy=1, + armour=0, + attackRange=6, + attackTime=1, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenarySoulrendOrb", + life=1, + lightningResist=0, + name="Daemon", + skillIds={ + [1]="EASRitualDaemonChaosProjectileRuckus", + [2]="GSRitualChaosPulse", + [3]="RitualDaemonChaosProjectile1", + [4]="RitualDaemonChaosProjectile2", + [5]="RitualDaemonChaosProjectile3", + [6]="RitualDaemonChaosProjectile4", + [7]="RitualDaemonChaosProjectile5", + [8]="RitualDaemonChaosProjectile6" + }, + stats={ + [1]={ + id="base_cannot_be_damaged", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [2]={ + id="base_cannot_be_stunned", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [3]={ + id="base_maximum_mana", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=100000 + }, + [4]={ + id="cannot_be_knocked_back", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [5]={ + id="immune_to_auras_from_other_entities", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [6]={ + id="immune_to_curses", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [7]={ + id="is_daemon", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [8]={ + id="is_hidden_monster", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [9]={ + id="mana_regeneration_rate_per_minute_%", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=100 + }, + [10]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=0 + }, + [11]={ + id="set_max_endurance_charges", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=0 + }, + [12]={ + id="set_max_frenzy_charges", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=0 + }, + [13]={ + id="set_max_power_charges", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=0 + }, + [14]={ + id="set_monster_do_not_fracture", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [15]={ + id="set_monster_no_drops_or_experience", + source="Metadata/Monsters/Daemon/AbstractDaemon", + value=1 + }, + [16]={ + id="set_phase_through_objects", + source="Metadata/Monsters/Mercenaries/MercenaryWitch/MercenarySoulrendOrb", + value=1 + } + } + }, + ["Metadata/Monsters/Mercenaries/MercenaryUnholyRelic_"]={ + accuracy=1, + armour=0, + attackRange=6, + attackTime=1.5, + chaosResist=0, + coldResist=0, + damage=1, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=0, + id="Metadata/Monsters/Mercenaries/MercenaryUnholyRelic_", + life=1, + lightningResist=0, + name="Unholy Relic", + skillIds={ + }, + stats={ + [1]={ + id="base_cannot_be_stunned", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=1 + }, + [2]={ + id="cannot_be_afflicted", + source="CannotBeAugmented", + value=1 + }, + [3]={ + id="cannot_be_knocked_back", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=1 + }, + [4]={ + id="cannot_be_tagged_by_sentinel", + source="CannotBeAugmented", + value=1 + }, + [5]={ + id="cannot_have_affliction_mods", + source="CannotBeAugmented", + value=1 + }, + [6]={ + id="cannot_have_azmeri_dust", + source="CannotBeAugmented", + value=1 + }, + [7]={ + id="cant_possess_this", + source="CannotBeAugmented", + value=1 + }, + [8]={ + id="cant_touch_this", + source="CannotBeAugmented", + value=1 + }, + [9]={ + id="immune_to_auras_from_other_entities", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=1 + }, + [10]={ + id="immune_to_curses", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=1 + }, + [11]={ + id="monster_no_drops_or_experience", + source="MonsterNoDropsOrExperience", + value=1 + }, + [12]={ + id="monster_rarity_damage_+%_final", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=-70 + }, + [13]={ + id="set_item_drop_slots", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=0 + }, + [14]={ + id="set_max_endurance_charges", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=0 + }, + [15]={ + id="set_max_frenzy_charges", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=0 + }, + [16]={ + id="set_max_power_charges", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=0 + }, + [17]={ + id="set_monster_do_not_fracture", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=1 + }, + [18]={ + id="set_monster_no_drops_or_experience", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=1 + }, + [19]={ + id="set_phase_through_objects", + source="Metadata/Monsters/Mercenaries/UnholyRelic", + value=1 + } + } + }, + ["Metadata/Monsters/Skeletons/MapSkeletonBossMeleeStandalone"]={ + accuracy=1, + armour=0.5, + attackRange=16, + attackTime=1.605, + chaosResist=25, + coldResist=40, + damage=1.87, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=40, + id="Metadata/Monsters/Skeletons/MapSkeletonBossMeleeStandalone", + life=4, + lightningResist=40, + name="Pagan Bishop of Agony", + skillIds={ + [1]="CurseNova", + [2]="ElementalWeaknessAuraMapBoss", + [3]="EnfeebleAuraMapBoss", + [4]="GeofriSlam", + [5]="Melee", + [6]="TemporalChainsBossCurseAura", + [7]="VulnerabilityAuraMapBoss" + }, + stats={ + [1]={ + id="base_block_%_damage_taken", + source="MonsterAttackBlock40Bypass10_", + value=10 + }, + [2]={ + id="cannot_be_stunned_for_ms_after_stun_finished", + source="StunRepeatImmunityMapBoss_", + value=2000 + }, + [3]={ + id="cannot_be_stunned_while_stunned", + source="StunRepeatImmunityMapBoss_", + value=1 + }, + [4]={ + id="monster_base_block_%", + source="MonsterAttackBlock40Bypass10_", + value=20 + }, + [5]={ + id="monster_dropped_item_quantity_+%", + source="MonsterMapBoss", + value=0 + }, + [6]={ + id="monster_dropped_item_rarity_+%", + source="MonsterMapBoss", + value=15000 + }, + [7]={ + id="monster_slain_experience_+%", + source="MonsterMapBoss", + value=100 + }, + [8]={ + id="number_of_additional_curses_allowed", + source="AdditionalCurseOnEnemiesMapBossGeofri_", + value=3 + }, + [9]={ + id="set_use_melee_pattern_range", + source="Metadata/Monsters/MonsterIgnoreMeleePatternRange", + value=0 + } + }, + weaponType1="One Handed Mace", + weaponType2="Shield" + }, + ["Metadata/Monsters/Skeletons/SkeletonLargeMapBossStandaloneMercenary"]={ + accuracy=1, + armour=0, + attackRange=9, + attackTime=2.25, + chaosResist=25, + coldResist=40, + damage=1.2, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=40, + id="Metadata/Monsters/Skeletons/SkeletonLargeMapBossStandaloneMercenary", + life=4, + lightningResist=40, + name="Burtok, Conjurer of Bones", + skillIds={ + [1]="BonePrison", + [2]="Melee", + [3]="SkeletonLargeMapBoneProjectile", + [4]="TalismanDegenMapBoss" + }, + stats={ + [1]={ + id="cannot_be_stunned_for_ms_after_stun_finished", + source="StunRepeatImmunityMapBoss_", + value=2000 + }, + [2]={ + id="cannot_be_stunned_while_stunned", + source="StunRepeatImmunityMapBoss_", + value=1 + }, + [3]={ + id="monster_dropped_item_quantity_+%", + source="MonsterMapBoss", + value=0 + }, + [4]={ + id="monster_dropped_item_rarity_+%", + source="MonsterMapBoss", + value=15000 + }, + [5]={ + id="monster_slain_experience_+%", + source="MonsterMapBoss", + value=100 + }, + [6]={ + id="set_use_melee_pattern_range", + source="Metadata/Monsters/MonsterIgnoreMeleePatternRange", + value=0 + } + }, + weaponType1="One Handed Mace" + }, + ["Metadata/Monsters/Voll/VollMapBossStandalone_Mercenary"]={ + accuracy=1, + armour=1, + attackRange=15, + attackTime=2.25, + chaosResist=25, + coldResist=40, + damage=1.8, + damageSpread=0.2, + energyShield=0, + evasion=0, + fireResist=40, + id="Metadata/Monsters/Voll/VollMapBossStandalone_Mercenary", + life=4, + lightningResist=40, + name="The Brittle Emperor", + skillIds={ + [1]="Melee", + [2]="VollCharge", + [3]="VollReviveUndead", + [4]="VollReviveUndeadWithMinions", + [5]="VollSlamMercenary" + }, + stats={ + [1]={ + id="base_block_%_damage_taken", + source="MonsterAttackBlock40Bypass10_", + value=10 + }, + [2]={ + id="cannot_be_stunned_for_ms_after_stun_finished", + source="StunRepeatImmunityMapBoss_", + value=2000 + }, + [3]={ + id="cannot_be_stunned_while_stunned", + source="StunRepeatImmunityMapBoss_", + value=1 + }, + [4]={ + id="monster_base_block_%", + source="MonsterAttackBlock40Bypass10_", + value=20 + }, + [5]={ + id="monster_dropped_item_quantity_+%", + source="MonsterMapBoss", + value=0 + }, + [6]={ + id="monster_dropped_item_rarity_+%", + source="MonsterMapBoss", + value=15000 + }, + [7]={ + id="monster_slain_experience_+%", + source="MonsterMapBoss", + value=100 + } + }, + weaponType1="One Handed Mace", + weaponType2="Shield" + } + }, + permanentMercenaryDamageMore=-30, + skillFamilies={ + FireballVariant={ + id="FireballVariant" + }, + Infrequent={ + id="Infrequent" + }, + MovementSkill={ + id="MovementSkill" + }, + StormcallVariant={ + id="StormcallVariant" + }, + WitherApplication={ + id="WitherApplication" + } + }, + skills={ + ABTTArmourEleMercenary={ + description="Applies a short duration buff to an ally, causing a portion of their armour to apply to elemental damage taken.", + familyId="Infrequent", + hash=52494, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="ABTTArmourEleMercenary", + name="Prismplate", + possibleSupportIds={ + }, + supportCountId="None" + }, + ABTTExtraImpaleMercenary={ + description="Applies a short duration buff to nearby allies, causing impales they inflict to last for one additional hit.", + hash=27763, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="ABTTExtraImpaleMercenary", + name="Brutal Teachings", + possibleSupportIds={ + }, + supportCountId="None" + }, + ABTTInvulnBubbleMercenary={ + description="Creates an impenetrable barrier around an allied target, briefly making them completely invulnerable to damage.", + familyId="Infrequent", + hash=45615, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="ABTTInvulnBubbleMercenary", + name="Impenetrable Bastion", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseDurationHigh", + [8]="IncreaseDurationLow", + [9]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + ABTTPhysEnrageMercenary={ + description="Applies a short duration buff to nearby allies, granting them physical damage over time multiplier and attack speed.", + hash=60880, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="ABTTPhysEnrageMercenary", + name="Bloodthirst", + possibleSupportIds={ + }, + supportCountId="None" + }, + AbsolutionMercenary={ + description="Damages enemies in an area, applying a debuff for a short duration. If a non-unique enemy dies while affected by the debuff, the corpse will be consumed to summon a Sentinel of Absolution for a secondary duration, or to refresh the duration and life of an existing one instead if you have the maximum number of them. ", + hash=15611, + icon="", + id="AbsolutionMercenary", + name="Absolution", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="LightningPenetrationHigh", + [14]="LightningPenetrationLow", + [15]="LightningPenetrationMid", + [16]="MinionDamageHigh", + [17]="MinionDamageLow", + [18]="MinionDamageMid", + [19]="MinionLifeHigh", + [20]="MinionLifeLow", + [21]="MinionLifeMid", + [22]="ShockChanceHigh", + [23]="ShockChanceLow", + [24]="ShockChanceMid", + [25]="SpellCascadeHigh", + [26]="SpellCascadeLow" + }, + secondarySkillId="AbsolutionMercenaryEncounter", + supportCountId="High" + }, + AbyssalCryMercenary={ + description="Performs a warcry, Hindering nearby enemies and causing them to explode when killed. The Hinder effect is proportional to the number of surrounding enemies. Taunts all nearby enemies to attack the user.", + hash=14992, + icon="", + id="AbyssalCryMercenary", + name="Abyssal Cry", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="WarcrySpeedHigh", + [9]="WarcrySpeedLow", + [10]="WarcrySpeedMid" + }, + supportCountId="Low" + }, + ActionSpeedAuraMercenary={ + description="Creates a temporary aura that grants action speed.", + hash=38072, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="ActionSpeedAuraMercenary", + name="Trarthan Agility", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="IncreaseDurationHigh", + [11]="IncreaseDurationLow", + [12]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + AlchemistsMarkMercenary={ + description="Curses an enemy, granting flask charges on hit and creating Burning Ground under the target if a hit Ignites them, and Caustic Ground if it Poisons them.", + hash=24179, + icon="", + id="AlchemistsMarkMercenary", + name="Alchemist's Mark", + possibleSupportIds={ + }, + supportCountId="None" + }, + AngerMercenary={ + description="Casts an aura that grants added fire damage to attacks and spells.", + hash=13235, + icon="", + id="AngerMercenary", + name="Anger", + possibleSupportIds={ + }, + supportCountId="None" + }, + ArcAltMercenary={ + description="[DNT] Unused", + hash=29533, + icon="", + id="ArcAltMercenary", + name="[DNT] Unused", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="LightningDamageLuckyHigh", + [5]="LightningPenetrationHigh", + [6]="LightningPenetrationLow", + [7]="LightningPenetrationMid", + [8]="ShockChanceHigh", + [9]="ShockChanceLow", + [10]="ShockChanceMid" + }, + supportCountId="High" + }, + ArcMercenary={ + description="An arc of lightning reaches from the caster to a targeted enemy and chains to other enemies, but not immediately back. Each time the arc chains, it will also chain a secondary arc to another enemy that the main arc has not already hit, which cannot chain further.", + hash=59005, + icon="", + id="ArcMercenary", + name="Arc", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="ArcSpecificDistanceHigh", + [7]="CastSpeedHigh", + [8]="CastSpeedLow", + [9]="CastSpeedMid", + [10]="LightningDamageLuckyHigh", + [11]="LightningPenetrationHigh", + [12]="LightningPenetrationLow", + [13]="LightningPenetrationMid", + [14]="ShockChanceHigh", + [15]="ShockChanceLow", + [16]="ShockChanceMid" + }, + secondarySkillId="ArcMercenaryEncounter", + supportCountId="High" + }, + ArcticArmourMercenary={ + description="Conjures an icy barrier that chills enemies on hit. The barrier creates chilled ground while moving, and causes less Fire and Physical damage while stationary.", + hash=55367, + icon="", + id="ArcticArmourMercenary", + name="Arctic Armour", + possibleSupportIds={ + }, + supportCountId="None" + }, + ArtilleryBallistaMercenary={ + description="Summons a ballista totem that propels a sequence of fiery arrows into the air. The arrows impact the ground in a line, each dealing area damage to enemies around it.", + familyId="Infrequent", + hash=35610, + icon="", + id="ArtilleryBallistaMercenary", + name="Artillery Ballista", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="ArtilleryBallistaSpecificOnslaughtHigh", + [3]="CooldownSpeedHigh", + [4]="CooldownSpeedLow", + [5]="CooldownSpeedMid", + [6]="FirePenetrationHigh", + [7]="FirePenetrationLow", + [8]="FirePenetrationMid", + [9]="IncreaseAreaOfEffectHigh", + [10]="IncreaseAreaOfEffectLow", + [11]="IncreaseAreaOfEffectMid", + [12]="MultiTotemHigh", + [13]="MultipleProjectilesHigh", + [14]="MultipleProjectilesLow", + [15]="TotemDefencesHigh", + [16]="TotemDefencesLow", + [17]="TotemDefencesMid" + }, + supportCountId="Medium" + }, + AspectOfTheSpiderMercenary={ + description="While active, periodically applies a Spider's Web debuff to nearby Enemies, and Hinders them. Each Spider's Web on an Enemy increases the Damage they take. Hinder reduces their movement speed.", + hash=19417, + icon="", + id="AspectOfTheSpiderMercenary", + name="Aspect of the Spider", + possibleSupportIds={ + }, + supportCountId="None" + }, + AssassinsMarkMercenary={ + description="Curses an enemy, making them more vulnerable to Critical Strikes. Killing the cursed enemy will grant life and mana, and a power charge.", + hash=47406, + icon="", + id="AssassinsMarkMercenary", + name="Assassin's Mark", + possibleSupportIds={ + }, + supportCountId="None" + }, + BallLightningAltMercenary={ + description="Creates a ball of lightning at a location that damages each enemy in an area around it repeatedly with bolts of lightning.", + hash=30663, + icon="", + id="BallLightningAltMercenary", + name="Ball Lightning of Static", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AddedLightningHigh", + [3]="AddedLightningLow", + [4]="AddedLightningMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="LightningDamageLuckyHigh", + [9]="LightningPenetrationHigh", + [10]="LightningPenetrationLow", + [11]="LightningPenetrationMid", + [12]="ShockChanceHigh", + [13]="ShockChanceLow", + [14]="ShockChanceMid" + }, + secondarySkillId="BallLightningAltMercenaryEncounter", + supportCountId="High" + }, + BallLightningAltTrapMercenary={ + description="Throws a trap which, once triggered, fires a single projectile which moves in a spiral while damaging each enemy in an area around it repeatedly with bolts of lightning.", + hash=37561, + icon="", + id="BallLightningAltTrapMercenary", + name="Ball Lightning of Orbiting Trap", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="LightningDamageLuckyHigh", + [8]="LightningPenetrationHigh", + [9]="LightningPenetrationLow", + [10]="LightningPenetrationMid", + [11]="TrapMineDamageHigh", + [12]="TrapMineDamageLow", + [13]="TrapMineDamageMid", + [14]="TrapMineThrowSpeedHigh", + [15]="TrapMineThrowSpeedLow", + [16]="TrapMineThrowSpeedMid", + [17]="TrapTriggerArcaneSurgeHigh", + [18]="TrapTriggerRadiusHigh", + [19]="TrapTriggerRadiusLow", + [20]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + BaneMercenary={ + description="Applies a debuff to enemies in an area, which deals chaos damage over time. Casting this spell also triggers any Hexes this Mercenary has.", + hash=63468, + icon="", + id="BaneMercenary", + name="Bane", + possibleSupportIds={ + [1]="DamageOverTimeReduceDurationHigh", + [2]="DamageOverTimeReduceDurationLow", + [3]="DamageOverTimeReduceDurationMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid" + }, + secondarySkillId="BaneMercenaryEncounter", + supportCountId="Low" + }, + BarrageAltMercenary={ + description="Fires projectiles repeatedly with a Bow or Wand. These projectiles have a small randomised spread.", + hash=12260, + icon="", + id="BarrageAltMercenary", + name="Barrage of Volley Fire", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="AttackSpeedHigh", + [4]="AttackSpeedLow", + [5]="AttackSpeedMid", + [6]="BrutalityHigh", + [7]="BrutalityLow", + [8]="BrutalityMid", + [9]="IgnoreEnemyPhysMitHigh", + [10]="IgnoreEnemyPhysMitLow", + [11]="IgnoreEnemyPhysMitMid", + [12]="IncreasedProjSpeedHigh", + [13]="IncreasedProjSpeedLow", + [14]="IncreasedProjSpeedMid", + [15]="MultipleProjectilesHigh", + [16]="MultipleProjectilesLow", + [17]="PierceHigh", + [18]="PierceLow", + [19]="PierceMid", + [20]="ProjectilesReturnHigh", + [21]="ReducedProjSpeedHigh", + [22]="ReducedProjSpeedLow", + [23]="ReducedProjSpeedMid" + }, + supportCountId="High" + }, + BarrageMercenary={ + description="Fires individual projectiles repeatedly with a Bow or Wand. These projectiles have a small randomised spread.", + hash=1356, + icon="", + id="BarrageMercenary", + name="Barrage", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedLightningHigh", + [5]="AddedLightningLow", + [6]="AddedLightningMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="EleDamageWithAttacksHigh", + [17]="EleDamageWithAttacksLow", + [18]="EleDamageWithAttacksMid", + [19]="IncreasedProjSpeedHigh", + [20]="IncreasedProjSpeedLow", + [21]="IncreasedProjSpeedMid", + [22]="MultipleProjectilesHigh", + [23]="MultipleProjectilesLow" + }, + supportCountId="High" + }, + BattlemagesCryMercenary={ + description="Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. The user and nearby allies gain a buff that boosts critical strike chance.", + hash=37344, + icon="", + id="BattlemagesCryMercenary", + name="Battlemage's Cry", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="WarcrySpeedHigh", + [9]="WarcrySpeedLow", + [10]="WarcrySpeedMid" + }, + supportCountId="Low" + }, + BearTrapMercenary={ + description="Throws a trap that damages and immobilises an enemy for a duration based on how much damage was dealt. After the immobilise expires, a debuff remains on the enemy for a duration, lowering their movement speed by an amount which lessens over time. The affected enemy will take increased damage from traps and mines until the debuff expires.", + hash=13711, + icon="", + id="BearTrapMercenary", + name="Bear Trap", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IgnoreEnemyPhysMitHigh", + [6]="IgnoreEnemyPhysMitLow", + [7]="IgnoreEnemyPhysMitMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="TrapMineThrowSpeedHigh", + [12]="TrapMineThrowSpeedLow", + [13]="TrapMineThrowSpeedMid", + [14]="TrapTriggerRadiusHigh", + [15]="TrapTriggerRadiusLow", + [16]="TrapTriggerRadiusMid" + }, + supportCountId="Low" + }, + BladeTrapMercenary={ + description="Throws a trap which, once triggered, swings two copies the equipped weapon around it in circles, each repeatedly damaging enemies it spins through.", + hash=11054, + icon="", + id="BladeTrapMercenary", + name="Blade Trap", + possibleSupportIds={ + [1]="ConcentratedEffectHigh", + [2]="ConcentratedEffectLow", + [3]="ConcentratedEffectMid", + [4]="CritDamageHigh", + [5]="CritDamageLow", + [6]="CritDamageMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="IncreaseAreaOfEffectLow", + [11]="IncreaseAreaOfEffectMid", + [12]="IncreaseAreaOfEffectMid", + [13]="MultiTrapHigh", + [14]="PhysGainAsChaosHigh", + [15]="PhysGainAsChaosMid", + [16]="TrapChargeGenHigh", + [17]="TrapMineDamageHigh", + [18]="TrapMineDamageLow", + [19]="TrapMineDamageMid", + [20]="TrapMineThrowSpeedHigh", + [21]="TrapMineThrowSpeedLow", + [22]="TrapMineThrowSpeedMid", + [23]="TrapTriggerRadiusHigh", + [24]="TrapTriggerRadiusLow", + [25]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + BladeVortexAltMercenary={ + description="This spell creates a swarm of ethereal blades which briefly orbit in an area around you, dealing damage and applying corrupted blood to all enemies in their radius.", + hash=8958, + icon="", + id="BladeVortexAltMercenary", + name="Corrupted Blade Vortex of the Scythe", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="IgnoreEnemyPhysMitHigh", + [11]="IgnoreEnemyPhysMitLow", + [12]="IgnoreEnemyPhysMitMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="IncreaseDurationHigh", + [17]="IncreaseDurationLow", + [18]="IncreaseDurationMid", + [19]="PhysGainAsChaosHigh", + [20]="PhysGainAsChaosMid" + }, + secondarySkillId="BladeVortexAltMercenaryEncounter", + supportCountId="High" + }, + BladeVortexMercenary={ + description="This spell creates ethereal blades which orbit in an area around the caster, dealing damage every 0.6 seconds to all enemies in their radius. As more blades are added, the damage becomes greater and more frequent.", + hash=25718, + icon="", + id="BladeVortexMercenary", + name="Blade Vortex", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="CritDamageHigh", + [8]="CritDamageLow", + [9]="CritDamageMid", + [10]="CriticalStrikeHigh", + [11]="CriticalStrikeLow", + [12]="CriticalStrikeMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="IncreaseDurationHigh", + [17]="IncreaseDurationLow", + [18]="IncreaseDurationMid", + [19]="PhysGainAsChaosHigh", + [20]="PhysGainAsChaosMid" + }, + supportCountId="High" + }, + BladefallAltMercenary={ + description="Casts a buff which causes volleys of ethereal weapons rain from the sky, dealing damage to enemies they impact.", + familyId="Infrequent", + hash=59477, + icon="", + id="BladefallAltMercenary", + name="Bladefall of Trarthus", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="ConcentratedEffectHigh", + [5]="ConcentratedEffectLow", + [6]="ConcentratedEffectMid", + [7]="CritDamageHigh", + [8]="CritDamageLow", + [9]="CritDamageMid", + [10]="CriticalStrikeHigh", + [11]="CriticalStrikeLow", + [12]="CriticalStrikeMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="PhysGainAsChaosHigh", + [17]="PhysGainAsChaosMid" + }, + supportCountId="High" + }, + BladefallMercenary={ + description="Ethereal weapons rain from the sky, dealing damage to enemies in a sequence of volleys. Enemies can be hit multiple times where these overlap.", + hash=37202, + icon="", + id="BladefallMercenary", + name="Bladefall", + possibleSupportIds={ + [1]="BladeFallSpecificAddedVolleysHigh", + [2]="BrutalityHigh", + [3]="BrutalityLow", + [4]="BrutalityMid", + [5]="CastSpeedHigh", + [6]="CastSpeedLow", + [7]="CastSpeedMid", + [8]="CritDamageHigh", + [9]="CritDamageLow", + [10]="CritDamageMid", + [11]="CriticalStrikeHigh", + [12]="CriticalStrikeLow", + [13]="CriticalStrikeMid", + [14]="IncreaseAreaOfEffectHigh", + [15]="IncreaseAreaOfEffectLow", + [16]="IncreaseAreaOfEffectMid", + [17]="PhysGainAsChaosHigh", + [18]="PhysGainAsChaosMid", + [19]="SpellCascadeHigh", + [20]="SpellCascadeLow" + }, + supportCountId="High" + }, + BladestormMercenary={ + description="Perform a spinning attack, damaging surrounding enemies and creating a bladestorm matching the active stance. The bladestorm repeatedly damages enemies, based on weapon damage and attack time, for a duration. Blood bladestorms are stationary and cause Bleeding, while Sand bladestorms move slowly forwards and Blind enemies. ", + hash=12357, + icon="", + id="BladestormMercenary", + name="Bladestorm", + possibleSupportIds={ + [1]="AilmentDamageHigh", + [2]="AilmentDamageLow", + [3]="AilmentDamageMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="BladestormSpecificAdditionalStormHigh", + [8]="BleedHigh", + [9]="BleedLow", + [10]="BleedMid", + [11]="BrutalityHigh", + [12]="BrutalityLow", + [13]="BrutalityMid", + [14]="DotMultiHigh", + [15]="DotMultiLow", + [16]="DotMultiMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="MeleePhysHigh", + [21]="MeleePhysLow", + [22]="MeleePhysMid" + }, + supportCountId="High" + }, + BlastRainAltMercenary={ + description="Fires a single arrow up in the air, to rain down at a targeted location. The arrow deals area damage around where it lands, as well as releasing a wave of fire which will apply a burning debuff to enemies.", + hash=18004, + icon="", + id="BlastRainAltMercenary", + name="Blast Rain of Trarthus", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BlastRainAltSpecificExtraBlastHigh", + [5]="CombustionHigh", + [6]="DamageOverTimeReduceDurationHigh", + [7]="DamageOverTimeReduceDurationLow", + [8]="DamageOverTimeReduceDurationMid", + [9]="DotMultiHigh", + [10]="DotMultiLow", + [11]="DotMultiMid", + [12]="EleDamageWithAttacksHigh", + [13]="EleDamageWithAttacksLow", + [14]="EleDamageWithAttacksMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="IncreaseDurationHigh", + [19]="IncreaseDurationLow", + [20]="IncreaseDurationMid" + }, + secondarySkillId="BlastRainAltMercenaryEncounter", + supportCountId="High" + }, + BlastRainColdMercenary={ + description="Fires arrows up in the air, to rain down in an area. Each arrow deals cold area damage around where it lands, and they will all overlap on the targeted location.", + hash=24409, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="BlastRainColdMercenary", + name="Icicle Rain", + possibleSupportIds={ + [1]="ColdPenetrationHigh", + [2]="ColdPenetrationLow", + [3]="ColdPenetrationMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="EleDamageWithAttacksHigh", + [8]="EleDamageWithAttacksLow", + [9]="EleDamageWithAttacksMid", + [10]="ForkHigh", + [11]="FreezeChanceHigh", + [12]="FreezeChanceLow", + [13]="FreezeChanceMid", + [14]="HypothermiaHigh", + [15]="HypothermiaLow", + [16]="HypothermiaMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="MultipleProjectilesHigh", + [21]="MultipleProjectilesLow", + [22]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + BlightMercenary={ + description="Apply a debuff to enemies which deals chaos damage over time. Enemies who aren't already debuffed by Blight are also hindered for a shorter secondary duration, slowing their movement. Continued channelling adds layers of damage to the debuff, each with their own duration.", + hash=8450, + icon="", + id="BlightMercenary", + name="Blight", + possibleSupportIds={ + [1]="BlightSpecificSecondaryDurationHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="ChannelSkillDamageReductionHigh", + [6]="ChannelSkillDamageReductionLow", + [7]="ChannelSkillDamageReductionMid", + [8]="DamageOverTimeReduceDurationHigh", + [9]="DamageOverTimeReduceDurationLow", + [10]="DamageOverTimeReduceDurationMid", + [11]="DotMultiHigh", + [12]="DotMultiLow", + [13]="DotMultiMid", + [14]="IncreaseAreaOfEffectHigh", + [15]="IncreaseAreaOfEffectLow", + [16]="IncreaseAreaOfEffectMid", + [17]="IncreaseDurationHigh", + [18]="IncreaseDurationLow", + [19]="IncreaseDurationMid" + }, + secondarySkillId="BlightMercenaryEncounter", + supportCountId="High" + }, + BlinkArrowMercenary={ + description="Fires an arrow at the target destination. When the arrow lands, the user is teleported to it and a clone is summoned at the old location. The clone is a minion that copies the bow and quiver.", + hash=10722, + icon="", + id="BlinkArrowMercenary", + name="Blink Arrow", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseDurationHigh", + [8]="IncreaseDurationLow", + [9]="IncreaseDurationMid", + [10]="IncreasedProjSpeedHigh", + [11]="IncreasedProjSpeedLow", + [12]="IncreasedProjSpeedMid", + [13]="MinionDamageHigh", + [14]="MinionDamageLow", + [15]="MinionDamageMid", + [16]="MinionLifeHigh", + [17]="MinionLifeLow", + [18]="MinionLifeMid" + }, + supportCountId="Medium" + }, + BloodMortarMercenary={ + description="Flings a mortar of blood in an arc which deals attack damage on impact and has a high chance to inflict bleeding.", + hash=26931, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="BloodMortarMercenary", + name="Blood Mortar", + possibleSupportIds={ + [1]="AilmentDamageHigh", + [2]="AilmentDamageLow", + [3]="AilmentDamageMid", + [4]="BleedHigh", + [5]="BleedLow", + [6]="BleedMid", + [7]="BrutalityHigh", + [8]="BrutalityLow", + [9]="BrutalityMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow" + }, + supportCountId="Medium" + }, + BodyswapMercenary={ + description="Explodes your body and recreates it at the location of a targeted enemy or corpse, dealing spell damage in an area at both locations. If targeting a corpse, the corpse will also explode, dealing damage around it.", + hash=4927, + icon="", + id="BodyswapMercenary", + name="Bodyswap", + possibleSupportIds={ + [1]="BodySwapSpecificDamageFromLifeHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="FirePenetrationHigh", + [6]="FirePenetrationLow", + [7]="FirePenetrationMid", + [8]="IgniteChanceHigh", + [9]="IgniteChanceLow", + [10]="IgniteChanceMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid" + }, + supportCountId="Low" + }, + BoneOfferingMercenary={ + description="Consumes a corpse, granting the owners minions the power to block both attacks and spells. The skill consumes other nearby corpses, increasing the duration for each corpse consumed.", + familyId="Infrequent", + hash=44467, + icon="", + id="BoneOfferingMercenary", + name="Bone Offering", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseDurationHigh", + [8]="IncreaseDurationLow", + [9]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + BoneshatterMercenary={ + description="Attack enemies with a forceful melee strike that also hurts the user. Successive uses will raise the damage dealt both to enemies and the user. Stunning an enemy with the strike releases a damaging pulse.", + hash=22696, + icon="", + id="BoneshatterMercenary", + name="Boneshatter", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BoneshatterSpecificTraumaDurationHigh", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="FortifyHigh", + [9]="IncreaseDurationHigh", + [10]="IncreaseDurationLow", + [11]="IncreaseDurationMid", + [12]="MaimOnHitHigh", + [13]="MeleePhysHigh", + [14]="MeleePhysLow", + [15]="MeleePhysMid", + [16]="MeleeSplashHigh", + [17]="MultistrikeHigh", + [18]="MultistrikeMid", + [19]="PulveriseHigh", + [20]="PulveriseLow", + [21]="PulveriseMid", + [22]="StrikeRangeHigh", + [23]="StrikeRangeLow", + [24]="StrikeRangeMid" + }, + supportCountId="High" + }, + BurningArrowMercenary={ + description="Fires a burning arrow that deals fire damage and has a chance to ignite.", + hash=34665, + icon="", + id="BurningArrowMercenary", + name="Burning Arrow", + possibleSupportIds={ + [1]="ArrowNovaHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BurningArrowSpecificAlwaysPierceHigh", + [6]="CombustionHigh", + [7]="DamageOverTimeReduceDurationHigh", + [8]="DamageOverTimeReduceDurationLow", + [9]="DamageOverTimeReduceDurationMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="FirePenetrationHigh", + [14]="FirePenetrationLow", + [15]="FirePenetrationMid", + [16]="ForkHigh", + [17]="IgniteChanceHigh", + [18]="IgniteChanceLow", + [19]="IgniteChanceMid", + [20]="MultipleProjectilesHigh", + [21]="MultipleProjectilesLow", + [22]="ProjectilesReturnHigh" + }, + secondarySkillId="BurningArrowMercenaryEncounter", + supportCountId="High" + }, + BurrowMercenary={ + description="Dive underground, dealing attack damage to nearby enemies and burrowing towards a targeted location. Then, erupt from the earth, dealing attack damage in an area.", + hash=31440, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="BurrowMercenary", + name="Burrow", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="ConcentratedEffectHigh", + [9]="ConcentratedEffectLow", + [10]="ConcentratedEffectMid", + [11]="CooldownSpeedHigh", + [12]="CooldownSpeedLow", + [13]="CooldownSpeedMid", + [14]="IncreaseAreaOfEffectHigh", + [15]="IncreaseAreaOfEffectLow", + [16]="IncreaseAreaOfEffectMid", + [17]="PulveriseHigh", + [18]="PulveriseLow", + [19]="PulveriseMid" + }, + supportCountId="Low" + }, + CGEBloodGroundMercenary={ + description="Creates a pool of boiling blood on using a travel skill, which deals physical damage over time to enemies within it.", + hash=44422, + icon="Art/2DArt/SkillIcons/HouseCyaxanSkill.dds", + id="CGEBloodGroundMercenary", + name="Boiling Blood", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="DamageOverTimeReduceDurationHigh", + [5]="DamageOverTimeReduceDurationHigh", + [6]="DamageOverTimeReduceDurationLow", + [7]="DamageOverTimeReduceDurationLow", + [8]="DamageOverTimeReduceDurationMid", + [9]="DamageOverTimeReduceDurationMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="IncreaseDurationHigh", + [17]="IncreaseDurationLow", + [18]="IncreaseDurationMid" + }, + supportCountId="Medium" + }, + CGEOilGroundSlowMercenary={ + description="Creates an area of oil covered ground, which slows all enemies within it", + hash=19268, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="CGEOilGroundSlowMercenary", + name="Oil Slick", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="DotMultiHigh", + [6]="DotMultiLow", + [7]="DotMultiMid", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="IncreaseDurationHigh", + [12]="IncreaseDurationLow", + [13]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + CallOfSteelMercenary={ + description="Calls impale debuffs from enemies, alive or dead, in a large surrounding area to gain steel shards. Deals reflected damage in a smaller area around each enemy based on the impales removed from them. Continues to grant shards over time until reaching maximum or until they are spent.", + hash=46131, + icon="", + id="CallOfSteelMercenary", + name="Call of Steel", + possibleSupportIds={ + }, + supportCountId="None" + }, + CausticArrowMercenary={ + description="Fires an arrow which deals chaos damage in an area on impact, and spreads caustic ground. Enemies standing on the caustic ground take chaos damage over time.", + hash=58174, + icon="", + id="CausticArrowMercenary", + name="Caustic Arrow", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="CausticArrowSpecificChaosConvertHigh", + [5]="DotMultiHigh", + [6]="DotMultiLow", + [7]="DotMultiMid", + [8]="ForkHigh", + [9]="IncreaseAreaOfEffectHigh", + [10]="IncreaseAreaOfEffectLow", + [11]="IncreaseAreaOfEffectMid", + [12]="IncreaseDurationHigh", + [13]="IncreaseDurationLow", + [14]="IncreaseDurationMid", + [15]="MirageArcherHigh", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="PhysGainAsChaosHigh", + [19]="PhysGainAsChaosMid", + [20]="PierceHigh", + [21]="PierceLow", + [22]="PierceMid", + [23]="WitherOnHitHigh", + [24]="WitherOnHitLow", + [25]="WitherOnHitMid" + }, + secondarySkillId="CausticArrowMercenaryEncounter", + supportCountId="High" + }, + ChainHookAltMercenary={ + description="Throws chains ahead, chaining targets hit. Enemies chained will grant rage when hit. When chains are broken, they snap and deal damage in an area around the target they were attached to.", + familyId="Infrequent", + hash=7182, + icon="", + id="ChainHookAltMercenary", + name="Chain Hook of Trarthus", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="PulveriseHigh", + [14]="PulveriseLow", + [15]="PulveriseMid", + [16]="RageOnMeleeHitHigh", + [17]="RageOnMeleeHitLow", + [18]="RageOnMeleeHitMid" + }, + supportCountId="High" + }, + ChaosGlacialCascadeMercenary={ + description="Pillars of unholy stone emerge from the ground in a series of small bursts, each damaging enemies caught in the area.", + hash=51539, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="ChaosGlacialCascadeMercenary", + name="Profane Cascade", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ChaosPenHigh", + [8]="ChaosPenLow", + [9]="ChaosPenMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="GlacialCascadeSpecificNumberOfSpikesHigh", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="PhysGainAsChaosHigh", + [21]="PhysGainAsChaosMid", + [22]="WitherOnHitHigh", + [23]="WitherOnHitLow", + [24]="WitherOnHitMid" + }, + supportCountId="High" + }, + ChargedDashSpellScalingMercenary={ + description="Projects an illusion which gains stages while it moves, until it stops at a maximum total distance. Waves of area damage frequently pulse along its path. Increases and reductions to spell damage apply to the damage this attack deals.", + familyId="Infrequent", + hash=5673, + icon="", + id="ChargedDashSpellScalingMercenary", + name="Charged Dash of the Arcane", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="PhysGainAsRandomHigh", + [11]="PhysGainAsRandomLow", + [12]="PhysGainAsRandomMid" + }, + supportCountId="Low" + }, + ClarityMercenary={ + description="Casts an aura that grants mana regeneration.", + hash=28785, + icon="", + id="ClarityMercenary", + name="Clarity", + possibleSupportIds={ + }, + supportCountId="None" + }, + CleaveMercenary={ + description="Swings equipped weapon in an arc, damaging monsters in an area. ", + hash=8445, + icon="", + id="CleaveMercenary", + name="Cleave", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="CleaveSpecificCullHigh", + [8]="IgnoreEnemyPhysMitHigh", + [9]="IgnoreEnemyPhysMitLow", + [10]="IgnoreEnemyPhysMitMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="MultistrikeHigh", + [15]="MultistrikeMid", + [16]="PulveriseHigh", + [17]="PulveriseLow", + [18]="PulveriseMid", + [19]="RageOnMeleeHitHigh", + [20]="RageOnMeleeHitLow", + [21]="RageOnMeleeHitMid" + }, + secondarySkillId="CleaveMercenaryEncounter", + supportCountId="High" + }, + CobraLashMercenary={ + description="Fires a poisonous projectile attack that will chain between enemies. ", + hash=16896, + icon="", + id="CobraLashMercenary", + name="Cobra Lash", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="CobraLashSpecificPoisonRegenHigh", + [7]="IncreasedProjSpeedHigh", + [8]="IncreasedProjSpeedLow", + [9]="IncreasedProjSpeedMid", + [10]="MultipleProjectilesHigh", + [11]="MultipleProjectilesLow", + [12]="PhysGainAsChaosHigh", + [13]="PhysGainAsChaosMid", + [14]="PoisonChanceHigh", + [15]="PoisonChanceLow", + [16]="PoisonChanceMid", + [17]="ProjectilesReturnHigh", + [18]="WitherOnHitHigh", + [19]="WitherOnHitLow", + [20]="WitherOnHitMid" + }, + supportCountId="High" + }, + ConductivityMercenary={ + description="Curses all targets in an area, lowering their lightning resistance and giving them a chance to be shocked when hit.", + hash=41484, + icon="", + id="ConductivityMercenary", + name="Conductivity", + possibleSupportIds={ + [1]="CurseEffectHigh", + [2]="IncreaseAreaOfEffectHigh", + [3]="IncreaseAreaOfEffectLow", + [4]="IncreaseAreaOfEffectMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid", + [8]="SpellCascadeLow" + }, + supportCountId="Low" + }, + ConflagrationMercenary={ + description="Fire arrows into the air that rain down around the targeted area, dealing area damage on impact and leaving the arrows stuck in the ground for a duration. If you move close to a stuck arrow, it will explode, dealing area damage and applying a fire damage over time debuff, as well as causing other stuck arrows in range to also explode.", + hash=21962, + icon="", + id="ConflagrationMercenary", + name="Conflagration", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="CombustionHigh", + [5]="ConflagrationSpecificInvertResistancesHigh", + [6]="DamageOverTimeReduceDurationHigh", + [7]="DamageOverTimeReduceDurationLow", + [8]="DamageOverTimeReduceDurationMid", + [9]="DotMultiHigh", + [10]="DotMultiLow", + [11]="DotMultiMid", + [12]="EleDamageWithAttacksHigh", + [13]="EleDamageWithAttacksLow", + [14]="EleDamageWithAttacksMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="IncreaseDurationHigh", + [19]="IncreaseDurationLow", + [20]="IncreaseDurationMid" + }, + secondarySkillId="ConflagrationMercenaryEncounter", + supportCountId="High" + }, + ConsecratedPathMercenary={ + description="Slams the ground at a targeted location. If an enemy is near the targetted location, teleport to it from a short distance away, slam, and create an area of consecrated ground. ", + hash=3093, + icon="", + id="ConsecratedPathMercenary", + name="Consecrated Path", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="CombustionHigh", + [8]="ConcentratedEffectHigh", + [9]="ConcentratedEffectLow", + [10]="ConcentratedEffectMid", + [11]="ConsecratedPathSpecificDamageGainHigh", + [12]="FirePenetrationHigh", + [13]="FirePenetrationLow", + [14]="FirePenetrationMid", + [15]="FistOfWarHigh", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="IncreaseDurationHigh", + [20]="IncreaseDurationLow", + [21]="IncreaseDurationMid" + }, + supportCountId="Medium" + }, + CreepingFrostTrapMercenary={ + description="Throws a trap which, once triggered, fire an icy projectile that bursts on impact or when reaching the targeted area, dealing area damage and creating a chilling area that deals cold damage over time. This area will creep across the ground towards nearby enemies until its duration expires.", + hash=9321, + icon="", + id="CreepingFrostTrapMercenary", + name="Creeping Frost Trap", + possibleSupportIds={ + [1]="ColdPenetrationHigh", + [2]="ColdPenetrationLow", + [3]="ColdPenetrationMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="MultiTrapHigh", + [8]="MultipleProjectilesHigh", + [9]="MultipleProjectilesLow", + [10]="NonDamagingAilmentEffectHigh", + [11]="NonDamagingAilmentEffectLow", + [12]="NonDamagingAilmentEffectMid", + [13]="TrapMineDamageHigh", + [14]="TrapMineDamageLow", + [15]="TrapMineDamageMid", + [16]="TrapMineThrowSpeedHigh", + [17]="TrapMineThrowSpeedLow", + [18]="TrapMineThrowSpeedMid", + [19]="TrapTriggerArcaneSurgeHigh", + [20]="TrapTriggerRadiusHigh", + [21]="TrapTriggerRadiusLow", + [22]="TrapTriggerRadiusMid" + }, + secondarySkillId="CreepingFrostTrapMercenaryEncounter", + supportCountId="High" + }, + CycloneReverseKnockbackMercenary={ + description="Moves towards a targeted location while spinning constantly attacking enemies in an area. Enemies struck by this skill are knocked inwards towards the attacker.", + hash=46739, + icon="", + id="CycloneReverseKnockbackMercenary", + name="Cyclone of the Empire", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="ChannelSkillDamageReductionHigh", + [5]="ChannelSkillDamageReductionLow", + [6]="ChannelSkillDamageReductionMid", + [7]="CycloneSpecificMoveSpeedHigh", + [8]="ImpaleChanceHigh", + [9]="ImpaleChanceLow", + [10]="ImpaleChanceMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="KnockbackLow", + [15]="MeleePhysHigh", + [16]="MeleePhysLow", + [17]="MeleePhysMid" + }, + supportCountId="Medium" + }, + DarkPactMercenary={ + description="Sacrifices life from a nearby allied Skeleton minion to deal chaos damage in an area around it. This effect will chain to other nearby allied skeletons. If there are no nearby allied Skeletons it will deal damage around the caster instead.", + hash=35371, + icon="", + id="DarkPactMercenary", + name="Dark Bargain", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ChaosPenHigh", + [8]="ChaosPenLow", + [9]="ChaosPenMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="WitherOnHitHigh", + [20]="WitherOnHitLow", + [21]="WitherOnHitMid" + }, + supportCountId="High" + }, + DashMercenary={ + description="Performs a series of quick teleports towards a targeted location.", + hash=60723, + icon="", + id="DashMercenary", + name="Dash", + possibleSupportIds={ + }, + supportCountId="None" + }, + DeceleratingProjectileMercenary={ + description="Fire a rapidly decelerating arrow that converts part of the physical damage it deals to chaos. When it comes to a stop, it will trigger Chaotic Burst.", + hash=18986, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="DeceleratingProjectileMercenary", + name="Chaotic Shot", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="ChaosPenHigh", + [5]="ChaosPenLow", + [6]="ChaosPenMid", + [7]="IncreasedProjSpeedHigh", + [8]="IncreasedProjSpeedLow", + [9]="IncreasedProjSpeedMid", + [10]="MultipleProjectilesHigh", + [11]="MultipleProjectilesLow", + [12]="PhysGainAsChaosHigh", + [13]="PhysGainAsChaosMid", + [14]="PoisonChanceHigh", + [15]="PoisonChanceLow", + [16]="PoisonChanceMid" + }, + supportCountId="High" + }, + DeceleratingProjectileMercenaryExplode={ + description="Deals physical and chaos attack damage in an area.", + hash=26913, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="DeceleratingProjectileMercenaryExplode", + name="Chaotic Burst", + possibleSupportIds={ + [1]="IncreaseAreaOfEffectHigh", + [2]="IncreaseAreaOfEffectLow", + [3]="IncreaseAreaOfEffectMid", + [4]="WitherOnHitHigh", + [5]="WitherOnHitLow", + [6]="WitherOnHitMid" + }, + supportCountId="Low" + }, + DecoyTotemMercenary={ + description="Summons a totem that taunts nearby monsters to attack it.", + familyId="Infrequent", + hash=38104, + icon="", + id="DecoyTotemMercenary", + name="Decoy Totem", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="TotemDefencesHigh", + [9]="TotemDefencesLow", + [10]="TotemDefencesMid" + }, + supportCountId="Medium" + }, + DesecrateMercenary={ + description="Desecrates the ground, spawning corpses based on monsters in the current area and dealing chaos damage over time to enemies.", + hash=21523, + icon="", + id="DesecrateMercenary", + name="Desecrate", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="DotMultiHigh", + [9]="DotMultiLow", + [10]="DotMultiMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="IncreaseDurationHigh", + [15]="IncreaseDurationLow", + [16]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + DespairMercenary={ + description="Curses all targets in an area, lowering their chaos resistance.", + hash=56742, + icon="", + id="DespairMercenary", + name="Despair", + possibleSupportIds={ + [1]="CurseEffectHigh", + [2]="IncreaseAreaOfEffectHigh", + [3]="IncreaseAreaOfEffectLow", + [4]="IncreaseAreaOfEffectMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid", + [8]="SpellCascadeLow" + }, + supportCountId="Low" + }, + DeterminationMercenary={ + description="Casts an aura that grants armour.", + hash=52845, + icon="", + id="DeterminationMercenary", + name="Determination", + possibleSupportIds={ + }, + supportCountId="None" + }, + DisciplineMercenary={ + description="Casts an aura that grants additional energy shield and increased energy shield recharge rate.", + hash=21708, + icon="", + id="DisciplineMercenary", + name="Discipline", + possibleSupportIds={ + }, + supportCountId="None" + }, + DivineIreMercenary={ + description="Channels raw energy to build up stages, damaging surrounding enemies. Releases to unleash this energy in a burst in the surrounding area and a beam forward. Maximum of 10 Stages.", + hash=45226, + icon="", + id="DivineIreMercenary", + name="Divine Ire", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="ChannelSkillDamageReductionHigh", + [5]="ChannelSkillDamageReductionLow", + [6]="ChannelSkillDamageReductionMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="DivineIreSpecificWidthHigh", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="LightningPenetrationHigh", + [15]="LightningPenetrationLow", + [16]="LightningPenetrationMid", + [17]="PhysGainAsRandomHigh", + [18]="PhysGainAsRandomLow", + [19]="PhysGainAsRandomMid", + [20]="ShockChanceLow", + [21]="ShockChanceMid" + }, + secondarySkillId="DivineIreMercenaryEncounter", + supportCountId="High" + }, + DivineRetributionMercenary={ + description="Retaliate against a blocked hit with a surge of divine power, causing multiple waves of lightning bursts to expand outward from a targeted location. ", + familyId="Infrequent", + hash=24685, + icon="", + id="DivineRetributionMercenary", + name="Divine Retribution", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="LightningPenetrationHigh", + [14]="LightningPenetrationLow", + [15]="LightningPenetrationMid", + [16]="PhysGainAsRandomHigh", + [17]="PhysGainAsRandomLow", + [18]="PhysGainAsRandomMid", + [19]="ShockChanceLow", + [20]="ShockChanceMid" + }, + supportCountId="High" + }, + DoLiterallyNothing={ + description="This really shouldn't be here...", + hash=51031, + icon="", + id="DoLiterallyNothing", + name="Do Nothing", + possibleSupportIds={ + }, + supportCountId="None" + }, + DominatingBlowMercenary={ + description="Attacks enemies with a melee strike, applying a debuff for a short duration. If a non-unique enemy dies while affected by the debuff, the enemy's corpse will be consumed and a Sentinel of Dominance with the same rarity, prefix and suffix modifiers will be summoned for a longer secondary duration.", + hash=43742, + icon="", + id="DominatingBlowMercenary", + name="Dominating Blow", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="HallowHigh", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="MeleeSplashHigh", + [12]="MinionDamageHigh", + [13]="MinionDamageLow", + [14]="MinionDamageMid", + [15]="MinionLifeHigh", + [16]="MinionLifeLow", + [17]="MinionLifeMid", + [18]="MultistrikeHigh", + [19]="MultistrikeMid" + }, + supportCountId="High" + }, + DonutBladesMercenary={ + description="Large blades spike upwards from the ground, dealing attack damage in an area.", + hash=28026, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="DonutBladesMercenary", + name="Triggerblades", + possibleSupportIds={ + [1]="BleedHigh", + [2]="BleedLow", + [3]="BleedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="ImpaleChanceHigh", + [11]="ImpaleChanceLow", + [12]="ImpaleChanceMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="MeleePhysHigh", + [17]="MeleePhysLow", + [18]="MeleePhysMid" + }, + supportCountId="Medium" + }, + DonutCircleMercenary={ + description="Rip stone from the earth, compacting it into a bludgeoning sphere to slam down onto enemies.", + familyId="Infrequent", + hash=17198, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="DonutCircleMercenary", + name="Seismic Crush", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="BrutalityHigh", + [3]="BrutalityLow", + [4]="BrutalityMid", + [5]="CastSpeedHigh", + [6]="CastSpeedLow", + [7]="CastSpeedMid", + [8]="CooldownSpeedHigh", + [9]="CooldownSpeedLow", + [10]="CooldownSpeedMid", + [11]="CritDamageHigh", + [12]="CritDamageLow", + [13]="CritDamageMid", + [14]="CriticalStrikeHigh", + [15]="CriticalStrikeLow", + [16]="CriticalStrikeMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="PhysGainAsChaosHigh", + [21]="PhysGainAsChaosMid" + }, + supportCountId="Medium" + }, + DoryanisTouchMercenary={ + description="Slams the ground with a fist, with less attack speed, but more damage. This attack deals Lightning Damage to enemies in a large area, with a chance to Shock them. Cannot be Evaded.", + familyId="Infrequent", + hash=39732, + icon="", + id="DoryanisTouchMercenary", + name="Touch of God", + possibleSupportIds={ + [1]="ConcentratedEffectHigh", + [2]="ConcentratedEffectLow", + [3]="ConcentratedEffectMid", + [4]="EleDamageWithAttacksHigh", + [5]="EleDamageWithAttacksLow", + [6]="EleDamageWithAttacksMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="PulveriseHigh", + [11]="PulveriseLow", + [12]="PulveriseMid", + [13]="ShockChanceHigh", + [14]="ShockChanceLow", + [15]="ShockChanceMid" + }, + supportCountId="High" + }, + DropArrowMercenary={ + description="Fires an incendiary arrow into the air which will create an area of molten ground on impact. Enemies within the molten ground take fire damage over time.", + hash=59200, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="DropArrowMercenary", + name="Molten Well", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="DotMultiHigh", + [9]="DotMultiLow", + [10]="DotMultiMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="IncreaseDurationHigh", + [15]="IncreaseDurationLow", + [16]="IncreaseDurationMid" + }, + secondarySkillId="DropArrowMercenaryEncounter", + supportCountId="High" + }, + DualStrikeMercenary={ + description="Attacks with both weapons, dealing the damage of both in one strike. ", + hash=10235, + icon="", + id="DualStrikeMercenary", + name="Dual Strike", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="FortifyHigh", + [8]="ImpaleChanceHigh", + [9]="ImpaleChanceLow", + [10]="ImpaleChanceMid", + [11]="MeleePhysHigh", + [12]="MeleePhysLow", + [13]="MeleePhysMid", + [14]="MeleeSplashHigh", + [15]="MultistrikeHigh", + [16]="MultistrikeMid", + [17]="StrikeRangeHigh", + [18]="StrikeRangeLow", + [19]="StrikeRangeMid" + }, + supportCountId="High" + }, + EarthquakeAltMercenary={ + description="Smashes the ground, dealing damage in an area and cracking the earth. The crack will erupt in a powerful aftershock after a long duration. Cracks created before the first one has erupted will not generate their own aftershocks.", + hash=41346, + icon="", + id="EarthquakeAltMercenary", + name="Earthquake of Amplification", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="IgnoreEnemyPhysMitHigh", + [11]="IgnoreEnemyPhysMitLow", + [12]="IgnoreEnemyPhysMitMid", + [13]="ImpaleChanceHigh", + [14]="ImpaleChanceLow", + [15]="ImpaleChanceMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="IncreaseDurationHigh", + [20]="IncreaseDurationLow", + [21]="IncreaseDurationMid", + [22]="PulveriseHigh", + [23]="PulveriseLow", + [24]="PulveriseMid" + }, + supportCountId="High" + }, + EarthquakeColdMercenary={ + description="Smashes the ground, dealing damage in an area and cracking the earth. The crack will erupt in a powerful aftershock after a duration. Physical damage dealt is partially converted to cold.", + familyId="Infrequent", + hash=14816, + icon="", + id="EarthquakeColdMercenary", + name="Earthquake of Winter", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="ColdPenetrationHigh", + [5]="ColdPenetrationLow", + [6]="ColdPenetrationMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="FistOfWarHigh", + [11]="FreezeChanceHigh", + [12]="FreezeChanceLow", + [13]="FreezeChanceMid", + [14]="HypothermiaHigh", + [15]="HypothermiaLow", + [16]="HypothermiaMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="PulveriseHigh", + [21]="PulveriseLow", + [22]="PulveriseMid", + [23]="ReduceDurationHigh", + [24]="ReduceDurationLow", + [25]="ReduceDurationMid" + }, + supportCountId="High" + }, + ElementalHitColdOnlyMercenary={ + description="If this attack hits an enemy, it will deal damage in an area around them, with the radius being larger if that enemy is suffering from a cold ailment.", + hash=8708, + icon="", + id="ElementalHitColdOnlyMercenary", + name="Elemental Hit of Ice", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="ColdPenetrationHigh", + [8]="ColdPenetrationLow", + [9]="ColdPenetrationMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="EleDamageWithAttacksHigh", + [17]="EleDamageWithAttacksLow", + [18]="EleDamageWithAttacksMid", + [19]="IncreaseAreaOfEffectHigh", + [20]="IncreaseAreaOfEffectLow", + [21]="IncreaseAreaOfEffectMid", + [22]="MeleeSplashHigh", + [23]="MultistrikeHigh", + [24]="MultistrikeMid" + }, + secondarySkillId="ElementalHitColdOnlyMercenaryEncounter", + supportCountId="High" + }, + ElementalWeaknessMercenary={ + description="Curses all targets in an area, lowering their elemental resistances.", + hash=5689, + icon="", + id="ElementalWeaknessMercenary", + name="Elemental Weakness", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CurseEffectHigh", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="SpellCascadeHigh", + [9]="SpellCascadeLow" + }, + supportCountId="Low" + }, + EnduringCryMercenary={ + description="Performs a warcry, taunting all nearby enemies to attack the user and granting a buff to the user and nearby allies. The user and allied players also gain endurance charges.", + familyId="Infrequent", + hash=20973, + icon="", + id="EnduringCryMercenary", + name="Enduring Cry", + possibleSupportIds={ + [1]="IncreaseAreaOfEffectHigh", + [2]="IncreaseAreaOfEffectLow", + [3]="IncreaseAreaOfEffectMid", + [4]="IncreaseDurationHigh", + [5]="IncreaseDurationLow", + [6]="IncreaseDurationMid", + [7]="WarcryRageHigh", + [8]="WarcryRageLow", + [9]="WarcryRageMid", + [10]="WarcrySpeedHigh", + [11]="WarcrySpeedLow", + [12]="WarcrySpeedMid" + }, + supportCountId="Low" + }, + EnfeebleMercenary={ + description="Casts an aura that curses all enemies in an area, reducing their accuracy and making them deal less damage.", + hash=26391, + icon="", + id="EnfeebleMercenary", + name="Blasphemy Enfeeble", + possibleSupportIds={ + }, + supportCountId="None" + }, + EnrageMercenary={ + description="Enrage for a short duration, gaining attack speed, movement speed and damage.", + hash=62530, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="EnrageMercenary", + name="Enrage", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + EnsnaringArrowMercenary={ + description="Fires an arrow that remains in the ground behind its final target, tethering that enemy to it. Ensnared enemies have less movement speed while trying to break the snare. The snare will break if they leave the area of effect.", + familyId="Infrequent", + hash=12667, + icon="", + id="EnsnaringArrowMercenary", + name="Ensnaring Arrow", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="EnsnaringArrowSpecificEffectHigh", + [5]="IgnoreEnemyPhysMitHigh", + [6]="IgnoreEnemyPhysMitLow", + [7]="IgnoreEnemyPhysMitMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="MaimOnHitHigh", + [12]="MultipleProjectilesHigh", + [13]="MultipleProjectilesLow" + }, + supportCountId="Medium" + }, + EnvyMercenary={ + description="Casts an aura that adds chaos damage to attacks and spells.", + hash=17515, + icon="", + id="EnvyMercenary", + name="Envy", + possibleSupportIds={ + }, + supportCountId="None" + }, + EssenceDrainAltMercenary={ + description="Fires a piercing projectile that applies a damage over time debuff when it hits. Healing the caster for a portion of the debuff damage.", + hash=39669, + icon="", + id="EssenceDrainAltMercenary", + name="Essence Drain of Wickedness", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="AltEssenceDrainSpecificLeechHigh", + [4]="DamageOverTimeReduceDurationHigh", + [5]="DamageOverTimeReduceDurationLow", + [6]="DamageOverTimeReduceDurationMid", + [7]="DotMultiHigh", + [8]="DotMultiLow", + [9]="DotMultiMid", + [10]="IncreaseDurationHigh", + [11]="IncreaseDurationLow", + [12]="IncreaseDurationMid", + [13]="MultipleProjectilesHigh", + [14]="MultipleProjectilesLow", + [15]="ProjectilesReturnHigh" + }, + secondarySkillId="EssenceDrainAltMercenaryEncounter", + supportCountId="High" + }, + EtherealKnivesMercenary={ + description="Fires an arc of knives outwards in front of the caster which deal physical damage.", + hash=50999, + icon="", + id="EtherealKnivesMercenary", + name="Ethereal Knives", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="CritDamageHigh", + [8]="CritDamageLow", + [9]="CritDamageMid", + [10]="CriticalStrikeHigh", + [11]="CriticalStrikeLow", + [12]="CriticalStrikeMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="PhysGainAsChaosHigh", + [19]="PhysGainAsChaosMid", + [20]="PierceHigh", + [21]="PierceLow", + [22]="PierceMid" + }, + secondarySkillId="EtherealKnivesMercenaryEncounter", + supportCountId="High" + }, + ExplosiveArrowBarrageMercenary={ + description="Fires a sequence of arrows which will stick into an enemy or wall, and then explode, dealing area damage around them, either after a duration or when the maximum number of arrows stuck to that target is reached. ", + hash=36298, + icon="", + id="ExplosiveArrowBarrageMercenary", + name="Explosive Arrow", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="ConcentratedEffectHigh", + [5]="ConcentratedEffectLow", + [6]="ConcentratedEffectMid", + [7]="DotMultiHigh", + [8]="DotMultiLow", + [9]="DotMultiMid", + [10]="ExplosiveArrowSpecificMaxHigh", + [11]="FirePenetrationHigh", + [12]="FirePenetrationLow", + [13]="FirePenetrationMid", + [14]="IgniteChanceHigh", + [15]="IgniteChanceLow", + [16]="IgniteChanceMid", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow" + }, + supportCountId="High" + }, + ExsanguinateMercenary={ + description="Releases several tendrils of blood. The tendrils deal physical damage and inflict a physical damage over time debuff to enemies, which can stack up to 3 times. Effects which allow skills to chain can apply to these tendrils.", + hash=40439, + icon="", + id="ExsanguinateMercenary", + name="Exsanguinate", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="DamageOverTimeReduceDurationHigh", + [8]="DamageOverTimeReduceDurationLow", + [9]="DamageOverTimeReduceDurationMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid" + }, + secondarySkillId="ExsanguinateMercenaryEncounter", + supportCountId="High" + }, + EyeOfWinterMercenary={ + description="Fires a single eye projectile which constantly releases shard projectiles in a spiral. The shards will damage enemies they impact, dealing cold damage. The eye cannot damage enemies. When the eye dissipates or collides with terrain, it releases a faster spiral of extra shards.", + hash=57063, + icon="", + id="EyeOfWinterMercenary", + name="Eye of Winter", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="BrittleChanceHigh", + [5]="CastSpeedHigh", + [6]="CastSpeedLow", + [7]="CastSpeedMid", + [8]="CriticalStrikeHigh", + [9]="CriticalStrikeLow", + [10]="CriticalStrikeMid", + [11]="FreezeChanceHigh", + [12]="FreezeChanceLow", + [13]="FreezeChanceMid", + [14]="IncreasedProjSpeedHigh", + [15]="IncreasedProjSpeedLow", + [16]="IncreasedProjSpeedMid", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow" + }, + supportCountId="High" + }, + FireAegisMercenary={ + description="Surrounds the caster with a fiery barrier which will absorb incoming fire damage up to a point, then break. This barrier will recharge over time.", + hash=50414, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="FireAegisMercenary", + name="Flame Aegis", + possibleSupportIds={ + }, + secondarySkillId="FireAegisMercenaryEncounter", + supportCountId="None" + }, + FireEnrageMercenary={ + description="Become enraged and cloaked in flame, gaining a percentage of physical damage as extra fire as well as movement speed and attack speed for a short duration.", + hash=8295, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="FireEnrageMercenary", + name="Inflame", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + FireballAltMercenary={ + description="Unleashes a ball of fire towards a targeted location which then explodes, damaging nearby foes.", + familyId="FireballVariant", + hash=37821, + icon="", + id="FireballAltMercenary", + name="Fireball of Impact", + possibleSupportIds={ + [1]="AilmentDamageHigh", + [2]="AilmentDamageLow", + [3]="AilmentDamageMid", + [4]="CombustionHigh", + [5]="EleFocusHigh", + [6]="EleFocusLow", + [7]="EleFocusMid", + [8]="FirePenetrationHigh", + [9]="FirePenetrationLow", + [10]="FirePenetrationMid", + [11]="FireballAltSpecificChanceToScorchHigh", + [12]="IgniteChanceHigh", + [13]="IgniteChanceLow", + [14]="IgniteChanceMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="MultipleProjectilesHigh", + [19]="MultipleProjectilesLow" + }, + secondarySkillId="FireballAltMercenaryEncounter", + supportCountId="High" + }, + FireballMercenary={ + description="Unleashes a ball of fire towards a target which explodes, damaging nearby foes.", + familyId="FireballVariant", + hash=324, + icon="", + id="FireballMercenary", + name="Fireball", + possibleSupportIds={ + [1]="AilmentDamageHigh", + [2]="AilmentDamageLow", + [3]="AilmentDamageMid", + [4]="CombustionHigh", + [5]="EleFocusHigh", + [6]="EleFocusLow", + [7]="EleFocusMid", + [8]="FirePenetrationHigh", + [9]="FirePenetrationLow", + [10]="FirePenetrationMid", + [11]="ForkHigh", + [12]="IgniteChanceHigh", + [13]="IgniteChanceLow", + [14]="IgniteChanceMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="IncreasedProjSpeedHigh", + [19]="IncreasedProjSpeedLow", + [20]="IncreasedProjSpeedMid", + [21]="MultipleProjectilesHigh", + [22]="MultipleProjectilesLow", + [23]="ProjectilesReturnHigh" + }, + secondarySkillId="FireballMercenaryEncounter", + supportCountId="High" + }, + FissureSlamMercenary={ + description="Creates a fiery fissure which deals attack damage, partially converting physical damage to fire. Enemies struck have a chance to be covered in ash.", + hash=42361, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="FissureSlamMercenary", + name="Ashen Fissure", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="CombustionHigh", + [8]="FirePenetrationHigh", + [9]="FirePenetrationLow", + [10]="FirePenetrationMid", + [11]="FistOfWarHigh", + [12]="IncreaseAreaOfEffectHigh", + [13]="IncreaseAreaOfEffectLow", + [14]="IncreaseAreaOfEffectMid", + [15]="IncreaseDurationHigh", + [16]="IncreaseDurationLow", + [17]="IncreaseDurationMid" + }, + supportCountId="Medium" + }, + FlameDashMercenary={ + description="Teleport to a location, damaging enemies and leaving a trail of burning ground.", + familyId="MovementSkill", + hash=56180, + icon="", + id="FlameDashMercenary", + name="Flame Dash", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseDurationHigh", + [8]="IncreaseDurationLow", + [9]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + FlameLinkMercenary={ + description="Targets an ally to apply a buff which links to them for a duration, which grants added fire damage to the linked target. If the target dies while linked, the caster will also die. ", + hash=47364, + icon="", + id="FlameLinkMercenary", + name="Flame Link", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="FlameLinkSpecificAddedFlatHigh", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + FlameSurgeMercenary={ + description="Strikes enemies with a surge of flame. Burning enemies are dealt more damage. Hitting an ignited enemy will create burning ground under them. Damage modifiers don't apply to this burning ground.", + familyId="Infrequent", + hash=8801, + icon="", + id="FlameSurgeMercenary", + name="Flame Surge", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="DamageOverTimeReduceDurationHigh", + [5]="DamageOverTimeReduceDurationLow", + [6]="DamageOverTimeReduceDurationMid", + [7]="FirePenetrationHigh", + [8]="FirePenetrationLow", + [9]="FirePenetrationMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid" + }, + supportCountId="High" + }, + FlameWallMercenary={ + description="Creates a wall of fire for a duration, which deals burning damage to everything in its area. Each enemy that enters the wall also receives a secondary burning debuff which persists for a short duration after leaving the wall. Non-enemy projectiles fired through the wall deal added fire damage and apply the wall's secondary debuff on hit.", + familyId="Infrequent", + hash=57450, + icon="", + id="FlameWallMercenary", + name="Flame Wall", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="EleFocusHigh", + [5]="EleFocusLow", + [6]="EleFocusMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="IncreaseDurationHigh", + [11]="IncreaseDurationLow", + [12]="IncreaseDurationMid" + }, + secondarySkillId="FlameWallMercenaryEncounter", + supportCountId="Medium" + }, + FlameblastMercenary={ + description="Channels to build up a large fiery explosion. The longer it is channelled, the larger the area of effect and damage of the explosion.", + hash=6446, + icon="", + id="FlameblastMercenary", + name="Flameblast", + possibleSupportIds={ + [1]="AilmentDamageHigh", + [2]="AilmentDamageLow", + [3]="AilmentDamageMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ChannelSkillDamageReductionHigh", + [8]="ChannelSkillDamageReductionLow", + [9]="ChannelSkillDamageReductionMid", + [10]="CombustionHigh", + [11]="FirePenetrationHigh", + [12]="FirePenetrationLow", + [13]="FirePenetrationMid", + [14]="FlameblastSpecificStagesHigh", + [15]="IgniteChanceHigh", + [16]="IgniteChanceLow", + [17]="IgniteChanceMid", + [18]="IncreaseAreaOfEffectHigh", + [19]="IncreaseAreaOfEffectLow", + [20]="IncreaseAreaOfEffectMid" + }, + secondarySkillId="FlameblastMercenaryEncounter", + supportCountId="High" + }, + FlammabilityBlasphemyMercenary={ + description="Casts an aura that curses all enemies in an area, lowering their fire resistance and giving them a chance to be ignited when hit.", + hash=39298, + icon="", + id="FlammabilityBlasphemyMercenary", + name="Blasphemy Flammability", + possibleSupportIds={ + }, + supportCountId="None" + }, + FlammabilityMercenary={ + description="Curses all targets in an area, lowering their fire resistance and giving them a chance to be ignited when hit.", + hash=40521, + icon="", + id="FlammabilityMercenary", + name="Flammability", + possibleSupportIds={ + [1]="CurseEffectHigh", + [2]="IncreaseAreaOfEffectHigh", + [3]="IncreaseAreaOfEffectLow", + [4]="IncreaseAreaOfEffectMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid", + [8]="SpellCascadeLow" + }, + supportCountId="Low" + }, + FleshOfferingMercenary={ + description="Consumes a corpse, which temporarily empowers the owners minions with swiftness. The skill consumes other nearby corpses, increasing the duration for each corpse consumed.", + familyId="Infrequent", + hash=61730, + icon="", + id="FleshOfferingMercenary", + name="Flesh Offering", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseDurationHigh", + [8]="IncreaseDurationLow", + [9]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + FlickerStrikeMercenary={ + description="Teleports the character to a nearby enemy and attacks with a melee weapon. Grants a buff that increases movement speed for a duration. The cooldown can be bypassed by expending a Frenzy Charge.", + hash=61669, + icon="", + id="FlickerStrikeMercenary", + name="Flicker Strike", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="FlickerStrikeSpecificConsumeAllImpalesHigh", + [8]="FortifyHigh", + [9]="ImpaleChanceHigh", + [10]="ImpaleChanceLow", + [11]="ImpaleChanceMid", + [12]="MeleePhysHigh", + [13]="MeleePhysLow", + [14]="MeleePhysMid", + [15]="MeleeSplashHigh", + [16]="MultistrikeHigh", + [17]="MultistrikeMid", + [18]="StrikeRangeHigh", + [19]="StrikeRangeLow", + [20]="StrikeRangeMid" + }, + supportCountId="High" + }, + ForbiddenRiteTotemMercenary={ + description="Creates a Spell Totem that casts an exploding projectile towards targets and extra projectiles surrounding it. The projectiles deal chaos damage based on the totem's life and energy shield. Casting this spell damages the totem.", + familyId="Infrequent", + hash=29071, + icon="", + id="ForbiddenRiteTotemMercenary", + name="Forbidden Rite Totem", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ChaosPenHigh", + [8]="ChaosPenLow", + [9]="ChaosPenMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="MultipleProjectilesHigh", + [20]="MultipleProjectilesLow", + [21]="ProjectilesReturnHigh", + [22]="TotemDefencesHigh", + [23]="TotemDefencesLow", + [24]="TotemDefencesMid", + [25]="WitherOnHitHigh", + [26]="WitherOnHitLow", + [27]="WitherOnHitMid" + }, + supportCountId="High" + }, + FrenzyMercenary={ + description="Performs an attack with a ranged weapon that grants a frenzy charge if it hits.", + hash=58592, + icon="", + id="FrenzyMercenary", + name="Frenzy", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="ArrowNovaHigh", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="ForkHigh", + [8]="MultipleProjectilesHigh", + [9]="MultipleProjectilesLow", + [10]="PierceHigh", + [11]="PierceLow", + [12]="PierceMid" + }, + supportCountId="Medium" + }, + FrostBladesMercenary={ + description="Attacks enemies with increased range, releasing icy blades from the first enemy hit which fly at other enemies.", + hash=22105, + icon="", + id="FrostBladesMercenary", + name="Frost Blades", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedLightningHigh", + [5]="AddedLightningLow", + [6]="AddedLightningMid", + [7]="AdditionalChainsLow", + [8]="AdditionalChainsLow", + [9]="AdditionalChainsMid", + [10]="AdditionalChainsMid", + [11]="AttackSpeedHigh", + [12]="AttackSpeedLow", + [13]="AttackSpeedMid", + [14]="ColdPenetrationHigh", + [15]="ColdPenetrationLow", + [16]="ColdPenetrationMid", + [17]="EleDamageWithAttacksHigh", + [18]="EleDamageWithAttacksLow", + [19]="EleDamageWithAttacksMid", + [20]="HypothermiaHigh", + [21]="HypothermiaLow", + [22]="HypothermiaMid", + [23]="MultipleProjectilesHigh", + [24]="MultipleProjectilesLow", + [25]="MultistrikeHigh", + [26]="MultistrikeMid", + [27]="PierceHigh", + [28]="PierceLow", + [29]="PierceMid", + [30]="ProjectilesReturnHigh" + }, + secondarySkillId="FrostBladesMercenaryEncounter", + supportCountId="High" + }, + FrostBombMercenary={ + description="Creates a crystal that pulses with cold for a duration. Each pulse applies a debuff to nearby enemies for a secondary duration which reduces life regeneration rate, and also inflicts Cold Exposure. When the crystal's duration ends, it explodes, dealing heavy cold damage to enemies around it.", + hash=10557, + icon="", + id="FrostBombMercenary", + name="Frost Bomb", + possibleSupportIds={ + [1]="IncreaseAreaOfEffectHigh", + [2]="IncreaseAreaOfEffectLow", + [3]="IncreaseAreaOfEffectMid", + [4]="ReduceDurationHigh", + [5]="ReduceDurationLow", + [6]="ReduceDurationMid", + [7]="SpellCascadeLow" + }, + supportCountId="Low" + }, + FrostShieldMercenary={ + description="Places a Frost Shield that drains energy shield for one second or until none remains, gaining stages while this drain occurs. The Frost Shield takes and prevents some damage from hits of allies while in its area. Enemies in the area are Chilled.", + hash=57491, + icon="", + id="FrostShieldMercenary", + name="Frost Shield", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="IncreaseDurationHigh", + [12]="IncreaseDurationLow", + [13]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + FrostWallMercenary={ + description="Creates a wall of ice which holds back enemies. Targets under the wall are damaged and pushed back.", + familyId="Infrequent", + hash=50009, + icon="", + id="FrostWallMercenary", + name="Frost Wall", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="IncreaseAreaOfEffectHigh", + [3]="IncreaseAreaOfEffectLow", + [4]="IncreaseAreaOfEffectMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid", + [8]="SpellCascadeLow" + }, + supportCountId="Low" + }, + FrostbiteMercenary={ + description="Curses all targets in an area, lowering their cold resistance and giving them a chance to be frozen when hit.", + hash=6479, + icon="", + id="FrostbiteMercenary", + name="Frostbite", + possibleSupportIds={ + [1]="CurseEffectHigh", + [2]="IncreaseAreaOfEffectHigh", + [3]="IncreaseAreaOfEffectLow", + [4]="IncreaseAreaOfEffectMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid", + [8]="SpellCascadeLow" + }, + supportCountId="Low" + }, + FrostblinkMercenary={ + description="Teleport to a location, damaging enemies and leaving Chilled ground in an area at both ends of the teleport.", + familyId="MovementSkill", + hash=40470, + icon="", + id="FrostblinkMercenary", + name="Frostblink", + possibleSupportIds={ + [1]="CooldownSpeedHigh", + [2]="CooldownSpeedLow", + [3]="CooldownSpeedMid", + [4]="FreezeChanceHigh", + [5]="FreezeChanceLow", + [6]="FreezeChanceMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid" + }, + supportCountId="Low" + }, + FrostboltMercenary={ + description="Fires a slow-moving projectile that pierces through enemies, dealing cold damage.", + hash=33663, + icon="", + id="FrostboltMercenary", + name="Frostbolt", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="ColdPenetrationHigh", + [5]="ColdPenetrationLow", + [6]="ColdPenetrationMid", + [7]="FreezeChanceHigh", + [8]="FreezeChanceLow", + [9]="FreezeChanceMid", + [10]="IncreasedProjSpeedHigh", + [11]="IncreasedProjSpeedLow", + [12]="IncreasedProjSpeedMid", + [13]="MultipleProjectilesHigh", + [14]="MultipleProjectilesLow", + [15]="ProjectilesReturnHigh" + }, + secondarySkillId="FrostboltMercenaryEncounter", + supportCountId="High" + }, + GalvanicArrowMercenary={ + description="Fire a trio of electrical arrows that quickly dissipate, vanishing shortly after being loosed. The arrows are fired with such force that they create a burst of lightning, damaging enemies in a cone in front of you.", + hash=27165, + icon="", + id="GalvanicArrowMercenary", + name="Galvanic Arrow", + possibleSupportIds={ + [1]="ArrowNovaHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="EleDamageWithAttacksHigh", + [6]="EleDamageWithAttacksLow", + [7]="EleDamageWithAttacksMid", + [8]="LightningDamageLuckyHigh", + [9]="LightningPenetrationHigh", + [10]="LightningPenetrationLow", + [11]="LightningPenetrationMid", + [12]="MultipleProjectilesHigh", + [13]="MultipleProjectilesLow" + }, + supportCountId="High" + }, + GigaFlameDashMercenary={ + description="Repeatedly teleport to many locations, damaging enemies and leaving trails of dangerous burning ground.", + familyId="Infrequent", + hash=24099, + icon="", + id="GigaFlameDashMercenary", + name="Greater Flame Dash", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="CombustionHigh", + [6]="CooldownSpeedHigh", + [7]="CooldownSpeedLow", + [8]="CooldownSpeedMid", + [9]="DamageOverTimeReduceDurationHigh", + [10]="DamageOverTimeReduceDurationLow", + [11]="DamageOverTimeReduceDurationMid", + [12]="EleFocusHigh", + [13]="EleFocusLow", + [14]="EleFocusMid", + [15]="IncreaseDurationHigh", + [16]="IncreaseDurationLow", + [17]="IncreaseDurationMid" + }, + supportCountId="High" + }, + GigaKineticBlastMercenary={ + description="Fires many projectiles from a Wand that cause series' of area explosions in a secondary radius around their points of impact, each damaging enemies.", + familyId="Infrequent", + hash=44258, + icon="", + id="GigaKineticBlastMercenary", + name="Greater Kinetic Blast", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedCooldownCountHigh", + [5]="AddedLightningHigh", + [6]="AddedLightningLow", + [7]="AddedLightningMid", + [8]="CooldownSpeedHigh", + [9]="CooldownSpeedLow", + [10]="CooldownSpeedMid", + [11]="CritDamageHigh", + [12]="CritDamageLow", + [13]="CritDamageMid", + [14]="CriticalStrikeHigh", + [15]="CriticalStrikeLow", + [16]="CriticalStrikeMid", + [17]="EleDamageWithAttacksHigh", + [18]="EleDamageWithAttacksLow", + [19]="EleDamageWithAttacksMid", + [20]="ForkHigh", + [21]="IncreasedProjSpeedHigh", + [22]="IncreasedProjSpeedLow", + [23]="IncreasedProjSpeedMid", + [24]="MultipleProjectilesHigh", + [25]="MultipleProjectilesLow" + }, + supportCountId="High" + }, + GigaLightningArrowMercenary={ + description="Fires multiple charged arrows which damage enemies by causing them to be struck by a bolt of lightning, which also damages a number of surrounding enemies. Lightning damage dealt by this skill has a chance to sap.", + familyId="Infrequent", + hash=38993, + icon="", + id="GigaLightningArrowMercenary", + name="Greater Lightning Arrow", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="ArrowNovaHigh", + [5]="AttackSpeedHigh", + [6]="AttackSpeedLow", + [7]="AttackSpeedMid", + [8]="EleDamageWithAttacksHigh", + [9]="EleDamageWithAttacksLow", + [10]="EleDamageWithAttacksMid", + [11]="ForkHigh", + [12]="LightningArrowSpecificAddedTargetsHigh", + [13]="LightningDamageLuckyHigh", + [14]="LightningPenetrationHigh", + [15]="LightningPenetrationLow", + [16]="LightningPenetrationMid", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow", + [19]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + GigaRaiseZombieMercenary={ + description="Raises a single gigantic zombie minion from a corpse, which will follow you and attack enemies with a melee strike.", + hash=52491, + icon="", + id="GigaRaiseZombieMercenary", + name="Raise Zombie of Gigantism", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="GiantZombieSpecificSlowZombieHigh", + [5]="IgnoreEnemyPhysMitHigh", + [6]="IgnoreEnemyPhysMitLow", + [7]="IgnoreEnemyPhysMitMid", + [8]="MinionChaosCloudHigh", + [9]="MinionDamageHigh", + [10]="MinionDamageLow", + [11]="MinionDamageMid", + [12]="MinionLifeHigh", + [13]="MinionLifeLow", + [14]="MinionLifeMid", + [15]="MultistrikeHigh", + [16]="MultistrikeMid" + }, + secondarySkillId="GigaRaiseZombieMercenaryEncounter", + supportCountId="High" + }, + GigaShockNovaMercenary={ + description="Repeatedly casts rings of Lightning, followed by larger Lightning novas. Each effect deals lightning damage to enemies caught in the area. Damage from this skill is highly likely to shock.", + familyId="Infrequent", + hash=50290, + icon="", + id="GigaShockNovaMercenary", + name="Greater Shock Nova", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="CriticalStrikeHigh", + [6]="CriticalStrikeLow", + [7]="CriticalStrikeMid", + [8]="GigaShockNovaSpecificAOEHigh", + [9]="IncreaseAreaOfEffectHigh", + [10]="IncreaseAreaOfEffectLow", + [11]="IncreaseAreaOfEffectMid", + [12]="LightningPenetrationHigh", + [13]="LightningPenetrationLow", + [14]="LightningPenetrationMid", + [15]="MaxShockHigh", + [16]="ShockChanceHigh", + [17]="ShockChanceLow", + [18]="ShockChanceMid" + }, + secondarySkillId="GigaShockNovaMercenaryEncounter", + supportCountId="High" + }, + GigaSoulrendMercenary={ + description="Fires a nova of slow moving projectiles that turn towards enemies in front of them, damaging and piercing through those they hit, and leeching some of that damage as energy shield. As the projectiles travel, they repeatedly applies a short but powerful chaos damage over time debuff to each enemy in an area around them.", + familyId="Infrequent", + hash=11671, + icon="", + id="GigaSoulrendMercenary", + name="Greater Soulrend", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="DamageOverTimeReduceDurationHigh", + [8]="DamageOverTimeReduceDurationLow", + [9]="DamageOverTimeReduceDurationMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="ProjectilesReturnHigh", + [19]="SoulrendSpecificBaseDurationHigh" + }, + secondarySkillId="GigaSoulrendMercenaryEncounter", + supportCountId="High" + }, + GigaStormCallMercenary={ + description="Sets markers at many locations. After a short duration, lightning strikes the markers, dealing damage around them.", + familyId="StormcallVariant", + hash=3148, + icon="", + id="GigaStormCallMercenary", + name="Greater Stormcall", + possibleSupportIds={ + [1]="CooldownSpeedHigh", + [2]="CooldownSpeedLow", + [3]="CooldownSpeedMid", + [4]="EleFocusHigh", + [5]="EleFocusLow", + [6]="EleFocusMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="LightningDamageLuckyHigh", + [11]="LightningPenetrationHigh", + [12]="LightningPenetrationLow", + [13]="LightningPenetrationMid", + [14]="ReduceDurationHigh", + [15]="ReduceDurationLow", + [16]="ReduceDurationMid", + [17]="ShockChanceHigh", + [18]="ShockChanceLow", + [19]="ShockChanceMid", + [20]="SpellCascadeHigh", + [21]="SpellCascadeLow" + }, + secondarySkillId="GigaStormCallMercenaryEncounter", + supportCountId="High" + }, + GigaVortexTrapMercenary={ + description="Throw multiple traps that cause icy blasts, dealing cold damage to enemies, and leaving behind whirling vortices which deals cold damage over time and chills enemies caught in them.", + familyId="Infrequent", + hash=3493, + icon="", + id="GigaVortexTrapMercenary", + name="Greater Vortex Trap", + possibleSupportIds={ + [1]="ColdPenetrationHigh", + [2]="ColdPenetrationLow", + [3]="ColdPenetrationMid", + [4]="DotMultiHigh", + [5]="DotMultiLow", + [6]="DotMultiMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="NonDamagingAilmentEffectHigh", + [11]="NonDamagingAilmentEffectLow", + [12]="NonDamagingAilmentEffectMid", + [13]="TrapMineDamageHigh", + [14]="TrapMineDamageLow", + [15]="TrapMineDamageMid", + [16]="TrapMineThrowSpeedHigh", + [17]="TrapMineThrowSpeedLow", + [18]="TrapMineThrowSpeedMid", + [19]="TrapTriggerArcaneSurgeHigh", + [20]="TrapTriggerRadiusHigh", + [21]="TrapTriggerRadiusLow", + [22]="TrapTriggerRadiusMid" + }, + secondarySkillId="GigaVortexTrapMercenaryEncounter", + supportCountId="High" + }, + GlacialHammerMercenary={ + description="Hits enemies, converting some of your physical damage to cold damage. If a non-unique enemy is frozen and is on less than one third life, they will shatter when hit by Glacial Hammer. If striking three times in a row, the third strike will freeze enemies more easily. Requires a Mace, Sceptre or Staff.", + hash=53217, + icon="", + id="GlacialHammerMercenary", + name="Glacial Hammer", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="ColdPenetrationHigh", + [5]="ColdPenetrationLow", + [6]="ColdPenetrationMid", + [7]="FreezeChanceHigh", + [8]="FreezeChanceLow", + [9]="FreezeChanceMid", + [10]="HypothermiaHigh", + [11]="HypothermiaLow", + [12]="HypothermiaMid", + [13]="NonDamagingAilmentEffectHigh", + [14]="NonDamagingAilmentEffectLow", + [15]="NonDamagingAilmentEffectMid", + [16]="StrikeRangeHigh", + [17]="StrikeRangeLow", + [18]="StrikeRangeMid" + }, + supportCountId="High" + }, + GraceMercenary={ + description="Casts an aura that grants evasion.", + hash=2792, + icon="", + id="GraceMercenary", + name="Grace", + possibleSupportIds={ + }, + supportCountId="None" + }, + GroundSlamMercenary={ + description="Slams the ground, creating a wave that travels forward and damages enemies with an increased chance to stun. The wave deals more damage to closer enemies. ", + hash=53728, + icon="", + id="GroundSlamMercenary", + name="Ground Slam", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="FortifyHigh", + [8]="GroundSlamSpecificAngleHigh", + [9]="IncreaseAreaOfEffectHigh", + [10]="IncreaseAreaOfEffectLow", + [11]="IncreaseAreaOfEffectMid", + [12]="LeechHigh", + [13]="LeechLow", + [14]="LeechMid", + [15]="MultistrikeHigh", + [16]="MultistrikeMid", + [17]="PulveriseHigh", + [18]="PulveriseLow", + [19]="PulveriseMid" + }, + supportCountId="High" + }, + HasteMercenary={ + description="Casts an aura that increases the movement speed, attack speed and cast speed.", + hash=52155, + icon="", + id="HasteMercenary", + name="Haste", + possibleSupportIds={ + }, + supportCountId="None" + }, + HatredMercenary={ + description="Casts an aura that grants extra cold damage based on physical damage.", + hash=24482, + icon="", + id="HatredMercenary", + name="Hatred", + possibleSupportIds={ + }, + supportCountId="None" + }, + HeavyStrikeAltMercenary={ + description="Attacks enemies with a forceful blow which has a higher chance to deal double damage the higher your intelligence. Increases and reductions to spell damage apply to attack damage with this skill.", + hash=38103, + icon="", + id="HeavyStrikeAltMercenary", + name="Heavy Strike of Trarthus", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="BrutalityHigh", + [8]="BrutalityLow", + [9]="BrutalityMid", + [10]="FortifyHigh", + [11]="HeavyStrikeSpecificMoreMaxPhysHigh", + [12]="MeleeSplashHigh", + [13]="MultistrikeHigh", + [14]="MultistrikeMid", + [15]="StrikeRangeHigh", + [16]="StrikeRangeLow", + [17]="StrikeRangeMid" + }, + supportCountId="High" + }, + HeavyStrikeMercenary={ + description="Attacks enemies with a forceful blow, with a chance to inflict Vulnerability on hit.", + hash=64565, + icon="", + id="HeavyStrikeMercenary", + name="Heavy Strike of Vulnerability", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="FortifyHigh", + [8]="HeavyStrikeSpecificMoreMaxPhysHigh", + [9]="MaimOnHitHigh", + [10]="MeleePhysHigh", + [11]="MeleePhysLow", + [12]="MeleePhysMid", + [13]="MeleeSplashHigh", + [14]="MultistrikeHigh", + [15]="MultistrikeMid", + [16]="StrikeRangeHigh", + [17]="StrikeRangeLow", + [18]="StrikeRangeMid" + }, + supportCountId="High" + }, + HeraldOfAshMercenary={ + description="Grants a buff providing fire damage based on physical damage. While the buff is active, on enemy kill, other enemies near them will be burned based on the overkill damage. ", + hash=44334, + icon="", + id="HeraldOfAshMercenary", + name="Herald of Ash", + possibleSupportIds={ + }, + supportCountId="None" + }, + HeraldOfIceMercenary={ + description="Grants a buff adding cold damage to spells and attacks. If you shatter an enemy, this skill will cause them to explode and deal AoE cold damage to enemies near them. This damage is not affected by modifiers to spell damage.", + hash=32807, + icon="", + id="HeraldOfIceMercenary", + name="Herald of Ice", + possibleSupportIds={ + }, + supportCountId="None" + }, + HeraldOfPurityMercenary={ + description="Grants a buff which provides more physical damage. When an enemy is killed while this buff is active, this skill will summon a Sentinel of Purity, or refresh the duration and life of an existing one instead if the maximum number is active. The Sentinels of Purity have a single-target melee attack and an area melee attack.", + hash=34212, + icon="", + id="HeraldOfPurityMercenary", + name="Herald of Purity", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="MinionDamageHigh", + [8]="MinionDamageLow", + [9]="MinionDamageMid", + [10]="MinionLifeHigh", + [11]="MinionLifeLow", + [12]="MinionLifeMid", + [13]="MultistrikeHigh", + [14]="MultistrikeMid", + [15]="PulveriseHigh", + [16]="PulveriseLow", + [17]="PulveriseMid" + }, + supportCountId="Medium" + }, + HolyFireMortarMercenary={ + description="Fling a blast of holy flame, which explodes on impact dealing a mixture of fire and physical area damage.", + hash=1577, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="HolyFireMortarMercenary", + name="Holy Mortar", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="CombustionHigh", + [8]="FirePenetrationHigh", + [9]="FirePenetrationLow", + [10]="FirePenetrationMid", + [11]="HolyMortarSpecificCoverInAshHigh", + [12]="IncreaseAreaOfEffectHigh", + [13]="IncreaseAreaOfEffectLow", + [14]="IncreaseAreaOfEffectMid", + [15]="IncreasedProjSpeedHigh", + [16]="IncreasedProjSpeedLow", + [17]="IncreasedProjSpeedMid", + [18]="MultipleProjectilesHigh", + [19]="MultipleProjectilesLow", + [20]="PhysGainAsRandomHigh", + [21]="PhysGainAsRandomLow", + [22]="PhysGainAsRandomMid" + }, + supportCountId="High" + }, + HolyFlameTotemMercenary={ + description="Summons a totem that channels to fire a stream of flame at nearby enemies, and creates an area of consecrated ground around the totem.", + familyId="Infrequent", + hash=47949, + icon="", + id="HolyFlameTotemMercenary", + name="Holy Flame Totem", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CombustionHigh", + [5]="FirePenetrationHigh", + [6]="FirePenetrationLow", + [7]="FirePenetrationMid", + [8]="HolyFlameTotemSpecificConcBlockHigh", + [9]="IncreaseDurationHigh", + [10]="IncreaseDurationLow", + [11]="IncreaseDurationMid", + [12]="IncreasedProjSpeedHigh", + [13]="IncreasedProjSpeedLow", + [14]="IncreasedProjSpeedMid", + [15]="MultiTotemHigh", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="PhysGainAsRandomHigh", + [19]="PhysGainAsRandomLow", + [20]="PhysGainAsRandomMid", + [21]="TotemDefencesHigh", + [22]="TotemDefencesLow", + [23]="TotemDefencesMid" + }, + supportCountId="Medium" + }, + HolyHammersMercenary={ + description="Slams the ground, calling down a Holy Hammer from above. On hitting an enemy, another Hammer will cascade forward, repeating if further enemies are hit, up to a cap. A Power Charge can be expended to call down additional Hammers to either side of the initial slam.", + hash=28506, + icon="", + id="HolyHammersMercenary", + name="Holy Hammers", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="CritDamageHigh", + [5]="CritDamageLow", + [6]="CritDamageMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="EleDamageWithAttacksHigh", + [11]="EleDamageWithAttacksLow", + [12]="EleDamageWithAttacksMid", + [13]="FistOfWarHigh", + [14]="HolyHammersSpecificPowerChargeHigh", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="PulveriseHigh", + [19]="PulveriseLow", + [20]="PulveriseMid" + }, + supportCountId="High" + }, + HolyStrikeMercenary={ + description="Infuse your weapon with holy energy and swing. Successfully hitting an enemy will summon forth a copy of your Main Hand weapon as a Holy Armament. These Holy Armaments are undamageable minions, and will attack the enemies you target with Holy Strike.", + hash=38655, + icon="", + id="HolyStrikeMercenary", + name="Holy Strike", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="HallowHigh", + [5]="HolyStrikesSpecificAdditionalMinionHigh", + [6]="IncreaseAreaOfEffectHigh", + [7]="IncreaseAreaOfEffectLow", + [8]="IncreaseAreaOfEffectMid", + [9]="MeleeSplashHigh", + [10]="MinionDamageHigh", + [11]="MinionDamageLow", + [12]="MinionDamageMid", + [13]="MultistrikeHigh", + [14]="MultistrikeMid" + }, + supportCountId="High" + }, + HydraForkArrowMercenary={ + description="Fires an arrow which forks multiple times as it travels and deals high cold damage to those hit.", + familyId="Infrequent", + hash=18232, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="HydraForkArrowMercenary", + name="Frigid Forkshot", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="ColdPenetrationHigh", + [4]="ColdPenetrationLow", + [5]="ColdPenetrationMid", + [6]="CooldownSpeedHigh", + [7]="CooldownSpeedLow", + [8]="CooldownSpeedMid", + [9]="EleDamageWithAttacksHigh", + [10]="EleDamageWithAttacksLow", + [11]="EleDamageWithAttacksMid", + [12]="ForkHigh", + [13]="FreezeChanceHigh", + [14]="FreezeChanceLow", + [15]="FreezeChanceMid", + [16]="HypothermiaHigh", + [17]="HypothermiaLow", + [18]="HypothermiaMid", + [19]="PierceHigh", + [20]="PierceLow", + [21]="PierceMid", + [22]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + IceCrashMercenary={ + description="Slams the ground, damaging enemies in an area around the impact in three stages of increasing size. Enemies take slightly less damage on the second and third stage, and can only be hit by one stage.", + hash=11018, + icon="", + id="IceCrashMercenary", + name="Ice Crash", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="ColdPenetrationHigh", + [5]="ColdPenetrationLow", + [6]="ColdPenetrationMid", + [7]="FistOfWarHigh", + [8]="IceCrashSpecificTertiaryRadiusHigh", + [9]="IncreaseAreaOfEffectHigh", + [10]="IncreaseAreaOfEffectLow", + [11]="IncreaseAreaOfEffectMid", + [12]="PulveriseHigh", + [13]="PulveriseLow", + [14]="PulveriseMid" + }, + supportCountId="High" + }, + IceNovaMercenary={ + description="A circle of ice expands from the caster.", + hash=61497, + icon="", + id="IceNovaMercenary", + name="Ice Nova", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="BrittleChanceHigh", + [5]="CastSpeedHigh", + [6]="CastSpeedLow", + [7]="CastSpeedMid", + [8]="ColdPenetrationHigh", + [9]="ColdPenetrationLow", + [10]="ColdPenetrationMid", + [11]="CriticalStrikeHigh", + [12]="CriticalStrikeLow", + [13]="CriticalStrikeMid", + [14]="EleFocusHigh", + [15]="EleFocusLow", + [16]="EleFocusMid", + [17]="FreezeChanceHigh", + [18]="FreezeChanceLow", + [19]="FreezeChanceMid", + [20]="IceNovaSpecificFirePerChillHigh", + [21]="NonDamagingAilmentEffectHigh", + [22]="NonDamagingAilmentEffectLow", + [23]="NonDamagingAilmentEffectMid" + }, + secondarySkillId="IceNovaMercenaryEncounter", + supportCountId="High" + }, + IceNovaProjectedMercenary={ + description="A circle of ice expands from the target.", + hash=61471, + icon="", + id="IceNovaProjectedMercenary", + name="Ice Nova of Projection", + possibleSupportIds={ + [1]="BrittleChanceHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="ColdPenetrationHigh", + [6]="ColdPenetrationLow", + [7]="ColdPenetrationMid", + [8]="CriticalStrikeHigh", + [9]="CriticalStrikeLow", + [10]="CriticalStrikeMid", + [11]="EleFocusHigh", + [12]="EleFocusLow", + [13]="EleFocusMid", + [14]="FreezeChanceHigh", + [15]="FreezeChanceLow", + [16]="FreezeChanceMid", + [17]="NonDamagingAilmentEffectHigh", + [18]="NonDamagingAilmentEffectLow", + [19]="NonDamagingAilmentEffectMid" + }, + secondarySkillId="IceNovaProjectedMercenaryEncounter", + supportCountId="High" + }, + IceShotMercenary={ + description="Fires an arrow that converts some physical damage to cold on its target and converts all physical damage to cold in a cone behind that target.", + hash=11495, + icon="", + id="IceShotMercenary", + name="Ice Shot", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="ColdPenetrationHigh", + [4]="ColdPenetrationLow", + [5]="ColdPenetrationMid", + [6]="EleDamageWithAttacksHigh", + [7]="EleDamageWithAttacksLow", + [8]="EleDamageWithAttacksMid", + [9]="ForkHigh", + [10]="HypothermiaHigh", + [11]="HypothermiaLow", + [12]="HypothermiaMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="PierceHigh", + [19]="PierceLow", + [20]="PierceMid", + [21]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + IceTrapMercenary={ + description="Throws a trap that creates a series of icy runic explosions when triggered, dealing cold damage to all enemies caught in the blasts.", + hash=62997, + icon="", + id="IceTrapMercenary", + name="Ice Trap", + possibleSupportIds={ + [1]="ColdPenetrationHigh", + [2]="ColdPenetrationLow", + [3]="ColdPenetrationMid", + [4]="ConcentratedEffectHigh", + [5]="ConcentratedEffectLow", + [6]="ConcentratedEffectMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="MultiTrapHigh", + [11]="NonDamagingAilmentEffectHigh", + [12]="NonDamagingAilmentEffectLow", + [13]="NonDamagingAilmentEffectMid", + [14]="TrapMineDamageHigh", + [15]="TrapMineDamageLow", + [16]="TrapMineDamageMid", + [17]="TrapMineThrowSpeedHigh", + [18]="TrapMineThrowSpeedLow", + [19]="TrapMineThrowSpeedMid", + [20]="TrapTriggerArcaneSurgeHigh", + [21]="TrapTriggerRadiusHigh", + [22]="TrapTriggerRadiusLow", + [23]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + IcestormMercenary={ + description="Icy bolts rain down over the targeted area. They explode when landing, dealing damage to nearby enemies and chilling them, as well as causing patches of chilled ground.", + familyId="Infrequent", + hash=28637, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="IcestormMercenary", + name="Icestorm", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="ColdPenetrationHigh", + [5]="ColdPenetrationLow", + [6]="ColdPenetrationMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="HypothermiaHigh", + [11]="HypothermiaLow", + [12]="HypothermiaMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="IncreaseDurationHigh", + [17]="IncreaseDurationLow", + [18]="IncreaseDurationMid", + [19]="NonDamagingAilmentEffectHigh", + [20]="NonDamagingAilmentEffectLow", + [21]="NonDamagingAilmentEffectMid", + [22]="SpellCascadeHigh", + [23]="SpellCascadeLow" + }, + supportCountId="High" + }, + InfernalBlowAltMercenary={ + description="Applies a charged debuff to themselves the first time the mercenary hits an enemy with this skill. Upon reaching 6 charges, or charges expiring, the charged debuff is removed to damage nearby enemies.", + hash=17147, + icon="", + id="InfernalBlowAltMercenary", + name="Infernal Blow of Immolation", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="AttackSpeedHigh", + [7]="AttackSpeedLow", + [8]="AttackSpeedMid", + [9]="CombustionHigh", + [10]="EleDamageWithAttacksHigh", + [11]="EleDamageWithAttacksLow", + [12]="EleDamageWithAttacksMid", + [13]="FirePenetrationHigh", + [14]="FirePenetrationLow", + [15]="FirePenetrationMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="MultistrikeHigh", + [20]="MultistrikeMid" + }, + secondarySkillId="InfernalBlowAltMercenaryEncounter", + supportCountId="High" + }, + InfernalCryMercenary={ + description="Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. The user and nearby allies gain a buff that grants a portion of their physical damage as extra fire damage. In addition to being taunted, enemies are inflicted with a secondary debuff causing them to explode when they die, dealing fire damage in an area.", + hash=59259, + icon="", + id="InfernalCryMercenary", + name="Infernal Cry", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="WarcryRageHigh", + [12]="WarcryRageLow", + [13]="WarcryRageMid", + [14]="WarcrySpeedHigh", + [15]="WarcrySpeedLow", + [16]="WarcrySpeedMid" + }, + supportCountId="Low" + }, + InspiringCryMercenary={ + description="Taunts nearby enemies while granting increased damage and mana regeneration rate to nearby allies.", + hash=65473, + icon="", + id="InspiringCryMercenary", + name="Inspiring Cry", + possibleSupportIds={ + [1]="CooldownSpeedHigh", + [2]="CooldownSpeedLow", + [3]="CooldownSpeedMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="IncreaseDurationHigh", + [8]="IncreaseDurationLow", + [9]="IncreaseDurationMid", + [10]="WarcrySpeedHigh", + [11]="WarcrySpeedLow", + [12]="WarcrySpeedMid" + }, + supportCountId="Low" + }, + IntimidatingCryMercenary={ + description="Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. The user and nearby allies gain a buff that grants movement speed.", + hash=38311, + icon="", + id="IntimidatingCryMercenary", + name="Intimidating Cry", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="WarcryRageHigh", + [12]="WarcryRageLow", + [13]="WarcryRageMid", + [14]="WarcrySpeedHigh", + [15]="WarcrySpeedLow", + [16]="WarcrySpeedMid" + }, + secondarySkillId="IntimidatingCryMercenaryEncounter", + supportCountId="Low" + }, + KineticBlastAltMercenary={ + description="Fires a projectile from a Wand that causes a series of area explosions in a secondary radius around its point of impact, each damaging enemies.", + hash=16356, + icon="", + id="KineticBlastAltMercenary", + name="Kinetic Blast of Clustering", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedLightningHigh", + [5]="AddedLightningLow", + [6]="AddedLightningMid", + [7]="AdditionalChainsLow", + [8]="AdditionalChainsMid", + [9]="AttackSpeedHigh", + [10]="AttackSpeedLow", + [11]="AttackSpeedMid", + [12]="CritDamageHigh", + [13]="CritDamageLow", + [14]="CritDamageMid", + [15]="CriticalStrikeHigh", + [16]="CriticalStrikeLow", + [17]="CriticalStrikeMid", + [18]="EleDamageWithAttacksHigh", + [19]="EleDamageWithAttacksLow", + [20]="EleDamageWithAttacksMid", + [21]="ForkHigh", + [22]="MultipleProjectilesHigh", + [23]="MultipleProjectilesLow", + [24]="PierceHigh", + [25]="PierceLow", + [26]="PierceMid", + [27]="ProjectilesReturnHigh", + [28]="SacredWispsHigh" + }, + supportCountId="High" + }, + KineticBoltMercenary={ + description="Fires a projectile that changes direction in a zig-zag pattern at regular intervals or when hitting enemies. Each time it changes direction, a secondary projectile breaks off, flying in the direction it changed away from.", + hash=12583, + icon="", + id="KineticBoltMercenary", + name="Kinetic Bolt", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedLightningHigh", + [5]="AddedLightningLow", + [6]="AddedLightningMid", + [7]="AdditionalChainsLow", + [8]="AdditionalChainsMid", + [9]="AttackSpeedHigh", + [10]="AttackSpeedLow", + [11]="AttackSpeedMid", + [12]="CritDamageHigh", + [13]="CritDamageLow", + [14]="CritDamageMid", + [15]="CriticalStrikeHigh", + [16]="CriticalStrikeLow", + [17]="CriticalStrikeMid", + [18]="EleDamageWithAttacksHigh", + [19]="EleDamageWithAttacksLow", + [20]="EleDamageWithAttacksMid", + [21]="MultipleProjectilesHigh", + [22]="MultipleProjectilesLow", + [23]="PierceHigh", + [24]="PierceLow", + [25]="PierceMid", + [26]="SacredWispsHigh" + }, + supportCountId="High" + }, + KineticRainAltXMercenary={ + description="Swing your wand to cause a number of projectiles to rain down within a large area in front of you, directly targeting the locations of enemies in the area. The locations where each projectile will land are shown with markers before they fall. Each projectile explodes when hitting the ground, dealing area damage.", + hash=32089, + icon="", + id="KineticRainAltXMercenary", + name="Kinetic Rain of Impact", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedLightningHigh", + [5]="AddedLightningLow", + [6]="AddedLightningMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="EleDamageWithAttacksHigh", + [17]="EleDamageWithAttacksLow", + [18]="EleDamageWithAttacksMid", + [19]="IncreaseAreaOfEffectHigh", + [20]="IncreaseAreaOfEffectLow", + [21]="IncreaseAreaOfEffectMid", + [22]="MultipleProjectilesHigh", + [23]="MultipleProjectilesLow", + [24]="SacredWispsHigh" + }, + supportCountId="High" + }, + LacerateMercenary={ + description="Slashes twice, releasing waves of force that damage enemies they hit. Enemies in the middle of the slashes can be hit by both. The slashes will have a chance to inflict bleeding in Blood Stance, or have a wider angle in Sand Stance. ", + hash=8136, + icon="", + id="LacerateMercenary", + name="Lacerate", + possibleSupportIds={ + [1]="AilmentDamageHigh", + [2]="AilmentDamageLow", + [3]="AilmentDamageMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="BleedHigh", + [8]="BleedLow", + [9]="BleedMid", + [10]="BrutalityHigh", + [11]="BrutalityLow", + [12]="BrutalityMid", + [13]="DotMultiHigh", + [14]="DotMultiLow", + [15]="DotMultiMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="MeleePhysHigh", + [20]="MeleePhysLow", + [21]="MeleePhysMid", + [22]="MultistrikeHigh", + [23]="MultistrikeMid" + }, + supportCountId="High" + }, + LancingSteelMercenary={ + description="Thrust an Axe or Sword forward, consuming Steel Shards to form a cluster of shards. The cluster will fire a number of projectiles in sequence, aiming at enemies in front of or close to it. Steel Shards are gained with the Call of Steel Skill.", + hash=43812, + icon="", + id="LancingSteelMercenary", + name="Lancing Steel", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BleedHigh", + [5]="BleedLow", + [6]="BleedMid", + [7]="BrutalityHigh", + [8]="BrutalityLow", + [9]="BrutalityMid", + [10]="ImpaleChanceHigh", + [11]="ImpaleChanceLow", + [12]="ImpaleChanceMid", + [13]="IncreasedProjSpeedHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="LancingSteelSpecificRandomProjHigh", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow", + [19]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + LeapSlamMercenary={ + description="Jump through the air, damaging and knocking back enemies when landing.", + hash=2135, + icon="", + id="LeapSlamMercenary", + name="Leap Slam", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="LeapSlamSpecificFrenzyOnHitHigh", + [11]="PulveriseHigh", + [12]="PulveriseLow", + [13]="PulveriseMid" + }, + supportCountId="Low" + }, + LeapSlamMercenaryAlt={ + description="Jump a short distance through the air, damaging and knocking back enemies with your weapon where you land. Enemies you would land on are pushed out of the way.", + hash=41915, + icon="", + id="LeapSlamMercenaryAlt", + name="Leap Slam of Groundbreaking", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="FortifyHigh", + [11]="IgnoreEnemyPhysMitHigh", + [12]="IgnoreEnemyPhysMitLow", + [13]="IgnoreEnemyPhysMitMid", + [14]="IncreaseAreaOfEffectHigh", + [15]="IncreaseAreaOfEffectLow", + [16]="IncreaseAreaOfEffectMid", + [17]="LeapSlamSpecificFrenzyOnHitHigh", + [18]="PulveriseHigh", + [19]="PulveriseLow", + [20]="PulveriseMid", + [21]="RageOnMeleeHitHigh", + [22]="RageOnMeleeHitLow", + [23]="RageOnMeleeHitMid" + }, + supportCountId="High" + }, + LightningArrowMercenary={ + description="Fires a charged arrow which damages enemies by causing them to be struck by a bolt of lightning, which also damages a number of surrounding enemies.", + hash=41051, + icon="", + id="LightningArrowMercenary", + name="Lightning Arrow", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="ArrowNovaHigh", + [5]="AttackSpeedHigh", + [6]="AttackSpeedLow", + [7]="AttackSpeedMid", + [8]="EleDamageWithAttacksHigh", + [9]="EleDamageWithAttacksLow", + [10]="EleDamageWithAttacksMid", + [11]="ForkHigh", + [12]="LightningArrowSpecificAddedTargetsHigh", + [13]="LightningDamageLuckyHigh", + [14]="LightningPenetrationHigh", + [15]="LightningPenetrationLow", + [16]="LightningPenetrationMid", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow", + [19]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + LightningSpireTrapMercenary={ + description="Throws a trap which, once triggered, will repeatedly strike multiple areas around it for a duration, dealing lightning damage.", + familyId="Infrequent", + hash=8075, + icon="", + id="LightningSpireTrapMercenary", + name="Lightning Spire Trap", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AddedLightningHigh", + [3]="AddedLightningLow", + [4]="AddedLightningMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="LightningDamageLuckyHigh", + [12]="LightningPenetrationHigh", + [13]="LightningPenetrationLow", + [14]="LightningPenetrationMid", + [15]="LightningSpireSpecificBeamsHigh", + [16]="TrapMineDamageHigh", + [17]="TrapMineDamageLow", + [18]="TrapMineDamageMid", + [19]="TrapMineThrowSpeedHigh", + [20]="TrapMineThrowSpeedLow", + [21]="TrapMineThrowSpeedMid", + [22]="TrapTriggerRadiusHigh", + [23]="TrapTriggerRadiusLow", + [24]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + LightningStrikeFireMercenary={ + description="Swings with fiery energies. In addition to converting some physical damage to fire damage, the stored energy is released from the weapon as projectiles as you strike, flying out to hit farther-away enemies. The projectiles cannot miss if the melee attack hit a target.", + hash=19178, + icon="", + id="LightningStrikeFireMercenary", + name="Flamebolt Strike", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsLow", + [6]="AdditionalChainsMid", + [7]="AdditionalChainsMid", + [8]="CombustionHigh", + [9]="EleDamageWithAttacksHigh", + [10]="EleDamageWithAttacksLow", + [11]="EleDamageWithAttacksMid", + [12]="FirePenetrationHigh", + [13]="FirePenetrationLow", + [14]="FirePenetrationMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="MultipleProjectilesHigh", + [19]="MultipleProjectilesLow", + [20]="PierceHigh", + [21]="PierceLow", + [22]="PierceMid", + [23]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + LightningTrapMercenary={ + description="Throws a trap that launches a ring of projectiles through the enemy that set it off, dealing lightning damage to them and subsequent targets.", + hash=17037, + icon="", + id="LightningTrapMercenary", + name="Lightning Trap", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="LightningDamageLuckyHigh", + [7]="LightningPenetrationHigh", + [8]="LightningPenetrationLow", + [9]="LightningPenetrationMid", + [10]="LightningTrapSpecificShockSlowHigh", + [11]="MultiTrapHigh", + [12]="MultipleProjectilesHigh", + [13]="MultipleProjectilesLow", + [14]="PierceHigh", + [15]="PierceLow", + [16]="PierceMid", + [17]="TrapChargeGenHigh", + [18]="TrapMineDamageHigh", + [19]="TrapMineDamageLow", + [20]="TrapMineDamageMid", + [21]="TrapMineThrowSpeedHigh", + [22]="TrapMineThrowSpeedLow", + [23]="TrapMineThrowSpeedMid", + [24]="TrapTriggerArcaneSurgeHigh", + [25]="TrapTriggerRadiusHigh", + [26]="TrapTriggerRadiusLow", + [27]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + LightningWarpMercenary={ + description="Waits for a duration before teleporting to a targeted destination, with the duration based on distance and movement speed. When the teleport occurs, lightning damage is dealt both around the area of arrival and departure.", + familyId="MovementSkill", + hash=28757, + icon="", + id="LightningWarpMercenary", + name="Lightning Warp", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="ReduceDurationHigh", + [8]="ReduceDurationLow", + [9]="ReduceDurationMid" + }, + supportCountId="Low" + }, + LightningWarpPhysMercenary={ + description="Teleport to a targeted destination. When the teleport occurs, physical damage is dealt to the area around both the origin and the destination.", + hash=22724, + icon="", + id="LightningWarpPhysMercenary", + name="Bloody Warp", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="PhysGainAsChaosHigh", + [14]="PhysGainAsChaosMid" + }, + supportCountId="Low" + }, + LightningWarpTrapsMercenary={ + description="Throws a trap which, once triggered, teleports to a targeted destination. When the teleport occurs, lightning damage is dealt to the area around both where the trap was and where it teleported to. ", + hash=5247, + icon="", + id="LightningWarpTrapsMercenary", + name="Lightning Warp Trap", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="LightningDamageLuckyHigh", + [8]="LightningPenetrationHigh", + [9]="LightningPenetrationLow", + [10]="LightningPenetrationMid", + [11]="MultiTrapHigh", + [12]="TrapMineDamageHigh", + [13]="TrapMineDamageLow", + [14]="TrapMineDamageMid", + [15]="TrapMineThrowSpeedHigh", + [16]="TrapMineThrowSpeedLow", + [17]="TrapMineThrowSpeedMid", + [18]="TrapTriggerArcaneSurgeHigh", + [19]="TrapTriggerRadiusHigh", + [20]="TrapTriggerRadiusLow", + [21]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + LunarisSpellBarrageTrapMercenary={ + description="[DNT] UNUSED", + hash=60048, + icon="Art/2DArt/SkillIcons/HouseCyaxanSkill.dds", + id="LunarisSpellBarrageTrapMercenary", + name="[DNT] UNUSED", + possibleSupportIds={ + [1]="ColdPenetrationHigh", + [2]="ColdPenetrationLow", + [3]="ColdPenetrationMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="MultiTrapHigh", + [8]="TrapMineDamageHigh", + [9]="TrapMineDamageLow", + [10]="TrapMineDamageMid", + [11]="TrapMineThrowSpeedHigh", + [12]="TrapMineThrowSpeedLow", + [13]="TrapMineThrowSpeedMid", + [14]="TrapTriggerArcaneSurgeHigh", + [15]="TrapTriggerRadiusHigh", + [16]="TrapTriggerRadiusLow", + [17]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + MalevolenceMercenary={ + description="Casts an aura that multiplies damage over time and increases skill effect duration.", + hash=1516, + icon="", + id="MalevolenceMercenary", + name="Malevolence", + possibleSupportIds={ + }, + supportCountId="None" + }, + MassEnduranceMercenary={ + description="Grants endurance charges to all nearby allies.", + hash=57171, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="MassEnduranceMercenary", + name="Endure", + possibleSupportIds={ + }, + supportCountId="None" + }, + MassFrenzyMercenary={ + description="Grants frenzy charges to all nearby allies.", + hash=59409, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="MassFrenzyMercenary", + name="Incite", + possibleSupportIds={ + }, + supportCountId="None" + }, + MercenaryLightningDelayedBlast={ + description="Creates a delayed explosion at a targeted area which unnerves enemies on hit. The explosion does physical damage partially converted to lightning.", + familyId="Infrequent", + hash=19034, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="MercenaryLightningDelayedBlast", + name="Unnerving Blast", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CriticalStrikeHigh", + [5]="CriticalStrikeLow", + [6]="CriticalStrikeMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="LightningPenetrationHigh", + [11]="LightningPenetrationLow", + [12]="LightningPenetrationMid", + [13]="PhysGainAsRandomHigh", + [14]="PhysGainAsRandomLow", + [15]="PhysGainAsRandomMid", + [16]="ShockChanceLow", + [17]="ShockChanceMid" + }, + supportCountId="High" + }, + MeteorUpheavalMercenary={ + description="Call a meteor from the skies, which crashes down dealing area fire damage to those it hits.", + familyId="Infrequent", + hash=40723, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="MeteorUpheavalMercenary", + name="Meteor", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AddedFireHigh", + [3]="AddedFireLow", + [4]="AddedFireMid", + [5]="CastSpeedHigh", + [6]="CastSpeedLow", + [7]="CastSpeedMid", + [8]="CombustionHigh", + [9]="CooldownSpeedHigh", + [10]="CooldownSpeedLow", + [11]="CooldownSpeedMid", + [12]="FirePenetrationHigh", + [13]="FirePenetrationLow", + [14]="FirePenetrationMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="IncreaseDurationHigh", + [19]="IncreaseDurationLow", + [20]="IncreaseDurationMid", + [21]="PhysGainAsRandomHigh", + [22]="PhysGainAsRandomLow", + [23]="PhysGainAsRandomMid" + }, + secondarySkillId="MeteorUpheavalMercenaryEncounter", + supportCountId="High" + }, + MirrorArrowMercenary={ + description="Fires an arrow at the target destination. When the arrow lands, a clone is summoned.", + hash=65447, + icon="", + id="MirrorArrowMercenary", + name="Mirror Arrow", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedCooldownCountHigh", + [5]="AdditionalChainsLow", + [6]="AdditionalChainsMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="CooldownSpeedHigh", + [11]="CooldownSpeedLow", + [12]="CooldownSpeedMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid", + [16]="IncreasedProjSpeedHigh", + [17]="IncreasedProjSpeedLow", + [18]="IncreasedProjSpeedMid", + [19]="MinionDamageHigh", + [20]="MinionDamageLow", + [21]="MinionDamageMid", + [22]="MinionLifeHigh", + [23]="MinionLifeLow", + [24]="MinionLifeMid", + [25]="MultipleProjectilesHigh", + [26]="MultipleProjectilesLow", + [27]="PierceHigh", + [28]="PierceLow", + [29]="PierceMid" + }, + supportCountId="High" + }, + MoltenShellMercenary={ + description="Applies a buff that adds armour, and can take some of the damage from hits before being depleted.", + hash=21036, + icon="", + id="MoltenShellMercenary", + name="Molten Shell", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="MoltenShellSpecificPDRHigh" + }, + supportCountId="Low" + }, + MoltenStrikeHolyMercenary={ + description="Attacks with physical and lightning damage. This attack causes balls of holy energy to launch forth from the enemies hit, divided amongst all enemies hit by the strike. These will deal area attack damage to enemies where they land.", + hash=53518, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="MoltenStrikeHolyMercenary", + name="Sanctified Strike", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="EleDamageWithAttacksHigh", + [5]="EleDamageWithAttacksLow", + [6]="EleDamageWithAttacksMid", + [7]="HolyMoltenStrikeSpecificLightningExposureHigh", + [8]="IncreasedProjSpeedHigh", + [9]="IncreasedProjSpeedLow", + [10]="IncreasedProjSpeedMid", + [11]="MultipleProjectilesHigh", + [12]="MultipleProjectilesLow", + [13]="PhysGainAsRandomHigh", + [14]="PhysGainAsRandomLow", + [15]="PhysGainAsRandomMid", + [16]="ReducedProjSpeedHigh", + [17]="ReducedProjSpeedLow", + [18]="ReducedProjSpeedMid" + }, + supportCountId="High" + }, + MoltenStrikeMercenary={ + description="Attacks with physical and fire damage. This attack causes balls of molten magma to launch forth from the enemies hit, divided amongst all enemies hit by the strike. These will deal area attack damage to enemies where they land.", + hash=899, + icon="", + id="MoltenStrikeMercenary", + name="Molten Strike", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="CombustionHigh", + [7]="EleDamageWithAttacksHigh", + [8]="EleDamageWithAttacksLow", + [9]="EleDamageWithAttacksMid", + [10]="FirePenetrationHigh", + [11]="FirePenetrationLow", + [12]="FirePenetrationMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="MoltenStrikeSpecificExtraProjHigh", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow" + }, + supportCountId="High" + }, + MoltenStrikePoisonMercenary={ + description="Attacks with physical and chaos damage. This attack causes balls of unholy energy to launch forth from the enemies hit, divided amongst all enemies hit by the strike. These will deal area attack damage to enemies where they land.", + hash=36446, + icon="", + id="MoltenStrikePoisonMercenary", + name="Profane Strike", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="AilmentDamageHigh", + [5]="AilmentDamageLow", + [6]="AilmentDamageMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="IncreasedProjSpeedHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="PhysGainAsChaosHigh", + [19]="PhysGainAsChaosMid", + [20]="PoisonChanceHigh", + [21]="PoisonChanceLow", + [22]="PoisonChanceMid" + }, + supportCountId="High" + }, + OfferingOfJudgementChaosMercenary={ + description="Creates a profane altar which continually deals chaos damage over time to enemies around it.", + familyId="Infrequent", + hash=50670, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="OfferingOfJudgementChaosMercenary", + name="Altar of Chaos", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="DamageOverTimeReduceDurationHigh", + [6]="DamageOverTimeReduceDurationLow", + [7]="DamageOverTimeReduceDurationMid", + [8]="DotMultiHigh", + [9]="DotMultiLow", + [10]="DotMultiMid", + [11]="IncreaseDurationHigh", + [12]="IncreaseDurationLow", + [13]="IncreaseDurationMid", + [14]="MultipleProjectilesHigh", + [15]="MultipleProjectilesLow" + }, + supportCountId="High" + }, + OrbOfStormsMercenary={ + description="Creates a stationary electrical orb that strikes enemies in its area of effect with beams of lightning that can then split to hit more enemies. ", + familyId="Infrequent", + hash=11879, + icon="", + id="OrbOfStormsMercenary", + name="Orb of Storms", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="IncreaseAreaOfEffectHigh", + [4]="IncreaseAreaOfEffectLow", + [5]="IncreaseAreaOfEffectMid", + [6]="OrbOfStormsSpecificShockCritKnockHigh" + }, + supportCountId="Medium" + }, + PerforateMercenary={ + description="Smash the ground to bring forth multiple spears to damage enemies. When in Blood Stance, multiple spikes burst from the ground in sequence, able to hit enemies multiple times. In Sand Stance, the spikes are thrust outwards. ", + hash=54006, + icon="", + id="PerforateMercenary", + name="Perforate", + possibleSupportIds={ + [1]="AilmentDamageHigh", + [2]="AilmentDamageLow", + [3]="AilmentDamageMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="BleedHigh", + [8]="BleedLow", + [9]="BleedMid", + [10]="BrutalityHigh", + [11]="BrutalityLow", + [12]="BrutalityMid", + [13]="DotMultiHigh", + [14]="DotMultiLow", + [15]="DotMultiMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="MeleePhysHigh", + [20]="MeleePhysLow", + [21]="MeleePhysMid", + [22]="MultistrikeHigh", + [23]="MultistrikeMid", + [24]="PerforateSpecificSpikesHigh" + }, + supportCountId="High" + }, + PestilentStrikeMercenary={ + description="Attacks enemies inflicting a debuff on hit. If a debuffed enemy dies while poisoned, Pestilent Strike inflicts a secondary chaos damage over time debuff on enemies around them, based on the poisons on the slain enemy. ", + hash=12262, + icon="", + id="PestilentStrikeMercenary", + name="Pestilent Strike", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="AilmentDamageHigh", + [5]="AilmentDamageLow", + [6]="AilmentDamageMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="MeleeSplashHigh", + [14]="MultistrikeHigh", + [15]="MultistrikeMid", + [16]="PhysGainAsChaosHigh", + [17]="PhysGainAsChaosMid", + [18]="PoisonChanceHigh", + [19]="PoisonChanceLow", + [20]="PoisonChanceMid", + [21]="StrikeRangeHigh", + [22]="StrikeRangeLow", + [23]="StrikeRangeMid" + }, + supportCountId="High" + }, + PhysStormCallMercenary={ + description="[DNT] Unused", + hash=11256, + icon="", + id="PhysStormCallMercenary", + name="[DNT] Unused", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="BrutalityHigh", + [3]="BrutalityLow", + [4]="BrutalityMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IgnoreEnemyPhysMitHigh", + [9]="IgnoreEnemyPhysMitLow", + [10]="IgnoreEnemyPhysMitMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="PhysGainAsChaosHigh", + [15]="PhysGainAsChaosMid", + [16]="ReduceDurationHigh", + [17]="ReduceDurationLow", + [18]="ReduceDurationMid", + [19]="SpellCascadeHigh", + [20]="SpellCascadeLow" + }, + supportCountId="High" + }, + PhysicalAegisMercenary={ + description="Surrounds the caster with a physical barrier which will absorb incoming physical damage up to a point, then break. This barrier will recharge over time.", + hash=17015, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="PhysicalAegisMercenary", + name="Physical Aegis", + possibleSupportIds={ + }, + secondarySkillId="PhysicalAegisMercenaryEncounter", + supportCountId="None" + }, + PhysicalBeaconMercenary={ + description="Creates numerous beacons in a large area which explode after a delay, dealing physical area damage. Each explosion creates a patch of consecrated ground.", + familyId="Infrequent", + hash=50866, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="PhysicalBeaconMercenary", + name="Beacons of Faith", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="BrutalityHigh", + [3]="BrutalityLow", + [4]="BrutalityMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="IncreaseDurationHigh", + [12]="IncreaseDurationLow", + [13]="IncreaseDurationMid", + [14]="PhysGainAsRandomHigh", + [15]="PhysGainAsRandomLow", + [16]="PhysGainAsRandomMid" + }, + supportCountId="High" + }, + PoachersMarkMercenary={ + description="Curses an enemy, lowering their physical damage reduction, and adding physical damage to all hits against them. Attacking the cursed enemy will grant life and mana, and killing them will grant a frenzy charge. ", + hash=27805, + icon="", + id="PoachersMarkMercenary", + name="Poacher's Mark", + possibleSupportIds={ + }, + supportCountId="None" + }, + PowerSiphonMercenary={ + description="Fires your wand to fire a single projectile each at a number of nearby enemies, granting a power charge if an enemy is killed by, or soon after, the hit.", + hash=26705, + icon="", + id="PowerSiphonMercenary", + name="Power Siphon", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AddedLightningHigh", + [5]="AddedLightningLow", + [6]="AddedLightningMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="EleDamageWithAttacksHigh", + [17]="EleDamageWithAttacksLow", + [18]="EleDamageWithAttacksMid", + [19]="MultipleProjectilesHigh", + [20]="MultipleProjectilesLow" + }, + supportCountId="Medium" + }, + PrecisionMercenary={ + description="Casts an aura that grants accuracy and critical strike chance.", + hash=36279, + icon="", + id="PrecisionMercenary", + name="Precision", + possibleSupportIds={ + }, + supportCountId="None" + }, + PrideMercenary={ + description="Casts an aura that causes nearby enemies to take more physical damage.", + hash=18793, + icon="", + id="PrideMercenary", + name="Pride", + possibleSupportIds={ + }, + supportCountId="None" + }, + ProximityShieldMercenary={ + description="Creates a barrier for a short duration which will negate incoming damage that originates from outside the barrier.", + hash=16018, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="ProximityShieldMercenary", + name="Proximity Shield", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="IncreaseDurationHigh", + [11]="IncreaseDurationLow", + [12]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + PunctureMercenary={ + description="Fires a puncturing arrow, which causes a bleeding debuff affected by modifiers to skill duration.", + hash=30431, + icon="", + id="PunctureMercenary", + name="Puncture", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="AilmentDamageHigh", + [4]="AilmentDamageLow", + [5]="AilmentDamageMid", + [6]="AttackSpeedHigh", + [7]="AttackSpeedLow", + [8]="AttackSpeedMid", + [9]="BrutalityHigh", + [10]="BrutalityLow", + [11]="BrutalityMid", + [12]="DamageOverTimeReduceDurationHigh", + [13]="DamageOverTimeReduceDurationLow", + [14]="DamageOverTimeReduceDurationMid", + [15]="DotMultiHigh", + [16]="DotMultiLow", + [17]="DotMultiMid", + [18]="ForkHigh", + [19]="IncreaseDurationHigh", + [20]="IncreaseDurationLow", + [21]="IncreaseDurationMid", + [22]="MultipleProjectilesHigh", + [23]="MultipleProjectilesLow", + [24]="PierceHigh", + [25]="PierceLow", + [26]="PierceMid" + }, + secondarySkillId="PunctureMercenaryEncounter", + supportCountId="High" + }, + PunishmentMercenary={ + description="Curses all targets in an area, causing them to be debilitated when they hit enemies and increasing damage they take while on low life.", + hash=32391, + icon="", + id="PunishmentMercenary", + name="Punishment", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CurseEffectHigh", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="SpellCascadeHigh", + [9]="SpellCascadeLow" + }, + supportCountId="Low" + }, + PurifyingFlameMercenary={ + description="Creates a wave of divine fire dealing damage in a line, then creates Consecrated Ground and deals damage in an area. A larger shockwave then expands outwards, damaging enemies standing on Consecrated Ground that were not already hit.", + hash=17763, + icon="", + id="PurifyingFlameMercenary", + name="Purifying Flame", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="FirePenetrationHigh", + [5]="FirePenetrationLow", + [6]="FirePenetrationMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="IncreaseDurationHigh", + [11]="IncreaseDurationLow", + [12]="IncreaseDurationMid", + [13]="PhysGainAsRandomHigh", + [14]="PhysGainAsRandomLow", + [15]="PhysGainAsRandomMid", + [16]="PurifyingFlameSpecificConsecratedGroundEffectHigh" + }, + secondarySkillId="PurifyingFlameMercenaryEncounter", + supportCountId="High" + }, + PurityOfFireMercenary={ + description="Casts an aura that grants fire resistance.", + hash=33728, + icon="", + id="PurityOfFireMercenary", + name="Purity of Fire", + possibleSupportIds={ + }, + supportCountId="None" + }, + PurityOfIceMercenary={ + description="Casts an aura that grants cold resistance.", + hash=13693, + icon="", + id="PurityOfIceMercenary", + name="Purity of Ice", + possibleSupportIds={ + }, + supportCountId="None" + }, + PurityOfLightningMercenary={ + description="Casts an aura that grants lightning resistance.", + hash=63233, + icon="", + id="PurityOfLightningMercenary", + name="Purity of Lightning", + possibleSupportIds={ + }, + supportCountId="None" + }, + QuickGuardAllyMercenary={ + description="Applies a buff to an ally which can take some damage from hits before being depleted.", + hash=17105, + icon="Art/2DArt/BuffIcons/QuickGuard.dds", + id="QuickGuardAllyMercenary", + name="Steelskin Ally", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + RainOfArrowsAltMercenary={ + description="Fires multiple arrows into the air, to slowly land in sequence after a delay, starting at the targeted location and spreading outwards in all directions. Each arrow deals damage in an area around it. Half of the arrows will land directly on targets if there are targets in their range.", + familyId="Infrequent", + hash=40759, + icon="", + id="RainOfArrowsAltMercenary", + name="Rain of Arrows of Saturation", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="IgnoreEnemyPhysMitHigh", + [8]="IgnoreEnemyPhysMitLow", + [9]="IgnoreEnemyPhysMitMid", + [10]="ImpaleChanceHigh", + [11]="ImpaleChanceLow", + [12]="ImpaleChanceMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="IncreasedProjSpeedHigh", + [17]="IncreasedProjSpeedLow", + [18]="IncreasedProjSpeedMid" + }, + supportCountId="High" + }, + RaiseSpectreAltMercenary={ + description="Raises a spectral version of a defeated foe as a temporary minion.", + hash=50349, + icon="", + id="RaiseSpectreAltMercenary", + name="Raise Spectre of Transience", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="MinionDamageHigh", + [14]="MinionDamageLow", + [15]="MinionDamageMid", + [16]="MinionLifeHigh", + [17]="MinionLifeLow", + [18]="MinionLifeMid", + [19]="MultipleProjectilesHigh", + [20]="MultipleProjectilesLow", + [21]="PhysGainAsRandomHigh", + [22]="PhysGainAsRandomLow", + [23]="PhysGainAsRandomMid" + }, + secondarySkillId="RaiseSpectreAltMercenaryEncounter", + supportCountId="High" + }, + RaiseZombieAltMercenary={ + description="Raises necromantic energies into the sky where they coalesce into a zombie minion. The minion then attacks by falling to the ground, causing an impact that deals damage in an area and kills the zombie.", + hash=57377, + icon="", + id="RaiseZombieAltMercenary", + name="Raise Zombie of Falling", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="CastSpeedHigh", + [8]="CastSpeedLow", + [9]="CastSpeedMid", + [10]="ConcentratedEffectHigh", + [11]="ConcentratedEffectLow", + [12]="ConcentratedEffectMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="MeleePhysHigh", + [17]="MeleePhysLow", + [18]="MeleePhysMid", + [19]="MinionChaosCloudHigh", + [20]="MinionDamageHigh", + [21]="MinionDamageLow", + [22]="MinionDamageMid", + [23]="PhysGainAsChaosHigh", + [24]="PhysGainAsChaosMid" + }, + secondarySkillId="RaiseZombieAltMercenaryEncounter", + supportCountId="High" + }, + RallyingCryMercenary={ + description="Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. Nearby allies gain a buff based on the user's weapon.", + hash=39265, + icon="", + id="RallyingCryMercenary", + name="Rallying Cry", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="WarcryRageHigh", + [12]="WarcryRageLow", + [13]="WarcryRageMid", + [14]="WarcrySpeedHigh", + [15]="WarcrySpeedLow", + [16]="WarcrySpeedMid" + }, + supportCountId="Low" + }, + ReapMercenary={ + description="Creates a bloody scythe that swipes an area applying a physical damage over time debuff and hitting enemies with physical damage.", + hash=14064, + icon="", + id="ReapMercenary", + name="Reap", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="DamageOverTimeReduceDurationHigh", + [11]="DamageOverTimeReduceDurationLow", + [12]="DamageOverTimeReduceDurationMid", + [13]="DotMultiHigh", + [14]="DotMultiHigh", + [15]="DotMultiLow", + [16]="DotMultiLow", + [17]="DotMultiMid", + [18]="DotMultiMid", + [19]="IgnoreEnemyPhysMitHigh", + [20]="IgnoreEnemyPhysMitLow", + [21]="IgnoreEnemyPhysMitMid", + [22]="IncreaseAreaOfEffectHigh", + [23]="IncreaseAreaOfEffectLow", + [24]="IncreaseAreaOfEffectMid", + [25]="IncreaseDurationHigh", + [26]="IncreaseDurationLow", + [27]="IncreaseDurationMid", + [28]="PhysGainAsChaosHigh", + [29]="PhysGainAsChaosMid", + [30]="SpellCascadeHigh", + [31]="SpellCascadeLow" + }, + secondarySkillId="ReapMercenaryEncounter", + supportCountId="High" + }, + RemoteSlamMercenary={ + description="Creates a burrowing charge which travels forwards and then explodes, dealing area damage. Damage from this skill has a chance to intimidate on hit.", + familyId="Infrequent", + hash=52105, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="RemoteSlamMercenary", + name="Tunnelslam", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="CooldownSpeedHigh", + [9]="CooldownSpeedLow", + [10]="CooldownSpeedMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="PulveriseHigh", + [15]="PulveriseLow", + [16]="PulveriseMid" + }, + supportCountId="Medium" + }, + RollingMagmaMercenary={ + description="Lob a fiery orb that deals area damage as it hits the ground. The skill chains, bouncing forward to deal damage multiple times.", + hash=30130, + icon="", + id="RollingMagmaMercenary", + name="Rolling Magma", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="CastSpeedHigh", + [4]="CastSpeedLow", + [5]="CastSpeedMid", + [6]="CombustionHigh", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="EleFocusHigh", + [11]="EleFocusLow", + [12]="EleFocusMid", + [13]="FirePenetrationHigh", + [14]="FirePenetrationLow", + [15]="FirePenetrationMid", + [16]="IgniteChanceHigh", + [17]="IgniteChanceLow", + [18]="IgniteChanceMid", + [19]="IncreaseAreaOfEffectHigh", + [20]="IncreaseAreaOfEffectLow", + [21]="IncreaseAreaOfEffectMid", + [22]="IncreasedProjSpeedHigh", + [23]="IncreasedProjSpeedLow", + [24]="IncreasedProjSpeedMid", + [25]="MultipleProjectilesHigh", + [26]="MultipleProjectilesLow", + [27]="ProjectilesReturnHigh", + [28]="ReducedProjSpeedHigh", + [29]="ReducedProjSpeedLow", + [30]="ReducedProjSpeedMid", + [31]="RollingMagmaAOEPerProjHigh" + }, + secondarySkillId="RollingMagmaMercenaryEncounter", + supportCountId="High" + }, + SSMHolySpectresMercenary={ + description="Raises a spectral version of a Holy Flame Elemental as a minion.", + hash=47078, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="SSMHolySpectresMercenary", + name="Raise Spectre: Holy Flame Elementals", + possibleSupportIds={ + }, + supportCountId="None" + }, + SSMMercenaryRelic={ + description="Summons a stationary Relic which generates an aura. Enemies in the aura will take damage based on their life when using movement skills.", + hash=62758, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="SSMMercenaryRelic", + name="Relic of Binding", + possibleSupportIds={ + }, + supportCountId="None" + }, + SSMMercenarySoulrendOrb={ + description="Summons a living void that seeks nearby enemies, continually firing bolts of chaotic energy while doing so.", + familyId="Infrequent", + hash=54144, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="SSMMercenarySoulrendOrb", + name="Summon Seeking Void", + possibleSupportIds={ + }, + supportCountId="None" + }, + SSMPaganBishopMercenary={ + description="Calls on a powerful undead clergyman which curses surrounding enemies.", + hash=4383, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="SSMPaganBishopMercenary", + name="Reinforce: Fallen Bishop", + possibleSupportIds={ + }, + secondarySkillId="SSMPaganBishopMercenaryEncounter", + supportCountId="None" + }, + SSMSkeletalBossMercenary={ + description="Calls on a Colossus of cursed bone to inflict pain on your foes.", + hash=53527, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="SSMSkeletalBossMercenary", + name="Reinforce: Fallen Osseotitan", + possibleSupportIds={ + }, + secondarySkillId="SSMSkeletalBossMercenaryEncounter", + supportCountId="None" + }, + SSMVollMercenary={ + description="Calls on a long dead emperor to deliver brutal justice to deserving enemies.", + hash=61523, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="SSMVollMercenary", + name="Reinforce: Fallen Emperor", + possibleSupportIds={ + }, + secondarySkillId="SSMVollMercenaryEncounter", + supportCountId="None" + }, + SandstormChaosMercenary={ + description="Surrounds the caster with whipping winds of profane energy that deals chaos damage over time to nearby enemies.", + familyId="Infrequent", + hash=13441, + icon="Art/2DArt/SkillIcons/HouseBardiyaSkill.dds", + id="SandstormChaosMercenary", + name="Scourstorm", + possibleSupportIds={ + [1]="CooldownSpeedHigh", + [2]="CooldownSpeedLow", + [3]="CooldownSpeedMid", + [4]="DamageOverTimeReduceDurationHigh", + [5]="DamageOverTimeReduceDurationLow", + [6]="DamageOverTimeReduceDurationMid", + [7]="DotMultiHigh", + [8]="DotMultiLow", + [9]="DotMultiMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid" + }, + supportCountId="Medium" + }, + ScorchingRayTotemMercenary={ + description="Creates a Spell Totem that unleashes a beam of fire that burns enemies it touches. Enemies in the beam raises the burning, adding a portion of the beam's damage in stages. Inflicts Fire Exposure at maximum stages. Enemies who leave the beam continue to burn for a duration.", + familyId="Infrequent", + hash=47293, + icon="", + id="ScorchingRayTotemMercenary", + name="Scorching Ray Totem", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CastSpeedHigh", + [3]="CastSpeedLow", + [4]="CastSpeedMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="ScorchingRayTotemSpecificLengthHigh", + [12]="TotemDefencesHigh", + [13]="TotemDefencesLow", + [14]="TotemDefencesMid" + }, + secondarySkillId="ScorchingRayTotemMercenaryEncounter", + supportCountId="Medium" + }, + ScourgeArrowAltMercenary={ + description="Fire an arrow that leaves a spore pod in its wake. The spore pod blooms, firing thorn arrows, which travel for a short time before dissipating. Modifiers that cause additional projectiles to be fired will only apply to the initial arrows, each of which leaves its own spore pod.", + hash=28502, + icon="", + id="ScourgeArrowAltMercenary", + name="Scourge Arrow of Menace", + possibleSupportIds={ + [1]="ArrowNovaHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="DotMultiHigh", + [6]="DotMultiLow", + [7]="DotMultiMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="MirageArcherHigh", + [12]="MultipleProjectilesHigh", + [13]="MultipleProjectilesLow", + [14]="PhysGainAsChaosHigh", + [15]="PhysGainAsChaosMid", + [16]="PoisonChanceHigh", + [17]="PoisonChanceLow", + [18]="PoisonChanceMid", + [19]="ScourgeArrowAltSpecificPodCountHigh", + [20]="WitherOnHitHigh", + [21]="WitherOnHitLow", + [22]="WitherOnHitMid" + }, + supportCountId="High" + }, + ShatteringSteelMercenary={ + description="Swing an Axe or Sword, firing projectiles which shatter on impact or soon after being launched, dealing area damage in front of where they shatter.", + hash=12729, + icon="", + id="ShatteringSteelMercenary", + name="Shattering Steel", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BleedHigh", + [5]="BleedLow", + [6]="BleedMid", + [7]="BrutalityHigh", + [8]="BrutalityLow", + [9]="BrutalityMid", + [10]="ImpaleChanceHigh", + [11]="ImpaleChanceLow", + [12]="ImpaleChanceMid", + [13]="IncreasedProjSpeedHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + ShieldChargeMercenary={ + description="Charges at a targeted location or enemy, pushing away enemies in the path and repeatedly dealing off-hand damage in a small area forwards. Deals damage in a larger area when reaching the target. The further travelled, the more damage dealt, and the greater the chance of stunning enemies.", + hash=22850, + icon="", + id="ShieldChargeMercenary", + name="Shield Charge", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="PulveriseHigh", + [11]="PulveriseLow", + [12]="PulveriseMid", + [13]="ShieldChargeSpecificCrushOnHitHigh" + }, + secondarySkillId="ShieldChargeMercenaryEncounter", + supportCountId="Medium" + }, + ShieldCrushMercenary={ + description="Swipe your shield, dealing area damage in three waves in front of you. Enemies can be hit by two of the waves where they overlap.", + hash=21201, + icon="", + id="ShieldCrushMercenary", + name="Shield Crush", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="FortifyHigh", + [8]="ImpaleChanceHigh", + [9]="ImpaleChanceLow", + [10]="ImpaleChanceMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="LeechHigh", + [15]="LeechLow", + [16]="LeechMid", + [17]="PulveriseHigh", + [18]="PulveriseLow", + [19]="PulveriseMid", + [20]="ShieldCrushSpecificAttackDamageFromShieldHigh" + }, + secondarySkillId="ShieldCrushMercenaryEncounter", + supportCountId="High" + }, + ShockwaveTotemMercenary={ + description="Summons a totem that shakes the earth around it, knocking back and damaging nearby enemies. A portion of physical damage the totem deals is converted to lightning.", + familyId="Infrequent", + hash=6651, + icon="", + id="ShockwaveTotemMercenary", + name="Shockwave Totem of Shocking", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CriticalStrikeHigh", + [5]="CriticalStrikeLow", + [6]="CriticalStrikeMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="IncreaseDurationHigh", + [11]="IncreaseDurationLow", + [12]="IncreaseDurationMid", + [13]="MultiTotemHigh", + [14]="PhysGainAsRandomHigh", + [15]="PhysGainAsRandomLow", + [16]="PhysGainAsRandomMid", + [17]="ShockwaveTotemSpecificAstralHigh", + [18]="TotemDefencesHigh", + [19]="TotemDefencesLow", + [20]="TotemDefencesMid" + }, + supportCountId="Medium" + }, + ShrapnelBallistaMercenary={ + description="Summons a ballista totem that fires multiple arrows with extreme force, breaking them apart into shrapnel. Enemies can be hit by multiple arrows from the same attack.", + familyId="Infrequent", + hash=61903, + icon="", + id="ShrapnelBallistaMercenary", + name="Shrapnel Ballista", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="IgnoreEnemyPhysMitHigh", + [8]="IgnoreEnemyPhysMitLow", + [9]="IgnoreEnemyPhysMitMid", + [10]="ImpaleChanceHigh", + [11]="ImpaleChanceLow", + [12]="ImpaleChanceMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="MultiTotemHigh", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow", + [19]="PierceHigh", + [20]="PierceLow", + [21]="PierceMid", + [22]="TotemDefencesHigh", + [23]="TotemDefencesLow", + [24]="TotemDefencesMid" + }, + supportCountId="High" + }, + SiegeBallistaAltMercenary={ + description="Summons a ring of ballista totems around a targeted location. These ballistae fire once at the targeted location and then expire.", + familyId="Infrequent", + hash=44144, + icon="", + id="SiegeBallistaAltMercenary", + name="Siege Ballista of Trarthus", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="IgnoreEnemyPhysMitHigh", + [8]="IgnoreEnemyPhysMitLow", + [9]="IgnoreEnemyPhysMitMid", + [10]="ImpaleChanceHigh", + [11]="ImpaleChanceLow", + [12]="ImpaleChanceMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="MultiTotemHigh", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow", + [19]="TotemDefencesHigh", + [20]="TotemDefencesLow", + [21]="TotemDefencesMid" + }, + supportCountId="High" + }, + SigilOfPowerMercenary={ + description="Places a Sigil on the ground, which grants a buff to allies in the area around it for a duration. The Sigil gains stages mana is spent in its area, making the buff more powerful.", + hash=33661, + icon="", + id="SigilOfPowerMercenary", + name="Sigil of Power", + possibleSupportIds={ + [1]="IncreaseAreaOfEffectHigh", + [2]="IncreaseAreaOfEffectLow", + [3]="IncreaseAreaOfEffectMid", + [4]="IncreaseDurationHigh", + [5]="IncreaseDurationLow", + [6]="IncreaseDurationMid" + }, + secondarySkillId="SigilOfPowerMercenaryEncounter", + supportCountId="Low" + }, + SmiteMercenary={ + description="Performs a melee attack, and causes lightning to strike a nearby enemy, dealing damage in an area. Each target can only be hit once by this skill. Hitting an enemy grants an aura for a duration.", + hash=55917, + icon="", + id="SmiteMercenary", + name="Smite", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="EleDamageWithAttacksHigh", + [5]="EleDamageWithAttacksLow", + [6]="EleDamageWithAttacksMid", + [7]="GenerosityHigh", + [8]="GenerosityLow", + [9]="GenerosityMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="SmiteSpecificAdditionalTargetHigh" + }, + supportCountId="High" + }, + SmokeMineMercenary={ + description="Throws a mine that will then cause teleportation when detonated. Creates clouds of smoke that blinds enemies, and gives a temporary buff to movement speed. ", + hash=64528, + icon="", + id="SmokeMineMercenary", + name="Smoke Mine", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="TrapMineThrowSpeedHigh", + [12]="TrapMineThrowSpeedLow", + [13]="TrapMineThrowSpeedMid" + }, + supportCountId="Low" + }, + SoulrendAltMercenary={ + description="Fires a projectile that deals chaos damage to enemies it hits and leeches some of that damage as energy shield.", + hash=10742, + icon="", + id="SoulrendAltMercenary", + name="Soulrend of Reaping", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="CastSpeedHigh", + [7]="CastSpeedLow", + [8]="CastSpeedMid", + [9]="ChaosPenHigh", + [10]="ChaosPenLow", + [11]="ChaosPenMid", + [12]="CritDamageHigh", + [13]="CritDamageLow", + [14]="CritDamageMid", + [15]="CriticalStrikeHigh", + [16]="CriticalStrikeLow", + [17]="CriticalStrikeMid", + [18]="MultipleProjectilesHigh", + [19]="MultipleProjectilesLow", + [20]="ProjectilesReturnHigh", + [21]="SoulrendAltSpecificChaosChillHigh", + [22]="WitherOnHitHigh", + [23]="WitherOnHitLow", + [24]="WitherOnHitMid" + }, + secondarySkillId="SoulrendAltMercenaryEncounter", + supportCountId="High" + }, + SparkMercenary={ + description="Launches unpredictable sparks that move randomly until they hit an enemy or expire.", + hash=5893, + icon="", + id="SparkMercenary", + name="Spark", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="EleFocusHigh", + [5]="EleFocusLow", + [6]="EleFocusMid", + [7]="IncreasedProjSpeedHigh", + [8]="IncreasedProjSpeedLow", + [9]="IncreasedProjSpeedMid", + [10]="LightningDamageLuckyHigh", + [11]="LightningPenetrationHigh", + [12]="LightningPenetrationLow", + [13]="LightningPenetrationMid", + [14]="MultipleProjectilesHigh", + [15]="MultipleProjectilesLow", + [16]="PierceHigh", + [17]="PierceLow", + [18]="PierceMid", + [19]="ProjectilesReturnHigh", + [20]="ShockChanceHigh", + [21]="ShockChanceLow", + [22]="ShockChanceMid", + [23]="SparkSpecificNovaHigh" + }, + secondarySkillId="SparkMercenaryEncounter", + supportCountId="High" + }, + SpectralHelixAltMercenary={ + description="Throws a trap which, once triggered, fires a spectral weapon. It spins around while flying in a large spiral, damaging enemies in its path, and bouncing if it collides with walls.", + hash=28988, + icon="", + id="SpectralHelixAltMercenary", + name="Spectral Helix of Trarthus", + possibleSupportIds={ + [1]="IncreasedProjSpeedHigh", + [2]="IncreasedProjSpeedLow", + [3]="IncreasedProjSpeedMid", + [4]="MultiTrapHigh", + [5]="ReducedProjSpeedHigh", + [6]="ReducedProjSpeedLow", + [7]="ReducedProjSpeedMid", + [8]="TrapChargeGenHigh", + [9]="TrapMineDamageHigh", + [10]="TrapMineDamageLow", + [11]="TrapMineDamageMid", + [12]="TrapMineThrowSpeedHigh", + [13]="TrapMineThrowSpeedLow", + [14]="TrapMineThrowSpeedMid", + [15]="TrapTriggerRadiusHigh", + [16]="TrapTriggerRadiusLow", + [17]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + SpectralHelixMercenary={ + description="Throws a spectral melee weapon. It spins around while flying in a large spiral, damaging enemies in its path, and bouncing if it collides with walls.", + hash=37916, + icon="", + id="SpectralHelixMercenary", + name="Spectral Helix", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="EleDamageWithAttacksHigh", + [8]="EleDamageWithAttacksLow", + [9]="EleDamageWithAttacksMid", + [10]="EleFocusHigh", + [11]="EleFocusLow", + [12]="EleFocusMid", + [13]="IncreasedProjSpeedHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="PhysGainAsRandomHigh", + [17]="PhysGainAsRandomLow", + [18]="PhysGainAsRandomMid", + [19]="ReducedProjSpeedHigh", + [20]="ReducedProjSpeedLow", + [21]="ReducedProjSpeedMid" + }, + supportCountId="High" + }, + SpectralShieldThrowAltMercenary={ + description="Throws a spectral shield as a piercing projectile which deals off-hand damage augmented by the defences of the shield. When it reaches the targeted location it will hover in place, repeatedly firing a number of smaller shards as projectiles in all directions. The rate at which it releases shards will increase until all shards have been fired.", + hash=41834, + icon="", + id="SpectralShieldThrowAltMercenary", + name="Spectral Shield Throw of Trarthus", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="AttackSpeedHigh", + [4]="AttackSpeedLow", + [5]="AttackSpeedMid", + [6]="BrutalityHigh", + [7]="BrutalityLow", + [8]="BrutalityMid", + [9]="ImpaleChanceHigh", + [10]="ImpaleChanceLow", + [11]="ImpaleChanceMid", + [12]="IncreasedProjSpeedHigh", + [13]="IncreasedProjSpeedLow", + [14]="IncreasedProjSpeedMid", + [15]="MultipleProjectilesHigh", + [16]="MultipleProjectilesLow", + [17]="PierceHigh", + [18]="PierceLow", + [19]="PierceMid" + }, + supportCountId="High" + }, + SpectralThrowAltMercenary={ + description="Throws a trap which, once triggered, fires many spectral weapons. They fly out in all directions and then return to where the trap triggered, in a spinning attack that damages enemies in their path.", + hash=62393, + icon="", + id="SpectralThrowAltMercenary", + name="Spectral Throw of Trarthus", + possibleSupportIds={ + [1]="IncreasedProjSpeedHigh", + [2]="IncreasedProjSpeedLow", + [3]="IncreasedProjSpeedMid", + [4]="MultiTrapHigh", + [5]="MultipleProjectilesHigh", + [6]="MultipleProjectilesLow", + [7]="ReducedProjSpeedHigh", + [8]="ReducedProjSpeedLow", + [9]="ReducedProjSpeedMid", + [10]="TrapChargeGenHigh", + [11]="TrapMineDamageHigh", + [12]="TrapMineDamageLow", + [13]="TrapMineDamageMid", + [14]="TrapMineThrowSpeedHigh", + [15]="TrapMineThrowSpeedLow", + [16]="TrapMineThrowSpeedMid", + [17]="TrapTriggerRadiusHigh", + [18]="TrapTriggerRadiusLow", + [19]="TrapTriggerRadiusMid" + }, + supportCountId="High" + }, + SplitArrowMercenary={ + description="Fires multiple arrows at different targets.", + hash=43202, + icon="", + id="SplitArrowMercenary", + name="Split Arrow", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="AttackSpeedHigh", + [4]="AttackSpeedLow", + [5]="AttackSpeedMid", + [6]="BleedHigh", + [7]="BleedLow", + [8]="BleedMid", + [9]="BrutalityHigh", + [10]="BrutalityLow", + [11]="BrutalityMid", + [12]="IgnoreEnemyPhysMitHigh", + [13]="IgnoreEnemyPhysMitLow", + [14]="IgnoreEnemyPhysMitMid", + [15]="IncreasedProjSpeedHigh", + [16]="IncreasedProjSpeedLow", + [17]="IncreasedProjSpeedMid", + [18]="MultipleProjectilesHigh", + [19]="MultipleProjectilesLow", + [20]="PierceHigh", + [21]="PierceLow", + [22]="PierceMid", + [23]="ProjectilesReturnHigh", + [24]="ReducedProjSpeedHigh", + [25]="ReducedProjSpeedLow", + [26]="ReducedProjSpeedMid" + }, + supportCountId="High" + }, + SplittingSteelMercenary={ + description="Fire a single projectile that splits on impact or at the targeted location, dealing area damage when it splits and again when the split projectiles explode at the end of their flight.", + hash=28511, + icon="", + id="SplittingSteelMercenary", + name="Splitting Steel", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BleedHigh", + [5]="BleedLow", + [6]="BleedMid", + [7]="BrutalityHigh", + [8]="BrutalityLow", + [9]="BrutalityMid", + [10]="ImpaleChanceHigh", + [11]="ImpaleChanceLow", + [12]="ImpaleChanceMid", + [13]="IncreasedProjSpeedHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + StaticStrikeMercenary={ + description="Attack with a melee weapon, gaining static energy for a duration if hitting an enemy. While statically charged, frequently hit a number of nearby enemies with beams, dealing attack damage.", + hash=24931, + icon="", + id="StaticStrikeMercenary", + name="Static Strike", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="EleDamageWithAttacksHigh", + [7]="EleDamageWithAttacksLow", + [8]="EleDamageWithAttacksMid", + [9]="IncreaseAreaOfEffectHigh", + [10]="IncreaseAreaOfEffectLow", + [11]="IncreaseAreaOfEffectMid", + [12]="IncreaseDurationHigh", + [13]="IncreaseDurationLow", + [14]="IncreaseDurationMid", + [15]="LightningPenetrationHigh", + [16]="LightningPenetrationLow", + [17]="LightningPenetrationMid" + }, + secondarySkillId="StaticStrikeMercenaryEncounteer", + supportCountId="High" + }, + StormCallAltMercenary={ + description="Sets a marker at a location. After a short duration, a bolt strikes the marker, dealing physical damage around it and causing bolts to strike at any other markers. Bolt impacts will leave behind a pool of boiling blood, which deals physical damage over time to enemies within it for a secondary duration.", + hash=2187, + icon="", + id="StormCallAltMercenary", + name="Storm Call of Trarthus", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="DamageOverTimeReduceDurationHigh", + [11]="DamageOverTimeReduceDurationLow", + [12]="DamageOverTimeReduceDurationMid", + [13]="DotMultiHigh", + [14]="DotMultiLow", + [15]="DotMultiMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="IncreaseDurationHigh", + [20]="IncreaseDurationLow", + [21]="IncreaseDurationMid", + [22]="PhysGainAsChaosHigh", + [23]="PhysGainAsChaosMid", + [24]="ReduceDurationHigh", + [25]="ReduceDurationLow", + [26]="ReduceDurationMid", + [27]="SpellCascadeHigh", + [28]="SpellCascadeLow" + }, + secondarySkillId="StormCallAltMercenaryEncounter", + supportCountId="High" + }, + StormCallMercenary={ + description="Sets a marker at a location. After a short duration, lightning strikes the marker, dealing damage around it.", + familyId="StormcallVariant", + hash=7549, + icon="", + id="StormCallMercenary", + name="Stormcall", + possibleSupportIds={ + [1]="CooldownSpeedHigh", + [2]="CooldownSpeedLow", + [3]="CooldownSpeedMid", + [4]="EleFocusHigh", + [5]="EleFocusLow", + [6]="EleFocusMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="LightningDamageLuckyHigh", + [11]="LightningPenetrationHigh", + [12]="LightningPenetrationLow", + [13]="LightningPenetrationMid", + [14]="ReduceDurationHigh", + [15]="ReduceDurationLow", + [16]="ReduceDurationMid", + [17]="ShockChanceHigh", + [18]="ShockChanceLow", + [19]="ShockChanceMid", + [20]="SpellCascadeHigh", + [21]="SpellCascadeLow", + [22]="StormCallSpecificResCritHigh" + }, + secondarySkillId="StormCallMercenaryEncounter", + supportCountId="High" + }, + StormRainMercenary={ + description="Fires an arrow into the air to land at a targeted location, dealing area damage. The arrow sticks in the ground where it lands, and periodically fires a beam of lightning to another arrow near it, dealing area damage between them.", + hash=17216, + icon="", + id="StormRainMercenary", + name="Storm Rain", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="EleDamageWithAttacksHigh", + [11]="EleDamageWithAttacksLow", + [12]="EleDamageWithAttacksMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="LightningDamageLuckyHigh", + [17]="LightningPenetrationHigh", + [18]="LightningPenetrationLow", + [19]="LightningPenetrationMid", + [20]="MultipleProjectilesHigh", + [21]="MultipleProjectilesLow", + [22]="StormRainSpecificNumberOfBurstsHigh" + }, + supportCountId="High" + }, + SummonHolyRelicMercenary={ + description="Summon a Holy Relic that stays nearby. When an enemy is hit with an attack, the Holy Relic triggers a nova spell with a short cooldown, that deals physical damage to enemies and grants life regeneration to allies in an area around it. This life regeneration is higher when applied to minions.", + hash=40812, + icon="", + id="SummonHolyRelicMercenary", + name="Holy Relic", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CooldownSpeedHigh", + [5]="CooldownSpeedLow", + [6]="CooldownSpeedMid", + [7]="HolyRelicSpecificRegenHigh", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="MinionDamageHigh", + [12]="MinionDamageLow", + [13]="MinionDamageMid", + [14]="PhysGainAsRandomHigh", + [15]="PhysGainAsRandomLow", + [16]="PhysGainAsRandomMid" + }, + supportCountId="High" + }, + SummonRagingSpiritMercenary={ + description="Summons a short-lived flaming skull that rushes at nearby enemies and attacks them rapidly, converting all its physical damage to fire. ", + hash=19108, + icon="", + id="SummonRagingSpiritMercenary", + name="Summon Raging Spirit", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="EleFocusHigh", + [5]="EleFocusLow", + [6]="EleFocusMid", + [7]="IgniteChanceHigh", + [8]="IgniteChanceLow", + [9]="IgniteChanceMid", + [10]="MinionChaosCloudHigh", + [11]="MinionDamageHigh", + [12]="MinionDamageLow", + [13]="MinionDamageMid", + [14]="MinionLifeHigh", + [15]="MinionLifeLow", + [16]="MinionLifeMid", + [17]="SRSSpecificShrinesHigh" + }, + supportCountId="High" + }, + SummonSkeletonsMercenary={ + description="Summons Skeleton Warrior minions. They use a melee attack and die after a duration.", + hash=17409, + icon="", + id="SummonSkeletonsMercenary", + name="Summon Skeletons", + possibleSupportIds={ + [1]="BrutalityHigh", + [2]="BrutalityLow", + [3]="BrutalityMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="IgnoreEnemyPhysMitHigh", + [8]="IgnoreEnemyPhysMitLow", + [9]="IgnoreEnemyPhysMitMid", + [10]="MinionChaosCloudHigh", + [11]="MinionDamageHigh", + [12]="MinionDamageLow", + [13]="MinionDamageMid", + [14]="MinionLifeHigh", + [15]="MinionLifeLow", + [16]="MinionLifeMid", + [17]="SummonSkeletonsSpecificArchersHigh" + }, + supportCountId="High" + }, + SummonSkitterbotsMercenary={ + description="Summons a Chilling Skitterbot and a Shocking Skitterbot, which will trigger traps and detonate mines. Mines detonated by Skitterbots will re-arm and can then be detonated again. The Skitterbots grant more trap and mine damage, and cannot be targeted or damaged.", + hash=44296, + icon="", + id="SummonSkitterbotsMercenary", + name="Summon Skitterbots", + possibleSupportIds={ + }, + supportCountId="None" + }, + SunderAltMercenary={ + description="Slams the ground, creating a slow wave of churning terrain that damages enemies in a sequence of areas. A number of enemies hit by the wave will release a shockwave, damaging other enemies around them. Using the skill again will stop the previous wave. When the wave reaches a target or terrain, it can restart aiming towards an enemy, if one is in range.", + hash=17654, + icon="", + id="SunderAltMercenary", + name="Sunder of Trarthus", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="ConcentratedEffectHigh", + [8]="ConcentratedEffectLow", + [9]="ConcentratedEffectMid", + [10]="IgnoreEnemyPhysMitHigh", + [11]="IgnoreEnemyPhysMitLow", + [12]="IgnoreEnemyPhysMitMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="PulveriseHigh", + [17]="PulveriseLow", + [18]="PulveriseMid", + [19]="SunderAltSpecificAdditionalChainHigh" + }, + secondarySkillId="SunderAltMercenaryEncounter", + supportCountId="High" + }, + SweepMercenary={ + description="Swings a two handed mace or a staff in a circle, calling down holy hammers to land randomly on a number of enemies struck. Hits from these holy hammers cannot be evaded.", + hash=7395, + icon="", + id="SweepMercenary", + name="Holy Sweep", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="ConcentratedEffectHigh", + [5]="ConcentratedEffectLow", + [6]="ConcentratedEffectMid", + [7]="EleDamageWithAttacksHigh", + [8]="EleDamageWithAttacksLow", + [9]="EleDamageWithAttacksMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="MeleePhysHigh", + [14]="MeleePhysLow", + [15]="MeleePhysMid", + [16]="MultistrikeHigh", + [17]="MultistrikeMid" + }, + supportCountId="High" + }, + TectonicSlamFireMercenary={ + description="Slams the ground, unleashing a fiery fissure forward, dealing area damage and randomly releasing a number of smaller fissures branching off from it. Consumes an Endurance Charge every third time the ground is slammed with this skill. ", + hash=6228, + icon="", + id="TectonicSlamFireMercenary", + name="Tectonic Slam", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="CombustionHigh", + [8]="FirePenetrationHigh", + [9]="FirePenetrationLow", + [10]="FirePenetrationMid", + [11]="FistOfWarHigh", + [12]="FortifyHigh", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="KnockbackLow", + [17]="MultistrikeHigh", + [18]="MultistrikeMid", + [19]="PulveriseHigh", + [20]="PulveriseLow", + [21]="PulveriseMid" + }, + supportCountId="High" + }, + TectonicSlamPhysMercenary={ + description="Create a cascading series of concussive eruptions which deal attack damage.", + familyId="Infrequent", + hash=40527, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="TectonicSlamPhysMercenary", + name="Tectonic Cascade", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="ConcentratedEffectHigh", + [9]="ConcentratedEffectLow", + [10]="ConcentratedEffectMid", + [11]="CooldownSpeedHigh", + [12]="CooldownSpeedLow", + [13]="CooldownSpeedMid", + [14]="IgnoreEnemyPhysMitHigh", + [15]="IgnoreEnemyPhysMitLow", + [16]="IgnoreEnemyPhysMitMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="LeechHigh", + [21]="LeechLow", + [22]="LeechMid", + [23]="PulveriseHigh", + [24]="PulveriseLow", + [25]="PulveriseMid" + }, + supportCountId="High" + }, + TempestShieldMercenary={ + description="Enchants the equipped shield with the power of storms, which lashes out to deal arcing lightning damage to attackers on block.", + hash=58855, + icon="", + id="TempestShieldMercenary", + name="Tempest Shield", + possibleSupportIds={ + }, + secondarySkillId="TempestShieldMercenaryEncounter", + supportCountId="None" + }, + TemporalAnomalyMercenary={ + description="Create a temporary tear through which the grasping hands of damned souls can claw, slowing enemies significantly.", + hash=26057, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="TemporalAnomalyMercenary", + name="Clutches of the Damned", + possibleSupportIds={ + }, + supportCountId="None" + }, + TemporalChainsMercenary={ + description="Curses all enemies in an area, lowering their action speed and making other effects on them expire more slowly.", + hash=7383, + icon="", + id="TemporalChainsMercenary", + name="Temporal Chains", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="CurseEffectHigh" + }, + supportCountId="Low" + }, + TornadoAltMercenary={ + description="Creates a Tornado of a random element that hinders and repeatedly damages enemies around it, converting physical damage to its element. The Tornado will chase down enemies for a duration.", + familyId="Infrequent", + hash=23225, + icon="", + id="TornadoAltMercenary", + name="Tornado of Elemental Turbulence", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="CriticalStrikeHigh", + [6]="CriticalStrikeLow", + [7]="CriticalStrikeMid", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="IncreaseDurationHigh", + [12]="IncreaseDurationLow", + [13]="IncreaseDurationMid", + [14]="PhysGainAsRandomHigh", + [15]="PhysGainAsRandomLow", + [16]="PhysGainAsRandomMid" + }, + supportCountId="Medium" + }, + TornadoShotMercenary={ + description="Fires a piercing shot that travels until it reaches the targeted location. It will then fire projectiles out in all directions from that point, which will travel for a short time before disappearing.", + hash=8030, + icon="", + id="TornadoShotMercenary", + name="Tornado Shot", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="ArrowNovaHigh", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="BrutalityHigh", + [8]="BrutalityLow", + [9]="BrutalityMid", + [10]="ForkHigh", + [11]="IgnoreEnemyPhysMitHigh", + [12]="IgnoreEnemyPhysMitLow", + [13]="IgnoreEnemyPhysMitMid", + [14]="ImpaleChanceHigh", + [15]="ImpaleChanceLow", + [16]="ImpaleChanceMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreasedProjSpeedLow", + [19]="IncreasedProjSpeedMid", + [20]="MirageArcherHigh", + [21]="MultipleProjectilesHigh", + [22]="MultipleProjectilesLow", + [23]="TornadoShotSpecificSecondaryProjHigh" + }, + supportCountId="High" + }, + ToxicRainMercenary={ + description="Fire arrows into the air that rain down around the targeted area, dealing damage to enemies they hit and creating spore pods where they land. Each spore pod deals chaos damage over time to nearby enemies and slows their movement speed. The pods last for a duration before bursting, dealing area damage.", + hash=38628, + icon="", + id="ToxicRainMercenary", + name="Toxic Rain", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="DotMultiHigh", + [5]="DotMultiLow", + [6]="DotMultiMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="IncreaseDurationHigh", + [11]="IncreaseDurationLow", + [12]="IncreaseDurationMid", + [13]="MirageArcherHigh", + [14]="MultipleProjectilesHigh", + [15]="MultipleProjectilesLow", + [16]="PhysGainAsChaosHigh", + [17]="PhysGainAsChaosMid", + [18]="ToxicRainSpecificGraspingVinesHigh", + [19]="WitherOnHitHigh", + [20]="WitherOnHitLow", + [21]="WitherOnHitMid" + }, + supportCountId="High" + }, + TriggeredFireSlamMercenary={ + description="On landing from Leap Slam, cause a fiery eruption which deals attack damage, partially converting physical to fire.", + hash=18149, + icon="Art/2DArt/SkillIcons/HouseKeitaSkill.dds", + id="TriggeredFireSlamMercenary", + name="Triggerslam", + possibleSupportIds={ + [1]="FirePenetrationHigh", + [2]="FirePenetrationLow", + [3]="FirePenetrationMid", + [4]="IgniteChanceHigh", + [5]="IgniteChanceLow", + [6]="IgniteChanceMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid" + }, + supportCountId="Medium" + }, + VaalAncestralWarchiefMercenary={ + description="Summons an Ancestor Totem which attacks enemies with a powerful cascading slam. If enemies are far away, it will leap toward them as it slams.", + familyId="Infrequent", + hash=38521, + icon="", + id="VaalAncestralWarchiefMercenary", + name="Vaal Ancestral Warchief", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="ConcentratedEffectHigh", + [9]="ConcentratedEffectLow", + [10]="ConcentratedEffectMid", + [11]="CooldownSpeedHigh", + [12]="CooldownSpeedLow", + [13]="CooldownSpeedMid", + [14]="IncreaseAreaOfEffectHigh", + [15]="IncreaseAreaOfEffectLow", + [16]="IncreaseAreaOfEffectMid", + [17]="MultiTotemHigh", + [18]="TotemDefencesHigh", + [19]="TotemDefencesLow", + [20]="TotemDefencesMid" + }, + supportCountId="High" + }, + VaalArcticArmourMercenary={ + description="Immediately encases the caster in ice, protecting for a duration or until taken damage from a number of hits, and also grants a buff once the cast time has finished. Cannot move or perform non-instant actions while protected in the ice. When the ice breaks, the buff is also removed.", + familyId="Infrequent", + hash=44455, + icon="", + id="VaalArcticArmourMercenary", + name="Vaal Arctic Armour", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseDurationHigh", + [6]="IncreaseDurationLow", + [7]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + VaalBurningArrowMercenary={ + description="Fires an arrow that explodes, dealing fire damage to its target and other nearby enemies, with an increased chance of igniting them.", + familyId="Infrequent", + hash=23512, + icon="", + id="VaalBurningArrowMercenary", + name="Vaal Burning Arrow", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CombustionHigh", + [3]="ConcentratedEffectHigh", + [4]="ConcentratedEffectLow", + [5]="ConcentratedEffectMid", + [6]="CooldownSpeedHigh", + [7]="CooldownSpeedLow", + [8]="CooldownSpeedMid", + [9]="DotMultiHigh", + [10]="DotMultiLow", + [11]="DotMultiMid", + [12]="FirePenetrationHigh", + [13]="FirePenetrationLow", + [14]="FirePenetrationMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="PierceHigh", + [19]="PierceLow", + [20]="PierceMid" + }, + secondarySkillId="VaalBurningArrowMercenaryEncounter", + supportCountId="High" + }, + VaalCausticArrowMercenary={ + description="Fires a slow-moving serpentine arrow which deals chaos damage while piercing enemies, and leaves a trail of caustic ground. Enemies standing on the caustic ground take chaos damage over time.", + familyId="Infrequent", + hash=36274, + icon="", + id="VaalCausticArrowMercenary", + name="Vaal Caustic Arrow", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="DamageOverTimeReduceDurationHigh", + [6]="DamageOverTimeReduceDurationLow", + [7]="DamageOverTimeReduceDurationMid", + [8]="DotMultiHigh", + [9]="DotMultiLow", + [10]="DotMultiMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="IncreaseDurationHigh", + [15]="IncreaseDurationLow", + [16]="IncreaseDurationMid", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow" + }, + secondarySkillId="VaalCausticArrowMercenaryEncounter", + supportCountId="High" + }, + VaalCleaveMercenary={ + description="Swings equipped weapon in an arc, damaging monsters in an area. Killing Blows on Rare or Unique enemies grant a buff that improves Cleave for a duration. Killing Blows on Rare Enemies also steal their modifiers for a secondary duration.", + familyId="Infrequent", + hash=12723, + icon="", + id="VaalCleaveMercenary", + name="Vaal Cleave", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="CooldownSpeedHigh", + [9]="CooldownSpeedLow", + [10]="CooldownSpeedMid", + [11]="IncreaseAreaOfEffectHigh", + [12]="IncreaseAreaOfEffectLow", + [13]="IncreaseAreaOfEffectMid", + [14]="PulveriseHigh", + [15]="PulveriseLow", + [16]="PulveriseMid", + [17]="RageOnMeleeHitHigh", + [18]="RageOnMeleeHitLow", + [19]="RageOnMeleeHitMid" + }, + secondarySkillId="VaalCleaveMercenaryEncounter", + supportCountId="High" + }, + VaalDoubleStrikeMercenary={ + description="Performs two fast strikes with a melee weapon, each of which summons a double for a duration to continuously attack monsters in this fashion.", + familyId="Infrequent", + hash=37132, + icon="", + id="VaalDoubleStrikeMercenary", + name="Vaal Double Strike", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="CooldownSpeedHigh", + [9]="CooldownSpeedLow", + [10]="CooldownSpeedMid", + [11]="FortifyHigh", + [12]="ImpaleChanceHigh", + [13]="ImpaleChanceLow", + [14]="ImpaleChanceMid", + [15]="IncreaseDurationHigh", + [16]="IncreaseDurationLow", + [17]="IncreaseDurationMid", + [18]="MeleePhysHigh", + [19]="MeleePhysLow", + [20]="MeleePhysMid", + [21]="MeleeSplashHigh", + [22]="StrikeRangeHigh", + [23]="StrikeRangeLow", + [24]="StrikeRangeMid", + [25]="VaalDoubleStrikeSpecificCloneSpeedHigh" + }, + supportCountId="High" + }, + VaalFlameblastMercenary={ + description="Targets an area and builds up stages in that area based on cast speed. It explodes every 3 stages, until it reaches a maximum of 15. As it gains more stages, the area gets smaller but the damage gets higher.", + familyId="Infrequent", + hash=29426, + icon="", + id="VaalFlameblastMercenary", + name="Vaal Flameblast", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AilmentDamageHigh", + [3]="AilmentDamageLow", + [4]="AilmentDamageMid", + [5]="CastSpeedHigh", + [6]="CastSpeedLow", + [7]="CastSpeedMid", + [8]="CombustionHigh", + [9]="FirePenetrationHigh", + [10]="FirePenetrationLow", + [11]="FirePenetrationMid", + [12]="FlameblastSpecificStagesHigh", + [13]="IgniteChanceHigh", + [14]="IgniteChanceLow", + [15]="IgniteChanceMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid" + }, + supportCountId="High" + }, + VaalGlacialHammerMercenary={ + description="Hits enemies, converting physical damage to cold damage. Traps enemies in a circle of ice so that they can't escape. ", + familyId="Infrequent", + hash=47031, + icon="", + id="VaalGlacialHammerMercenary", + name="Vaal Glacial Hammer", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdLow", + [3]="AddedColdMid", + [4]="ColdPenetrationHigh", + [5]="ColdPenetrationLow", + [6]="ColdPenetrationMid", + [7]="CooldownSpeedHigh", + [8]="CooldownSpeedLow", + [9]="CooldownSpeedMid", + [10]="EleDamageWithAttacksHigh", + [11]="EleDamageWithAttacksLow", + [12]="EleDamageWithAttacksMid", + [13]="FreezeChanceHigh", + [14]="FreezeChanceLow", + [15]="FreezeChanceMid", + [16]="HypothermiaHigh", + [17]="HypothermiaLow", + [18]="HypothermiaMid", + [19]="IncreaseAreaOfEffectHigh", + [20]="IncreaseAreaOfEffectLow", + [21]="IncreaseAreaOfEffectMid", + [22]="IncreaseDurationHigh", + [23]="IncreaseDurationLow", + [24]="IncreaseDurationMid" + }, + supportCountId="High" + }, + VaalGraceMercenary={ + description="Casts a temporary aura that grants additional chance to evade attacks, and makes suppressed spell damage unlucky.", + familyId="Infrequent", + hash=58425, + icon="", + id="VaalGraceMercenary", + name="Vaal Grace", + possibleSupportIds={ + }, + supportCountId="None" + }, + VaalGroundSlamMercenary={ + description="Slams the ground, creating a wave that travels in all directions that damages enemies with an increased chance to stun. The wave deals more damage to closer enemies.", + familyId="Infrequent", + hash=10712, + icon="", + id="VaalGroundSlamMercenary", + name="Vaal Ground Slam", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="BrutalityHigh", + [6]="BrutalityLow", + [7]="BrutalityMid", + [8]="ConcentratedEffectHigh", + [9]="ConcentratedEffectLow", + [10]="ConcentratedEffectMid", + [11]="CooldownSpeedHigh", + [12]="CooldownSpeedLow", + [13]="CooldownSpeedMid", + [14]="IgnoreEnemyPhysMitHigh", + [15]="IgnoreEnemyPhysMitLow", + [16]="IgnoreEnemyPhysMitMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="LeechHigh", + [21]="LeechLow", + [22]="LeechMid", + [23]="PulveriseHigh", + [24]="PulveriseLow", + [25]="PulveriseMid", + [26]="VaalGroundSlamSpecificStunDurationHigh" + }, + supportCountId="High" + }, + VaalIceShotMercenary={ + description="Fires an arrow that converts some physical damage to cold on its target and converts all physical damage to cold in a cone behind that target. Summons a squad of Mirage Sharpshooters for a duration.", + familyId="Infrequent", + hash=16381, + icon="", + id="VaalIceShotMercenary", + name="Vaal Ice Shot", + possibleSupportIds={ + [1]="AdditionalChainsLow", + [2]="AdditionalChainsMid", + [3]="ColdPenetrationHigh", + [4]="ColdPenetrationLow", + [5]="ColdPenetrationMid", + [6]="CooldownSpeedHigh", + [7]="CooldownSpeedLow", + [8]="CooldownSpeedMid", + [9]="EleDamageWithAttacksHigh", + [10]="EleDamageWithAttacksLow", + [11]="EleDamageWithAttacksMid", + [12]="ForkHigh", + [13]="FreezeChanceHigh", + [14]="FreezeChanceLow", + [15]="FreezeChanceMid", + [16]="HypothermiaHigh", + [17]="HypothermiaLow", + [18]="HypothermiaMid", + [19]="IncreaseAreaOfEffectHigh", + [20]="IncreaseAreaOfEffectLow", + [21]="IncreaseAreaOfEffectMid", + [22]="MultipleProjectilesHigh", + [23]="MultipleProjectilesLow", + [24]="PierceHigh", + [25]="PierceLow", + [26]="PierceMid", + [27]="ProjectilesReturnHigh" + }, + supportCountId="High" + }, + VaalLightningArrowMercenary={ + description="Fires charged arrows, which repeatedly travel for a short time before changing direction. When they hit enemies, they are struck by a bolt of lightning which damages a number of surrounding enemies.", + familyId="Infrequent", + hash=22000, + icon="", + id="VaalLightningArrowMercenary", + name="Vaal Lightning Arrow", + possibleSupportIds={ + [1]="AddedLightningHigh", + [2]="AddedLightningLow", + [3]="AddedLightningMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="AttackSpeedHigh", + [7]="AttackSpeedLow", + [8]="AttackSpeedMid", + [9]="EleDamageWithAttacksHigh", + [10]="EleDamageWithAttacksLow", + [11]="EleDamageWithAttacksMid", + [12]="ForkHigh", + [13]="LightningDamageLuckyHigh", + [14]="LightningPenetrationHigh", + [15]="LightningPenetrationLow", + [16]="LightningPenetrationMid", + [17]="MultipleProjectilesHigh", + [18]="MultipleProjectilesLow", + [19]="VaalLightningArrowSpecificRedirectHigh" + }, + supportCountId="High" + }, + VaalLightningTrapMercenary={ + description="Throws a trap that launches a ring of projectiles through the enemy that set it off, dealing lightning damage to them and subsequent targets and leaving a trail of shocked ground.", + familyId="Infrequent", + hash=25149, + icon="", + id="VaalLightningTrapMercenary", + name="Vaal Lightning Trap", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AddedLightningHigh", + [3]="AddedLightningLow", + [4]="AddedLightningMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="LightningPenetrationHigh", + [12]="LightningPenetrationLow", + [13]="LightningPenetrationMid", + [14]="MultipleProjectilesHigh", + [15]="MultipleProjectilesLow", + [16]="TrapMineDamageHigh", + [17]="TrapMineDamageLow", + [18]="TrapMineDamageMid", + [19]="TrapTriggerRadiusHigh", + [20]="TrapTriggerRadiusLow", + [21]="TrapTriggerRadiusMid" + }, + supportCountId="Low" + }, + VaalMoltenStrikeMercenary={ + description="Attacks with physical and fire damage. This attack causes balls of molten magma to launch forth causing area attack damage to enemies where they land.", + familyId="Infrequent", + hash=42219, + icon="", + id="VaalMoltenStrikeMercenary", + name="Vaal Molten Strike", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AdditionalChainsLow", + [5]="AdditionalChainsMid", + [6]="CombustionHigh", + [7]="EleDamageWithAttacksHigh", + [8]="EleDamageWithAttacksLow", + [9]="EleDamageWithAttacksMid", + [10]="FirePenetrationHigh", + [11]="FirePenetrationLow", + [12]="FirePenetrationMid", + [13]="IncreaseAreaOfEffectHigh", + [14]="IncreaseAreaOfEffectLow", + [15]="IncreaseAreaOfEffectMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow" + }, + secondarySkillId="VaalMoltenStrikeMercenaryEncounter", + supportCountId="High" + }, + VaalReapMercenary={ + description="Creates a bloody scythes that swipes an area, hitting enemies with physical damage. An area of boiling blood is left beneath them for a duration which deals physical damage over time.", + familyId="Infrequent", + hash=1185, + icon="", + id="VaalReapMercenary", + name="Vaal Reap", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="BrutalityHigh", + [3]="BrutalityLow", + [4]="BrutalityMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="DamageOverTimeReduceDurationHigh", + [9]="DamageOverTimeReduceDurationLow", + [10]="DamageOverTimeReduceDurationMid", + [11]="DotMultiHigh", + [12]="DotMultiLow", + [13]="DotMultiMid", + [14]="IgnoreEnemyPhysMitHigh", + [15]="IgnoreEnemyPhysMitLow", + [16]="IgnoreEnemyPhysMitMid", + [17]="IncreaseAreaOfEffectHigh", + [18]="IncreaseAreaOfEffectLow", + [19]="IncreaseAreaOfEffectMid", + [20]="IncreaseDurationHigh", + [21]="IncreaseDurationLow", + [22]="IncreaseDurationMid", + [23]="VaalReapSpecificFireDebuffHigh" + }, + secondarySkillId="VaalReapMercenaryEncounter", + supportCountId="High" + }, + VaalSplitArrowMercenary={ + description="Fires multiple arrows which redirect and split midair multiple times.", + familyId="Infrequent", + hash=8546, + icon="", + id="VaalSplitArrowMercenary", + name="Greater Split Arrow", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="IgnoreEnemyPhysMitHigh", + [8]="IgnoreEnemyPhysMitLow", + [9]="IgnoreEnemyPhysMitMid", + [10]="IncreasedProjSpeedHigh", + [11]="IncreasedProjSpeedLow", + [12]="IncreasedProjSpeedMid", + [13]="MultipleProjectilesHigh", + [14]="MultipleProjectilesLow", + [15]="ProjectilesReturnHigh", + [16]="ReducedProjSpeedHigh", + [17]="ReducedProjSpeedLow", + [18]="ReducedProjSpeedMid" + }, + supportCountId="High" + }, + VaalVitalityMercenary={ + description="Casts a temporary aura that grants life regeneration.", + hash=14889, + icon="Art/2DArt/SkillIcons/HouseCyaxanSkill.dds", + id="VaalVitalityMercenary", + name="Vaal Vitality", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid" + }, + supportCountId="Low" + }, + VenomGyreMercenary={ + description="Fires a returning projectile that can be caught. Caught projectiles spiral outwards when you use Whirling Blades and do not return.", + hash=59831, + icon="", + id="VenomGyreMercenary", + name="Venom Gyre", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="AilmentDamageHigh", + [5]="AilmentDamageLow", + [6]="AilmentDamageMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="IncreasedProjSpeedHigh", + [14]="IncreasedProjSpeedLow", + [15]="IncreasedProjSpeedMid", + [16]="MultipleProjectilesHigh", + [17]="MultipleProjectilesLow", + [18]="PhysGainAsChaosHigh", + [19]="PhysGainAsChaosMid", + [20]="PoisonChanceHigh", + [21]="PoisonChanceLow", + [22]="PoisonChanceMid" + }, + supportCountId="High" + }, + VigilantStrikeMercenary={ + description="Attacks enemies with a powerful melee strike which grants Fortification, reducing damage taken from hits. The cooldown can be bypassed by expending an Endurance Charge.", + familyId="Infrequent", + hash=4988, + icon="", + id="VigilantStrikeMercenary", + name="Vigilant Strike", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AttackSpeedHigh", + [3]="AttackSpeedLow", + [4]="AttackSpeedMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseDurationHigh", + [9]="IncreaseDurationLow", + [10]="IncreaseDurationMid", + [11]="MeleePhysHigh", + [12]="MeleePhysLow", + [13]="MeleePhysMid", + [14]="MeleeSplashHigh", + [15]="StrikeRangeHigh", + [16]="StrikeRangeLow", + [17]="StrikeRangeMid", + [18]="VigilantStrikeSpecificShareFortifyHigh" + }, + supportCountId="High" + }, + ViperStrikeMercenary={ + description="Hits enemies, converting some of the physical damage to chaos damage and inflicting poison which will be affected by modifiers to skill duration. If dual wielding, will strike with both weapons.", + hash=22227, + icon="", + id="ViperStrikeMercenary", + name="Viper Strike", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="AilmentDamageHigh", + [5]="AilmentDamageLow", + [6]="AilmentDamageMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="DotMultiHigh", + [11]="DotMultiLow", + [12]="DotMultiMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid", + [16]="MeleeSplashHigh", + [17]="MultistrikeHigh", + [18]="MultistrikeMid", + [19]="PhysGainAsChaosHigh", + [20]="PhysGainAsChaosMid", + [21]="PoisonChanceHigh", + [22]="PoisonChanceLow", + [23]="PoisonChanceMid", + [24]="StrikeRangeHigh", + [25]="StrikeRangeLow", + [26]="StrikeRangeMid" + }, + secondarySkillId="ViperStrikeMercenaryEncounter", + supportCountId="High" + }, + VitalityMercenary={ + description="Casts an aura that grants life regeneration.", + hash=40419, + icon="", + id="VitalityMercenary", + name="Vitality", + possibleSupportIds={ + }, + supportCountId="None" + }, + VoidSphereMercenary={ + description="Creates a Void Sphere which Hinders enemies in an area around it, with the debuff being stronger on enemies closer to the sphere. It also regularly releases pulses of area damage. The Void Sphere will consume the corpses of any enemies which die in its area.", + hash=52783, + icon="", + id="VoidSphereMercenary", + name="Void Sphere", + possibleSupportIds={ + [1]="CooldownSpeedHigh", + [2]="CooldownSpeedLow", + [3]="CooldownSpeedMid", + [4]="CritDamageHigh", + [5]="CritDamageLow", + [6]="CritDamageMid", + [7]="CriticalStrikeHigh", + [8]="CriticalStrikeLow", + [9]="CriticalStrikeMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid", + [16]="PhysGainAsChaosHigh", + [17]="PhysGainAsChaosMid", + [18]="VoidSphereSpecificTickRateHigh", + [19]="WitherOnHitHigh", + [20]="WitherOnHitLow", + [21]="WitherOnHitMid" + }, + supportCountId="Medium" + }, + VolcanicFissureAltMercenary={ + description="Slam the ground, creating a winding fissure that deals area damage while travelling outwards. When it reaches the target location it erupts dealing damage in an area. After erupting, the fissure can continue to move towards enemies to cause further eruptions.", + hash=53235, + icon="", + id="VolcanicFissureAltMercenary", + name="Volcanic Fissure of Snaking", + possibleSupportIds={ + [1]="AddedFireHigh", + [2]="AddedFireLow", + [3]="AddedFireMid", + [4]="AttackSpeedHigh", + [5]="AttackSpeedLow", + [6]="AttackSpeedMid", + [7]="CombustionHigh", + [8]="FirePenetrationHigh", + [9]="FirePenetrationLow", + [10]="FirePenetrationMid", + [11]="FistOfWarHigh", + [12]="IgniteChanceHigh", + [13]="IgniteChanceLow", + [14]="IgniteChanceMid", + [15]="IncreaseAreaOfEffectHigh", + [16]="IncreaseAreaOfEffectLow", + [17]="IncreaseAreaOfEffectMid", + [18]="KnockbackLow", + [19]="PulveriseHigh", + [20]="PulveriseLow", + [21]="PulveriseMid", + [22]="VolcanicFissureSpecificRepeatHigh" + }, + secondarySkillId="VolcanicFissureAltMercenaryEncounter", + supportCountId="High" + }, + VoltaxicBurstMercenary={ + description="Each cast of this spell waits for a short duration, releasing a burst of lightning and chaos spell damage in the surrounding area when that duration ends. Enemies killed by this damage, or shortly after, will explode.", + hash=52144, + icon="", + id="VoltaxicBurstMercenary", + name="Voltaxic Burst", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="CastSpeedHigh", + [5]="CastSpeedLow", + [6]="CastSpeedMid", + [7]="ChaosPenHigh", + [8]="ChaosPenLow", + [9]="ChaosPenMid", + [10]="CritDamageHigh", + [11]="CritDamageLow", + [12]="CritDamageMid", + [13]="CriticalStrikeHigh", + [14]="CriticalStrikeLow", + [15]="CriticalStrikeMid", + [16]="IncreaseAreaOfEffectHigh", + [17]="IncreaseAreaOfEffectLow", + [18]="IncreaseAreaOfEffectMid", + [19]="IncreaseDurationHigh", + [20]="IncreaseDurationLow", + [21]="IncreaseDurationMid", + [22]="ReduceDurationHigh", + [23]="ReduceDurationLow", + [24]="ReduceDurationMid", + [25]="VoltaxicBurstSpecificConvertLightningToChaosHigh", + [26]="WitherOnHitHigh", + [27]="WitherOnHitLow", + [28]="WitherOnHitMid" + }, + supportCountId="High" + }, + VortexMercenary={ + description="An icy blast explodes around the caster, dealing cold damage to enemies, and leaving behind a whirling vortex which deals cold damage over time and chills enemies caught in it.", + familyId="Infrequent", + hash=31928, + icon="", + id="VortexMercenary", + name="Vortex", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="DamageOverTimeReduceDurationHigh", + [5]="DamageOverTimeReduceDurationLow", + [6]="DamageOverTimeReduceDurationMid", + [7]="HypothermiaHigh", + [8]="HypothermiaLow", + [9]="HypothermiaMid", + [10]="IncreaseAreaOfEffectHigh", + [11]="IncreaseAreaOfEffectLow", + [12]="IncreaseAreaOfEffectMid", + [13]="IncreaseDurationHigh", + [14]="IncreaseDurationLow", + [15]="IncreaseDurationMid", + [16]="NonDamagingAilmentEffectHigh", + [17]="NonDamagingAilmentEffectLow", + [18]="NonDamagingAilmentEffectMid" + }, + secondarySkillId="VortexMercenaryEncounter", + supportCountId="High" + }, + WaveOfConvictionAltMercenary={ + description="An expanding wave of energy surges outwards, damaging enemies in a ring-shaped area over a duration. The ring then returns, damaging enemies again on the way back.", + familyId="Infrequent", + hash=4286, + icon="", + id="WaveOfConvictionAltMercenary", + name="Wave of Conviction of Trarthus", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AddedFireHigh", + [3]="AddedFireLow", + [4]="AddedFireMid", + [5]="CombustionHigh", + [6]="CooldownSpeedHigh", + [7]="CooldownSpeedLow", + [8]="CooldownSpeedMid", + [9]="FirePenetrationHigh", + [10]="FirePenetrationLow", + [11]="FirePenetrationMid", + [12]="IncreaseAreaOfEffectHigh", + [13]="IncreaseAreaOfEffectLow", + [14]="IncreaseAreaOfEffectMid", + [15]="IncreaseDurationHigh", + [16]="IncreaseDurationLow", + [17]="IncreaseDurationMid", + [18]="PhysGainAsRandomHigh", + [19]="PhysGainAsRandomLow", + [20]="PhysGainAsRandomMid" + }, + supportCountId="Medium" + }, + WaveOfConvictionLightningMercenary={ + description="An expanding wave of energy surges forward, damaging enemies in a cone-shaped area over a duration. Each enemy hit is inflicted with Exposure matching the element of which they took the highest damage", + hash=14732, + icon="", + id="WaveOfConvictionLightningMercenary", + name="Wave of Conviction", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="AddedLightningHigh", + [3]="AddedLightningLow", + [4]="AddedLightningMid", + [5]="CooldownSpeedHigh", + [6]="CooldownSpeedLow", + [7]="CooldownSpeedMid", + [8]="IncreaseAreaOfEffectHigh", + [9]="IncreaseAreaOfEffectLow", + [10]="IncreaseAreaOfEffectMid", + [11]="IncreaseDurationHigh", + [12]="IncreaseDurationLow", + [13]="IncreaseDurationMid", + [14]="LightningPenetrationHigh", + [15]="LightningPenetrationLow", + [16]="LightningPenetrationMid", + [17]="PhysGainAsRandomHigh", + [18]="PhysGainAsRandomLow", + [19]="PhysGainAsRandomMid" + }, + supportCountId="Low" + }, + WhirlingBladesMercenary={ + description="Dive through enemies, dealing weapon damage. If dual wielding attacks with both weapons, dealing the damage of both in one hit. Only works with Daggers, Claws, and One-Handed Swords.", + hash=10823, + icon="", + id="WhirlingBladesMercenary", + name="Whirling Blades", + possibleSupportIds={ + [1]="AddedChaosHigh", + [2]="AddedChaosLow", + [3]="AddedChaosMid", + [4]="AddedColdHigh", + [5]="AddedColdLow", + [6]="AddedColdMid", + [7]="AttackSpeedHigh", + [8]="AttackSpeedLow", + [9]="AttackSpeedMid", + [10]="BrutalityHigh", + [11]="BrutalityLow", + [12]="BrutalityMid", + [13]="FortifyHigh" + }, + supportCountId="Low" + }, + WildStrikeMercenary={ + description="Strike enemies, converting physical damage to a random element. Depending on the element chosen, causes a fiery explosion, an arcing bolt of lightning, or an icy wave. The same element is not chosen twice in a row.", + hash=40957, + icon="", + id="WildStrikeMercenary", + name="Wild Strike", + possibleSupportIds={ + [1]="AddedColdHigh", + [2]="AddedColdHigh", + [3]="AddedColdLow", + [4]="AddedColdLow", + [5]="AddedColdMid", + [6]="AddedColdMid", + [7]="AddedLightningHigh", + [8]="AddedLightningLow", + [9]="AddedLightningMid", + [10]="AdditionalChainsLow", + [11]="AdditionalChainsMid", + [12]="AttackSpeedHigh", + [13]="AttackSpeedLow", + [14]="AttackSpeedMid", + [15]="ColdPenetrationHigh", + [16]="ColdPenetrationLow", + [17]="ColdPenetrationMid", + [18]="EleDamageWithAttacksHigh", + [19]="EleDamageWithAttacksLow", + [20]="EleDamageWithAttacksMid", + [21]="HypothermiaHigh", + [22]="HypothermiaLow", + [23]="HypothermiaMid", + [24]="MultipleProjectilesHigh", + [25]="MultipleProjectilesHigh", + [26]="MultipleProjectilesLow", + [27]="MultipleProjectilesLow", + [28]="MultistrikeHigh", + [29]="MultistrikeMid", + [30]="ProjectilesReturnHigh", + [31]="WildStrikeSpecificEleWeakOnHitHigh" + }, + secondarySkillId="WildStrikeMercenaryEncounter", + supportCountId="High" + }, + WindSlashMercenary={ + description="Release an arc of pure force, dealing area damage.", + hash=19808, + icon="Art/2DArt/SkillIcons/HouseAzadiSkill.dds", + id="WindSlashMercenary", + name="Slicing Wind", + possibleSupportIds={ + [1]="AttackSpeedHigh", + [2]="AttackSpeedLow", + [3]="AttackSpeedMid", + [4]="BrutalityHigh", + [5]="BrutalityLow", + [6]="BrutalityMid", + [7]="IncreaseAreaOfEffectHigh", + [8]="IncreaseAreaOfEffectLow", + [9]="IncreaseAreaOfEffectMid", + [10]="KnockbackLow", + [11]="LeechHigh", + [12]="LeechLow", + [13]="LeechMid", + [14]="MeleePhysHigh", + [15]="MeleePhysLow", + [16]="MeleePhysMid", + [17]="PulveriseHigh", + [18]="PulveriseLow", + [19]="PulveriseMid", + [20]="RageOnMeleeHitHigh", + [21]="RageOnMeleeHitLow", + [22]="RageOnMeleeHitMid" + }, + secondarySkillId="WindSlashMercenaryEncounter", + supportCountId="High" + }, + WitherTotemMercenary={ + description="Creates a Spell Totem that casts a debilitating debuff on enemies in an area, hindering their movement and also inflicts the Withered debuff, which increases the Chaos Damage they take and can stack up to 15 times.", + familyId="WitherApplication", + hash=1911, + icon="", + id="WitherTotemMercenary", + name="Wither Totem", + possibleSupportIds={ + [1]="CastSpeedHigh", + [2]="CastSpeedLow", + [3]="CastSpeedMid", + [4]="IncreaseAreaOfEffectHigh", + [5]="IncreaseAreaOfEffectLow", + [6]="IncreaseAreaOfEffectMid", + [7]="IncreaseDurationHigh", + [8]="IncreaseDurationLow", + [9]="IncreaseDurationMid", + [10]="TotemDefencesHigh", + [11]="TotemDefencesLow", + [12]="TotemDefencesMid" + }, + supportCountId="Low" + }, + WitheringStepMercenary={ + description="Grants Elusive and a buff that grants Phasing. While this buff is active, enemies in the surrounding area will be Withered.", + familyId="WitherApplication", + hash=10320, + icon="", + id="WitheringStepMercenary", + name="Withering Step", + possibleSupportIds={ + [1]="AddedCooldownCountHigh", + [2]="CooldownSpeedHigh", + [3]="CooldownSpeedLow", + [4]="CooldownSpeedMid", + [5]="IncreaseAreaOfEffectHigh", + [6]="IncreaseAreaOfEffectLow", + [7]="IncreaseAreaOfEffectMid", + [8]="WitheringStepSpecificWitherStacksHigh" + }, + supportCountId="Low" + }, + WrathMercenary={ + description="Casts an aura that adds lightning damage to attacks, and makes spells deal more lightning damage.", + hash=38326, + icon="", + id="WrathMercenary", + name="Wrath", + possibleSupportIds={ + }, + secondarySkillId="WrathMercenaryEncounter", + supportCountId="None" + }, + ZealotryMercenary={ + description="Casts an aura that grants bonuses to damage and critical strike chance of spells, and gives a chance to create Consecrated Ground against stronger enemies.", + hash=14498, + icon="", + id="ZealotryMercenary", + name="Zealotry", + possibleSupportIds={ + }, + supportCountId="None" + } + }, + skillsByHash={ + ["10235"]={ + [1]="DualStrikeMercenary" + }, + ["10320"]={ + [1]="WitheringStepMercenary" + }, + ["10557"]={ + [1]="FrostBombMercenary" + }, + ["10712"]={ + [1]="VaalGroundSlamMercenary" + }, + ["10722"]={ + [1]="BlinkArrowMercenary" + }, + ["10742"]={ + [1]="SoulrendAltMercenary" + }, + ["10823"]={ + [1]="WhirlingBladesMercenary" + }, + ["11018"]={ + [1]="IceCrashMercenary" + }, + ["11054"]={ + [1]="BladeTrapMercenary" + }, + ["11256"]={ + [1]="PhysStormCallMercenary" + }, + ["11495"]={ + [1]="IceShotMercenary" + }, + ["11671"]={ + [1]="GigaSoulrendMercenary" + }, + ["1185"]={ + [1]="VaalReapMercenary" + }, + ["11879"]={ + [1]="OrbOfStormsMercenary" + }, + ["12260"]={ + [1]="BarrageAltMercenary" + }, + ["12262"]={ + [1]="PestilentStrikeMercenary" + }, + ["12357"]={ + [1]="BladestormMercenary" + }, + ["12583"]={ + [1]="KineticBoltMercenary" + }, + ["12667"]={ + [1]="EnsnaringArrowMercenary" + }, + ["12723"]={ + [1]="VaalCleaveMercenary" + }, + ["12729"]={ + [1]="ShatteringSteelMercenary" + }, + ["13235"]={ + [1]="AngerMercenary" + }, + ["13441"]={ + [1]="SandstormChaosMercenary" + }, + ["1356"]={ + [1]="BarrageMercenary" + }, + ["13693"]={ + [1]="PurityOfIceMercenary" + }, + ["13711"]={ + [1]="BearTrapMercenary" + }, + ["14064"]={ + [1]="ReapMercenary" + }, + ["14498"]={ + [1]="ZealotryMercenary" + }, + ["14732"]={ + [1]="WaveOfConvictionLightningMercenary" + }, + ["14816"]={ + [1]="EarthquakeColdMercenary" + }, + ["14889"]={ + [1]="VaalVitalityMercenary" + }, + ["14992"]={ + [1]="AbyssalCryMercenary" + }, + ["1516"]={ + [1]="MalevolenceMercenary" + }, + ["15611"]={ + [1]="AbsolutionMercenary" + }, + ["1577"]={ + [1]="HolyFireMortarMercenary" + }, + ["16018"]={ + [1]="ProximityShieldMercenary" + }, + ["16356"]={ + [1]="KineticBlastAltMercenary" + }, + ["16381"]={ + [1]="VaalIceShotMercenary" + }, + ["16896"]={ + [1]="CobraLashMercenary" + }, + ["17015"]={ + [1]="PhysicalAegisMercenary" + }, + ["17037"]={ + [1]="LightningTrapMercenary" + }, + ["17105"]={ + [1]="QuickGuardAllyMercenary" + }, + ["17147"]={ + [1]="InfernalBlowAltMercenary" + }, + ["17198"]={ + [1]="DonutCircleMercenary" + }, + ["17216"]={ + [1]="StormRainMercenary" + }, + ["17409"]={ + [1]="SummonSkeletonsMercenary" + }, + ["17515"]={ + [1]="EnvyMercenary" + }, + ["17654"]={ + [1]="SunderAltMercenary" + }, + ["17763"]={ + [1]="PurifyingFlameMercenary" + }, + ["18004"]={ + [1]="BlastRainAltMercenary" + }, + ["18149"]={ + [1]="TriggeredFireSlamMercenary" + }, + ["18232"]={ + [1]="HydraForkArrowMercenary" + }, + ["18793"]={ + [1]="PrideMercenary" + }, + ["18986"]={ + [1]="DeceleratingProjectileMercenary" + }, + ["19034"]={ + [1]="MercenaryLightningDelayedBlast" + }, + ["19108"]={ + [1]="SummonRagingSpiritMercenary" + }, + ["1911"]={ + [1]="WitherTotemMercenary" + }, + ["19178"]={ + [1]="LightningStrikeFireMercenary" + }, + ["19268"]={ + [1]="CGEOilGroundSlowMercenary" + }, + ["19417"]={ + [1]="AspectOfTheSpiderMercenary" + }, + ["19808"]={ + [1]="WindSlashMercenary" + }, + ["20973"]={ + [1]="EnduringCryMercenary" + }, + ["21036"]={ + [1]="MoltenShellMercenary" + }, + ["21201"]={ + [1]="ShieldCrushMercenary" + }, + ["2135"]={ + [1]="LeapSlamMercenary" + }, + ["21523"]={ + [1]="DesecrateMercenary" + }, + ["21708"]={ + [1]="DisciplineMercenary" + }, + ["2187"]={ + [1]="StormCallAltMercenary" + }, + ["21962"]={ + [1]="ConflagrationMercenary" + }, + ["22000"]={ + [1]="VaalLightningArrowMercenary" + }, + ["22105"]={ + [1]="FrostBladesMercenary" + }, + ["22227"]={ + [1]="ViperStrikeMercenary" + }, + ["22696"]={ + [1]="BoneshatterMercenary" + }, + ["22724"]={ + [1]="LightningWarpPhysMercenary" + }, + ["22850"]={ + [1]="ShieldChargeMercenary" + }, + ["23225"]={ + [1]="TornadoAltMercenary" + }, + ["23512"]={ + [1]="VaalBurningArrowMercenary" + }, + ["24099"]={ + [1]="GigaFlameDashMercenary" + }, + ["24179"]={ + [1]="AlchemistsMarkMercenary" + }, + ["24409"]={ + [1]="BlastRainColdMercenary" + }, + ["24482"]={ + [1]="HatredMercenary" + }, + ["24685"]={ + [1]="DivineRetributionMercenary" + }, + ["24931"]={ + [1]="StaticStrikeMercenary" + }, + ["25149"]={ + [1]="VaalLightningTrapMercenary" + }, + ["25718"]={ + [1]="BladeVortexMercenary" + }, + ["26057"]={ + [1]="TemporalAnomalyMercenary" + }, + ["26391"]={ + [1]="EnfeebleMercenary" + }, + ["26705"]={ + [1]="PowerSiphonMercenary" + }, + ["26913"]={ + [1]="DeceleratingProjectileMercenaryExplode" + }, + ["26931"]={ + [1]="BloodMortarMercenary" + }, + ["27165"]={ + [1]="GalvanicArrowMercenary" + }, + ["27763"]={ + [1]="ABTTExtraImpaleMercenary" + }, + ["27805"]={ + [1]="PoachersMarkMercenary" + }, + ["2792"]={ + [1]="GraceMercenary" + }, + ["28026"]={ + [1]="DonutBladesMercenary" + }, + ["28502"]={ + [1]="ScourgeArrowAltMercenary" + }, + ["28506"]={ + [1]="HolyHammersMercenary" + }, + ["28511"]={ + [1]="SplittingSteelMercenary" + }, + ["28637"]={ + [1]="IcestormMercenary" + }, + ["28757"]={ + [1]="LightningWarpMercenary" + }, + ["28785"]={ + [1]="ClarityMercenary" + }, + ["28988"]={ + [1]="SpectralHelixAltMercenary" + }, + ["29071"]={ + [1]="ForbiddenRiteTotemMercenary" + }, + ["29426"]={ + [1]="VaalFlameblastMercenary" + }, + ["29533"]={ + [1]="ArcAltMercenary" + }, + ["30130"]={ + [1]="RollingMagmaMercenary" + }, + ["30431"]={ + [1]="PunctureMercenary" + }, + ["30663"]={ + [1]="BallLightningAltMercenary" + }, + ["3093"]={ + [1]="ConsecratedPathMercenary" + }, + ["31440"]={ + [1]="BurrowMercenary" + }, + ["3148"]={ + [1]="GigaStormCallMercenary" + }, + ["31928"]={ + [1]="VortexMercenary" + }, + ["32089"]={ + [1]="KineticRainAltXMercenary" + }, + ["32391"]={ + [1]="PunishmentMercenary" + }, + ["324"]={ + [1]="FireballMercenary" + }, + ["32807"]={ + [1]="HeraldOfIceMercenary" + }, + ["33661"]={ + [1]="SigilOfPowerMercenary" + }, + ["33663"]={ + [1]="FrostboltMercenary" + }, + ["33728"]={ + [1]="PurityOfFireMercenary" + }, + ["34212"]={ + [1]="HeraldOfPurityMercenary" + }, + ["34665"]={ + [1]="BurningArrowMercenary" + }, + ["3493"]={ + [1]="GigaVortexTrapMercenary" + }, + ["35371"]={ + [1]="DarkPactMercenary" + }, + ["35610"]={ + [1]="ArtilleryBallistaMercenary" + }, + ["36274"]={ + [1]="VaalCausticArrowMercenary" + }, + ["36279"]={ + [1]="PrecisionMercenary" + }, + ["36298"]={ + [1]="ExplosiveArrowBarrageMercenary" + }, + ["36446"]={ + [1]="MoltenStrikePoisonMercenary" + }, + ["37132"]={ + [1]="VaalDoubleStrikeMercenary" + }, + ["37202"]={ + [1]="BladefallMercenary" + }, + ["37344"]={ + [1]="BattlemagesCryMercenary" + }, + ["37561"]={ + [1]="BallLightningAltTrapMercenary" + }, + ["37821"]={ + [1]="FireballAltMercenary" + }, + ["37916"]={ + [1]="SpectralHelixMercenary" + }, + ["38072"]={ + [1]="ActionSpeedAuraMercenary" + }, + ["38103"]={ + [1]="HeavyStrikeAltMercenary" + }, + ["38104"]={ + [1]="DecoyTotemMercenary" + }, + ["38311"]={ + [1]="IntimidatingCryMercenary" + }, + ["38326"]={ + [1]="WrathMercenary" + }, + ["38521"]={ + [1]="VaalAncestralWarchiefMercenary" + }, + ["38628"]={ + [1]="ToxicRainMercenary" + }, + ["38655"]={ + [1]="HolyStrikeMercenary" + }, + ["38993"]={ + [1]="GigaLightningArrowMercenary" + }, + ["39265"]={ + [1]="RallyingCryMercenary" + }, + ["39298"]={ + [1]="FlammabilityBlasphemyMercenary" + }, + ["39669"]={ + [1]="EssenceDrainAltMercenary" + }, + ["39732"]={ + [1]="DoryanisTouchMercenary" + }, + ["40419"]={ + [1]="VitalityMercenary" + }, + ["40439"]={ + [1]="ExsanguinateMercenary" + }, + ["40470"]={ + [1]="FrostblinkMercenary" + }, + ["40521"]={ + [1]="FlammabilityMercenary" + }, + ["40527"]={ + [1]="TectonicSlamPhysMercenary" + }, + ["40723"]={ + [1]="MeteorUpheavalMercenary" + }, + ["40759"]={ + [1]="RainOfArrowsAltMercenary" + }, + ["40812"]={ + [1]="SummonHolyRelicMercenary" + }, + ["40957"]={ + [1]="WildStrikeMercenary" + }, + ["41051"]={ + [1]="LightningArrowMercenary" + }, + ["41346"]={ + [1]="EarthquakeAltMercenary" + }, + ["41484"]={ + [1]="ConductivityMercenary" + }, + ["41834"]={ + [1]="SpectralShieldThrowAltMercenary" + }, + ["41915"]={ + [1]="LeapSlamMercenaryAlt" + }, + ["42219"]={ + [1]="VaalMoltenStrikeMercenary" + }, + ["42361"]={ + [1]="FissureSlamMercenary" + }, + ["4286"]={ + [1]="WaveOfConvictionAltMercenary" + }, + ["43202"]={ + [1]="SplitArrowMercenary" + }, + ["43742"]={ + [1]="DominatingBlowMercenary" + }, + ["43812"]={ + [1]="LancingSteelMercenary" + }, + ["4383"]={ + [1]="SSMPaganBishopMercenary" + }, + ["44144"]={ + [1]="SiegeBallistaAltMercenary" + }, + ["44258"]={ + [1]="GigaKineticBlastMercenary" + }, + ["44296"]={ + [1]="SummonSkitterbotsMercenary" + }, + ["44334"]={ + [1]="HeraldOfAshMercenary" + }, + ["44422"]={ + [1]="CGEBloodGroundMercenary" + }, + ["44455"]={ + [1]="VaalArcticArmourMercenary" + }, + ["44467"]={ + [1]="BoneOfferingMercenary" + }, + ["45226"]={ + [1]="DivineIreMercenary" + }, + ["45615"]={ + [1]="ABTTInvulnBubbleMercenary" + }, + ["46131"]={ + [1]="CallOfSteelMercenary" + }, + ["46739"]={ + [1]="CycloneReverseKnockbackMercenary" + }, + ["47031"]={ + [1]="VaalGlacialHammerMercenary" + }, + ["47078"]={ + [1]="SSMHolySpectresMercenary" + }, + ["47293"]={ + [1]="ScorchingRayTotemMercenary" + }, + ["47364"]={ + [1]="FlameLinkMercenary" + }, + ["47406"]={ + [1]="AssassinsMarkMercenary" + }, + ["47949"]={ + [1]="HolyFlameTotemMercenary" + }, + ["4927"]={ + [1]="BodyswapMercenary" + }, + ["4988"]={ + [1]="VigilantStrikeMercenary" + }, + ["50009"]={ + [1]="FrostWallMercenary" + }, + ["50290"]={ + [1]="GigaShockNovaMercenary" + }, + ["50349"]={ + [1]="RaiseSpectreAltMercenary" + }, + ["50414"]={ + [1]="FireAegisMercenary" + }, + ["50670"]={ + [1]="OfferingOfJudgementChaosMercenary" + }, + ["50866"]={ + [1]="PhysicalBeaconMercenary" + }, + ["50999"]={ + [1]="EtherealKnivesMercenary" + }, + ["51031"]={ + [1]="DoLiterallyNothing" + }, + ["51539"]={ + [1]="ChaosGlacialCascadeMercenary" + }, + ["52105"]={ + [1]="RemoteSlamMercenary" + }, + ["52144"]={ + [1]="VoltaxicBurstMercenary" + }, + ["52155"]={ + [1]="HasteMercenary" + }, + ["5247"]={ + [1]="LightningWarpTrapsMercenary" + }, + ["52491"]={ + [1]="GigaRaiseZombieMercenary" + }, + ["52494"]={ + [1]="ABTTArmourEleMercenary" + }, + ["52783"]={ + [1]="VoidSphereMercenary" + }, + ["52845"]={ + [1]="DeterminationMercenary" + }, + ["53217"]={ + [1]="GlacialHammerMercenary" + }, + ["53235"]={ + [1]="VolcanicFissureAltMercenary" + }, + ["53518"]={ + [1]="MoltenStrikeHolyMercenary" + }, + ["53527"]={ + [1]="SSMSkeletalBossMercenary" + }, + ["53728"]={ + [1]="GroundSlamMercenary" + }, + ["54006"]={ + [1]="PerforateMercenary" + }, + ["54144"]={ + [1]="SSMMercenarySoulrendOrb" + }, + ["55367"]={ + [1]="ArcticArmourMercenary" + }, + ["55917"]={ + [1]="SmiteMercenary" + }, + ["56180"]={ + [1]="FlameDashMercenary" + }, + ["5673"]={ + [1]="ChargedDashSpellScalingMercenary" + }, + ["56742"]={ + [1]="DespairMercenary" + }, + ["5689"]={ + [1]="ElementalWeaknessMercenary" + }, + ["57063"]={ + [1]="EyeOfWinterMercenary" + }, + ["57171"]={ + [1]="MassEnduranceMercenary" + }, + ["57377"]={ + [1]="RaiseZombieAltMercenary" + }, + ["57450"]={ + [1]="FlameWallMercenary" + }, + ["57491"]={ + [1]="FrostShieldMercenary" + }, + ["58174"]={ + [1]="CausticArrowMercenary" + }, + ["58425"]={ + [1]="VaalGraceMercenary" + }, + ["58592"]={ + [1]="FrenzyMercenary" + }, + ["58855"]={ + [1]="TempestShieldMercenary" + }, + ["5893"]={ + [1]="SparkMercenary" + }, + ["59005"]={ + [1]="ArcMercenary" + }, + ["59200"]={ + [1]="DropArrowMercenary" + }, + ["59259"]={ + [1]="InfernalCryMercenary" + }, + ["59409"]={ + [1]="MassFrenzyMercenary" + }, + ["59477"]={ + [1]="BladefallAltMercenary" + }, + ["59831"]={ + [1]="VenomGyreMercenary" + }, + ["60048"]={ + [1]="LunarisSpellBarrageTrapMercenary" + }, + ["60723"]={ + [1]="DashMercenary" + }, + ["60880"]={ + [1]="ABTTPhysEnrageMercenary" + }, + ["61471"]={ + [1]="IceNovaProjectedMercenary" + }, + ["61497"]={ + [1]="IceNovaMercenary" + }, + ["61523"]={ + [1]="SSMVollMercenary" + }, + ["61669"]={ + [1]="FlickerStrikeMercenary" + }, + ["61730"]={ + [1]="FleshOfferingMercenary" + }, + ["61903"]={ + [1]="ShrapnelBallistaMercenary" + }, + ["6228"]={ + [1]="TectonicSlamFireMercenary" + }, + ["62393"]={ + [1]="SpectralThrowAltMercenary" + }, + ["62530"]={ + [1]="EnrageMercenary" + }, + ["62758"]={ + [1]="SSMMercenaryRelic" + }, + ["62997"]={ + [1]="IceTrapMercenary" + }, + ["63233"]={ + [1]="PurityOfLightningMercenary" + }, + ["63468"]={ + [1]="BaneMercenary" + }, + ["6446"]={ + [1]="FlameblastMercenary" + }, + ["64528"]={ + [1]="SmokeMineMercenary" + }, + ["64565"]={ + [1]="HeavyStrikeMercenary" + }, + ["6479"]={ + [1]="FrostbiteMercenary" + }, + ["65447"]={ + [1]="MirrorArrowMercenary" + }, + ["65473"]={ + [1]="InspiringCryMercenary" + }, + ["6651"]={ + [1]="ShockwaveTotemMercenary" + }, + ["7182"]={ + [1]="ChainHookAltMercenary" + }, + ["7383"]={ + [1]="TemporalChainsMercenary" + }, + ["7395"]={ + [1]="SweepMercenary" + }, + ["7549"]={ + [1]="StormCallMercenary" + }, + ["8030"]={ + [1]="TornadoShotMercenary" + }, + ["8075"]={ + [1]="LightningSpireTrapMercenary" + }, + ["8136"]={ + [1]="LacerateMercenary" + }, + ["8295"]={ + [1]="FireEnrageMercenary" + }, + ["8445"]={ + [1]="CleaveMercenary" + }, + ["8450"]={ + [1]="BlightMercenary" + }, + ["8546"]={ + [1]="VaalSplitArrowMercenary" + }, + ["8708"]={ + [1]="ElementalHitColdOnlyMercenary" + }, + ["8801"]={ + [1]="FlameSurgeMercenary" + }, + ["8958"]={ + [1]="BladeVortexAltMercenary" + }, + ["899"]={ + [1]="MoltenStrikeMercenary" + }, + ["9321"]={ + [1]="CreepingFrostTrapMercenary" + } + }, + summonedMinions={ + SSMHolySpectresMercenary="Metadata/Monsters/HolyFireElemental/HolyFireElementalSolarisBeam", + SSMMercenaryRelic="Metadata/Monsters/Mercenaries/MercenaryUnholyRelic_", + SSMMercenarySoulrendOrb="Metadata/Monsters/Mercenaries/MercenarySoulrendOrb", + SSMPaganBishopMercenary="Metadata/Monsters/Skeletons/MapSkeletonBossMeleeStandalone", + SSMPaganBishopMercenaryEncounter="Metadata/Monsters/Skeletons/MapSkeletonBossMeleeStandalone", + SSMSkeletalBossMercenary="Metadata/Monsters/Skeletons/SkeletonLargeMapBossStandaloneMercenary", + SSMSkeletalBossMercenaryEncounter="Metadata/Monsters/Skeletons/SkeletonLargeMapBossStandaloneMercenary", + SSMVollMercenary="Metadata/Monsters/Voll/VollMapBossStandalone_Mercenary", + SSMVollMercenaryEncounter="Metadata/Monsters/Voll/VollMapBossStandalone_Mercenary" + }, + supportFamilies={ + AddedChaos={ + id="AddedChaos" + }, + AddedCold={ + id="AddedCold" + }, + AddedFire={ + id="AddedFire" + }, + AddedLightning={ + id="AddedLightning" + }, + AdditionalChains={ + id="AdditionalChains" + }, + AilmentDamage={ + id="AilmentDamage" + }, + AttackSpeed={ + id="AttackSpeed" + }, + Bleed={ + id="Bleed" + }, + Brutality={ + id="Brutality" + }, + CastSpeed={ + id="CastSpeed" + }, + ChannelSkillDamageReduction={ + id="ChannelSkillDamageReduction" + }, + ChaosPen={ + id="ChaosPen" + }, + ColdPenetration={ + id="ColdPenetration" + }, + ConcEffect={ + id="ConcEffect" + }, + Cooldown={ + id="Cooldown" + }, + CritChance={ + id="CritChance" + }, + CritDamage={ + id="CritDamage" + }, + DOTReducedDuration={ + id="DOTReducedDuration" + }, + DotMulti={ + id="DotMulti" + }, + Duration={ + id="Duration" + }, + EleFocus={ + id="EleFocus" + }, + Excommunicate={ + id="Excommunicate" + }, + FirePenetration={ + id="FirePenetration" + }, + FreezeChance={ + id="FreezeChance" + }, + Generosity={ + id="Generosity" + }, + Hypothermia={ + id="Hypothermia" + }, + IgniteChance={ + id="IgniteChance" + }, + IgnorePhysMit={ + id="IgnorePhysMit" + }, + ImpaleChance={ + id="ImpaleChance" + }, + IncreaseAreaOfEffect={ + id="IncreaseAreaOfEffect" + }, + LightPenetration={ + id="LightPenetration" + }, + MeleePhys={ + id="MeleePhys" + }, + MinionDamage={ + id="MinionDamage" + }, + MinionLife={ + id="MinionLife" + }, + MultipleProjectiles={ + id="MultipleProjectiles" + }, + Multistrike={ + id="Multistrike" + }, + NonDamagingAilmentEffect={ + id="NonDamagingAilmentEffect" + }, + PhysGainAs={ + id="PhysGainAs" + }, + Pierce={ + id="Pierce" + }, + PoisonChance={ + id="PoisonChance" + }, + ProjectileSpeed={ + id="ProjectileSpeed" + }, + Pulverise={ + id="Pulverise" + }, + RageOnHit={ + id="RageOnHit" + }, + RageWarcry={ + id="RageWarcry" + }, + ShockChance={ + id="ShockChance" + }, + SpellCascade={ + id="SpellCascade" + }, + StrikeRange={ + id="StrikeRange" + }, + TotemDefences={ + id="TotemDefences" + }, + TrapMineDamage={ + id="TrapMineDamage" + }, + TrapThrowSpeed={ + id="TrapThrowSpeed" + }, + WED={ + id="WED" + }, + WarcrySpeed={ + id="WarcrySpeed" + }, + WitherOnHit={ + id="WitherOnHit" + } + }, + supports={ + AddedChaosHigh={ + familyId="AddedChaos", + hash=11914, + icon="Art/2DItems/Gems/Support/AddedChaosDamage.dds", + id="AddedChaosHigh", + name="Greater Added Chaos", + stats={ + [1]={ + id="global_minimum_added_chaos_damage", + value=73 + }, + [2]={ + id="global_maximum_added_chaos_damage", + value=109 + } + }, + variant=3 + }, + AddedChaosLow={ + familyId="AddedChaos", + hash=45284, + icon="Art/2DItems/Gems/Support/AddedChaosDamage.dds", + id="AddedChaosLow", + name="Lesser Added Chaos", + stats={ + [1]={ + id="global_minimum_added_chaos_damage", + value=10 + }, + [2]={ + id="global_maximum_added_chaos_damage", + value=16 + } + }, + variant=1 + }, + AddedChaosMid={ + familyId="AddedChaos", + hash=31430, + icon="Art/2DItems/Gems/Support/AddedChaosDamage.dds", + id="AddedChaosMid", + name="Added Chaos", + stats={ + [1]={ + id="global_minimum_added_chaos_damage", + value=33 + }, + [2]={ + id="global_maximum_added_chaos_damage", + value=49 + } + }, + variant=2 + }, + AddedColdHigh={ + familyId="AddedCold", + hash=60094, + icon="Art/2DItems/Gems/Support/AddedColdDamage.dds", + id="AddedColdHigh", + name="Greater Added Cold", + stats={ + [1]={ + id="global_minimum_added_cold_damage", + value=73 + }, + [2]={ + id="global_maximum_added_cold_damage", + value=109 + } + }, + variant=3 + }, + AddedColdLow={ + familyId="AddedCold", + hash=13069, + icon="Art/2DItems/Gems/Support/AddedColdDamage.dds", + id="AddedColdLow", + name="Lesser Added Cold", + stats={ + [1]={ + id="global_minimum_added_cold_damage", + value=10 + }, + [2]={ + id="global_maximum_added_cold_damage", + value=16 + } + }, + variant=1 + }, + AddedColdMid={ + familyId="AddedCold", + hash=52758, + icon="Art/2DItems/Gems/Support/AddedColdDamage.dds", + id="AddedColdMid", + name="Added Cold", + stats={ + [1]={ + id="global_minimum_added_cold_damage", + value=33 + }, + [2]={ + id="global_maximum_added_cold_damage", + value=49 + } + }, + variant=2 + }, + AddedCooldownCountHigh={ + hash=50475, + icon="Art/2DItems/Gems/Support/SecondWindSupport.dds", + id="AddedCooldownCountHigh", + name="Second Wind", + stats={ + [1]={ + id="support_added_cooldown_count_if_not_instant", + value=1 + } + }, + variant=3 + }, + AddedFireHigh={ + familyId="AddedFire", + hash=6121, + icon="Art/2DItems/Gems/Support/AddedFireDamage.dds", + id="AddedFireHigh", + name="Greater Added Fire", + stats={ + [1]={ + id="physical_damage_%_to_add_as_fire", + value=30 + } + }, + variant=3 + }, + AddedFireLow={ + familyId="AddedFire", + hash=42977, + icon="Art/2DItems/Gems/Support/AddedFireDamage.dds", + id="AddedFireLow", + name="Lesser Added Fire", + stats={ + [1]={ + id="physical_damage_%_to_add_as_fire", + value=10 + } + }, + variant=1 + }, + AddedFireMid={ + familyId="AddedFire", + hash=45439, + icon="Art/2DItems/Gems/Support/AddedFireDamage.dds", + id="AddedFireMid", + name="Added Fire", + stats={ + [1]={ + id="physical_damage_%_to_add_as_fire", + value=20 + } + }, + variant=2 + }, + AddedLightningHigh={ + familyId="AddedLightning", + hash=40533, + icon="Art/2DItems/Gems/Support/AddedLightningDamage.dds", + id="AddedLightningHigh", + name="Greater Added Lightning", + stats={ + [1]={ + id="global_minimum_added_lightning_damage", + value=9 + }, + [2]={ + id="global_maximum_added_lightning_damage", + value=168 + } + }, + variant=3 + }, + AddedLightningLow={ + familyId="AddedLightning", + hash=36665, + icon="Art/2DItems/Gems/Support/AddedLightningDamage.dds", + id="AddedLightningLow", + name="Lesser Added Lightning", + stats={ + [1]={ + id="global_minimum_added_lightning_damage", + value=1 + }, + [2]={ + id="global_maximum_added_lightning_damage", + value=23 + } + }, + variant=1 + }, + AddedLightningMid={ + familyId="AddedLightning", + hash=64283, + icon="Art/2DItems/Gems/Support/AddedLightningDamage.dds", + id="AddedLightningMid", + name="Added Lightning", + stats={ + [1]={ + id="global_minimum_added_lightning_damage", + value=4 + }, + [2]={ + id="global_maximum_added_lightning_damage", + value=75 + } + }, + variant=2 + }, + AdditionalChainsLow={ + familyId="AdditionalChains", + hash=14317, + icon="Art/2DItems/Gems/Support/chain.dds", + id="AdditionalChainsLow", + name="Lesser Chain", + stats={ + [1]={ + id="number_of_chains", + value=1 + } + }, + variant=1 + }, + AdditionalChainsMid={ + familyId="AdditionalChains", + hash=31052, + icon="Art/2DItems/Gems/Support/chain.dds", + id="AdditionalChainsMid", + name="Chain", + stats={ + [1]={ + id="number_of_chains", + value=3 + } + }, + variant=2 + }, + AilmentDamageHigh={ + familyId="AilmentDamage", + hash=65362, + icon="Art/2DItems/Gems/Support/DeadlyAilments.dds", + id="AilmentDamageHigh", + name="Greater Ailment Damage", + stats={ + [1]={ + id="support_better_ailments_ailment_damage_+%_final", + value=30 + }, + [2]={ + id="support_better_ailments_hit_damage_+%_final", + value=-30 + } + }, + variant=3 + }, + AilmentDamageLow={ + familyId="AilmentDamage", + hash=44527, + icon="Art/2DItems/Gems/Support/DeadlyAilments.dds", + id="AilmentDamageLow", + name="Lesser Ailment Damage", + stats={ + [1]={ + id="support_better_ailments_ailment_damage_+%_final", + value=15 + }, + [2]={ + id="support_better_ailments_hit_damage_+%_final", + value=-30 + } + }, + variant=1 + }, + AilmentDamageMid={ + familyId="AilmentDamage", + hash=9607, + icon="Art/2DItems/Gems/Support/DeadlyAilments.dds", + id="AilmentDamageMid", + name="Ailment Damage", + stats={ + [1]={ + id="support_better_ailments_ailment_damage_+%_final", + value=20 + }, + [2]={ + id="support_better_ailments_hit_damage_+%_final", + value=-30 + } + }, + variant=2 + }, + AltEssenceDrainSpecificLeechHigh={ + hash=56511, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="AltEssenceDrainSpecificLeechHigh", + name="Gilded Additional Leech", + stats={ + [1]={ + id="siphon_life_leech_from_damage_permyriad", + value=3000 + } + }, + variant=3 + }, + ArcSpecificDistanceHigh={ + hash=31571, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ArcSpecificDistanceHigh", + name="Gilded Chain Distance", + stats={ + [1]={ + id="arc_damage_+%_final_for_each_remaining_chain", + value=10 + } + }, + variant=3 + }, + ArrowNovaHigh={ + hash=58429, + icon="Art/2DItems/Gems/Support/GreenRainSupportGem.dds", + id="ArrowNovaHigh", + name="Arrow Nova", + stats={ + [1]={ + id="projectiles_nova", + value=1 + }, + [2]={ + id="projectiles_rain", + value=1 + }, + [3]={ + id="skill_can_only_use_bow", + value=1 + }, + [4]={ + id="skill_is_rain_skill", + value=1 + }, + [5]={ + id="number_of_additional_projectiles", + value=3 + } + }, + variant=3 + }, + ArtilleryBallistaSpecificOnslaughtHigh={ + hash=25001, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ArtilleryBallistaSpecificOnslaughtHigh", + name="Gilded Totemic Onslaught", + stats={ + [1]={ + id="has_onslaught_if_totem_summoned_recently", + value=1 + } + }, + variant=3 + }, + AttackSpeedHigh={ + familyId="AttackSpeed", + hash=50485, + icon="Art/2DItems/Gems/Support/FasterAttacks.dds", + id="AttackSpeedHigh", + name="Greater Faster Attacks", + stats={ + [1]={ + id="attack_speed_+%", + value=35 + } + }, + variant=3 + }, + AttackSpeedLow={ + familyId="AttackSpeed", + hash=52447, + icon="Art/2DItems/Gems/Support/FasterAttacks.dds", + id="AttackSpeedLow", + name="Lesser Faster Attacks", + stats={ + [1]={ + id="attack_speed_+%", + value=15 + } + }, + variant=1 + }, + AttackSpeedMid={ + familyId="AttackSpeed", + hash=987, + icon="Art/2DItems/Gems/Support/FasterAttacks.dds", + id="AttackSpeedMid", + name="Faster Attacks", + stats={ + [1]={ + id="attack_speed_+%", + value=25 + } + }, + variant=2 + }, + BladeFallSpecificAddedVolleysHigh={ + hash=1075, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="BladeFallSpecificAddedVolleysHigh", + name="Gilded Volleys", + stats={ + [1]={ + id="bladefall_number_of_volleys", + value=2 + } + }, + variant=3 + }, + BladestormSpecificAdditionalStormHigh={ + hash=10682, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="BladestormSpecificAdditionalStormHigh", + name="Gilded Maximum Storms", + stats={ + [1]={ + id="bladestorm_maximum_number_of_storms_allowed", + value=1 + } + }, + variant=3 + }, + BlastRainAltSpecificExtraBlastHigh={ + hash=49189, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="BlastRainAltSpecificExtraBlastHigh", + name="Gilded Blasting", + stats={ + [1]={ + id="blast_rain_%_chance_for_additional_blast", + value=50 + } + }, + variant=3 + }, + BleedHigh={ + familyId="Bleed", + hash=31439, + icon="Art/2DItems/Gems/Support/ChanceToBleed.dds", + id="BleedHigh", + name="Greater Chance to Bleed", + stats={ + [1]={ + id="bleed_on_hit_with_attacks_%", + value=50 + }, + [2]={ + id="base_bleed_duration_+%", + value=40 + } + }, + variant=3 + }, + BleedLow={ + familyId="Bleed", + hash=42600, + icon="Art/2DItems/Gems/Support/ChanceToBleed.dds", + id="BleedLow", + name="Lesser Chance to Bleed", + stats={ + [1]={ + id="bleed_on_hit_with_attacks_%", + value=20 + }, + [2]={ + id="base_bleed_duration_+%", + value=20 + } + }, + variant=1 + }, + BleedMid={ + familyId="Bleed", + hash=38948, + icon="Art/2DItems/Gems/Support/ChanceToBleed.dds", + id="BleedMid", + name="Chance to Bleed", + stats={ + [1]={ + id="bleed_on_hit_with_attacks_%", + value=35 + }, + [2]={ + id="base_bleed_duration_+%", + value=20 + } + }, + variant=2 + }, + BlightSpecificSecondaryDurationHigh={ + hash=3180, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="BlightSpecificSecondaryDurationHigh", + name="Gilded Hinder Duration", + stats={ + [1]={ + id="blight_secondary_skill_effect_duration_+%", + value=80 + } + }, + variant=3 + }, + BodySwapSpecificDamageFromLifeHigh={ + hash=9300, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="BodySwapSpecificDamageFromLifeHigh", + name="Gilded Damage from Life", + stats={ + [1]={ + id="spell_base_fire_damage_%_maximum_life", + value=2 + } + }, + variant=3 + }, + BoneshatterSpecificTraumaDurationHigh={ + hash=21276, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="BoneshatterSpecificTraumaDurationHigh", + name="Gilded Trauma Duration", + stats={ + [1]={ + id="boneshatter_trauma_base_duration_ms", + value=2000 + } + }, + variant=3 + }, + BrittleChanceHigh={ + hash=54837, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="BrittleChanceHigh", + name="Brittle Chance", + stats={ + [1]={ + id="chance_to_inflict_frostburn_%", + value=30 + } + }, + variant=3 + }, + BrutalityHigh={ + familyId="Brutality", + hash=59345, + icon="Art/2DItems/Gems/Support/Brutality.dds", + id="BrutalityHigh", + name="Greater Brutality", + stats={ + [1]={ + id="deal_no_elemental_damage", + value=1 + }, + [2]={ + id="base_deal_no_chaos_damage", + value=1 + }, + [3]={ + id="support_brutality_physical_damage_+%_final", + value=30 + } + }, + variant=3 + }, + BrutalityLow={ + familyId="Brutality", + hash=55807, + icon="Art/2DItems/Gems/Support/Brutality.dds", + id="BrutalityLow", + name="Lesser Brutality", + stats={ + [1]={ + id="deal_no_elemental_damage", + value=1 + }, + [2]={ + id="base_deal_no_chaos_damage", + value=1 + }, + [3]={ + id="support_brutality_physical_damage_+%_final", + value=15 + } + }, + variant=1 + }, + BrutalityMid={ + familyId="Brutality", + hash=64271, + icon="Art/2DItems/Gems/Support/Brutality.dds", + id="BrutalityMid", + name="Brutality", + stats={ + [1]={ + id="deal_no_elemental_damage", + value=1 + }, + [2]={ + id="base_deal_no_chaos_damage", + value=1 + }, + [3]={ + id="support_brutality_physical_damage_+%_final", + value=20 + } + }, + variant=2 + }, + BurningArrowSpecificAlwaysPierceHigh={ + familyId="Pierce", + hash=10482, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="BurningArrowSpecificAlwaysPierceHigh", + name="Gilded Pierce", + stats={ + [1]={ + id="always_pierce", + value=1 + } + }, + variant=3 + }, + CastSpeedHigh={ + familyId="CastSpeed", + hash=8607, + icon="Art/2DItems/Gems/Support/FasterCast.dds", + id="CastSpeedHigh", + name="Greater Faster Casting", + stats={ + [1]={ + id="base_cast_speed_+%", + value=35 + } + }, + variant=3 + }, + CastSpeedLow={ + familyId="CastSpeed", + hash=43469, + icon="Art/2DItems/Gems/Support/FasterCast.dds", + id="CastSpeedLow", + name="Lesser Faster Casting", + stats={ + [1]={ + id="base_cast_speed_+%", + value=15 + } + }, + variant=1 + }, + CastSpeedMid={ + familyId="CastSpeed", + hash=38851, + icon="Art/2DItems/Gems/Support/FasterCast.dds", + id="CastSpeedMid", + name="Faster Casting", + stats={ + [1]={ + id="base_cast_speed_+%", + value=25 + } + }, + variant=2 + }, + CausticArrowSpecificChaosConvertHigh={ + hash=39101, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="CausticArrowSpecificChaosConvertHigh", + name="Gilded Caustic Conversion", + stats={ + [1]={ + id="skill_physical_damage_%_to_convert_to_chaos", + value=40 + } + }, + variant=3 + }, + ChannelSkillDamageReductionHigh={ + familyId="ChannelSkillDamageReduction", + hash=63104, + icon="Art/2DItems/Gems/Support/StormBarrier.dds", + id="ChannelSkillDamageReductionHigh", + name="Greater Infused Channelling", + stats={ + [1]={ + id="support_storm_barrier_damage_taken_when_hit_+%_final_while_channelling", + value=-10 + } + }, + variant=3 + }, + ChannelSkillDamageReductionLow={ + familyId="ChannelSkillDamageReduction", + hash=59986, + icon="Art/2DItems/Gems/Support/StormBarrier.dds", + id="ChannelSkillDamageReductionLow", + name="Lesser Infused Channelling", + stats={ + [1]={ + id="support_storm_barrier_damage_taken_when_hit_+%_final_while_channelling", + value=-5 + } + }, + variant=1 + }, + ChannelSkillDamageReductionMid={ + familyId="ChannelSkillDamageReduction", + hash=34697, + icon="Art/2DItems/Gems/Support/StormBarrier.dds", + id="ChannelSkillDamageReductionMid", + name="Infused Channelling", + stats={ + [1]={ + id="support_storm_barrier_damage_taken_when_hit_+%_final_while_channelling", + value=-8 + } + }, + variant=2 + }, + ChaosPenHigh={ + familyId="ChaosPen", + hash=39984, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="ChaosPenHigh", + name="Greater Chaos Penetration", + stats={ + [1]={ + id="reduce_enemy_chaos_resistance_%", + value=20 + } + }, + variant=3 + }, + ChaosPenLow={ + familyId="ChaosPen", + hash=25880, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="ChaosPenLow", + name="Lesser Chaos Penetration", + stats={ + [1]={ + id="reduce_enemy_chaos_resistance_%", + value=10 + } + }, + variant=1 + }, + ChaosPenMid={ + familyId="ChaosPen", + hash=33975, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="ChaosPenMid", + name="Chaos Penetration", + stats={ + [1]={ + id="reduce_enemy_chaos_resistance_%", + value=15 + } + }, + variant=2 + }, + CleaveSpecificCullHigh={ + hash=42140, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="CleaveSpecificCullHigh", + name="Gilded Cull", + stats={ + [1]={ + id="kill_enemy_on_hit_if_under_10%_life", + value=1 + } + }, + variant=3 + }, + CobraLashSpecificPoisonRegenHigh={ + hash=51944, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="CobraLashSpecificPoisonRegenHigh", + name="Gilded Bitterwound", + stats={ + [1]={ + id="enemy_life_regeneration_rate_+%_for_4_seconds_on_hit", + value=-50 + } + }, + variant=3 + }, + ColdPenetrationHigh={ + familyId="ColdPenetration", + hash=26094, + icon="Art/2DItems/Gems/Support/ColdPenetration.dds", + id="ColdPenetrationHigh", + name="Greater Cold Penetration", + stats={ + [1]={ + id="base_reduce_enemy_cold_resistance_%", + value=12 + } + }, + variant=3 + }, + ColdPenetrationLow={ + familyId="ColdPenetration", + hash=40565, + icon="Art/2DItems/Gems/Support/ColdPenetration.dds", + id="ColdPenetrationLow", + name="Lesser Cold Penetration", + stats={ + [1]={ + id="base_reduce_enemy_cold_resistance_%", + value=8 + } + }, + variant=1 + }, + ColdPenetrationMid={ + familyId="ColdPenetration", + hash=54628, + icon="Art/2DItems/Gems/Support/ColdPenetration.dds", + id="ColdPenetrationMid", + name="Cold Penetration", + stats={ + [1]={ + id="base_reduce_enemy_cold_resistance_%", + value=10 + } + }, + variant=2 + }, + CombustionHigh={ + hash=58581, + icon="Art/2DItems/Gems/Support/ChancetoIgnite.dds", + id="CombustionHigh", + name="Combustion", + stats={ + [1]={ + id="ignites_apply_fire_resistance_+", + value=-10 + } + }, + variant=3 + }, + ConcentratedEffectHigh={ + familyId="ConcEffect", + hash=51806, + icon="Art/2DItems/Gems/Support/ConcentratedAOE.dds", + id="ConcentratedEffectHigh", + name="Greater Concentrated Effect", + stats={ + [1]={ + id="support_concentrated_effect_skill_area_of_effect_+%_final", + value=-30 + }, + [2]={ + id="support_area_concentrate_area_damage_+%_final", + value=40 + } + }, + variant=3 + }, + ConcentratedEffectLow={ + familyId="ConcEffect", + hash=42698, + icon="Art/2DItems/Gems/Support/ConcentratedAOE.dds", + id="ConcentratedEffectLow", + name="Lesser Concentrated Effect", + stats={ + [1]={ + id="support_concentrated_effect_skill_area_of_effect_+%_final", + value=-30 + }, + [2]={ + id="support_area_concentrate_area_damage_+%_final", + value=20 + } + }, + variant=1 + }, + ConcentratedEffectMid={ + familyId="ConcEffect", + hash=21489, + icon="Art/2DItems/Gems/Support/ConcentratedAOE.dds", + id="ConcentratedEffectMid", + name="Concentrated Effect", + stats={ + [1]={ + id="support_concentrated_effect_skill_area_of_effect_+%_final", + value=-30 + }, + [2]={ + id="support_area_concentrate_area_damage_+%_final", + value=30 + } + }, + variant=2 + }, + ConflagrationSpecificInvertResistancesHigh={ + hash=62171, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ConflagrationSpecificInvertResistancesHigh", + name="Gilded Inversion", + stats={ + [1]={ + id="treat_enemy_resistances_as_negated_on_elemental_damage_hit_%_chance", + value=35 + } + }, + variant=3 + }, + ConsecratedPathSpecificDamageGainHigh={ + hash=10782, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ConsecratedPathSpecificDamageGainHigh", + name="Gilded Consecration", + stats={ + [1]={ + id="your_consecrated_ground_grants_damage_+%", + value=40 + } + }, + variant=3 + }, + CooldownSpeedHigh={ + familyId="Cooldown", + hash=10608, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="CooldownSpeedHigh", + name="Greater Cooldown Recovery", + stats={ + [1]={ + id="base_cooldown_speed_+%", + value=40 + } + }, + variant=3 + }, + CooldownSpeedLow={ + familyId="Cooldown", + hash=30881, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="CooldownSpeedLow", + name="Lesser Cooldown Recovery", + stats={ + [1]={ + id="base_cooldown_speed_+%", + value=20 + } + }, + variant=1 + }, + CooldownSpeedMid={ + familyId="Cooldown", + hash=48875, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="CooldownSpeedMid", + name="Cooldown Recovery", + stats={ + [1]={ + id="base_cooldown_speed_+%", + value=30 + } + }, + variant=2 + }, + CritDamageHigh={ + familyId="CritDamage", + hash=55659, + icon="Art/2DItems/Gems/Support/IncreasedCriticalDamage.dds", + id="CritDamageHigh", + name="Greater Critical Damage", + stats={ + [1]={ + id="base_critical_strike_multiplier_+", + value=70 + } + }, + variant=3 + }, + CritDamageLow={ + familyId="CritDamage", + hash=30688, + icon="Art/2DItems/Gems/Support/IncreasedCriticalDamage.dds", + id="CritDamageLow", + name="Lesser Critical Damage", + stats={ + [1]={ + id="base_critical_strike_multiplier_+", + value=30 + } + }, + variant=1 + }, + CritDamageMid={ + familyId="CritDamage", + hash=32189, + icon="Art/2DItems/Gems/Support/IncreasedCriticalDamage.dds", + id="CritDamageMid", + name="Critical Damage", + stats={ + [1]={ + id="base_critical_strike_multiplier_+", + value=45 + } + }, + variant=2 + }, + CriticalStrikeHigh={ + familyId="CritChance", + hash=62220, + icon="Art/2DItems/Gems/Support/IncreasedCriticalStrikes.dds", + id="CriticalStrikeHigh", + name="Greater Critical Chance", + stats={ + [1]={ + id="critical_strike_chance_+%", + value=200 + } + }, + variant=3 + }, + CriticalStrikeLow={ + familyId="CritChance", + hash=23209, + icon="Art/2DItems/Gems/Support/IncreasedCriticalStrikes.dds", + id="CriticalStrikeLow", + name="Lesser Critical Chance", + stats={ + [1]={ + id="critical_strike_chance_+%", + value=80 + } + }, + variant=1 + }, + CriticalStrikeMid={ + familyId="CritChance", + hash=61471, + icon="Art/2DItems/Gems/Support/IncreasedCriticalStrikes.dds", + id="CriticalStrikeMid", + name="Critical Chance", + stats={ + [1]={ + id="critical_strike_chance_+%", + value=120 + } + }, + variant=2 + }, + CurseEffectHigh={ + hash=3263, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="CurseEffectHigh", + name="Greater Curse Effect", + stats={ + [1]={ + id="curse_effect_+%", + value=20 + } + }, + variant=3 + }, + CycloneSpecificMoveSpeedHigh={ + hash=17178, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="CycloneSpecificMoveSpeedHigh", + name="Gilded Faster Cyclone", + stats={ + [1]={ + id="cyclone_movement_speed_+%_final", + value=35 + } + }, + variant=3 + }, + DamageOverTimeReduceDurationHigh={ + familyId="DOTReducedDuration", + hash=65240, + icon="Art/2DItems/Gems/Support/SupportRapidDecayGem.dds", + id="DamageOverTimeReduceDurationHigh", + name="Greater Swift Affliction", + stats={ + [1]={ + id="support_rapid_decay_damage_over_time_+%_final", + value=30 + }, + [2]={ + id="support_swift_affliction_skill_effect_and_damaging_ailment_duration_+%_final", + value=-20 + } + }, + variant=3 + }, + DamageOverTimeReduceDurationLow={ + familyId="DOTReducedDuration", + hash=834, + icon="Art/2DItems/Gems/Support/SupportRapidDecayGem.dds", + id="DamageOverTimeReduceDurationLow", + name="Lesser Swift Affliction", + stats={ + [1]={ + id="support_rapid_decay_damage_over_time_+%_final", + value=15 + }, + [2]={ + id="support_swift_affliction_skill_effect_and_damaging_ailment_duration_+%_final", + value=-20 + } + }, + variant=1 + }, + DamageOverTimeReduceDurationMid={ + familyId="DOTReducedDuration", + hash=64281, + icon="Art/2DItems/Gems/Support/SupportRapidDecayGem.dds", + id="DamageOverTimeReduceDurationMid", + name="Swift Affliction", + stats={ + [1]={ + id="support_rapid_decay_damage_over_time_+%_final", + value=20 + }, + [2]={ + id="support_swift_affliction_skill_effect_and_damaging_ailment_duration_+%_final", + value=-20 + } + }, + variant=2 + }, + DarkPactSpecificMaledictionOnHitHigh={ + hash=48949, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="DarkPactSpecificMaledictionOnHitHigh", + name="Gilded Malediction", + stats={ + [1]={ + id="malediction_on_hit", + value=1 + } + }, + variant=3 + }, + DivineIreSpecificWidthHigh={ + hash=13568, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="DivineIreSpecificWidthHigh", + name="Gilded Beam Width", + stats={ + [1]={ + id="divine_tempest_beam_width_+%", + value=40 + } + }, + variant=3 + }, + DotMultiHigh={ + familyId="DotMulti", + hash=37460, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="DotMultiHigh", + name="Greater DoT Multiplier", + stats={ + [1]={ + id="dot_multiplier_+", + value=35 + } + }, + variant=3 + }, + DotMultiLow={ + familyId="DotMulti", + hash=22977, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="DotMultiLow", + name="Lesser DoT Multiplier", + stats={ + [1]={ + id="dot_multiplier_+", + value=15 + } + }, + variant=1 + }, + DotMultiMid={ + familyId="DotMulti", + hash=6927, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="DotMultiMid", + name="DoT Multiplier", + stats={ + [1]={ + id="dot_multiplier_+", + value=25 + } + }, + variant=2 + }, + EleDamageWithAttacksHigh={ + familyId="WED", + hash=28416, + icon="Art/2DItems/Gems/Support/WeaponElementalDamage.dds", + id="EleDamageWithAttacksHigh", + name="Greater Elemental Damage with Attacks", + stats={ + [1]={ + id="support_attack_skills_elemental_damage_+%_final", + value=30 + } + }, + variant=3 + }, + EleDamageWithAttacksLow={ + familyId="WED", + hash=59712, + icon="Art/2DItems/Gems/Support/WeaponElementalDamage.dds", + id="EleDamageWithAttacksLow", + name="Lesser Elemental Damage with Attacks", + stats={ + [1]={ + id="support_attack_skills_elemental_damage_+%_final", + value=15 + } + }, + variant=1 + }, + EleDamageWithAttacksMid={ + familyId="WED", + hash=44886, + icon="Art/2DItems/Gems/Support/WeaponElementalDamage.dds", + id="EleDamageWithAttacksMid", + name="Elemental Damage with Attacks", + stats={ + [1]={ + id="support_attack_skills_elemental_damage_+%_final", + value=20 + } + }, + variant=2 + }, + EleFocusHigh={ + familyId="EleFocus", + hash=31600, + icon="Art/2DItems/Gems/Support/ElementalFocus.dds", + id="EleFocusHigh", + name="Greater Elemental Focus", + stats={ + [1]={ + id="support_gem_elemental_damage_+%_final", + value=30 + }, + [2]={ + id="cannot_inflict_status_ailments", + value=1 + } + }, + variant=3 + }, + EleFocusLow={ + familyId="EleFocus", + hash=30359, + icon="Art/2DItems/Gems/Support/ElementalFocus.dds", + id="EleFocusLow", + name="Lesser Elemental Focus", + stats={ + [1]={ + id="support_gem_elemental_damage_+%_final", + value=15 + }, + [2]={ + id="cannot_inflict_status_ailments", + value=1 + } + }, + variant=1 + }, + EleFocusMid={ + familyId="EleFocus", + hash=37388, + icon="Art/2DItems/Gems/Support/ElementalFocus.dds", + id="EleFocusMid", + name="Elemental Focus", + stats={ + [1]={ + id="support_gem_elemental_damage_+%_final", + value=20 + }, + [2]={ + id="cannot_inflict_status_ailments", + value=1 + } + }, + variant=2 + }, + EnduringCrySpecificOnslaughtGainHigh={ + hash=52432, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="EnduringCrySpecificOnslaughtGainHigh", + name="Gilded Onslaught on Cry", + stats={ + [1]={ + id="you_and_nearby_allys_gain_onslaught_for_4_seconds_on_warcry", + value=1 + } + }, + variant=3 + }, + EnsnaringArrowSpecificEffectHigh={ + hash=25565, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="EnsnaringArrowSpecificEffectHigh", + name="Gilded Ensnare Effect", + stats={ + [1]={ + id="tethered_enemies_take_attack_projectile_damage_taken_+%", + value=10 + } + }, + variant=3 + }, + ExcommunicateHigh={ + familyId="Excommunicate", + hash=8617, + icon="Art/2DItems/Gems/Support/Excommunicate.dds", + id="ExcommunicateHigh", + name="Greater Excommunicate", + stats={ + [1]={ + id="support_excommunicate_on_melee_attack_hit_for_X_ms", + value=3000 + }, + [2]={ + id="physical_damage_%_to_add_as_lightning", + value=20 + }, + [3]={ + id="physical_damage_%_to_add_as_fire", + value=20 + } + }, + variant=3 + }, + ExcommunicateLow={ + familyId="Excommunicate", + hash=29922, + icon="Art/2DItems/Gems/Support/Excommunicate.dds", + id="ExcommunicateLow", + name="Lesser Excommunicate", + stats={ + [1]={ + id="support_excommunicate_on_melee_attack_hit_for_X_ms", + value=3000 + }, + [2]={ + id="physical_damage_%_to_add_as_lightning", + value=10 + }, + [3]={ + id="physical_damage_%_to_add_as_fire", + value=10 + } + }, + variant=1 + }, + ExcommunicateMid={ + familyId="Excommunicate", + hash=45433, + icon="Art/2DItems/Gems/Support/Excommunicate.dds", + id="ExcommunicateMid", + name="Excommunicate", + stats={ + [1]={ + id="support_excommunicate_on_melee_attack_hit_for_X_ms", + value=3000 + }, + [2]={ + id="physical_damage_%_to_add_as_lightning", + value=15 + }, + [3]={ + id="physical_damage_%_to_add_as_fire", + value=15 + } + }, + variant=2 + }, + ExplosiveArrowSpecificMaxHigh={ + hash=42966, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ExplosiveArrowSpecificMaxHigh", + name="Gilded Maximum Explosions", + stats={ + [1]={ + id="explosive_arrow_stack_limit", + value=2 + } + }, + variant=3 + }, + FirePenetrationHigh={ + familyId="FirePenetration", + hash=54494, + icon="Art/2DItems/Gems/Support/FirePenetration.dds", + id="FirePenetrationHigh", + name="Greater Fire Penetration", + stats={ + [1]={ + id="base_reduce_enemy_fire_resistance_%", + value=12 + } + }, + variant=3 + }, + FirePenetrationLow={ + familyId="FirePenetration", + hash=46010, + icon="Art/2DItems/Gems/Support/FirePenetration.dds", + id="FirePenetrationLow", + name="Lesser Fire Penetration", + stats={ + [1]={ + id="base_reduce_enemy_fire_resistance_%", + value=8 + } + }, + variant=1 + }, + FirePenetrationMid={ + familyId="FirePenetration", + hash=62885, + icon="Art/2DItems/Gems/Support/FirePenetration.dds", + id="FirePenetrationMid", + name="Fire Penetration", + stats={ + [1]={ + id="base_reduce_enemy_fire_resistance_%", + value=10 + } + }, + variant=2 + }, + FireballAltSpecificChanceToScorchHigh={ + hash=19004, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="FireballAltSpecificChanceToScorchHigh", + name="Gilded Scorch Chance", + stats={ + [1]={ + id="chance_to_scorch_%", + value=50 + } + }, + variant=3 + }, + FistOfWarHigh={ + hash=12347, + icon="Art/2DItems/Gems/Support/FistOfWarGem.dds", + id="FistOfWarHigh", + name="Fist of War", + stats={ + [1]={ + id="support_ancestral_slam_big_hit_max_count", + value=1 + }, + [2]={ + id="support_ancestral_slam_big_hit_damage_with_hits_and_ailments_+%_final", + value=20 + }, + [3]={ + id="support_ancestral_slam_big_hit_area_+%", + value=60 + }, + [4]={ + id="ancestral_slam_interval_duration", + value=1760 + } + }, + variant=3 + }, + FlameLinkSpecificAddedFlatHigh={ + hash=36350, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="FlameLinkSpecificAddedFlatHigh", + name="Gilded Empowered Link", + stats={ + [1]={ + id="flame_link_minimum_fire_damage", + value=38 + }, + [2]={ + id="flame_link_maximum_fire_damage", + value=56 + } + }, + variant=3 + }, + FlameblastSpecificStagesHigh={ + hash=48614, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="FlameblastSpecificStagesHigh", + name="Gilded Maximum Stages", + stats={ + [1]={ + id="flameblast_maximum_stages", + value=3 + } + }, + variant=3 + }, + FlickerStrikeSpecificConsumeAllImpalesHigh={ + hash=52383, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="FlickerStrikeSpecificConsumeAllImpalesHigh", + name="Gilded Impale Extraction", + stats={ + [1]={ + id="consume_all_impales_remaining_hits_on_hit_%_chance", + value=50 + } + }, + variant=3 + }, + ForkHigh={ + hash=32052, + icon="Art/2DItems/Gems/Support/Fork.dds", + id="ForkHigh", + name="Greater Fork", + stats={ + [1]={ + id="projectiles_fork", + value=1 + } + }, + variant=3 + }, + FortifyHigh={ + hash=31664, + icon="Art/2DItems/Gems/Support/FortifyGem.dds", + id="FortifyHigh", + name="Greater Fortify", + stats={ + [1]={ + id="fortify_on_hit", + value=1 + } + }, + variant=3 + }, + FreezeChanceHigh={ + familyId="FreezeChance", + hash=12387, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="FreezeChanceHigh", + name="Greater Freeze Chance", + stats={ + [1]={ + id="base_chance_to_freeze_%", + value=60 + } + }, + variant=3 + }, + FreezeChanceLow={ + familyId="FreezeChance", + hash=34226, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="FreezeChanceLow", + name="Lesser Freeze Chance", + stats={ + [1]={ + id="base_chance_to_freeze_%", + value=20 + } + }, + variant=1 + }, + FreezeChanceMid={ + familyId="FreezeChance", + hash=27458, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="FreezeChanceMid", + name="Freeze Chance", + stats={ + [1]={ + id="base_chance_to_freeze_%", + value=40 + } + }, + variant=2 + }, + GenerosityHigh={ + familyId="Generosity", + hash=53367, + icon="Art/2DItems/Gems/Support/GenerositySupport.dds", + id="GenerosityHigh", + name="Greater Generosity", + stats={ + [1]={ + id="aura_cannot_affect_self", + value=1 + }, + [2]={ + id="non_curse_aura_effect_+%", + value=30 + } + }, + variant=3 + }, + GenerosityLow={ + familyId="Generosity", + hash=59349, + icon="Art/2DItems/Gems/Support/GenerositySupport.dds", + id="GenerosityLow", + name="Lesser Generosity", + stats={ + [1]={ + id="aura_cannot_affect_self", + value=1 + }, + [2]={ + id="non_curse_aura_effect_+%", + value=10 + } + }, + variant=1 + }, + GenerosityMid={ + familyId="Generosity", + hash=35435, + icon="Art/2DItems/Gems/Support/GenerositySupport.dds", + id="GenerosityMid", + name="Generosity", + stats={ + [1]={ + id="aura_cannot_affect_self", + value=1 + }, + [2]={ + id="non_curse_aura_effect_+%", + value=20 + } + }, + variant=2 + }, + GiantZombieSpecificSlowZombieHigh={ + hash=29562, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="GiantZombieSpecificSlowZombieHigh", + name="Gilded Lumbering Dead", + stats={ + [1]={ + id="minion_attack_speed_+%", + value=50 + }, + [2]={ + id="minion_movement_speed_+%", + value=-30 + } + }, + variant=3 + }, + GigaShockNovaSpecificAOEHigh={ + hash=21678, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="GigaShockNovaSpecificAOEHigh", + name="Gilded Inhibitor", + stats={ + [1]={ + id="enemies_you_shock_cast_speed_+%", + value=-25 + } + }, + variant=3 + }, + GlacialCascadeSpecificNumberOfSpikesHigh={ + hash=32431, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="GlacialCascadeSpecificNumberOfSpikesHigh", + name="Gilded Cascade Count", + stats={ + [1]={ + id="upheaval_number_of_spikes", + value=2 + } + }, + variant=3 + }, + GroundSlamSpecificAngleHigh={ + hash=39050, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="GroundSlamSpecificAngleHigh", + name="Gilded Increased Angle", + stats={ + [1]={ + id="ground_slam_angle_+%", + value=40 + } + }, + variant=3 + }, + HallowHigh={ + hash=56233, + icon="Art/2DItems/Gems/Support/HallowingFlame.dds", + id="HallowHigh", + name="Hallow", + stats={ + [1]={ + id="support_hallow_inflict_hallowing_flame_on_melee_hit", + value=1 + }, + [2]={ + id="hallowing_flame_duration_ms", + value=6000 + } + }, + variant=3 + }, + HeavyStrikeSpecificMoreMaxPhysHigh={ + hash=3194, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="HeavyStrikeSpecificMoreMaxPhysHigh", + name="Gilded Heft", + stats={ + [1]={ + id="unique_ryuslathas_clutches_maximum_physical_attack_damage_+%_final", + value=40 + } + }, + variant=3 + }, + HolyFlameTotemSpecificConcBlockHigh={ + hash=4032, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="HolyFlameTotemSpecificConcBlockHigh", + name="Gilded Divine Shield", + stats={ + [1]={ + id="additional_block_%_while_on_consecrated_ground", + value=35 + } + }, + variant=3 + }, + HolyHammersSpecificPowerChargeHigh={ + hash=6109, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="HolyHammersSpecificPowerChargeHigh", + name="Gilded Power Charge on Critical Strike", + stats={ + [1]={ + id="add_power_charge_on_critical_strike_%", + value=100 + } + }, + variant=3 + }, + HolyMoltenStrikeSpecificLightningExposureHigh={ + hash=50741, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="HolyMoltenStrikeSpecificLightningExposureHigh", + name="Gilded Exposure on Hit", + stats={ + [1]={ + id="base_inflict_lightning_exposure_on_hit_%_chance", + value=30 + } + }, + variant=3 + }, + HolyMortarSpecificCoverInAshHigh={ + hash=37275, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="HolyMortarSpecificCoverInAshHigh", + name="Gilded Ash", + stats={ + [1]={ + id="cover_in_ash_on_hit_%", + value=50 + } + }, + variant=3 + }, + HolyRelicSpecificRegenHigh={ + hash=44238, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="HolyRelicSpecificRegenHigh", + name="Gilded Relic Recovery", + stats={ + [1]={ + id="holy_relic_nova_life_regeneration_rate_per_minute", + value=1500 + } + }, + variant=3 + }, + HolyStrikesSpecificAdditionalMinionHigh={ + hash=8720, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="HolyStrikesSpecificAdditionalMinionHigh", + name="Gilded Extra Armaments", + stats={ + [1]={ + id="base_holy_strike_maximum_number_of_animated_weapons", + value=2 + } + }, + variant=3 + }, + HypothermiaHigh={ + familyId="Hypothermia", + hash=53145, + icon="Art/2DItems/Gems/Support/DamageAgainstChilled.dds", + id="HypothermiaHigh", + name="Greater Hypothermia", + stats={ + [1]={ + id="support_hypothermia_damage_+%_vs_chilled_enemies_final", + value=30 + }, + [2]={ + id="support_hypothermia_cold_damage_over_time_+%_final", + value=30 + } + }, + variant=3 + }, + HypothermiaLow={ + familyId="Hypothermia", + hash=26146, + icon="Art/2DItems/Gems/Support/DamageAgainstChilled.dds", + id="HypothermiaLow", + name="Lesser Hypothermia", + stats={ + [1]={ + id="support_hypothermia_damage_+%_vs_chilled_enemies_final", + value=15 + }, + [2]={ + id="support_hypothermia_cold_damage_over_time_+%_final", + value=15 + } + }, + variant=1 + }, + HypothermiaMid={ + familyId="Hypothermia", + hash=38571, + icon="Art/2DItems/Gems/Support/DamageAgainstChilled.dds", + id="HypothermiaMid", + name="Hypothermia", + stats={ + [1]={ + id="support_hypothermia_damage_+%_vs_chilled_enemies_final", + value=20 + }, + [2]={ + id="support_hypothermia_cold_damage_over_time_+%_final", + value=20 + } + }, + variant=2 + }, + IceCrashSpecificTertiaryRadiusHigh={ + hash=29166, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="IceCrashSpecificTertiaryRadiusHigh", + name="Gilded Icecrash Radius", + stats={ + [1]={ + id="active_skill_base_tertiary_area_of_effect_radius", + value=5 + } + }, + variant=3 + }, + IceNovaSpecificFirePerChillHigh={ + hash=17213, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="IceNovaSpecificFirePerChillHigh", + name="Gilded Freezer Burn", + stats={ + [1]={ + id="cold_damage_%_to_add_as_fire", + value=30 + } + }, + variant=3 + }, + IgniteChanceHigh={ + familyId="IgniteChance", + hash=10997, + icon="Art/2DItems/Gems/Support/ChancetoIgnite.dds", + id="IgniteChanceHigh", + name="Greater Ignite Chance", + stats={ + [1]={ + id="base_chance_to_ignite_%", + value=60 + } + }, + variant=3 + }, + IgniteChanceLow={ + familyId="IgniteChance", + hash=52335, + icon="Art/2DItems/Gems/Support/ChancetoIgnite.dds", + id="IgniteChanceLow", + name="Lesser Ignite Chance", + stats={ + [1]={ + id="base_chance_to_ignite_%", + value=20 + } + }, + variant=1 + }, + IgniteChanceMid={ + familyId="IgniteChance", + hash=50303, + icon="Art/2DItems/Gems/Support/ChancetoIgnite.dds", + id="IgniteChanceMid", + name="Ignite Chance", + stats={ + [1]={ + id="base_chance_to_ignite_%", + value=40 + } + }, + variant=2 + }, + IgnoreEnemyPhysMitHigh={ + familyId="IgnorePhysMit", + hash=33557, + icon="Art/2DItems/Gems/Support/MercSilverStrDexSupportGem.dds", + id="IgnoreEnemyPhysMitHigh", + name="Greater Mitigation Ignore", + stats={ + [1]={ + id="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + value=30 + } + }, + variant=3 + }, + IgnoreEnemyPhysMitLow={ + familyId="IgnorePhysMit", + hash=16261, + icon="Art/2DItems/Gems/Support/MercSilverStrDexSupportGem.dds", + id="IgnoreEnemyPhysMitLow", + name="Lesser Mitigation Ignore", + stats={ + [1]={ + id="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + value=20 + } + }, + variant=1 + }, + IgnoreEnemyPhysMitMid={ + familyId="IgnorePhysMit", + hash=4351, + icon="Art/2DItems/Gems/Support/MercSilverStrDexSupportGem.dds", + id="IgnoreEnemyPhysMitMid", + name="Mitigation Ignore", + stats={ + [1]={ + id="hits_ignore_enemy_monster_physical_damage_reduction_%_chance", + value=25 + } + }, + variant=2 + }, + ImpaleChanceHigh={ + familyId="ImpaleChance", + hash=29720, + icon="Art/2DItems/Gems/Support/impale.dds", + id="ImpaleChanceHigh", + name="Greater Impale Chance", + stats={ + [1]={ + id="impale_on_hit_%_chance", + value=60 + } + }, + variant=3 + }, + ImpaleChanceLow={ + familyId="ImpaleChance", + hash=54252, + icon="Art/2DItems/Gems/Support/impale.dds", + id="ImpaleChanceLow", + name="Lesser Impale Chance", + stats={ + [1]={ + id="impale_on_hit_%_chance", + value=20 + } + }, + variant=1 + }, + ImpaleChanceMid={ + familyId="ImpaleChance", + hash=11497, + icon="Art/2DItems/Gems/Support/impale.dds", + id="ImpaleChanceMid", + name="Impale Chance", + stats={ + [1]={ + id="impale_on_hit_%_chance", + value=40 + } + }, + variant=2 + }, + IncreaseAreaOfEffectHigh={ + familyId="IncreaseAreaOfEffect", + hash=19113, + icon="Art/2DItems/Gems/Support/IncreasedAOE.dds", + id="IncreaseAreaOfEffectHigh", + name="Greater Area of Effect", + stats={ + [1]={ + id="base_skill_area_of_effect_+%", + value=60 + } + }, + variant=3 + }, + IncreaseAreaOfEffectLow={ + familyId="IncreaseAreaOfEffect", + hash=22670, + icon="Art/2DItems/Gems/Support/IncreasedAOE.dds", + id="IncreaseAreaOfEffectLow", + name="Lesser Increased Area of Effect", + stats={ + [1]={ + id="base_skill_area_of_effect_+%", + value=20 + } + }, + variant=1 + }, + IncreaseAreaOfEffectMid={ + familyId="IncreaseAreaOfEffect", + hash=53342, + icon="Art/2DItems/Gems/Support/IncreasedAOE.dds", + id="IncreaseAreaOfEffectMid", + name="Increased Area of Effect", + stats={ + [1]={ + id="base_skill_area_of_effect_+%", + value=40 + } + }, + variant=2 + }, + IncreaseDurationHigh={ + familyId="Duration", + hash=26568, + icon="Art/2DItems/Gems/Support/IncreasedDuration.dds", + id="IncreaseDurationHigh", + name="Greater More Duration", + stats={ + [1]={ + id="support_more_duration_skill_effect_duration_+%_final", + value=40 + } + }, + variant=3 + }, + IncreaseDurationLow={ + familyId="Duration", + hash=2602, + icon="Art/2DItems/Gems/Support/IncreasedDuration.dds", + id="IncreaseDurationLow", + name="Lesser More Duration", + stats={ + [1]={ + id="support_more_duration_skill_effect_duration_+%_final", + value=15 + } + }, + variant=1 + }, + IncreaseDurationMid={ + familyId="Duration", + hash=50222, + icon="Art/2DItems/Gems/Support/IncreasedDuration.dds", + id="IncreaseDurationMid", + name="More Duration", + stats={ + [1]={ + id="support_more_duration_skill_effect_duration_+%_final", + value=25 + } + }, + variant=2 + }, + IncreasedProjSpeedHigh={ + familyId="ProjectileSpeed", + hash=14517, + icon="Art/2DItems/Gems/Support/FasterProjectiles.dds", + id="IncreasedProjSpeedHigh", + name="Greater Faster Projectiles", + stats={ + [1]={ + id="base_projectile_speed_+%", + value=40 + } + }, + variant=3 + }, + IncreasedProjSpeedLow={ + familyId="ProjectileSpeed", + hash=25199, + icon="Art/2DItems/Gems/Support/FasterProjectiles.dds", + id="IncreasedProjSpeedLow", + name="Lesser Faster Projectiles", + stats={ + [1]={ + id="base_projectile_speed_+%", + value=15 + } + }, + variant=1 + }, + IncreasedProjSpeedMid={ + familyId="ProjectileSpeed", + hash=57644, + icon="Art/2DItems/Gems/Support/FasterProjectiles.dds", + id="IncreasedProjSpeedMid", + name="Faster Projectiles", + stats={ + [1]={ + id="base_projectile_speed_+%", + value=30 + } + }, + variant=2 + }, + KnockbackLow={ + hash=65002, + icon="Art/2DItems/Gems/Support/Knockback.dds", + id="KnockbackLow", + name="Knockback", + stats={ + [1]={ + id="global_knockback", + value=1 + }, + [2]={ + id="knockback_distance_+%", + value=40 + } + }, + variant=1 + }, + LancingSteelSpecificRandomProjHigh={ + hash=60983, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="LancingSteelSpecificRandomProjHigh", + name="Gilded Scattershot", + stats={ + [1]={ + id="random_projectile_direction", + value=1 + }, + [2]={ + id="number_of_additional_projectiles", + value=4 + } + }, + variant=3 + }, + LeapSlamSpecificFrenzyOnHitHigh={ + hash=48738, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="LeapSlamSpecificFrenzyOnHitHigh", + name="Gilded Frenzy", + stats={ + [1]={ + id="add_frenzy_charge_on_skill_hit_%", + value=100 + } + }, + variant=3 + }, + LeechHigh={ + hash=41756, + icon="Art/2DItems/Gems/Support/LifeLeech.dds", + id="LeechHigh", + name="Greater Leech", + stats={ + [1]={ + id="life_leech_from_any_damage_permyriad", + value=600 + } + }, + variant=3 + }, + LeechLow={ + hash=32130, + icon="Art/2DItems/Gems/Support/LifeLeech.dds", + id="LeechLow", + name="Lesser Leech", + stats={ + [1]={ + id="life_leech_from_any_damage_permyriad", + value=200 + } + }, + variant=1 + }, + LeechMid={ + hash=3240, + icon="Art/2DItems/Gems/Support/LifeLeech.dds", + id="LeechMid", + name="Leech", + stats={ + [1]={ + id="life_leech_from_any_damage_permyriad", + value=400 + } + }, + variant=2 + }, + LightningArrowSpecificAddedTargetsHigh={ + hash=58471, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="LightningArrowSpecificAddedTargetsHigh", + name="Gilded Extra Targets", + stats={ + [1]={ + id="lightning_arrow_maximum_number_of_extra_targets", + value=2 + } + }, + variant=3 + }, + LightningDamageLuckyHigh={ + hash=24343, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="LightningDamageLuckyHigh", + name="Greater Lucky Lightning Damage", + stats={ + [1]={ + id="extra_damage_rolls_with_lightning_damage_on_non_critical_hits", + value=1 + } + }, + variant=3 + }, + LightningPenetrationHigh={ + familyId="LightPenetration", + hash=26815, + icon="Art/2DItems/Gems/Support/LightningPenetration.dds", + id="LightningPenetrationHigh", + name="Greater Lightning Penetration", + stats={ + [1]={ + id="base_reduce_enemy_lightning_resistance_%", + value=12 + } + }, + variant=3 + }, + LightningPenetrationLow={ + familyId="LightPenetration", + hash=37739, + icon="Art/2DItems/Gems/Support/LightningPenetration.dds", + id="LightningPenetrationLow", + name="Lesser Lightning Penetration", + stats={ + [1]={ + id="base_reduce_enemy_lightning_resistance_%", + value=8 + } + }, + variant=1 + }, + LightningPenetrationMid={ + familyId="LightPenetration", + hash=41256, + icon="Art/2DItems/Gems/Support/LightningPenetration.dds", + id="LightningPenetrationMid", + name="Lightning Penetration", + stats={ + [1]={ + id="base_reduce_enemy_lightning_resistance_%", + value=10 + } + }, + variant=2 + }, + LightningSpireSpecificBeamsHigh={ + hash=25885, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="LightningSpireSpecificBeamsHigh", + name="Gilded Reactor", + stats={ + [1]={ + id="lightning_tower_trap_additional_number_of_beams", + value=10 + }, + [2]={ + id="damage_+%", + value=-80 + } + }, + variant=3 + }, + LightningTrapSpecificShockSlowHigh={ + hash=26713, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="LightningTrapSpecificShockSlowHigh", + name="Gilded Electrocuting", + stats={ + [1]={ + id="enemies_you_shock_movement_speed_+%", + value=-50 + } + }, + variant=3 + }, + MaimOnHitHigh={ + hash=56389, + icon="Art/2DItems/Gems/Support/Maim.dds", + id="MaimOnHitHigh", + name="Maim", + stats={ + [1]={ + id="global_maim_on_hit", + value=1 + }, + [2]={ + id="support_maimed_enemies_physical_damage_taken_+%", + value=10 + } + }, + variant=3 + }, + MaxShockHigh={ + hash=64801, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="MaxShockHigh", + name="Maximum Shock Effect", + stats={ + [1]={ + id="shock_maximum_magnitude_+", + value=10 + } + }, + variant=3 + }, + MeleePhysHigh={ + familyId="MeleePhys", + hash=63342, + icon="Art/2DItems/Gems/Support/IncreasedPhysicalDamage.dds", + id="MeleePhysHigh", + name="Greater Melee Physical Damage", + stats={ + [1]={ + id="support_melee_physical_damage_+%_final", + value=20 + }, + [2]={ + id="support_melee_physical_damage_poison_and_bleeding_damage_+%_final_from_melee_hits", + value=20 + } + }, + variant=3 + }, + MeleePhysLow={ + familyId="MeleePhys", + hash=64940, + icon="Art/2DItems/Gems/Support/IncreasedPhysicalDamage.dds", + id="MeleePhysLow", + name="Lesser Melee Physical Damage", + stats={ + [1]={ + id="support_melee_physical_damage_+%_final", + value=10 + }, + [2]={ + id="support_melee_physical_damage_poison_and_bleeding_damage_+%_final_from_melee_hits", + value=10 + } + }, + variant=1 + }, + MeleePhysMid={ + familyId="MeleePhys", + hash=53516, + icon="Art/2DItems/Gems/Support/IncreasedPhysicalDamage.dds", + id="MeleePhysMid", + name="Melee Physical Damage", + stats={ + [1]={ + id="support_melee_physical_damage_+%_final", + value=15 + }, + [2]={ + id="support_melee_physical_damage_poison_and_bleeding_damage_+%_final_from_melee_hits", + value=15 + } + }, + variant=2 + }, + MeleeSplashHigh={ + hash=40660, + icon="Art/2DItems/Gems/Support/Splash.dds", + id="MeleeSplashHigh", + name="Melee Splash", + stats={ + [1]={ + id="melee_splash_area_of_effect_+%_final", + value=35 + }, + [2]={ + id="melee_splash", + value=1 + }, + [3]={ + id="support_melee_splash_damage_+%_final_for_splash", + value=-30 + } + }, + variant=3 + }, + MinionChaosCloudHigh={ + hash=13016, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="MinionChaosCloudHigh", + name="Minion Caustic Death", + stats={ + [1]={ + id="minion_caustic_cloud_on_death_maximum_life_per_minute_to_deal_as_chaos_damage_%", + value=150 + } + }, + variant=3 + }, + MinionDamageHigh={ + familyId="MinionDamage", + hash=52472, + icon="Art/2DItems/Gems/Support/MinionDamage.dds", + id="MinionDamageHigh", + name="Greater Minion Damage", + stats={ + [1]={ + id="support_minion_damage_minion_life_+%_final", + value=-25 + }, + [2]={ + id="support_minion_damage_+%_final", + value=30 + } + }, + variant=3 + }, + MinionDamageLow={ + familyId="MinionDamage", + hash=8821, + icon="Art/2DItems/Gems/Support/MinionDamage.dds", + id="MinionDamageLow", + name="Lesser Minion Damage", + stats={ + [1]={ + id="support_minion_damage_minion_life_+%_final", + value=-25 + }, + [2]={ + id="support_minion_damage_+%_final", + value=15 + } + }, + variant=1 + }, + MinionDamageMid={ + familyId="MinionDamage", + hash=28579, + icon="Art/2DItems/Gems/Support/MinionDamage.dds", + id="MinionDamageMid", + name="Minion Damage", + stats={ + [1]={ + id="support_minion_damage_minion_life_+%_final", + value=-25 + }, + [2]={ + id="support_minion_damage_+%_final", + value=20 + } + }, + variant=2 + }, + MinionLifeHigh={ + familyId="MinionLife", + hash=31863, + icon="Art/2DItems/Gems/Support/MinionDamage.dds", + id="MinionLifeHigh", + name="Greater Minion Life", + stats={ + [1]={ + id="support_minion_maximum_life_+%_final", + value=60 + } + }, + variant=3 + }, + MinionLifeLow={ + familyId="MinionLife", + hash=23582, + icon="Art/2DItems/Gems/Support/MinionDamage.dds", + id="MinionLifeLow", + name="Lesser Minion Life", + stats={ + [1]={ + id="support_minion_maximum_life_+%_final", + value=25 + } + }, + variant=1 + }, + MinionLifeMid={ + familyId="MinionLife", + hash=20579, + icon="Art/2DItems/Gems/Support/MinionDamage.dds", + id="MinionLifeMid", + name="Minion Life", + stats={ + [1]={ + id="support_minion_maximum_life_+%_final", + value=40 + } + }, + variant=2 + }, + MirageArcherHigh={ + hash=37727, + icon="Art/2DItems/Gems/Support/MirageArcher.dds", + id="MirageArcherHigh", + name="Mirage Archer", + stats={ + [1]={ + id="skill_can_own_mirage_archers", + value=1 + }, + [2]={ + id="summon_mirage_archer_on_hit", + value=1 + }, + [3]={ + id="disable_skill_if_weapon_not_bow", + value=1 + }, + [4]={ + id="support_mirage_archer_base_duration", + value=4000 + }, + [5]={ + id="support_mirage_archer_attack_speed_+%_final", + value=-60 + }, + [6]={ + id="mirage_archer_projectile_additional_height_offset", + value=-138 + } + }, + variant=3 + }, + MoltenShellSpecificPDRHigh={ + hash=26792, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="MoltenShellSpecificPDRHigh", + name="Gilded Physical Damage Reduction", + stats={ + [1]={ + id="additional_physical_damage_reduction_%_while_affected_by_guard_skill", + value=15 + } + }, + variant=3 + }, + MoltenStrikeSpecificExtraProjHigh={ + hash=2205, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="MoltenStrikeSpecificExtraProjHigh", + name="Gilded Molten Eruption", + stats={ + [1]={ + id="molten_strike_every_5th_attack_fire_X_additional_projectiles", + value=5 + } + }, + variant=3 + }, + MultiTotemHigh={ + hash=17097, + icon="Art/2DItems/Gems/Support/MultipleTotems.dds", + id="MultiTotemHigh", + name="Multiple Totems", + stats={ + [1]={ + id="summon_2_totems", + value=1 + }, + [2]={ + id="base_number_of_totems_allowed", + value=2 + } + }, + variant=3 + }, + MultiTrapHigh={ + hash=2555, + icon="Art/2DItems/Gems/Support/MultiTrap.dds", + id="MultiTrapHigh", + name="Multiple Traps", + stats={ + [1]={ + id="number_of_additional_traps_to_throw", + value=2 + } + }, + variant=3 + }, + MultipleProjectilesHigh={ + familyId="MultipleProjectiles", + hash=49419, + icon="Art/2DItems/Gems/Support/GreaterMultipleProjectiles.dds", + id="MultipleProjectilesHigh", + name="Greater Multiple Projectiles", + stats={ + [1]={ + id="number_of_additional_projectiles", + value=3 + } + }, + variant=3 + }, + MultipleProjectilesLow={ + familyId="MultipleProjectiles", + hash=12054, + icon="Art/2DItems/Gems/Support/LesserMultipleProjectiles.dds", + id="MultipleProjectilesLow", + name="Multiple Projectiles", + stats={ + [1]={ + id="number_of_additional_projectiles", + value=2 + } + }, + variant=1 + }, + MultistrikeHigh={ + familyId="Multistrike", + hash=25973, + icon="Art/2DItems/Gems/Support/multipleattacks.dds", + id="MultistrikeHigh", + name="Greater Multistrike", + stats={ + [1]={ + id="base_melee_attack_repeat_count", + value=2 + }, + [2]={ + id="support_multiple_attacks_melee_attack_speed_+%_final", + value=15 + }, + [3]={ + id="support_multiple_attack_damage_+%_final", + value=-15 + } + }, + variant=3 + }, + MultistrikeMid={ + familyId="Multistrike", + hash=62638, + icon="Art/2DItems/Gems/Support/multipleattacks.dds", + id="MultistrikeMid", + name="Multistrike", + stats={ + [1]={ + id="base_melee_attack_repeat_count", + value=1 + }, + [2]={ + id="support_multiple_attacks_melee_attack_speed_+%_final", + value=15 + }, + [3]={ + id="support_multiple_attack_damage_+%_final", + value=-15 + } + }, + variant=2 + }, + NonDamagingAilmentEffectHigh={ + familyId="NonDamagingAilmentEffect", + hash=33272, + icon="Art/2DItems/Gems/Support/UnboundAilments.dds", + id="NonDamagingAilmentEffectHigh", + name="Greater Ailment Effect", + stats={ + [1]={ + id="non_damaging_ailment_effect_+%", + value=50 + } + }, + variant=3 + }, + NonDamagingAilmentEffectLow={ + familyId="NonDamagingAilmentEffect", + hash=12388, + icon="Art/2DItems/Gems/Support/UnboundAilments.dds", + id="NonDamagingAilmentEffectLow", + name="Lesser Ailment Effect", + stats={ + [1]={ + id="non_damaging_ailment_effect_+%", + value=30 + } + }, + variant=1 + }, + NonDamagingAilmentEffectMid={ + familyId="NonDamagingAilmentEffect", + hash=61972, + icon="Art/2DItems/Gems/Support/UnboundAilments.dds", + id="NonDamagingAilmentEffectMid", + name="Ailment Effect", + stats={ + [1]={ + id="non_damaging_ailment_effect_+%", + value=40 + } + }, + variant=2 + }, + OrbOfStormsSpecificShockCritKnockHigh={ + familyId="CritChance", + hash=40212, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="OrbOfStormsSpecificShockCritKnockHigh", + name="Gilded Jolt", + stats={ + [1]={ + id="critical_strikes_always_knockback_shocked_enemies", + value=1 + }, + [2]={ + id="base_spell_critical_strike_chance", + value=1000 + } + }, + variant=3 + }, + PerforateSpecificSpikesHigh={ + hash=9460, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="PerforateSpecificSpikesHigh", + name="Gilded Maximum Spikes", + stats={ + [1]={ + id="blood_spears_base_number_of_spears", + value=2 + } + }, + variant=3 + }, + PhysGainAsChaosHigh={ + familyId="PhysGainAs", + hash=58214, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="PhysGainAsChaosHigh", + name="Greater Physical as Extra Chaos", + stats={ + [1]={ + id="physical_damage_%_to_add_as_chaos", + value=30 + } + }, + variant=3 + }, + PhysGainAsChaosMid={ + familyId="PhysGainAs", + hash=51009, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="PhysGainAsChaosMid", + name="Physical as Extra Chaos", + stats={ + [1]={ + id="physical_damage_%_to_add_as_chaos", + value=15 + } + }, + variant=2 + }, + PhysGainAsRandomHigh={ + familyId="PhysGainAs", + hash=45050, + icon="Art/2DItems/Gems/Support/MercSilverStrIntSupportGem.dds", + id="PhysGainAsRandomHigh", + name="Greater Physical as Extra", + stats={ + [1]={ + id="physical_damage_%_to_add_as_random_element", + value=35 + } + }, + variant=3 + }, + PhysGainAsRandomLow={ + familyId="PhysGainAs", + hash=28037, + icon="Art/2DItems/Gems/Support/MercSilverStrIntSupportGem.dds", + id="PhysGainAsRandomLow", + name="Lesser Physical as Extra", + stats={ + [1]={ + id="physical_damage_%_to_add_as_random_element", + value=10 + } + }, + variant=1 + }, + PhysGainAsRandomMid={ + familyId="PhysGainAs", + hash=39342, + icon="Art/2DItems/Gems/Support/MercSilverStrIntSupportGem.dds", + id="PhysGainAsRandomMid", + name="Physical as Extra", + stats={ + [1]={ + id="physical_damage_%_to_add_as_random_element", + value=20 + } + }, + variant=2 + }, + PierceHigh={ + familyId="Pierce", + hash=27970, + icon="Art/2DItems/Gems/Support/Pierce.dds", + id="PierceHigh", + name="Greater Pierce", + stats={ + [1]={ + id="projectile_base_number_of_targets_to_pierce", + value=5 + } + }, + variant=3 + }, + PierceLow={ + familyId="Pierce", + hash=6040, + icon="Art/2DItems/Gems/Support/Pierce.dds", + id="PierceLow", + name="Lesser Pierce", + stats={ + [1]={ + id="projectile_base_number_of_targets_to_pierce", + value=1 + } + }, + variant=1 + }, + PierceMid={ + familyId="Pierce", + hash=56267, + icon="Art/2DItems/Gems/Support/Pierce.dds", + id="PierceMid", + name="Pierce", + stats={ + [1]={ + id="projectile_base_number_of_targets_to_pierce", + value=3 + } + }, + variant=2 + }, + PoisonChanceHigh={ + familyId="PoisonChance", + hash=9585, + icon="Art/2DItems/Gems/Support/Poison.dds", + id="PoisonChanceHigh", + name="Greater Chance to Poison", + stats={ + [1]={ + id="base_chance_to_poison_on_hit_%", + value=50 + } + }, + variant=3 + }, + PoisonChanceLow={ + familyId="PoisonChance", + hash=1864, + icon="Art/2DItems/Gems/Support/Poison.dds", + id="PoisonChanceLow", + name="Lesser Chance to Poison", + stats={ + [1]={ + id="base_chance_to_poison_on_hit_%", + value=20 + } + }, + variant=1 + }, + PoisonChanceMid={ + familyId="PoisonChance", + hash=58384, + icon="Art/2DItems/Gems/Support/Poison.dds", + id="PoisonChanceMid", + name="Chance to Poison", + stats={ + [1]={ + id="base_chance_to_poison_on_hit_%", + value=35 + } + }, + variant=2 + }, + ProjectilesReturnHigh={ + hash=5293, + icon="Art/2DItems/Gems/Support/ReturnProjectiles.dds", + id="ProjectilesReturnHigh", + name="Return", + stats={ + [1]={ + id="projectiles_return", + value=1 + } + }, + variant=3 + }, + PulveriseHigh={ + familyId="Pulverise", + hash=64416, + icon="Art/2DItems/Gems/Support/Pulverize.dds", + id="PulveriseHigh", + name="Greater Pulverise", + stats={ + [1]={ + id="support_pulverise_attack_speed_+%_final", + value=-15 + }, + [2]={ + id="support_pulverise_melee_area_damage_+%_final", + value=30 + }, + [3]={ + id="base_skill_area_of_effect_+%", + value=40 + } + }, + variant=3 + }, + PulveriseLow={ + familyId="Pulverise", + hash=35729, + icon="Art/2DItems/Gems/Support/Pulverize.dds", + id="PulveriseLow", + name="Lesser Pulverise", + stats={ + [1]={ + id="support_pulverise_attack_speed_+%_final", + value=-15 + }, + [2]={ + id="support_pulverise_melee_area_damage_+%_final", + value=15 + }, + [3]={ + id="base_skill_area_of_effect_+%", + value=15 + } + }, + variant=1 + }, + PulveriseMid={ + familyId="Pulverise", + hash=64717, + icon="Art/2DItems/Gems/Support/Pulverize.dds", + id="PulveriseMid", + name="Pulverise", + stats={ + [1]={ + id="support_pulverise_attack_speed_+%_final", + value=-15 + }, + [2]={ + id="support_pulverise_melee_area_damage_+%_final", + value=20 + }, + [3]={ + id="base_skill_area_of_effect_+%", + value=30 + } + }, + variant=2 + }, + PurifyingFlameSpecificConsecratedGroundEffectHigh={ + hash=56144, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="PurifyingFlameSpecificConsecratedGroundEffectHigh", + name="Gilded Purified Ground", + stats={ + [1]={ + id="consecrated_ground_effect_+%", + value=30 + } + }, + variant=3 + }, + RageOnMeleeHitHigh={ + familyId="RageOnHit", + hash=57658, + icon="Art/2DItems/Gems/Support/RageSupport.dds", + id="RageOnMeleeHitHigh", + name="Greater Rage on Hit", + stats={ + [1]={ + id="gain_x_rage_on_melee_hit", + value=6 + } + }, + variant=3 + }, + RageOnMeleeHitLow={ + familyId="RageOnHit", + hash=55249, + icon="Art/2DItems/Gems/Support/RageSupport.dds", + id="RageOnMeleeHitLow", + name="Lesser Rage on Hit", + stats={ + [1]={ + id="gain_x_rage_on_melee_hit", + value=2 + } + }, + variant=1 + }, + RageOnMeleeHitMid={ + familyId="RageOnHit", + hash=64986, + icon="Art/2DItems/Gems/Support/RageSupport.dds", + id="RageOnMeleeHitMid", + name="Rage on Hit", + stats={ + [1]={ + id="gain_x_rage_on_melee_hit", + value=4 + } + }, + variant=2 + }, + ReduceDurationHigh={ + familyId="Duration", + hash=61947, + icon="Art/2DItems/Gems/Support/ReduceDuration.dds", + id="ReduceDurationHigh", + name="Greater Less Duration", + stats={ + [1]={ + id="support_more_duration_skill_effect_duration_+%_final", + value=-40 + } + }, + variant=3 + }, + ReduceDurationLow={ + familyId="Duration", + hash=54768, + icon="Art/2DItems/Gems/Support/ReduceDuration.dds", + id="ReduceDurationLow", + name="Lesser Less Duration", + stats={ + [1]={ + id="support_more_duration_skill_effect_duration_+%_final", + value=-15 + } + }, + variant=1 + }, + ReduceDurationMid={ + familyId="Duration", + hash=65114, + icon="Art/2DItems/Gems/Support/ReduceDuration.dds", + id="ReduceDurationMid", + name="Less Duration", + stats={ + [1]={ + id="support_more_duration_skill_effect_duration_+%_final", + value=-25 + } + }, + variant=2 + }, + ReducedProjSpeedHigh={ + familyId="ProjectileSpeed", + hash=44952, + icon="Art/2DItems/Gems/Support/SlowerProjectiles.dds", + id="ReducedProjSpeedHigh", + name="Greater Slower Projectiles", + stats={ + [1]={ + id="base_projectile_speed_+%", + value=-40 + } + }, + variant=3 + }, + ReducedProjSpeedLow={ + familyId="ProjectileSpeed", + hash=15866, + icon="Art/2DItems/Gems/Support/SlowerProjectiles.dds", + id="ReducedProjSpeedLow", + name="Lesser Slower Projectiles", + stats={ + [1]={ + id="base_projectile_speed_+%", + value=-15 + } + }, + variant=1 + }, + ReducedProjSpeedMid={ + familyId="ProjectileSpeed", + hash=2210, + icon="Art/2DItems/Gems/Support/SlowerProjectiles.dds", + id="ReducedProjSpeedMid", + name="Slower Projectiles", + stats={ + [1]={ + id="base_projectile_speed_+%", + value=-30 + } + }, + variant=2 + }, + RollingMagmaAOEPerProjHigh={ + familyId="IncreaseAreaOfEffect", + hash=28387, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="RollingMagmaAOEPerProjHigh", + name="Gilded Area per Projectile", + stats={ + [1]={ + id="active_skill_has_skill_area_of_effect_+%_final_per_additional_projectile", + value=5 + } + }, + variant=3 + }, + SRSSpecificShrinesHigh={ + hash=40676, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="SRSSpecificShrinesHigh", + name="Gilded Devotion", + stats={ + [1]={ + id="summoned_raging_spirits_have_diamond_and_massive_shrine_buff", + value=1 + } + }, + variant=3 + }, + SacredWispsHigh={ + hash=45969, + icon="Art/2DItems/Gems/Support/WandWispSupport.dds", + id="SacredWispsHigh", + name="Greater Sacred Wisps", + stats={ + [1]={ + id="summon_sacred_wisps_on_hit", + value=1 + } + }, + variant=3 + }, + ScorchingRayTotemSpecificLengthHigh={ + hash=59468, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ScorchingRayTotemSpecificLengthHigh", + name="Gilded Conflagrant", + stats={ + [1]={ + id="fire_beam_length_+%", + value=100 + } + }, + variant=3 + }, + ScourgeArrowAltSpecificPodCountHigh={ + hash=20568, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ScourgeArrowAltSpecificPodCountHigh", + name="Gilded Additional Pods", + stats={ + [1]={ + id="scourge_arrow_X_pods_per_projectile", + value=1 + } + }, + variant=3 + }, + ShieldChargeSpecificCrushOnHitHigh={ + hash=39307, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ShieldChargeSpecificCrushOnHitHigh", + name="Gilded Crush", + stats={ + [1]={ + id="chance_to_crush_on_hit_%", + value=50 + } + }, + variant=3 + }, + ShieldCrushSpecificAttackDamageFromShieldHigh={ + hash=30406, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ShieldCrushSpecificAttackDamageFromShieldHigh", + name="Gilded Shield Damage", + stats={ + [1]={ + id="attack_damage_+%_per_75_armour_or_evasion_on_shield", + value=3 + } + }, + variant=3 + }, + ShockChanceHigh={ + familyId="ShockChance", + hash=38046, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="ShockChanceHigh", + name="Greater Shock Chance", + stats={ + [1]={ + id="base_chance_to_shock_%", + value=60 + } + }, + variant=3 + }, + ShockChanceLow={ + familyId="ShockChance", + hash=9710, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="ShockChanceLow", + name="Lesser Shock Chance", + stats={ + [1]={ + id="base_chance_to_shock_%", + value=20 + } + }, + variant=1 + }, + ShockChanceMid={ + familyId="ShockChance", + hash=64846, + icon="Art/2DItems/Gems/Support/MercSilverIntSupportGem.dds", + id="ShockChanceMid", + name="Shock Chance", + stats={ + [1]={ + id="base_chance_to_shock_%", + value=40 + } + }, + variant=2 + }, + ShockwaveTotemSpecificAstralHigh={ + hash=41118, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ShockwaveTotemSpecificAstralHigh", + name="Gilded Astral Totem", + stats={ + [1]={ + id="nova_spells_cast_at_target_location", + value=1 + } + }, + variant=3 + }, + SmiteSpecificAdditionalTargetHigh={ + hash=37259, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="SmiteSpecificAdditionalTargetHigh", + name="Gilded Extra Targets", + stats={ + [1]={ + id="smite_chance_for_lighting_to_strike_extra_target_%", + value=100 + } + }, + variant=3 + }, + SoulrendAltSpecificChaosChillHigh={ + hash=38317, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="SoulrendAltSpecificChaosChillHigh", + name="Gilded Hopelessness", + stats={ + [1]={ + id="chaos_damage_can_chill", + value=1 + } + }, + variant=3 + }, + SoulrendSpecificBaseDurationHigh={ + hash=55998, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="SoulrendSpecificBaseDurationHigh", + name="Gilded Additional Duration", + stats={ + [1]={ + id="base_skill_effect_duration", + value=1000 + } + }, + variant=3 + }, + SparkSpecificNovaHigh={ + familyId="MultipleProjectiles", + hash=42155, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="SparkSpecificNovaHigh", + name="Gilded Nova", + stats={ + [1]={ + id="projectiles_nova", + value=1 + } + }, + variant=3 + }, + SpellCascadeHigh={ + familyId="SpellCascade", + hash=1751, + icon="Art/2DItems/Gems/Support/SpellCascade.dds", + id="SpellCascadeHigh", + name="Spell Cascade", + stats={ + [1]={ + id="support_spell_cascade_number_of_cascades_per_side", + value=2 + } + }, + variant=3 + }, + SpellCascadeLow={ + familyId="SpellCascade", + hash=65120, + icon="Art/2DItems/Gems/Support/SpellCascade.dds", + id="SpellCascadeLow", + name="Lesser Spell Cascade", + stats={ + [1]={ + id="support_spell_cascade_number_of_cascades_per_side", + value=1 + } + }, + variant=1 + }, + StormCallSpecificResCritHigh={ + familyId="CritChance", + hash=22587, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="StormCallSpecificResCritHigh", + name="Gilded Voltage", + stats={ + [1]={ + id="critical_strike_chance_increased_by_overcapped_lightning_resistance", + value=1 + } + }, + variant=3 + }, + StormRainSpecificNumberOfBurstsHigh={ + hash=30722, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="StormRainSpecificNumberOfBurstsHigh", + name="Gilded Additional Pulses", + stats={ + [1]={ + id="storm_rain_pulse_count", + value=2 + } + }, + variant=3 + }, + StrikeRangeHigh={ + familyId="StrikeRange", + hash=812, + icon="Art/2DItems/Gems/Support/MercSilverStrSupportGem.dds", + id="StrikeRangeHigh", + name="Greater Strike Distance", + stats={ + [1]={ + id="melee_range_+", + value=6 + } + }, + variant=3 + }, + StrikeRangeLow={ + familyId="StrikeRange", + hash=30389, + icon="Art/2DItems/Gems/Support/MercSilverStrSupportGem.dds", + id="StrikeRangeLow", + name="Lesser Strike Distance", + stats={ + [1]={ + id="melee_range_+", + value=2 + } + }, + variant=1 + }, + StrikeRangeMid={ + familyId="StrikeRange", + hash=59784, + icon="Art/2DItems/Gems/Support/MercSilverStrSupportGem.dds", + id="StrikeRangeMid", + name="Strike Distance", + stats={ + [1]={ + id="melee_range_+", + value=4 + } + }, + variant=2 + }, + SummonSkeletonsSpecificArchersHigh={ + hash=52378, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="SummonSkeletonsSpecificArchersHigh", + name="Gilded Archers", + stats={ + [1]={ + id="chance_for_melee_skeletons_to_summon_as_archer_skeletons_%", + value=100 + } + }, + variant=3 + }, + SunderAltSpecificAdditionalChainHigh={ + hash=4006, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="SunderAltSpecificAdditionalChainHigh", + name="Gilded Snaking", + stats={ + [1]={ + id="sunder_number_of_fake_chains", + value=1 + } + }, + variant=3 + }, + TornadoShotSpecificSecondaryProjHigh={ + hash=18499, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="TornadoShotSpecificSecondaryProjHigh", + name="Gilded Secondary Shots", + stats={ + [1]={ + id="tornado_shot_num_of_secondary_projectiles", + value=2 + } + }, + variant=3 + }, + TotemDefencesHigh={ + familyId="TotemDefences", + hash=1227, + icon="Art/2DItems/Gems/Support/MercSilverStrIntSupportGem.dds", + id="TotemDefencesHigh", + name="Greater Ironwood", + stats={ + [1]={ + id="totem_additional_physical_damage_reduction_%", + value=30 + }, + [2]={ + id="totem_elemental_resistance_%", + value=60 + } + }, + variant=3 + }, + TotemDefencesLow={ + familyId="TotemDefences", + hash=230, + icon="Art/2DItems/Gems/Support/MercSilverStrIntSupportGem.dds", + id="TotemDefencesLow", + name="Lesser Ironwood", + stats={ + [1]={ + id="totem_additional_physical_damage_reduction_%", + value=10 + }, + [2]={ + id="totem_elemental_resistance_%", + value=30 + } + }, + variant=1 + }, + TotemDefencesMid={ + familyId="TotemDefences", + hash=6667, + icon="Art/2DItems/Gems/Support/MercSilverStrIntSupportGem.dds", + id="TotemDefencesMid", + name="Ironwood", + stats={ + [1]={ + id="totem_additional_physical_damage_reduction_%", + value=20 + }, + [2]={ + id="totem_elemental_resistance_%", + value=40 + } + }, + variant=2 + }, + ToxicRainSpecificGraspingVinesHigh={ + hash=32361, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="ToxicRainSpecificGraspingVinesHigh", + name="Gilded Grasp", + stats={ + [1]={ + id="add_x_grasping_vines_on_hit", + value=1 + } + }, + variant=3 + }, + TrapChargeGenHigh={ + hash=5081, + icon="Art/2DItems/Gems/Support/PowerFrenzyCharge.dds", + id="TrapChargeGenHigh", + name="Charged Traps", + stats={ + [1]={ + id="%_chance_to_gain_frenzy_charge_on_trap_triggered_by_an_enemy", + value=40 + } + }, + variant=3 + }, + TrapMineDamageHigh={ + familyId="TrapMineDamage", + hash=59079, + icon="Art/2DItems/Gems/Support/TrapAndMineDamage.dds", + id="TrapMineDamageHigh", + name="Greater Trap and Mine Damage", + stats={ + [1]={ + id="support_trap_and_mine_damage_+%_final", + value=30 + }, + [2]={ + id="support_trap_and_mine_damage_trap_throwing_speed_+%_final", + value=-25 + } + }, + variant=3 + }, + TrapMineDamageLow={ + familyId="TrapMineDamage", + hash=49954, + icon="Art/2DItems/Gems/Support/TrapAndMineDamage.dds", + id="TrapMineDamageLow", + name="Lesser Trap and Mine Damage", + stats={ + [1]={ + id="support_trap_and_mine_damage_+%_final", + value=15 + }, + [2]={ + id="support_trap_and_mine_damage_trap_throwing_speed_+%_final", + value=-25 + } + }, + variant=1 + }, + TrapMineDamageMid={ + familyId="TrapMineDamage", + hash=31171, + icon="Art/2DItems/Gems/Support/TrapAndMineDamage.dds", + id="TrapMineDamageMid", + name="Trap and Mine Damage", + stats={ + [1]={ + id="support_trap_and_mine_damage_+%_final", + value=20 + }, + [2]={ + id="support_trap_and_mine_damage_trap_throwing_speed_+%_final", + value=-25 + } + }, + variant=2 + }, + TrapMineThrowSpeedHigh={ + familyId="TrapThrowSpeed", + hash=58938, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="TrapMineThrowSpeedHigh", + name="Greater Throwing Speed", + stats={ + [1]={ + id="trap_throwing_speed_+%", + value=40 + }, + [2]={ + id="mine_laying_speed_+%", + value=40 + } + }, + variant=3 + }, + TrapMineThrowSpeedLow={ + familyId="TrapThrowSpeed", + hash=32260, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="TrapMineThrowSpeedLow", + name="Lesser Throwing Speed", + stats={ + [1]={ + id="trap_throwing_speed_+%", + value=15 + }, + [2]={ + id="mine_laying_speed_+%", + value=15 + } + }, + variant=1 + }, + TrapMineThrowSpeedMid={ + familyId="TrapThrowSpeed", + hash=3465, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="TrapMineThrowSpeedMid", + name="Throwing Speed", + stats={ + [1]={ + id="trap_throwing_speed_+%", + value=30 + }, + [2]={ + id="mine_laying_speed_+%", + value=30 + } + }, + variant=2 + }, + TrapTriggerArcaneSurgeHigh={ + hash=14557, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="TrapTriggerArcaneSurgeHigh", + name="Arcane Traps", + stats={ + [1]={ + id="gain_arcane_surge_when_trap_triggered_by_an_enemy", + value=1 + } + }, + variant=3 + }, + TrapTriggerRadiusHigh={ + hash=54156, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="TrapTriggerRadiusHigh", + name="Greater Trigger Radius", + stats={ + [1]={ + id="trap_trigger_radius_+%", + value=60 + } + }, + variant=3 + }, + TrapTriggerRadiusLow={ + hash=40446, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="TrapTriggerRadiusLow", + name="Lesser Trigger Radius", + stats={ + [1]={ + id="trap_trigger_radius_+%", + value=20 + } + }, + variant=1 + }, + TrapTriggerRadiusMid={ + hash=819, + icon="Art/2DItems/Gems/Support/MercSilverDexIntSupportGem.dds", + id="TrapTriggerRadiusMid", + name="Trigger Radius", + stats={ + [1]={ + id="trap_trigger_radius_+%", + value=40 + } + }, + variant=2 + }, + VaalDoubleStrikeSpecificCloneSpeedHigh={ + hash=56315, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VaalDoubleStrikeSpecificCloneSpeedHigh", + name="Gilded Clone Speed", + stats={ + [1]={ + id="doubles_have_movement_speed_+%", + value=40 + } + }, + variant=3 + }, + VaalGroundSlamSpecificStunDurationHigh={ + hash=26618, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VaalGroundSlamSpecificStunDurationHigh", + name="Gilded Stun Duration", + stats={ + [1]={ + id="base_stun_duration_+%", + value=30 + } + }, + variant=3 + }, + VaalLightningArrowSpecificRedirectHigh={ + hash=11052, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VaalLightningArrowSpecificRedirectHigh", + name="Gilded Uncertainty", + stats={ + [1]={ + id="vaal_lightning_arrow_number_of_redirects", + value=3 + } + }, + variant=3 + }, + VaalReapSpecificFireDebuffHigh={ + hash=50273, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VaalReapSpecificFireDebuffHigh", + name="Gilded Searing Agony", + stats={ + [1]={ + id="reap_debuff_deals_fire_damage_instead_of_physical_damage", + value=1 + } + }, + variant=3 + }, + VigilantStrikeSpecificShareFortifyHigh={ + hash=60910, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VigilantStrikeSpecificShareFortifyHigh", + name="Gilded Fortification", + stats={ + [1]={ + id="fortify_applies_to_nearby_allies_for_X_seconds", + value=8 + } + }, + variant=3 + }, + VoidSphereSpecificTickRateHigh={ + hash=12569, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VoidSphereSpecificTickRateHigh", + name="Gilded Sphere Frequency", + stats={ + [1]={ + id="blackhole_pulse_frequency_+%", + value=35 + } + }, + variant=3 + }, + VolcanicFissureSpecificRepeatHigh={ + hash=3609, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VolcanicFissureSpecificRepeatHigh", + name="Gilded Additional Fissures", + stats={ + [1]={ + id="vaal_volcanic_fissure_crack_repeat_count", + value=1 + } + }, + variant=3 + }, + VoltaxicBurstSpecificConvertLightningToChaosHigh={ + hash=17946, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="VoltaxicBurstSpecificConvertLightningToChaosHigh", + name="Gilded Voltaxic Conversion", + stats={ + [1]={ + id="skill_lightning_damage_%_to_convert_to_chaos", + value=40 + } + }, + variant=3 + }, + WarcryRageHigh={ + familyId="RageWarcry", + hash=13784, + icon="Art/2DItems/Gems/Support/MercSilverStrSupportGem.dds", + id="WarcryRageHigh", + name="Greater Raging Cry", + stats={ + [1]={ + id="gain_rage_when_you_use_a_warcry", + value=20 + } + }, + variant=3 + }, + WarcryRageLow={ + familyId="RageWarcry", + hash=49237, + icon="Art/2DItems/Gems/Support/MercSilverStrSupportGem.dds", + id="WarcryRageLow", + name="Lesser Raging Cry", + stats={ + [1]={ + id="gain_rage_when_you_use_a_warcry", + value=10 + } + }, + variant=1 + }, + WarcryRageMid={ + familyId="RageWarcry", + hash=36496, + icon="Art/2DItems/Gems/Support/MercSilverStrSupportGem.dds", + id="WarcryRageMid", + name="Raging Cry", + stats={ + [1]={ + id="gain_rage_when_you_use_a_warcry", + value=15 + } + }, + variant=2 + }, + WarcrySpeedHigh={ + familyId="WarcrySpeed", + hash=52142, + icon="Art/2DItems/Gems/Support/UrgentOrdersSupport.dds", + id="WarcrySpeedHigh", + name="Greater Warcry Speed", + stats={ + [1]={ + id="warcry_speed_+%", + value=75 + } + }, + variant=3 + }, + WarcrySpeedLow={ + familyId="WarcrySpeed", + hash=55470, + icon="Art/2DItems/Gems/Support/UrgentOrdersSupport.dds", + id="WarcrySpeedLow", + name="Lesser Warcry Speed", + stats={ + [1]={ + id="warcry_speed_+%", + value=35 + } + }, + variant=1 + }, + WarcrySpeedMid={ + familyId="WarcrySpeed", + hash=47477, + icon="Art/2DItems/Gems/Support/UrgentOrdersSupport.dds", + id="WarcrySpeedMid", + name="Warcry Speed", + stats={ + [1]={ + id="warcry_speed_+%", + value=50 + } + }, + variant=2 + }, + WildStrikeSpecificEleWeakOnHitHigh={ + hash=3756, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="WildStrikeSpecificEleWeakOnHitHigh", + name="Gilded Elemental Weakness on Hit", + stats={ + [1]={ + id="curse_on_hit_%_elemental_weakness", + value=50 + } + }, + variant=3 + }, + WitherOnHitHigh={ + familyId="WitherOnHit", + hash=61510, + icon="Art/2DItems/Gems/Support/WitherGemSupport.dds", + id="WitherOnHitHigh", + name="Greater Wither on Hit", + stats={ + [1]={ + id="withered_on_hit_chance_%", + value=45 + }, + [2]={ + id="support_withered_base_duration_ms", + value=2000 + } + }, + variant=3 + }, + WitherOnHitLow={ + familyId="WitherOnHit", + hash=53673, + icon="Art/2DItems/Gems/Support/WitherGemSupport.dds", + id="WitherOnHitLow", + name="Lesser Wither on Hit", + stats={ + [1]={ + id="withered_on_hit_chance_%", + value=15 + }, + [2]={ + id="support_withered_base_duration_ms", + value=2000 + } + }, + variant=1 + }, + WitherOnHitMid={ + familyId="WitherOnHit", + hash=15235, + icon="Art/2DItems/Gems/Support/WitherGemSupport.dds", + id="WitherOnHitMid", + name="Wither on Hit", + stats={ + [1]={ + id="withered_on_hit_chance_%", + value=30 + }, + [2]={ + id="support_withered_base_duration_ms", + value=2000 + } + }, + variant=2 + }, + WitheringStepSpecificWitherStacksHigh={ + hash=55952, + icon="Art/2DItems/Gems/Support/MercGoldSupportGem.dds", + id="WitheringStepSpecificWitherStacksHigh", + name="Gilded Wither Stacks", + stats={ + [1]={ + id="slither_wither_stacks", + value=5 + } + }, + variant=3 + } + }, + supportsByHash={ + ["10482"]={ + [1]="BurningArrowSpecificAlwaysPierceHigh" + }, + ["10608"]={ + [1]="CooldownSpeedHigh" + }, + ["10682"]={ + [1]="BladestormSpecificAdditionalStormHigh" + }, + ["1075"]={ + [1]="BladeFallSpecificAddedVolleysHigh" + }, + ["10782"]={ + [1]="ConsecratedPathSpecificDamageGainHigh" + }, + ["10997"]={ + [1]="IgniteChanceHigh" + }, + ["11052"]={ + [1]="VaalLightningArrowSpecificRedirectHigh" + }, + ["11497"]={ + [1]="ImpaleChanceMid" + }, + ["11914"]={ + [1]="AddedChaosHigh" + }, + ["12054"]={ + [1]="MultipleProjectilesLow" + }, + ["1227"]={ + [1]="TotemDefencesHigh" + }, + ["12347"]={ + [1]="FistOfWarHigh" + }, + ["12387"]={ + [1]="FreezeChanceHigh" + }, + ["12388"]={ + [1]="NonDamagingAilmentEffectLow" + }, + ["12569"]={ + [1]="VoidSphereSpecificTickRateHigh" + }, + ["13016"]={ + [1]="MinionChaosCloudHigh" + }, + ["13069"]={ + [1]="AddedColdLow" + }, + ["13568"]={ + [1]="DivineIreSpecificWidthHigh" + }, + ["13784"]={ + [1]="WarcryRageHigh" + }, + ["14317"]={ + [1]="AdditionalChainsLow" + }, + ["14517"]={ + [1]="IncreasedProjSpeedHigh" + }, + ["14557"]={ + [1]="TrapTriggerArcaneSurgeHigh" + }, + ["15235"]={ + [1]="WitherOnHitMid" + }, + ["15866"]={ + [1]="ReducedProjSpeedLow" + }, + ["16261"]={ + [1]="IgnoreEnemyPhysMitLow" + }, + ["17097"]={ + [1]="MultiTotemHigh" + }, + ["17178"]={ + [1]="CycloneSpecificMoveSpeedHigh" + }, + ["17213"]={ + [1]="IceNovaSpecificFirePerChillHigh" + }, + ["1751"]={ + [1]="SpellCascadeHigh" + }, + ["17946"]={ + [1]="VoltaxicBurstSpecificConvertLightningToChaosHigh" + }, + ["18499"]={ + [1]="TornadoShotSpecificSecondaryProjHigh" + }, + ["1864"]={ + [1]="PoisonChanceLow" + }, + ["19004"]={ + [1]="FireballAltSpecificChanceToScorchHigh" + }, + ["19113"]={ + [1]="IncreaseAreaOfEffectHigh" + }, + ["20568"]={ + [1]="ScourgeArrowAltSpecificPodCountHigh" + }, + ["20579"]={ + [1]="MinionLifeMid" + }, + ["21276"]={ + [1]="BoneshatterSpecificTraumaDurationHigh" + }, + ["21489"]={ + [1]="ConcentratedEffectMid" + }, + ["21678"]={ + [1]="GigaShockNovaSpecificAOEHigh" + }, + ["2205"]={ + [1]="MoltenStrikeSpecificExtraProjHigh" + }, + ["2210"]={ + [1]="ReducedProjSpeedMid" + }, + ["22587"]={ + [1]="StormCallSpecificResCritHigh" + }, + ["22670"]={ + [1]="IncreaseAreaOfEffectLow" + }, + ["22977"]={ + [1]="DotMultiLow" + }, + ["230"]={ + [1]="TotemDefencesLow" + }, + ["23209"]={ + [1]="CriticalStrikeLow" + }, + ["23582"]={ + [1]="MinionLifeLow" + }, + ["24343"]={ + [1]="LightningDamageLuckyHigh" + }, + ["25001"]={ + [1]="ArtilleryBallistaSpecificOnslaughtHigh" + }, + ["25199"]={ + [1]="IncreasedProjSpeedLow" + }, + ["2555"]={ + [1]="MultiTrapHigh" + }, + ["25565"]={ + [1]="EnsnaringArrowSpecificEffectHigh" + }, + ["25880"]={ + [1]="ChaosPenLow" + }, + ["25885"]={ + [1]="LightningSpireSpecificBeamsHigh" + }, + ["25973"]={ + [1]="MultistrikeHigh" + }, + ["2602"]={ + [1]="IncreaseDurationLow" + }, + ["26094"]={ + [1]="ColdPenetrationHigh" + }, + ["26146"]={ + [1]="HypothermiaLow" + }, + ["26568"]={ + [1]="IncreaseDurationHigh" + }, + ["26618"]={ + [1]="VaalGroundSlamSpecificStunDurationHigh" + }, + ["26713"]={ + [1]="LightningTrapSpecificShockSlowHigh" + }, + ["26792"]={ + [1]="MoltenShellSpecificPDRHigh" + }, + ["26815"]={ + [1]="LightningPenetrationHigh" + }, + ["27458"]={ + [1]="FreezeChanceMid" + }, + ["27970"]={ + [1]="PierceHigh" + }, + ["28037"]={ + [1]="PhysGainAsRandomLow" + }, + ["28387"]={ + [1]="RollingMagmaAOEPerProjHigh" + }, + ["28416"]={ + [1]="EleDamageWithAttacksHigh" + }, + ["28579"]={ + [1]="MinionDamageMid" + }, + ["29166"]={ + [1]="IceCrashSpecificTertiaryRadiusHigh" + }, + ["29562"]={ + [1]="GiantZombieSpecificSlowZombieHigh" + }, + ["29720"]={ + [1]="ImpaleChanceHigh" + }, + ["29922"]={ + [1]="ExcommunicateLow" + }, + ["30359"]={ + [1]="EleFocusLow" + }, + ["30389"]={ + [1]="StrikeRangeLow" + }, + ["30406"]={ + [1]="ShieldCrushSpecificAttackDamageFromShieldHigh" + }, + ["30688"]={ + [1]="CritDamageLow" + }, + ["30722"]={ + [1]="StormRainSpecificNumberOfBurstsHigh" + }, + ["30881"]={ + [1]="CooldownSpeedLow" + }, + ["31052"]={ + [1]="AdditionalChainsMid" + }, + ["31171"]={ + [1]="TrapMineDamageMid" + }, + ["31430"]={ + [1]="AddedChaosMid" + }, + ["31439"]={ + [1]="BleedHigh" + }, + ["31571"]={ + [1]="ArcSpecificDistanceHigh" + }, + ["31600"]={ + [1]="EleFocusHigh" + }, + ["31664"]={ + [1]="FortifyHigh" + }, + ["3180"]={ + [1]="BlightSpecificSecondaryDurationHigh" + }, + ["31863"]={ + [1]="MinionLifeHigh" + }, + ["3194"]={ + [1]="HeavyStrikeSpecificMoreMaxPhysHigh" + }, + ["32052"]={ + [1]="ForkHigh" + }, + ["32130"]={ + [1]="LeechLow" + }, + ["32189"]={ + [1]="CritDamageMid" + }, + ["32260"]={ + [1]="TrapMineThrowSpeedLow" + }, + ["32361"]={ + [1]="ToxicRainSpecificGraspingVinesHigh" + }, + ["3240"]={ + [1]="LeechMid" + }, + ["32431"]={ + [1]="GlacialCascadeSpecificNumberOfSpikesHigh" + }, + ["3263"]={ + [1]="CurseEffectHigh" + }, + ["33272"]={ + [1]="NonDamagingAilmentEffectHigh" + }, + ["33557"]={ + [1]="IgnoreEnemyPhysMitHigh" + }, + ["33975"]={ + [1]="ChaosPenMid" + }, + ["34226"]={ + [1]="FreezeChanceLow" + }, + ["3465"]={ + [1]="TrapMineThrowSpeedMid" + }, + ["34697"]={ + [1]="ChannelSkillDamageReductionMid" + }, + ["35435"]={ + [1]="GenerosityMid" + }, + ["35729"]={ + [1]="PulveriseLow" + }, + ["3609"]={ + [1]="VolcanicFissureSpecificRepeatHigh" + }, + ["36350"]={ + [1]="FlameLinkSpecificAddedFlatHigh" + }, + ["36496"]={ + [1]="WarcryRageMid" + }, + ["36665"]={ + [1]="AddedLightningLow" + }, + ["37259"]={ + [1]="SmiteSpecificAdditionalTargetHigh" + }, + ["37275"]={ + [1]="HolyMortarSpecificCoverInAshHigh" + }, + ["37388"]={ + [1]="EleFocusMid" + }, + ["37460"]={ + [1]="DotMultiHigh" + }, + ["3756"]={ + [1]="WildStrikeSpecificEleWeakOnHitHigh" + }, + ["37727"]={ + [1]="MirageArcherHigh" + }, + ["37739"]={ + [1]="LightningPenetrationLow" + }, + ["38046"]={ + [1]="ShockChanceHigh" + }, + ["38317"]={ + [1]="SoulrendAltSpecificChaosChillHigh" + }, + ["38571"]={ + [1]="HypothermiaMid" + }, + ["38851"]={ + [1]="CastSpeedMid" + }, + ["38948"]={ + [1]="BleedMid" + }, + ["39050"]={ + [1]="GroundSlamSpecificAngleHigh" + }, + ["39101"]={ + [1]="CausticArrowSpecificChaosConvertHigh" + }, + ["39307"]={ + [1]="ShieldChargeSpecificCrushOnHitHigh" + }, + ["39342"]={ + [1]="PhysGainAsRandomMid" + }, + ["39984"]={ + [1]="ChaosPenHigh" + }, + ["4006"]={ + [1]="SunderAltSpecificAdditionalChainHigh" + }, + ["40212"]={ + [1]="OrbOfStormsSpecificShockCritKnockHigh" + }, + ["4032"]={ + [1]="HolyFlameTotemSpecificConcBlockHigh" + }, + ["40446"]={ + [1]="TrapTriggerRadiusLow" + }, + ["40533"]={ + [1]="AddedLightningHigh" + }, + ["40565"]={ + [1]="ColdPenetrationLow" + }, + ["40660"]={ + [1]="MeleeSplashHigh" + }, + ["40676"]={ + [1]="SRSSpecificShrinesHigh" + }, + ["41118"]={ + [1]="ShockwaveTotemSpecificAstralHigh" + }, + ["41256"]={ + [1]="LightningPenetrationMid" + }, + ["41756"]={ + [1]="LeechHigh" + }, + ["42140"]={ + [1]="CleaveSpecificCullHigh" + }, + ["42155"]={ + [1]="SparkSpecificNovaHigh" + }, + ["42600"]={ + [1]="BleedLow" + }, + ["42698"]={ + [1]="ConcentratedEffectLow" + }, + ["42966"]={ + [1]="ExplosiveArrowSpecificMaxHigh" + }, + ["42977"]={ + [1]="AddedFireLow" + }, + ["43469"]={ + [1]="CastSpeedLow" + }, + ["4351"]={ + [1]="IgnoreEnemyPhysMitMid" + }, + ["44238"]={ + [1]="HolyRelicSpecificRegenHigh" + }, + ["44527"]={ + [1]="AilmentDamageLow" + }, + ["44886"]={ + [1]="EleDamageWithAttacksMid" + }, + ["44952"]={ + [1]="ReducedProjSpeedHigh" + }, + ["45050"]={ + [1]="PhysGainAsRandomHigh" + }, + ["45284"]={ + [1]="AddedChaosLow" + }, + ["45433"]={ + [1]="ExcommunicateMid" + }, + ["45439"]={ + [1]="AddedFireMid" + }, + ["45969"]={ + [1]="SacredWispsHigh" + }, + ["46010"]={ + [1]="FirePenetrationLow" + }, + ["47477"]={ + [1]="WarcrySpeedMid" + }, + ["48614"]={ + [1]="FlameblastSpecificStagesHigh" + }, + ["48738"]={ + [1]="LeapSlamSpecificFrenzyOnHitHigh" + }, + ["48875"]={ + [1]="CooldownSpeedMid" + }, + ["48949"]={ + [1]="DarkPactSpecificMaledictionOnHitHigh" + }, + ["49189"]={ + [1]="BlastRainAltSpecificExtraBlastHigh" + }, + ["49237"]={ + [1]="WarcryRageLow" + }, + ["49419"]={ + [1]="MultipleProjectilesHigh" + }, + ["49954"]={ + [1]="TrapMineDamageLow" + }, + ["50222"]={ + [1]="IncreaseDurationMid" + }, + ["50273"]={ + [1]="VaalReapSpecificFireDebuffHigh" + }, + ["50303"]={ + [1]="IgniteChanceMid" + }, + ["50475"]={ + [1]="AddedCooldownCountHigh" + }, + ["50485"]={ + [1]="AttackSpeedHigh" + }, + ["50741"]={ + [1]="HolyMoltenStrikeSpecificLightningExposureHigh" + }, + ["5081"]={ + [1]="TrapChargeGenHigh" + }, + ["51009"]={ + [1]="PhysGainAsChaosMid" + }, + ["51806"]={ + [1]="ConcentratedEffectHigh" + }, + ["51944"]={ + [1]="CobraLashSpecificPoisonRegenHigh" + }, + ["52142"]={ + [1]="WarcrySpeedHigh" + }, + ["52335"]={ + [1]="IgniteChanceLow" + }, + ["52378"]={ + [1]="SummonSkeletonsSpecificArchersHigh" + }, + ["52383"]={ + [1]="FlickerStrikeSpecificConsumeAllImpalesHigh" + }, + ["52432"]={ + [1]="EnduringCrySpecificOnslaughtGainHigh" + }, + ["52447"]={ + [1]="AttackSpeedLow" + }, + ["52472"]={ + [1]="MinionDamageHigh" + }, + ["52758"]={ + [1]="AddedColdMid" + }, + ["5293"]={ + [1]="ProjectilesReturnHigh" + }, + ["53145"]={ + [1]="HypothermiaHigh" + }, + ["53342"]={ + [1]="IncreaseAreaOfEffectMid" + }, + ["53367"]={ + [1]="GenerosityHigh" + }, + ["53516"]={ + [1]="MeleePhysMid" + }, + ["53673"]={ + [1]="WitherOnHitLow" + }, + ["54156"]={ + [1]="TrapTriggerRadiusHigh" + }, + ["54252"]={ + [1]="ImpaleChanceLow" + }, + ["54494"]={ + [1]="FirePenetrationHigh" + }, + ["54628"]={ + [1]="ColdPenetrationMid" + }, + ["54768"]={ + [1]="ReduceDurationLow" + }, + ["54837"]={ + [1]="BrittleChanceHigh" + }, + ["55249"]={ + [1]="RageOnMeleeHitLow" + }, + ["55470"]={ + [1]="WarcrySpeedLow" + }, + ["55659"]={ + [1]="CritDamageHigh" + }, + ["55807"]={ + [1]="BrutalityLow" + }, + ["55952"]={ + [1]="WitheringStepSpecificWitherStacksHigh" + }, + ["55998"]={ + [1]="SoulrendSpecificBaseDurationHigh" + }, + ["56144"]={ + [1]="PurifyingFlameSpecificConsecratedGroundEffectHigh" + }, + ["56233"]={ + [1]="HallowHigh" + }, + ["56267"]={ + [1]="PierceMid" + }, + ["56315"]={ + [1]="VaalDoubleStrikeSpecificCloneSpeedHigh" + }, + ["56389"]={ + [1]="MaimOnHitHigh" + }, + ["56511"]={ + [1]="AltEssenceDrainSpecificLeechHigh" + }, + ["57644"]={ + [1]="IncreasedProjSpeedMid" + }, + ["57658"]={ + [1]="RageOnMeleeHitHigh" + }, + ["58214"]={ + [1]="PhysGainAsChaosHigh" + }, + ["58384"]={ + [1]="PoisonChanceMid" + }, + ["58429"]={ + [1]="ArrowNovaHigh" + }, + ["58471"]={ + [1]="LightningArrowSpecificAddedTargetsHigh" + }, + ["58581"]={ + [1]="CombustionHigh" + }, + ["58938"]={ + [1]="TrapMineThrowSpeedHigh" + }, + ["59079"]={ + [1]="TrapMineDamageHigh" + }, + ["59345"]={ + [1]="BrutalityHigh" + }, + ["59349"]={ + [1]="GenerosityLow" + }, + ["59468"]={ + [1]="ScorchingRayTotemSpecificLengthHigh" + }, + ["59712"]={ + [1]="EleDamageWithAttacksLow" + }, + ["59784"]={ + [1]="StrikeRangeMid" + }, + ["59986"]={ + [1]="ChannelSkillDamageReductionLow" + }, + ["60094"]={ + [1]="AddedColdHigh" + }, + ["6040"]={ + [1]="PierceLow" + }, + ["60910"]={ + [1]="VigilantStrikeSpecificShareFortifyHigh" + }, + ["60983"]={ + [1]="LancingSteelSpecificRandomProjHigh" + }, + ["6109"]={ + [1]="HolyHammersSpecificPowerChargeHigh" + }, + ["6121"]={ + [1]="AddedFireHigh" + }, + ["61471"]={ + [1]="CriticalStrikeMid" + }, + ["61510"]={ + [1]="WitherOnHitHigh" + }, + ["61947"]={ + [1]="ReduceDurationHigh" + }, + ["61972"]={ + [1]="NonDamagingAilmentEffectMid" + }, + ["62171"]={ + [1]="ConflagrationSpecificInvertResistancesHigh" + }, + ["62220"]={ + [1]="CriticalStrikeHigh" + }, + ["62638"]={ + [1]="MultistrikeMid" + }, + ["62885"]={ + [1]="FirePenetrationMid" + }, + ["63104"]={ + [1]="ChannelSkillDamageReductionHigh" + }, + ["63342"]={ + [1]="MeleePhysHigh" + }, + ["64271"]={ + [1]="BrutalityMid" + }, + ["64281"]={ + [1]="DamageOverTimeReduceDurationMid" + }, + ["64283"]={ + [1]="AddedLightningMid" + }, + ["64416"]={ + [1]="PulveriseHigh" + }, + ["64717"]={ + [1]="PulveriseMid" + }, + ["64801"]={ + [1]="MaxShockHigh" + }, + ["64846"]={ + [1]="ShockChanceMid" + }, + ["64940"]={ + [1]="MeleePhysLow" + }, + ["64986"]={ + [1]="RageOnMeleeHitMid" + }, + ["65002"]={ + [1]="KnockbackLow" + }, + ["65114"]={ + [1]="ReduceDurationMid" + }, + ["65120"]={ + [1]="SpellCascadeLow" + }, + ["65240"]={ + [1]="DamageOverTimeReduceDurationHigh" + }, + ["65362"]={ + [1]="AilmentDamageHigh" + }, + ["6667"]={ + [1]="TotemDefencesMid" + }, + ["6927"]={ + [1]="DotMultiMid" + }, + ["812"]={ + [1]="StrikeRangeHigh" + }, + ["819"]={ + [1]="TrapTriggerRadiusMid" + }, + ["834"]={ + [1]="DamageOverTimeReduceDurationLow" + }, + ["8607"]={ + [1]="CastSpeedHigh" + }, + ["8617"]={ + [1]="ExcommunicateHigh" + }, + ["8720"]={ + [1]="HolyStrikesSpecificAdditionalMinionHigh" + }, + ["8821"]={ + [1]="MinionDamageLow" + }, + ["9300"]={ + [1]="BodySwapSpecificDamageFromLifeHigh" + }, + ["9460"]={ + [1]="PerforateSpecificSpikesHigh" + }, + ["9585"]={ + [1]="PoisonChanceHigh" + }, + ["9607"]={ + [1]="AilmentDamageMid" + }, + ["9710"]={ + [1]="ShockChanceLow" + }, + ["987"]={ + [1]="AttackSpeedMid" + } + } +} diff --git a/src/Data/MercenaryStatMap.lua b/src/Data/MercenaryStatMap.lua new file mode 100644 index 00000000000..e51f34c2975 --- /dev/null +++ b/src/Data/MercenaryStatMap.lua @@ -0,0 +1,985 @@ +-- Path of Building +-- +-- Mercenary-only stat mappings and standard support templates. +-- Raw values are exported from MercenarySupports; this file only describes +-- how those values participate in PoB's existing calculation model. +-- +return function(mod, flag, skill) + +local allyBuff = { type = "GlobalEffect", effectType = "Buff", applyAllies = true } +local allyWarcry = { type = "GlobalEffect", effectType = "Warcry", unscalable = true } +local selfBuff = { type = "GlobalEffect", effectType = "Buff" } +local enemyDebuff = { type = "GlobalEffect", effectType = "Debuff" } + +local scorchingRayTotemStages = { + ["fire_beam_additional_stack_damage_+%_final"] = { + mod("Damage", "MORE", nil, 0, 0, { type = "Multiplier", var = "ScorchingRayTotemStageAfterFirst" }), + base = 100, + }, + ["display_max_fire_beam_stacks"] = { + mod("Multiplier:ScorchingRayTotemMaxStages", "BASE", nil), + }, +} + +local function calculateCorruptedBlood(activeSkill, output) + local skillData = activeSkill.skillData + skillData.PhysicalDot = activeSkill.actor.averageDamage * (skillData.corruptedBloodDamagePercent or 0) / 6000 + local stacksPerHit = skillData.corruptedBloodStacksPerHit or 1 + local stacks = math.min(10, math.max(1, math.floor((output.DurationSecondary or 0) / skillData.hitTimeOverride + 1e-9)) * stacksPerHit) + skillData.corruptedBloodStacks = stacks + if stacks > 1 then + activeSkill.skillModList:NewMod("Damage", "MORE", (stacks - 1) * 100, "Corrupted Blood stacks", 0, KeywordFlag.PhysicalDot) + end +end + +return { + statMap = { + ["barrage_final_volley_fires_x_additional_projectiles_simultaneously"] = { + skill("barrageFinalVolleyAdditionalProjectiles", nil), + }, + ["maximum_number_of_vaal_ice_shot_mirages"] = { + skill("vaalIceShotMirageCount", nil), + }, + ["%_chance_to_gain_frenzy_charge_on_trap_triggered_by_an_enemy"] = { + flag("UseFrenzyCharges"), + skill("frenzyChargeOnTrapTriggerChance", nil), + }, + ["active_skill_has_skill_area_of_effect_+%_final_per_additional_projectile"] = { + mod("AreaOfEffect", "MORE", nil, 0, 0, { type = "PerStat", stat = "ProjectileCount", subtract = 1 }), + }, + ["abyssal_cry_%_max_life_as_chaos_on_death"] = { + skill("corpseExplosionLifeMultiplier", nil), + div = 100, + }, + ["abyssal_cry_movement_velocity_+%_per_one_hundred_nearby_enemies"] = { + skill("hinderPerNearbyEnemy", nil), + div = 100, + }, + ["add_endurance_charge_on_skill_hit_%"] = { + flag("UseEnduranceCharges"), + skill("enduranceChargeOnHitChance", nil), + }, + ["add_frenzy_charge_on_skill_hit_%"] = { + flag("UseFrenzyCharges"), + skill("frenzyChargeOnHitChance", nil), + }, + ["add_power_charge_on_critical_strike_%"] = { + flag("UsePowerCharges"), + skill("powerChargeOnCritChance", nil), + }, + ["add_x_grasping_vines_on_hit"] = { + mod("Multiplier:GraspingVinesAffectingEnemy", "BASE", nil, 0, 0, enemyDebuff), + }, + ["additional_block_%_while_on_consecrated_ground"] = { + mod("BlockChance", "BASE", nil, 0, 0, { type = "Condition", var = "OnConsecratedGround" }), + }, + ["additional_physical_damage_reduction_%_while_affected_by_guard_skill"] = { + mod("PhysicalDamageReduction", "BASE", nil, 0, 0, { type = "Condition", var = "AffectedByGuardSkill" }), + }, + ["attack_damage_+%_per_75_armour_or_evasion_on_shield"] = { + mod("Damage", "INC", nil, ModFlag.Attack, 0, { type = "PerStat", statList = { "ArmourOnWeapon 2", "EvasionOnWeapon 2" }, div = 75 }), + }, + ["base_maximum_mana"] = { + mod("Mana", "BASE", nil), + }, + ["base_spell_critical_strike_chance"] = { + mod("CritChance", "BASE", nil, ModFlag.Spell), + div = 100, + }, + ["beacon_placement_radius"] = { + skill("beaconPlacementRadius", nil), + }, + ["blackhole_pulse_frequency_+%"] = { + mod("VoidSphereFrequency", "INC", nil), + }, + ["bladestorm_maximum_number_of_storms_allowed"] = { + skill("maximumBladestorms", nil), + }, + ["blast_rain_%_chance_for_additional_blast"] = { + mod("Damage", "MORE", nil, ModFlag.Hit), + skill("chanceForAdditionalBlast", nil), + }, + ["blight_secondary_skill_effect_duration_+%"] = { + mod("SecondaryDuration", "INC", nil), + }, + ["chance_for_melee_skeletons_to_summon_as_archer_skeletons_%"] = { + skill("summonSkeletonArchersChance", nil), + }, + ["chance_to_crush_on_hit_%"] = { + flag("Condition:Crushed", enemyDebuff), + skill("crushOnHitChance", nil), + }, + ["chance_to_gain_power_charge_on_rare_or_unique_enemy_hit_%"] = { + flag("UsePowerCharges"), + skill("powerChargeOnRareOrUniqueHitChance", nil), + }, + ["chance_to_intimidate_on_hit_%"] = { + flag("Condition:Intimidated", enemyDebuff), + skill("intimidateOnHitChance", nil), + }, + ["chance_to_inflict_frostburn_%"] = { + mod("EnemyBrittleChance", "BASE", nil), + }, + ["chance_to_unnerve_on_hit_%"] = { + flag("Condition:Unnerved", enemyDebuff), + skill("unnerveOnHitChance", nil), + }, + ["cast_on_trigger_cascade_event_%"] = { + skill("cascadeTriggerChance", nil), + }, + ["chaos_damage_can_chill"] = { + flag("ChaosCanChill"), + }, + ["consume_all_impales_remaining_hits_on_hit_%_chance"] = { + skill("consumeImpalesChance", nil), + }, + ["cover_in_ash_on_hit_%"] = { + mod("CoveredInAshEffect", "BASE", 20, 0, 0, enemyDebuff), + skill("coverInAshOnHitChance", nil), + }, + ["cover_in_frost_on_hit"] = { + mod("CoveredInFrostEffect", "BASE", 20, 0, 0, enemyDebuff), + }, + ["corrupted_blood_on_hit_%_average_damage_to_deal_per_minute_per_stack"] = { + skill("corruptedBloodDamagePercent", nil), + }, + ["corrupted_blood_on_hit_duration"] = { + skill("durationSecondary", nil), + div = 1000, + }, + ["corrupted_blood_on_hit_num_stacks"] = { + skill("corruptedBloodStacksPerHit", nil), + }, + ["critical_strike_chance_increased_by_overcapped_lightning_resistance"] = { + flag("CritChanceIncreasedByOvercappedLightningRes"), + }, + ["critical_strikes_always_knockback_shocked_enemies"] = { + skill("criticalStrikesKnockbackShockedEnemies", true), + }, + ["decelerating_projectile_speed_variation_+%"] = { + skill("deceleratingProjectileSpeedVariation", nil), + }, + ["curse_on_hit_%_elemental_weakness"] = { + skill("elementalWeaknessOnHitChance", nil), + }, + ["curse_on_hit_%_vulnerability"] = { + skill("vulnerabilityOnHitChance", nil), + }, + ["disable_skill_if_weapon_not_bow"] = { + skill("requiresBow", true), + }, + ["divine_tempest_beam_width_+%"] = { + skill("beamWidthMultiplier", nil), + }, + ["doubles_have_movement_speed_+%"] = { + skill("doubleMovementSpeedMultiplier", nil), + }, + ["elemental_hit_cannot_roll_fire_damage"] = { + flag("DealNoFire"), + }, + ["elemental_hit_cannot_roll_lightning_damage"] = { + flag("DealNoLightning"), + }, + ["enemies_you_shock_cast_speed_+%"] = { + mod("Speed", "INC", nil, ModFlag.Cast, 0, enemyDebuff, { type = "Condition", var = "Shocked" }), + }, + ["enemies_you_shock_movement_speed_+%"] = { + mod("MovementSpeed", "INC", nil, 0, 0, enemyDebuff, { type = "Condition", var = "Shocked" }), + }, + ["enemies_taunted_by_your_warcies_are_intimidated"] = { + flag("Condition:Intimidated", enemyDebuff), + }, + ["enduring_cry_grants_x_additional_endurance_charges"] = { + flag("UseEnduranceCharges", allyWarcry), + mod("EnduranceCharges", "OVERRIDE", nil, 0, 0, allyWarcry), + }, + ["enemy_life_regeneration_rate_+%_for_4_seconds_on_hit"] = { + mod("LifeRegen", "INC", nil, 0, 0, enemyDebuff), + }, + ["extra_damage_rolls_with_lightning_damage_on_non_critical_hits"] = { + flag("LightningNoCritLucky"), + }, + ["enemy_knockback_direction_is_reversed"] = { + skill("reverseKnockback", true), + }, + ["fire_mortar_second_hit_damage_+%_final"] = { + mod("Damage", "MORE", nil, ModFlag.Hit, 0, { type = "SkillPart", skillPart = 2 }), + }, + ["fire_beam_length_+%"] = { + skill("beamLengthMultiplier", nil), + }, + ["firestorm_avoid_unwalkable_terrain"] = { + skill("avoidUnwalkableTerrain", true), + }, + ["fortify_applies_to_nearby_allies_for_X_seconds"] = { + flag("Condition:Fortified", allyBuff), + skill("fortifyShareDuration", nil), + }, + ["fortify_on_hit"] = { + flag("Condition:Fortified", selfBuff), + }, + ["gain_arcane_surge_when_trap_triggered_by_an_enemy"] = { + flag("Condition:ArcaneSurge", selfBuff), + }, + ["gain_rage_when_you_use_a_warcry"] = { + flag("Condition:CanGainRage"), + skill("rageOnWarcry", nil), + }, + ["gain_x_rage_on_melee_hit"] = { + flag("Condition:CanGainRage"), + skill("rageOnMeleeHit", nil), + }, + ["global_maim_on_hit"] = { + flag("Condition:Maimed", enemyDebuff), + }, + ["ground_slam_angle_+%"] = { + skill("groundSlamAngleMultiplier", nil), + }, + ["ground_blood_art_variation"] = { + skill("groundEffectArtVariation", nil), + }, + ["ground_fire_art_variation"] = { + skill("groundEffectArtVariation", nil), + }, + ["ground_temporal_anomaly_art_variation"] = { + skill("groundEffectArtVariation", nil), + }, + ["hallowing_flame_duration_ms"] = { + skill("hallowingFlameDuration", nil), + div = 1000, + }, + ["has_onslaught_if_totem_summoned_recently"] = { + flag("Onslaught", selfBuff), + }, + ["hits_ignore_enemy_monster_physical_damage_reduction_%_chance"] = { + mod("ChanceToIgnoreEnemyPhysicalDamageReduction", "BASE", nil, ModFlag.Hit), + }, + ["infernal_cry_%_max_life_as_fire_on_death"] = { + skill("corpseExplosionLifeMultiplier", nil), + div = 100, + }, + ["immune_to_auras_from_other_entities"] = { + flag("AlliesAurasCannotAffectSelf"), + }, + ["immune_to_curses"] = { + flag("CurseImmune"), + }, + ["lightning_arrow_maximum_number_of_extra_targets"] = { + skill("maximumExtraTargets", nil), + }, + ["lightning_tower_trap_additional_number_of_beams"] = { + mod("MaximumWaves", "BASE", nil), + }, + ["malediction_on_hit"] = { + flag("HasMalediction", enemyDebuff), + }, + ["mana_degeneration_per_minute_%"] = { + skill("manaDegenerationPercentPerSecond", nil), + div = 60, + }, + ["mana_regeneration_rate_per_minute_%"] = { + mod("ManaRegenPercent", "BASE", nil), + div = 60, + }, + ["melee_splash"] = { + skill("meleeSplash", true), + }, + ["melee_splash_area_of_effect_+%_final"] = { + mod("AreaOfEffect", "MORE", nil), + }, + ["minion_caustic_cloud_on_death_maximum_life_per_minute_to_deal_as_chaos_damage_%"] = { + mod("ExtraMinionSkill", "LIST", { skillId = "SiegebreakerCausticGround" }), + mod("MinionModifier", "LIST", { mod = mod("Multiplier:SiegebreakerCausticGroundPercent", "BASE", nil) }), + div = 60, + }, + ["mirage_archer_projectile_additional_height_offset"] = { + skill("mirageArcherProjectileHeightOffset", nil), + }, + ["no_barrage_projectile_spread"] = { + skill("noBarrageProjectileSpread", true), + }, + ["nova_spells_cast_at_target_location"] = { + skill("novaCastAtTarget", true), + }, + ["number_of_beacons"] = { + skill("beaconCount", nil), + }, + ["number_of_endurance_charges_to_gain"] = { + flag("UseEnduranceCharges", allyBuff), + mod("EnduranceCharges", "OVERRIDE", nil, 0, 0, allyBuff), + }, + ["number_of_frenzy_charges_to_gain"] = { + flag("UseFrenzyCharges", allyBuff), + mod("FrenzyCharges", "OVERRIDE", nil, 0, 0, allyBuff), + }, + ["number_of_projectiles_override"] = { + mod("ProjectileCount", "OVERRIDE", nil), + }, + ["physical_damage_%_to_add_as_random_element"] = { + mod("PhysicalDamageGainAsRandom", "BASE", nil), + }, + ["projectiles_nova"] = { + skill("projectilesNova", true), + }, + ["projectiles_barrage"] = { + flag("SequentialProjectiles"), + }, + ["projectiles_fire_at_ground"] = { + skill("projectilesFireAtGround", true), + }, + ["projectiles_fork_after_traveling_X_units_distance"] = { + skill("projectileForkDistance", nil), + }, + ["projectiles_rain"] = { + skill("projectilesRain", true), + }, + ["projectiles_return"] = { + skill("projectilesReturn", true), + }, + ["random_projectile_direction"] = { + skill("randomProjectileDirection", true), + }, + ["reap_debuff_deals_fire_damage_instead_of_physical_damage"] = { + flag("ReapDebuffIsFireDamage"), + }, + ["scourge_arrow_X_pods_per_projectile"] = { + skill("scourgeArrowPodsPerProjectile", nil), + }, + ["siphon_life_leech_from_damage_permyriad"] = { + mod("DamageLifeLeech", "BASE", nil), + div = 100, + }, + ["skill_can_only_use_bow"] = { + skill("requiresBow", true), + }, + ["skill_surge_type_override"] = { + skill("surgeTypeOverride", nil), + }, + ["skill_is_rain_skill"] = { + skill("isRainSkill", true), + }, + ["smite_chance_for_lighting_to_strike_extra_target_%"] = { + skill("smiteExtraTargetChance", nil), + }, + ["slam_ancestor_totem_grant_owner_melee_damage_+%_final"] = { + mod("Damage", "MORE", nil, ModFlag.Melee, 0, selfBuff), + }, + ["spell_damage_modifiers_apply_to_attack_damage"] = { + flag("SpellDamageAppliesToAttacks"), + }, + ["storm_rain_pulse_count"] = { + skill("stormRainPulseCount", nil), + }, + ["storm_cloud_destroy_when_caster_dies"] = { + skill("destroyWhenCasterDies", true), + }, + ["summon_2_totems"] = { + mod("ActiveTotemLimit", "BASE", 1), + skill("totemsSummonedPerCast", 2), + }, + ["summoned_raging_spirits_have_diamond_and_massive_shrine_buff"] = { + mod("MinionModifier", "LIST", { mod = flag("Condition:DiamondShrine") }), + mod("MinionModifier", "LIST", { mod = flag("Condition:MassiveShrine") }), + }, + ["summon_specific_monsters_in_front_offset"] = { + skill("summonFrontOffset", nil), + }, + ["summon_specific_monsters_radius_+%"] = { + skill("summonRadiusMultiplier", nil), + }, + ["support_ancestral_slam_big_hit_max_count"] = { + skill("fistOfWarMaxCount", nil), + }, + ["support_melee_splash_damage_+%_final_for_splash"] = { + mod("Damage", "MORE", nil, ModFlag.Hit, 0, { type = "SkillPart", skillPart = 2 }), + }, + ["support_spell_cascade_number_of_cascades_per_side"] = { + skill("spellCascadeCountPerSide", nil), + }, + -- PoB's wither model is stack-based and already assumes a 2s duration. + -- 3.29.3 exports that duration explicitly; do not treat it as skill duration. + ["support_withered_base_duration_ms"] = { + }, + ["totem_additional_physical_damage_reduction_%"] = { + skill("totemPhysicalDamageReduction", nil), + }, + ["totem_elemental_resistance_%"] = { + mod("TotemElementalResist", "BASE", nil), + }, + ["totem_ignores_vaal_skill_cost"] = { + skill("totemIgnoresVaalSkillCost", true), + }, + ["unique_ryuslathas_clutches_maximum_physical_attack_damage_+%_final"] = { + mod("MaxPhysicalDamage", "MORE", nil, ModFlag.Attack), + }, + ["upheaval_number_of_spikes"] = { + skill("upheavalSpikeCount", nil), + }, + ["vaal_lightning_arrow_number_of_redirects"] = { + skill("vaalLightningArrowRedirectCount", nil), + }, + ["vaal_volcanic_fissure_crack_repeat_count"] = { + skill("vaalVolcanicFissureRepeatCount", nil), + }, + ["voll_slam_damage_+%_final_at_centre"] = { + mod("Damage", "MORE", nil, 0, 0, { type = "SkillPart", skillPart = 2 }), + }, + ["you_and_nearby_allys_gain_onslaught_for_4_seconds_on_warcry"] = { + flag("Onslaught", allyBuff), + }, + ["your_consecrated_ground_grants_damage_+%"] = { + mod("Damage", "INC", nil, 0, 0, allyBuff), + }, + }, + -- These reviewed stats are display/AI/engine metadata or mechanics that the + -- existing PoB skill model intentionally represents without a stat-map mod. + -- Keep this list Mercenary-specific so newly exported stats fail closed. + knownUncalculatedStats = { + ["absolution_blast_chance_to_summon_on_hitting_rare_or_unique_%"] = true, + ["action_attack_or_cast_time_uses_animation_length"] = true, + ["action_ignores_crit_tracking"] = true, + ["active_skill_additional_projectiles_fire_parallel_x_dist"] = true, + ["active_skill_area_of_effect_description_mode"] = true, + ["active_skill_display_aegis_variation"] = true, + ["active_skill_ground_consecration_radius_+"] = true, + ["active_skill_minion_from_alternate_gem_index"] = true, + ["active_skill_projectile_speed_+%_variation_final"] = true, + ["active_skill_secondary_area_of_effect_description_mode"] = true, + ["active_skill_tertiary_area_of_effect_description_mode"] = true, + ["additional_main_hand_hits_per_combo_average"] = true, + ["aegis_recharge_delay_ms"] = true, + ["alternate_minion"] = true, + ["always_stun_enemies_that_are_on_full_life"] = true, + ["ancestor_totem_parent_activiation_range"] = true, + ["animation_effect_variation"] = true, + ["arc_additional_delay_ms"] = true, + ["arc_chain_distance"] = true, + ["arc_enhanced_behaviour"] = true, + ["arctic_armour_chill_when_hit_duration"] = true, + ["arctic_breath_maximum_number_of_skulls_allowed"] = true, + ["attack_is_melee_override"] = true, + ["attack_is_not_melee_override"] = true, + ["base_circle_of_power_mana_spend_per_upgrade"] = true, + ["base_deal_no_attack_damage"] = true, + ["base_deal_no_damage"] = true, + ["base_deal_no_secondary_damage"] = true, + ["base_deal_no_spell_damage"] = true, + ["base_display_minion_actor_level"] = true, + ["base_from_skill_shock_art_variation"] = true, + ["base_is_projectile"] = true, + ["base_max_number_of_dominated_magic_monsters"] = true, + ["base_max_number_of_dominated_normal_monsters"] = true, + ["base_max_number_of_dominated_rare_monsters"] = true, + ["base_max_number_of_vaal_absolution_sentinels"] = true, + ["base_max_number_of_vaal_dominated_monsters"] = true, + ["base_mine_duration"] = true, + ["base_skill_is_mined"] = true, + ["base_skill_is_totemified"] = true, + ["base_skill_is_trapped"] = true, + ["base_skill_number_of_additional_hits"] = true, + ["base_smite_number_of_targets"] = true, + ["base_sunder_wave_delay_ms"] = true, + ["base_totem_range"] = true, + ["base_trap_duration"] = true, + ["base_weapon_trap_total_rotation_%"] = true, + ["bear_trap_movement_speed_+%_final"] = true, + ["blackhole_hinder_%"] = true, + ["bladefall_blade_left_in_ground_for_every_X_volleys"] = true, + ["bladefall_create_X_lingering_blades_per_volley"] = true, + ["blast_rain_arrow_delay_ms"] = true, + ["blind_art_variation"] = true, + ["blood_ground_leaving_area_lasts_for_ms"] = true, + ["blood_spears_aoe_modifiers_apply_to_blood_spear_placement_range_at_%_value"] = true, + ["blood_tendrils_beam_count"] = true, + ["call_of_steel_reload_amount"] = true, + ["call_of_steel_reload_time"] = true, + ["cannot_cancel_skill_before_contact_point"] = true, + ["cannot_stun"] = true, + ["cannot_use_spectre_corpses"] = true, + ["cast_on_gain_skill"] = true, + ["chain_hook_attaches_to_X_targets"] = true, + ["chain_hook_max_attached_targets"] = true, + ["chance_to_grant_frenzy_charge_on_death_%"] = true, + ["chance_to_grant_power_charge_on_death_%"] = true, + ["charged_dash_skill_inherent_movement_speed_+%_final"] = true, + ["cluster_burst_spawn_amount"] = true, + ["consecrated_ground_immune_to_curses"] = true, + ["console_skill_dont_chase"] = true, + ["corpse_explosion_monster_life_%_lightning"] = true, + ["create_consecrated_ground_on_hit_%_vs_rare_or_unique_enemy"] = true, + ["damage_cannot_be_reflected"] = true, + ["damage_cannot_be_reflected_or_leech_if_used_by_other_object"] = true, + ["damage_originates_from_initiator_location"] = true, + ["damage_taken_from_suppressed_hits_is_unlucky"] = true, + ["debilitate_self_for_x_milliseconds_on_hit"] = true, + ["desecrate_corpse_level"] = true, + ["desecrate_maximum_number_of_corpses"] = true, + ["desecrate_number_of_corpses_to_create"] = true, + ["disable_mine_detonation_cascade"] = true, + ["disable_visual_hit_effect"] = true, + ["display_minion_monster_type"] = true, + ["display_projectiles_chain_when_impacting_ground"] = true, + ["display_skill_deals_secondary_damage"] = true, + ["divine_retribution_blasts_per_wave"] = true, + ["divine_retribution_num_waves"] = true, + ["divine_tempest_base_number_of_nearby_enemies_to_zap"] = true, + ["divine_tempest_beam_width_+"] = true, + ["dominating_blow_chance_to_summon_on_hitting_unqiue_%"] = true, + ["eye_of_winter_base_explosion_shards"] = true, + ["firestorm_drop_ground_ice_duration_ms"] = true, + ["firestorm_max_number_of_storms"] = true, + ["firewall_attached_projectile_effect_mtx"] = true, + ["fixed_projectile_spread"] = true, + ["flame_dash_repeats_target_previous_location"] = true, + ["flame_surge_burning_ground_creation_cooldown_ms"] = true, + ["frost_globe_stage_gain_interval_ms"] = true, + ["ground_ice_art_variation"] = true, + ["ground_smoke_art_variation"] = true, + ["herald_of_light_summon_champion_on_kill"] = true, + ["herald_of_light_summon_champion_on_unique_or_rare_enemy_hit_%"] = true, + ["holy_hammers_maximum_number_of_hammerslam_cascades"] = true, + ["holy_hammers_num_additional_hammerslams_if_consuming_power_charge"] = true, + ["holy_strike_animates_owners_main_hand_weapon"] = true, + ["holy_sweep_number_of_holy_bolts_to_create"] = true, + ["ignite_art_variation"] = true, + ["ignores_proximity_shield"] = true, + ["ignores_trap_and_mine_cooldown_limit"] = true, + ["is_area_damage"] = true, + ["is_dominated"] = true, + ["is_ranged_attack_totem"] = true, + ["is_remote_mine"] = true, + ["is_trap"] = true, + ["kinetic_bolt_forks_apply_to_zig_zags"] = true, + ["kinetic_wand_base_number_of_zig_zags"] = true, + ["leap_slam_always_knockback_within_range"] = true, + ["lightning_trap_projectiles_leave_shocking_ground"] = true, + ["mamba_strike_deal_%_of_all_poison_total_damage_per_minute"] = true, + ["max_number_of_lightning_warp_markers"] = true, + ["maximum_number_of_blades_left_in_ground"] = true, + ["maximum_number_of_snapping_adder_projectiles"] = true, + ["maximum_number_of_summoned_doubles"] = true, + ["melee_defer_damage_prediction"] = true, + ["mine_cannot_rearm"] = true, + ["mine_detonates_instantly"] = true, + ["minimum_rain_of_spores_movement_speed_+%_final_cap"] = true, + ["minion_actor_scale_+%"] = true, + ["minion_dies_when_parent_dies"] = true, + ["minion_life_regeneration_rate_per_minute_%_if_blocked_recently"] = true, + ["minions_cannot_taunt_enemies"] = true, + ["modifiers_to_totem_duration_also_affect_soul_prevention_duration"] = true, + ["modifiers_to_trap_throw_speed_apply_to_lightning_spire_trap_frequency"] = true, + ["molten_strike_projectiles_chain_when_impacting_ground"] = true, + ["monster_projectile_variation"] = true, + ["movement_velocity_cap"] = true, + ["napalm_arrow_maximum_number_of_unprimed_arrows_allowed"] = true, + ["no_movement_speed"] = true, + ["number_of_allowed_firewalls"] = true, + ["number_of_monsters_to_summon"] = true, + ["orb_of_storms_maximum_number_of_hits"] = true, + ["override_turn_duration_ms"] = true, + ["pact_of_ghorr_can_modify_damage_over_time_of_skill"] = true, + ["phase_through_objects"] = true, + ["projectile_angle_variance"] = true, + ["projectile_firing_forward_distance_override"] = true, + ["projectile_random_angle_based_on_distance_to_target_location_%"] = true, + ["projectile_speed_variation_+%"] = true, + ["projectile_spread_radius"] = true, + ["projectile_uses_contact_position"] = true, + ["projectiles_are_not_fired"] = true, + ["projectiles_can_shotgun"] = true, + ["projectiles_can_split_at_end_of_range"] = true, + ["projectiles_can_split_from_terrain"] = true, + ["rain_of_spores_vines_movement_speed_+%_final"] = true, + ["shield_charge_attack_time_+30%_if_no_charge"] = true, + ["shield_charge_scaling_stun_threshold_reduction_+%_at_maximum_range"] = true, + ["shock_art_variation"] = true, + ["show_number_of_projectiles"] = true, + ["single_primary_projectile"] = true, + ["skeletal_chains_no_minions_targets_self"] = true, + ["skill_angle_+%_in_sand_stance"] = true, + ["skill_can_add_multiple_charges_per_action"] = true, + ["skill_can_fire_wand_projectiles"] = true, + ["skill_cannot_be_interrupted"] = true, + ["skill_cannot_be_knocked_back"] = true, + ["skill_cannot_be_stunned"] = true, + ["skill_cannot_be_stunned_before_contact_point"] = true, + ["skill_is_ice_storm"] = true, + ["skill_is_steel_skill_reload"] = true, + ["skill_maximum_travel_distance_+%"] = true, + ["skill_override_pvp_scaling_time_ms"] = true, + ["skill_projectiles_cannot_return"] = true, + ["skill_travel_distance_+%"] = true, + ["smite_lightning_target_range"] = true, + ["snapping_adder_%_chance_to_retain_projectile_on_release"] = true, + ["snapping_adder_maximum_projectiles_released"] = true, + ["soulfeast_number_of_secondary_projectiles"] = true, + ["spectral_helix_rotations_%"] = true, + ["spectral_throw_forget_hit_list_time_override"] = true, + ["spell_maximum_action_distance_+%"] = true, + ["spider_aspect_web_interval_ms"] = true, + ["static_strike_number_of_beam_targets"] = true, + ["stationary_shield_throw_interval_acceleration_%_per_interval"] = true, + ["stationary_shield_throw_projectiles_per_interval"] = true, + ["summoned_monsters_are_minions"] = true, + ["summoned_monsters_no_drops_or_experience"] = true, + ["sunder_shockwave_limit_per_cascade"] = true, + ["sunder_wave_min_steps"] = true, + ["tectonic_slam_side_crack_additional_chance_%"] = true, + ["tectonic_slam_side_crack_additional_chance_%_per_endurance_charge"] = true, + ["tethered_movement_speed_+%_final_per_rope"] = true, + ["tethered_movement_speed_+%_final_per_rope_vs_rare"] = true, + ["tethered_movement_speed_+%_final_per_rope_vs_unique"] = true, + ["tethering_arrow_display_rope_limit"] = true, + ["throw_traps_in_circle_radius"] = true, + ["tornado_hinder"] = true, + ["tornado_movement_speed_+%"] = true, + ["total_projectile_spread_angle_override"] = true, + ["totem_formation_radius_override"] = true, + ["totem_placement_range_+%"] = true, + ["totems_cannot_evade"] = true, + ["trap_override_pvp_scaling_time_ms"] = true, + ["trap_variation"] = true, + ["traps_do_not_explode_on_timeout"] = true, + ["trauma_strike_shockwave_area_of_effect_+%_per_100ms_stun_duration_up_to_400%"] = true, + ["use_intimidating_cry_buff_visual_for_intimidate"] = true, + ["vaal_burning_arrow_explode_on_hit"] = true, + ["vaal_caustic_arrow_ground_art_variation"] = true, + ["vaal_cleave_steal_mods_on_kill"] = true, + ["vaal_ice_shot_modifiers_to_projectile_count_do_not_apply_to_mirages"] = true, + ["vaal_lightning_arrow_fork_and_chain_modifiers_apply_to_number_of_redirects"] = true, + ["virulent_arrow_number_of_pod_projectiles"] = true, + ["visual_hit_effect_chaos_is_green"] = true, + ["visual_hit_effect_elemental_is_holy"] = true, + ["wall_expand_delay_ms"] = true, + ["warcry_gain_mp_from_allies"] = true, + ["weapon_trap_rotation_speed_+%_if_dual_wielding"] = true, + ["weapon_trap_total_rotation_%_if_dual_wielding"] = true, + }, + knownMonsterStats = { + base_mana_regeneration_rate_per_minute = true, + base_number_of_remote_mines_allowed = true, + base_number_of_traps_allowed = true, + cannot_be_afflicted = true, + cannot_be_tagged_by_sentinel = true, + cannot_have_affliction_mods = true, + cannot_have_azmeri_dust = true, + cant_possess_this = true, + cant_touch_this = true, + keystone_minion_instability = true, + kill_traps_mines_and_totems_on_death = true, + ["life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window"] = true, + ["map_related_item_drop_chance_+%_final_from_league"] = true, + max_steel_ammo = true, + maximum_rage = true, + mines_invulnerable_for_duration_ms = true, + monster_no_additional_player_scaling = true, + monster_no_drops_or_experience = true, + ["monster_rarity_attack_cast_speed_+%_and_damage_-%_final"] = true, + ["monster_rarity_damage_+%_final"] = true, + number_of_additional_totems_allowed = true, + rage_loss_delay_ms = true, + ["set_base_attack_speed_+%_per_frenzy_charge"] = true, + ["set_base_attack_speed_+%_per_frenzy_charge_if_not_player_minion"] = true, + ["set_base_cast_speed_+%_per_frenzy_charge"] = true, + ["set_base_cast_speed_+%_per_frenzy_charge_if_not_player_minion"] = true, + ["set_base_mana_cost_-%"] = true, + ["set_critical_strike_chance_+%_per_power_charge"] = true, + ["set_critical_strike_chance_+%_per_power_charge_if_not_player_minion"] = true, + ["set_damage_taken_from_labyrinth_traps_+%"] = true, + ["set_elemental_damage_reduction_%_per_endurance_charge"] = true, + set_ignore_skill_weapon_restrictions = true, + set_item_drop_slots = true, + ["set_labyrinth_trap_degen_effect_on_self_+%"] = true, + ["set_minion_damage_taken_+%"] = true, + ["set_movement_velocity_+%_per_frenzy_charge_if_not_player_minion"] = true, + set_movement_velocity_cap = true, + ["set_physical_damage_%_to_add_as_cold_per_brine_charge"] = true, + ["set_physical_damage_%_to_add_as_lightning_per_brine_charge"] = true, + ["set_physical_damage_reduction_%_per_endurance_charge"] = true, + ["set_physical_damage_reduction_%_per_endurance_charge_if_not_player_minion"] = true, + ["set_resist_all_elements_%_per_endurance_charge"] = true, + ["set_resist_all_elements_%_per_endurance_charge_if_not_player_minion"] = true, + ["set_totem_life_+%_final"] = true, + traps_explode_on_timeout = true, + traps_invulnerable_for_duration_ms = true, + }, + -- Summoned Mercenary minion stats that PoB does not calculate. Combat-relevant + -- minion stats belong in statMap instead; this list is engine/loot/AI metadata. + -- Overlap with knownMonsterStats is allowed by the generated-data test, so only + -- minion-unique exemptions live here. + knownUncalculatedMinionStats = { + cannot_be_stunned_for_ms_after_stun_finished = true, + cannot_be_stunned_while_stunned = true, + is_daemon = true, + is_hidden_monster = true, + ["monster_dropped_item_quantity_+%"] = true, + ["monster_dropped_item_rarity_+%"] = true, + ["monster_slain_experience_+%"] = true, + set_monster_do_not_fracture = true, + set_monster_no_drops_or_experience = true, + set_phase_through_objects = true, + set_use_melee_pattern_range = true, + }, + -- MercenarySkills references one of four support counts by name, and + -- MercenarySupportCounts holds nothing but those names; the numbers are not in + -- GGG's data at all. These maximums are hand-authored from in-game observation. + -- (Distribution across the 272 skill rows: High 151, Low 49, None 46, Medium 26.) + supportCounts = { + None = { maximum = 0 }, + Low = { maximum = 2 }, + Medium = { maximum = 3 }, + High = { maximum = 5 }, + }, + -- Builds whose weapon configuration includes a Shield. DAT does not distinguish + -- "can hold a shield" from "needs a shield", so every shield-capable build is + -- classified here and export fails if a new one is missing. + shieldPolicy = { + AurasMinionsTemplarSmite = "required", + AurasMinionsTemplarSmiteNoble = "required", + AurasMinionsTemplarSmiteRuckusNoble = "required", + AurasMinionsTemplarSpectres = "optional", + AurasMinionsTemplarSpectresNoble = "optional", + ChaosMinionWitchInstability = "required", + ChaosMinionWitchInstabilityNoble = "required", + Crit1HShadowPhysSpell = "optional", + Crit1HShadowPhysSpellNoble = "optional", + ElementalWitchCold = "optional", + ElementalWitchColdNoble = "optional", + ElementalWitchFire = "optional", + ElementalWitchLightning = "optional", + ElementalWitchLightningNoble = "optional", + MeleeStrikesMarauderFire = "optional", + MiscScionWandAttacks = "required", + MiscScionWandAttacksNoble = "required", + PhysicalDuelistShields = "required", + PhysicalDuelistShieldsNoble = "required", + TrapsMinesShadowCold = "required", + }, + -- Non-DAT behavior the Mercenary actor needs. The permanent damage penalty's + -- maximum is exported from Noble Blood's PassiveSkills row; the 3.29.1 + -- level taper lives in `MercenaryTools.permanentDamageMore`. + permanentMercenary = { + -- Damage over Time the Mercenary itself takes. + damageOverTimeTakenMore = -80, + -- A Taunted enemy deals less Damage to anyone other than whoever Taunted it, + -- so the character and their Minions take less Damage while the Mercenary is + -- holding the Taunt. + tauntedDamageTakenMore = -10, + }, + -- A Mercenary skill reuses the `preDamageFunc` of the player skill it was + -- derived from, and with it that function's inputs. GGG's data does not always + -- give the Mercenary variant the stats that populate them, which would leave + -- the function reading nil. Every base whose function is inherited therefore + -- lists the skill-data keys it reads without its own fallback, and validation + -- rejects both a Mercenary skill that cannot populate one and a newly + -- inherited function that has no entry here at all. + preDamageFuncInputs = { + BallLightningAltX = { "duration", "strikeInterval" }, + BallLightningAltY = { "duration", "strikeInterval" }, + BladeVortex = { "hitFrequency", "hitFrequencyPerBlade" }, + BladefallAltZ = { "hitFrequency", "incVolleyFrequency" }, + BlastRain = { }, + Bodyswap = { "selfFireExplosionLifeMultiplier" }, + ChargedDash = { }, + DarkPact = { "ChaosMax", "ChaosMin", "lifeDealtAsChaos" }, + DivineIre = { }, + Earthquake = { "duration" }, + EyeOfWinter = { }, + Flameblast = { }, + ForbiddenRite = { "ChaosMax", "ChaosMin", "SelfDamageTakenES", "SelfDamageTakenLife", "energyShieldDealtAsChaos", "lifeDealtAsChaos" }, + HeraldOfAsh = { "hoaMoreBurn", "hoaOverkillPercent" }, + InfernalBlowAltX = { }, + LancingSteel = { }, + LightningSpireTrap = { "duration", "radius", "repeatInterval" }, + MoltenShell = { "moltenShellReflect" }, + -- Reads the ball, chain-minimum and chain-maximum radii through the area of + -- effect output rather than any stat of its own. + MoltenStrike = { "radius", "radiusSecondary", "radiusTertiary" }, + OrbOfStorms = { "hitFrequency" }, + Perforate = { }, + ShrapnelBallista = { }, + Spark = { "duration" }, + StaticStrike = { "repeatFrequency" }, + StormRain = { "hitFrequency" }, + TornadoAltY = { "damageInterval" }, + TornadoShot = { }, + ToxicRain = { }, + VaalLightningArrow = { }, + VoidSphere = { "repeatFrequency" }, + VoltaxicBurst = { "duration" }, + Vortex = { }, + WaveOfConviction = { }, + WaveOfConvictionAltY = { }, + }, + -- Mercenary skills that GGG's data gives none of the stats their base skill's + -- `preDamageFunc` reads, because the Mercenary version does not have that + -- damage component at all. Dropping the inherited function keeps the missing + -- component out of the numbers instead of reporting it as zero. + droppedPreDamageFuncs = { + -- Explodes the targeted corpse (`corpse_explosion_monster_life_permillage_fire`, + -- handled by `explodeCorpse`) and has no self-explosion Life multiplier. + BodyswapMercenary = "no self-explosion Life multiplier stat", + -- Has none of Molten Shell's + -- `molten_shell_%_of_absorbed_damage_dealt_as_reflected_fire`, so the + -- Mercenary version deals no reflected Fire damage. + MoltenShellMercenary = "no reflected Fire damage stat", + }, + supportTemplates = { + ArrowNovaHigh = "SupportArrowNova", + TrapChargeGenHigh = "SupportChargedTraps", + MirageArcherHigh = "SupportMirageArcher", + ProjectilesReturnHigh = "SupportReturningProjectiles", + FortifyHigh = "SupportFortify", + MaimOnHitHigh = "SupportMaim", + MeleeSplashHigh = "SupportMeleeSplash", + MultiTotemHigh = "SupportMultipleTotems", + FistOfWarHigh = "SupportFistofWar", + SpellCascadeHigh = "SupportSpellCascade", + SpellCascadeLow = "SupportSpellCascade", + HallowHigh = "SupportHallow", + }, + auxiliarySkills = { + ["curse_on_hit_%_elemental_weakness"] = "ElementalWeaknessMercenary", + ["curse_on_hit_%_vulnerability"] = "Vulnerability", + ["summon_sacred_wisps_on_hit"] = "SummonSacredWisp", + }, + defaultSkillParts = { + ElementalHitColdOnlyMercenary = 3, + ElementalHitColdOnlyMercenaryEncounter = 3, + }, + skillOverrides = { + BarrageMercenary = { + preDamageFunc = function(activeSkill, output) + if activeSkill.skillPart == 2 then + activeSkill.skillData.dpsMultiplier = output.ProjectileCount + 2 * (activeSkill.skillData.barrageFinalVolleyAdditionalProjectiles or 0) + end + end, + }, + BarrageAltMercenary = { + preDamageFunc = function(activeSkill, output) + if activeSkill.skillPart == 2 then + activeSkill.skillData.dpsMultiplier = output.ProjectileCount + 2 * (activeSkill.skillData.barrageFinalVolleyAdditionalProjectiles or 0) + end + end, + }, + ActionSpeedAuraMercenary = { + statMap = { + ["action_speed_-%"] = { + mod("ActionSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Trarthan Agility", applyAllies = true }), + mult = -1, + }, + }, + }, + AbyssalCryMercenary = { + baseMods = { + skill("explodeCorpse", true), + skill("corpseExplosionDamageType", "Chaos"), + }, + statMap = { + ["base_movement_velocity_+%"] = { + mod("MovementSpeed", "INC", nil, 0, 0, enemyDebuff), + }, + }, + }, + DonutCircleMercenary = { + parts = { + { name = "Outer Area" }, + { name = "Centre" }, + }, + }, + EnduringCryMercenary = { + statMap = { + ["life_regeneration_rate_per_minute_%"] = { + mod("LifeRegenPercent", "BASE", nil, 0, 0, allyWarcry), + div = 60, + }, + }, + }, + EnrageMercenary = { + statMap = { + ["attack_and_cast_speed_+%"] = { + mod("Speed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Enrage" }), + }, + ["base_movement_velocity_+%"] = { + mod("MovementSpeed", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Enrage" }), + }, + ["damage_+%"] = { + mod("Damage", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Enrage" }), + }, + }, + }, + HolyFireMortarMercenary = { + parts = { + { name = "First Hit" }, + { name = "Second Hit" }, + }, + }, + InfernalCryMercenary = { + baseMods = { + skill("explodeCorpse", true), + skill("corpseExplosionDamageType", "Fire"), + skill("showAverage", true), + }, + }, + -- Scorching Ray's stages are implemented per skill name, and the Spectre skill + -- this inherits from leaves them out, so the Mercenary version restates the + -- player mapping under its own name. Unlike the player skill there is no + -- "Maximum Stages" part to select, so the stage cap is not tied to a part: a + -- Totem channels its target continuously and ramps to the cap on its own. + ScorchingRayTotemMercenary = { statMap = scorchingRayTotemStages }, + ScorchingRayTotemMercenaryEncounter = { statMap = scorchingRayTotemStages }, + TemporalAnomalyMercenary = { + statMap = { + ["action_speed_-%"] = { + mod("ActionSpeed", "INC", nil, 0, 0, enemyDebuff), + mult = -1, + }, + }, + }, + -- Vaal Flameblast's 15 maximum stages are a base mod on the player skill instead + -- of a stat, so nothing implements the stat that the Mercenary's Maximum Stages + -- support grants. Stage counts add, the way Flameblast's own stat does. + VaalFlameblastMercenary = { + statMap = { + ["flameblast_maximum_stages"] = { + mod("Multiplier:VaalFlameblastMaxStages", "BASE", nil), + }, + }, + }, + VaalVitalityMercenary = { + statMap = { + ["life_regeneration_rate_per_minute_%"] = { + mod("LifeRegenPercent", "BASE", nil, 0, 0, { type = "GlobalEffect", effectType = "Aura", effectName = "Vaal Vitality", applyAllies = true }), + div = 60, + }, + }, + }, + -- The generated skill data exposes the extra hit but no runtime DPS + -- multiplier, so keep the Mercenary multiplier explicit here. + VaalDoubleStrikeMercenary = { + baseMods = { + skill("dpsMultiplier", 2), + }, + }, + VaalIceShotMercenary = { + preDamageFunc = function(activeSkill, output) + activeSkill.skillData.dpsMultiplier = 1 + (activeSkill.skillData.vaalIceShotMirageCount or 0) + end, + }, + BladeVortexAltMercenary = { + preDamageFunc = calculateCorruptedBlood, + baseMods = { + flag("dotIsCorruptingBlood"), + skill("debuffSecondary", true), + }, + }, + BladeVortexAltMercenaryEncounter = { + preDamageFunc = calculateCorruptedBlood, + baseMods = { + flag("dotIsCorruptingBlood"), + skill("debuffSecondary", true), + }, + }, + }, +} +end diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index c975e8c33ab..37de1ca0348 100755 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -15272,11 +15272,11 @@ c["Enduring Cry has 46% increased Cooldown Recovery Rate"]={{[1]={[1]={includeTr c["Enduring Cry has 49% increased Cooldown Recovery Rate"]={{[1]={[1]={includeTransfigured=true,skillName="Enduring Cry",type="SkillName"},flags=0,keywordFlags=0,name="CooldownRecovery",type="INC",value=49}},nil} c["Enemies Become Chilled as they Unfreeze, causing 30% reduced Action Speed"]={nil,"Enemies Become Chilled as they Unfreeze, causing 30% reduced Action Speed "} c["Enemies Become Chilled as they Unfreeze, causing 30% reduced Action Speed 30% chance to Freeze Enemies which are Chilled"]={nil,"Enemies Become Chilled as they Unfreeze, causing 30% reduced Action Speed 30% chance to Freeze Enemies which are Chilled "} -c["Enemies Blinded by you cannot inflict Damaging Ailments"]={nil,"you cannot inflict Damaging Ailments "} -c["Enemies Blinded by you cannot inflict Damaging Ailments Grants Level 20 Blazing Glare"]={nil,"you cannot inflict Damaging Ailments Grants Level 20 Blazing Glare "} -c["Enemies Blinded by you have 100% reduced Critical Strike Chance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="CritChance",type="INC",value=-100}}}},nil} -c["Enemies Blinded by you have 25% reduced Critical Strike Chance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="CritChance",type="INC",value=-25}}}},nil} -c["Enemies Blinded by you have Malediction"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="HasMalediction",type="FLAG",value=true}}}},nil} +c["Enemies Blinded by you cannot inflict Damaging Ailments"]={nil,"cannot inflict Damaging Ailments "} +c["Enemies Blinded by you cannot inflict Damaging Ailments Grants Level 20 Blazing Glare"]={nil,"cannot inflict Damaging Ailments Grants Level 20 Blazing Glare "} +c["Enemies Blinded by you have 100% reduced Critical Strike Chance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="CritChance",type="INC",value=-100}}}},nil} +c["Enemies Blinded by you have 25% reduced Critical Strike Chance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="CritChance",type="INC",value=-25}}}},nil} +c["Enemies Blinded by you have Malediction"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="HasMalediction",type="FLAG",value=true}}}},nil} c["Enemies Cannot Leech Life From you"]={nil,"Enemies Cannot Leech Life From you "} c["Enemies Cannot Leech Mana From you"]={nil,"Enemies Cannot Leech Mana From you "} c["Enemies Cannot Leech Mana From you 10% of Damage taken Recouped as Mana"]={nil,"Enemies Cannot Leech Mana From you 10% of Damage taken Recouped as Mana "} @@ -15285,27 +15285,27 @@ c["Enemies Chilled by your Hits can be Shattered as though Frozen Enemies Chille c["Enemies Chilled by your Hits have Cold Damage taken increased by Chill Effect"]={{[1]={flags=0,keywordFlags=0,name="ChillEffectIncColdDamageTaken",type="FLAG",value=true}},nil} c["Enemies Chilled by your Hits have Damage taken increased by Chill Effect"]={{[1]={flags=0,keywordFlags=0,name="ChillEffectIncDamageTaken",type="FLAG",value=true}},nil} c["Enemies Chilled by your Hits lessen their Damage dealt by half of Chill Effect"]={{[1]={flags=0,keywordFlags=0,name="ChillEffectLessDamageDealt",type="FLAG",value=true}},nil} -c["Enemies Cursed by you are Hindered if 25% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=25,type="MultiplierThreshold",var="CurseExpired"},[2]={type="ActorCondition",var="Cursed"},flags=0,keywordFlags=0,name="Condition:Hindered",type="FLAG",value=true}}}},nil} -c["Enemies Cursed by you have 50% reduced Life Regeneration Rate"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="LifeRegen",type="INC",value=-50}}}},nil} -c["Enemies Cursed by you have Malediction if 33% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=33,type="MultiplierThreshold",var="CurseExpired"},[2]={type="ActorCondition",var="Cursed"},flags=0,keywordFlags=0,name="HasMalediction",type="FLAG",value=true}}}},nil} -c["Enemies Cursed by you take 25% increased Damage if 75% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Cursed"},[2]={actor="enemy",threshold=75,type="MultiplierThreshold",var="CurseExpired"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=25}}}},nil} -c["Enemies Cursed by you take 35% increased Damage if 75% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Cursed"},[2]={actor="enemy",threshold=75,type="MultiplierThreshold",var="CurseExpired"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=35}}}},nil} -c["Enemies Frozen by you take 10% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Frozen"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=10}}}},nil} -c["Enemies Frozen by you take 20% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Frozen"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=20}}}},nil} -c["Enemies Hindered by you have 30% reduced Life Regeneration rate"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Hindered"},flags=0,keywordFlags=0,name="LifeRegen",type="INC",value=-30}}}},nil} -c["Enemies Hindered by you take 10% increased Chaos Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Hindered"},flags=0,keywordFlags=0,name="ChaosDamageTaken",type="INC",value=10}}}},nil} +c["Enemies Cursed by you are Hindered if 25% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=25,type="MultiplierThreshold",var="CurseExpired"},[2]={actor="enemy",sourceOwned=true,type="ActorCondition",var="Cursed"},flags=0,keywordFlags=0,name="Condition:Hindered",type="FLAG",value=true}}}},nil} +c["Enemies Cursed by you have 50% reduced Life Regeneration Rate"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="LifeRegen",type="INC",value=-50}}}},nil} +c["Enemies Cursed by you have Malediction if 33% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=33,type="MultiplierThreshold",var="CurseExpired"},[2]={actor="enemy",sourceOwned=true,type="ActorCondition",var="Cursed"},flags=0,keywordFlags=0,name="HasMalediction",type="FLAG",value=true}}}},nil} +c["Enemies Cursed by you take 25% increased Damage if 75% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Cursed"},[2]={actor="enemy",threshold=75,type="MultiplierThreshold",var="CurseExpired"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=25}}}},nil} +c["Enemies Cursed by you take 35% increased Damage if 75% of Curse Duration expired"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Cursed"},[2]={actor="enemy",threshold=75,type="MultiplierThreshold",var="CurseExpired"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=35}}}},nil} +c["Enemies Frozen by you take 10% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Frozen"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=10}}}},nil} +c["Enemies Frozen by you take 20% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Frozen"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=20}}}},nil} +c["Enemies Hindered by you have 30% reduced Life Regeneration rate"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Hindered"},flags=0,keywordFlags=0,name="LifeRegen",type="INC",value=-30}}}},nil} +c["Enemies Hindered by you take 10% increased Chaos Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Hindered"},flags=0,keywordFlags=0,name="ChaosDamageTaken",type="INC",value=10}}}},nil} c["Enemies Hitting you have 10% chance to gain an Endurance, "]={nil,"Enemies Hitting you have 10% chance to gain an Endurance, "} c["Enemies Hitting you have 10% chance to gain an Endurance, Frenzy or Power Charge"]={nil,"Enemies Hitting you have 10% chance to gain an Endurance, Frenzy or Power Charge "} -c["Enemies Ignited by you during Effect have Malediction"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="HasMalediction",type="FLAG",value=true}}}},nil} -c["Enemies Ignited by you during Effect take 10% increased Damage"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Ignited"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=10}}}},nil} -c["Enemies Ignited by you during Effect take 9% increased Damage"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Ignited"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=9}}}},nil} -c["Enemies Ignited by you have -5% to Fire Resistance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="FireResist",type="BASE",value=-5}}}},nil} -c["Enemies Ignited by you have 13% of Physical Damage they deal converted to Fire"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToFire",type="BASE",value=13}}}},nil} -c["Enemies Ignited by you have 15% of Physical Damage they deal converted to Fire"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToFire",type="BASE",value=15}}}},nil} -c["Enemies Ignited by you have 40% of Physical Damage they deal converted to Fire"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToFire",type="BASE",value=40}}}},nil} +c["Enemies Ignited by you during Effect have Malediction"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="HasMalediction",type="FLAG",value=true}}}},nil} +c["Enemies Ignited by you during Effect take 10% increased Damage"]={{[1]={[1]={actor="enemy",sourceOwned=true,type="ActorCondition",var="Ignited"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=10}}}},nil} +c["Enemies Ignited by you during Effect take 9% increased Damage"]={{[1]={[1]={actor="enemy",sourceOwned=true,type="ActorCondition",var="Ignited"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=9}}}},nil} +c["Enemies Ignited by you have -5% to Fire Resistance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="FireResist",type="BASE",value=-5}}}},nil} +c["Enemies Ignited by you have 13% of Physical Damage they deal converted to Fire"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToFire",type="BASE",value=13}}}},nil} +c["Enemies Ignited by you have 15% of Physical Damage they deal converted to Fire"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToFire",type="BASE",value=15}}}},nil} +c["Enemies Ignited by you have 40% of Physical Damage they deal converted to Fire"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Ignited"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToFire",type="BASE",value=40}}}},nil} c["Enemies Ignited by you take Chaos Damage instead of Fire Damage from Ignite"]={{[1]={flags=0,keywordFlags=0,name="IgniteToChaos",type="FLAG",value=true}},nil} -c["Enemies Ignited or Chilled by you have -5% to Elemental Resistances"]={{[1]={[1]={actor="enemy",type="ActorCondition",varList={[1]="Ignited",[2]="Chilled"}},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-5}}}},nil} -c["Enemies Intimidated by you have 13% increased duration of stuns against them"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Intimidated"},flags=0,keywordFlags=0,name="Duration",type="INC",value=13}}}}," of stuns against them "} +c["Enemies Ignited or Chilled by you have -5% to Elemental Resistances"]={{[1]={[1]={actor="enemy",sourceOwned=true,type="ActorCondition",varList={[1]="Ignited",[2]="Chilled"}},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-5}}}},nil} +c["Enemies Intimidated by you have 13% increased duration of stuns against them"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Intimidated"},flags=0,keywordFlags=0,name="Duration",type="INC",value=13}}}}," of stuns against them "} c["Enemies Killed by Zombies' Hits Explode, dealing 20% of their Life as Fire Damage"]={nil,"Zombies' Hits Explode, dealing 20% of their Life as Fire Damage "} c["Enemies Killed by Zombies' Hits Explode, dealing 20% of their Life as Fire Damage Enemies Killed by Zombies' Hits Explode, dealing 50% of their Life as Fire Damage"]={nil,"Zombies' Hits Explode, dealing 20% of their Life as Fire Damage Enemies Killed by Zombies' Hits Explode, dealing 50% of their Life as Fire Damage "} c["Enemies Killed by Zombies' Hits Explode, dealing 50% of their Life as Fire Damage"]={nil,"Zombies' Hits Explode, dealing 50% of their Life as Fire Damage "} @@ -15321,29 +15321,29 @@ c["Enemies Killed with Attack Hits have a 15% chance to Explode, dealing a tenth c["Enemies Killed with Attack or Spell Hits Explode, dealing 10% of their Life as Fire Damage"]={{[1]={flags=0,keywordFlags=0,name="ExplodeMod",type="LIST",value={amount=10,chance=1,keyOfScaledMod="chance",type="Fire"}},[2]={flags=0,keywordFlags=0,name="CanExplode",type="FLAG",value=true}},nil} c["Enemies Killed with Attack or Spell Hits Explode, dealing 5% of their Life as Fire Damage"]={{[1]={flags=0,keywordFlags=0,name="ExplodeMod",type="LIST",value={amount=5,chance=1,keyOfScaledMod="chance",type="Fire"}},[2]={flags=0,keywordFlags=0,name="CanExplode",type="FLAG",value=true}},nil} c["Enemies Killed with Wand Hits have a 10% chance to Explode, dealing a quarter of their Life as Chaos Damage"]={{[1]={[1]={type="Condition",var="UsingWand"},flags=0,keywordFlags=0,name="ExplodeMod",type="LIST",value={amount=25,chance=0.1,keyOfScaledMod="chance",type="Chaos"}},[2]={flags=0,keywordFlags=0,name="CanExplode",type="FLAG",value=true}},nil} -c["Enemies Maimed by you take 10% increased Damage Over Time"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Maimed"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTakenOverTime",type="INC",value=10}}}},nil} -c["Enemies Maimed by you take 5% increased Damage Over Time"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Maimed"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTakenOverTime",type="INC",value=5}}}},nil} -c["Enemies Poisoned by you cannot Regenerate Life"]={nil,"you cannot Regenerate Life "} -c["Enemies Poisoned by you cannot Regenerate Life +6% to Damage over Time Multiplier for Poison while wielding a Claw or Dagger"]={nil,"you cannot Regenerate Life +6% to Damage over Time Multiplier for Poison while wielding a Claw or Dagger "} -c["Enemies Poisoned by you cannot deal Critical Strikes"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="NeverCrit",type="FLAG",value=true}}},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="Condition:NeverCrit",type="FLAG",value=true}}}},nil} -c["Enemies Poisoned by you have -5% to Chaos Resistance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="ChaosResist",type="BASE",value=-5}}}},nil} -c["Enemies Poisoned by you have 10% of Physical Damage they deal converted to Chaos"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToChaos",type="BASE",value=10}}}},nil} -c["Enemies Shocked by you are Debilitated"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Shocked"},flags=0,keywordFlags=0,name="Condition:Debilitated",type="FLAG",value=true}}}},nil} -c["Enemies Shocked by you have 13% of Physical Damage they deal converted to Lightning"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Shocked"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToLightning",type="BASE",value=13}}}},nil} -c["Enemies Shocked by you have 15% of Physical Damage they deal converted to Lightning"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Shocked"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToLightning",type="BASE",value=15}}}},nil} -c["Enemies Shocked or Frozen by you take 5% increased Elemental Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",varList={[1]="Shocked",[2]="Frozen"}},flags=0,keywordFlags=0,name="ElementalDamageTaken",type="INC",value=5}}}},nil} -c["Enemies Taunted by you cannot Evade Attacks"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="CannotEvade",type="FLAG",value=true}}}},nil} -c["Enemies Taunted by you take 10% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=10}}}},nil} -c["Enemies Taunted by you take 15% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=15}}}},nil} -c["Enemies Taunted by you take 6% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=6}}}},nil} +c["Enemies Maimed by you take 10% increased Damage Over Time"]={{[1]={[1]={actor="enemy",sourceOwned=true,type="ActorCondition",var="Maimed"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTakenOverTime",type="INC",value=10}}}},nil} +c["Enemies Maimed by you take 5% increased Damage Over Time"]={{[1]={[1]={actor="enemy",sourceOwned=true,type="ActorCondition",var="Maimed"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="DamageTakenOverTime",type="INC",value=5}}}},nil} +c["Enemies Poisoned by you cannot Regenerate Life"]={nil,"cannot Regenerate Life "} +c["Enemies Poisoned by you cannot Regenerate Life +6% to Damage over Time Multiplier for Poison while wielding a Claw or Dagger"]={nil,"cannot Regenerate Life +6% to Damage over Time Multiplier for Poison while wielding a Claw or Dagger "} +c["Enemies Poisoned by you cannot deal Critical Strikes"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="NeverCrit",type="FLAG",value=true}}},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="Condition:NeverCrit",type="FLAG",value=true}}}},nil} +c["Enemies Poisoned by you have -5% to Chaos Resistance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="ChaosResist",type="BASE",value=-5}}}},nil} +c["Enemies Poisoned by you have 10% of Physical Damage they deal converted to Chaos"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Poisoned"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToChaos",type="BASE",value=10}}}},nil} +c["Enemies Shocked by you are Debilitated"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Shocked"},flags=0,keywordFlags=0,name="Condition:Debilitated",type="FLAG",value=true}}}},nil} +c["Enemies Shocked by you have 13% of Physical Damage they deal converted to Lightning"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Shocked"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToLightning",type="BASE",value=13}}}},nil} +c["Enemies Shocked by you have 15% of Physical Damage they deal converted to Lightning"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Shocked"},flags=0,keywordFlags=0,name="PhysicalDamageConvertToLightning",type="BASE",value=15}}}},nil} +c["Enemies Shocked or Frozen by you take 5% increased Elemental Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",varList={[1]="Shocked",[2]="Frozen"}},flags=0,keywordFlags=0,name="ElementalDamageTaken",type="INC",value=5}}}},nil} +c["Enemies Taunted by you cannot Evade Attacks"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="CannotEvade",type="FLAG",value=true}}}},nil} +c["Enemies Taunted by you take 10% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=10}}}},nil} +c["Enemies Taunted by you take 15% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=15}}}},nil} +c["Enemies Taunted by you take 6% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=6}}}},nil} c["Enemies Taunted by your Warcries Explode on death, dealing 8% of their maximum Life as Chaos Damage"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Taunted"},[2]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="ExplodeMod",type="LIST",value={amount=8,chance=1,keyOfScaledMod="chance",type="Chaos"}},[2]={flags=0,keywordFlags=0,name="CanExplode",type="FLAG",value=true}},nil} -c["Enemies Taunted by your Warcries are Intimidated"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="Condition:Intimidated",type="FLAG",value=true}}}},nil} -c["Enemies Taunted by your Warcries take 13% increased Damage"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=13}}}},nil} -c["Enemies Taunted by your Warcries take 23% increased Damage"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=23}}}},nil} -c["Enemies Taunted by your Warcries take 8% increased Damage"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=8}}}},nil} -c["Enemies Withered by you have -2% to all Resistances"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=1,type="MultiplierThreshold",var="WitheredStack"},flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-2}}},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=1,type="MultiplierThreshold",var="WitheredStack"},flags=0,keywordFlags=0,name="ChaosResist",type="BASE",value=-2}}}},nil} -c["Enemies affected by your Spider's Webs deal 10% reduced Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=1,type="MultiplierThreshold",var="Spider's WebStack"},flags=0,keywordFlags=0,name="Damage",type="INC",value=-10}}}},nil} -c["Enemies affected by your Spider's Webs have -10% to All Resistances"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=1,type="MultiplierThreshold",var="Spider's WebStack"},flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-10}}},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={threshold=1,type="MultiplierThreshold",var="Spider's WebStack"},flags=0,keywordFlags=0,name="ChaosResist",type="BASE",value=-10}}}},nil} +c["Enemies Taunted by your Warcries are Intimidated"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="Condition:Intimidated",type="FLAG",value=true}}}},nil} +c["Enemies Taunted by your Warcries take 13% increased Damage"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=13}}}},nil} +c["Enemies Taunted by your Warcries take 23% increased Damage"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=23}}}},nil} +c["Enemies Taunted by your Warcries take 8% increased Damage"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Taunted"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=8}}}},nil} +c["Enemies Withered by you have -2% to all Resistances"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,threshold=1,type="MultiplierThreshold",var="WitheredStack"},flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-2}}},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,threshold=1,type="MultiplierThreshold",var="WitheredStack"},flags=0,keywordFlags=0,name="ChaosResist",type="BASE",value=-2}}}},nil} +c["Enemies affected by your Spider's Webs deal 10% reduced Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,threshold=1,type="MultiplierThreshold",var="Spider's WebStack"},flags=0,keywordFlags=0,name="Damage",type="INC",value=-10}}}},nil} +c["Enemies affected by your Spider's Webs have -10% to All Resistances"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,threshold=1,type="MultiplierThreshold",var="Spider's WebStack"},flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-10}}},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,threshold=1,type="MultiplierThreshold",var="Spider's WebStack"},flags=0,keywordFlags=0,name="ChaosResist",type="BASE",value=-10}}}},nil} c["Enemies display their Monster Category"]={nil,"Enemies display their Monster Category "} c["Enemies display their Monster Category 120% increased Evasion and Energy Shield"]={nil,"Enemies display their Monster Category 120% increased Evasion and Energy Shield "} c["Enemies do not block your movement for 4 seconds on Rampage"]={nil,"Enemies do not block your movement for 4 seconds on Rampage "} @@ -15375,10 +15375,10 @@ c["Enemies take 8% increased Damage for each type of Ailment you have inflicted c["Enemies you Attack Reflect 100 Physical Damage to you"]={nil,"Enemies you Attack Reflect 100 Physical Damage to you "} c["Enemies you Attack Reflect 100 Physical Damage to you +0.2 metres to Weapon Range"]={nil,"Enemies you Attack Reflect 100 Physical Damage to you +0.2 metres to Weapon Range "} c["Enemies you Attack have 20% chance to Reflect 0 to 0 Chaos Damage to you"]={nil,"Enemies you Attack have 20% chance to Reflect 0 to 0 Chaos Damage to you "} -c["Enemies you Curse are Hindered, with 15% reduced Movement Speed"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="Condition:Hindered",type="FLAG",value=true}}}},nil} -c["Enemies you Curse are Unnerved"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="Condition:Unnerved",type="FLAG",value=true}}}},nil} +c["Enemies you Curse are Hindered, with 15% reduced Movement Speed"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="Condition:Hindered",type="FLAG",value=true}}}},nil} +c["Enemies you Curse are Unnerved"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="Condition:Unnerved",type="FLAG",value=true}}}},nil} c["Enemies you Curse cannot Recharge Energy Shield"]={nil,"cannot Recharge Energy Shield "} -c["Enemies you Curse take 6% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=6}}}},nil} +c["Enemies you Curse take 6% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",var="Cursed"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=6}}}},nil} c["Enemies you Freeze remain Frozen for at least 2 seconds"]={nil,"Enemies you Freeze remain Frozen for at least 2 seconds "} c["Enemies you Freeze remain Frozen for at least 2 seconds Hits that fail to Freeze due to insufficient Freeze Duration inflict Hoarfrost"]={nil,"Enemies you Freeze remain Frozen for at least 2 seconds Hits that fail to Freeze due to insufficient Freeze Duration inflict Hoarfrost "} c["Enemies you Kill Explode, dealing 3% of their Life as Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="ExplodeMod",type="LIST",value={amount=3,chance=1,keyOfScaledMod="chance",type="Physical"}},[2]={flags=0,keywordFlags=0,name="CanExplode",type="FLAG",value=true}},nil} @@ -16958,7 +16958,7 @@ c["Hits ignore Enemy Physical Damage Reduction"]={nil,"Hits ignore Enemy Physica c["Hits ignore Enemy Physical Damage Reduction if you've Blocked in the past 20 seconds"]={nil,"Hits ignore Enemy Physical Damage Reduction if you've Blocked in the past 20 seconds "} c["Hits that Stun Enemies have Culling Strike"]={{[1]={flags=0,keywordFlags=0,name="Condition:maceMasteryStunCullSpecced",type="FLAG",value=true}},nil} c["Hits that deal Elemental Damage remove Exposure to those Elements and inflict Exposure to other Elements"]={nil,"Hits that deal Elemental Damage remove Exposure to those Elements and inflict Exposure to other Elements "} -c["Hits that deal Elemental Damage remove Exposure to those Elements and inflict Exposure to other Elements Exposure inflicted this way applies -25% to Resistances"]={{[1]={flags=0,keywordFlags=0,name="ElementalEquilibrium",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",varList={[1]="HitByColdDamage",[2]="HitByLightningDamage"}},flags=0,keywordFlags=0,name="FireExposure",type="BASE",value=-25}}},[3]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",varList={[1]="HitByFireDamage",[2]="HitByLightningDamage"}},flags=0,keywordFlags=0,name="ColdExposure",type="BASE",value=-25}}},[4]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",varList={[1]="HitByFireDamage",[2]="HitByColdDamage"}},flags=0,keywordFlags=0,name="LightningExposure",type="BASE",value=-25}}}},nil} +c["Hits that deal Elemental Damage remove Exposure to those Elements and inflict Exposure to other Elements Exposure inflicted this way applies -25% to Resistances"]={{[1]={flags=0,keywordFlags=0,name="ElementalEquilibrium",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",varList={[1]="HitByColdDamage",[2]="HitByLightningDamage"}},flags=0,keywordFlags=0,name="FireExposure",type="BASE",value=-25}}},[3]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",varList={[1]="HitByFireDamage",[2]="HitByLightningDamage"}},flags=0,keywordFlags=0,name="ColdExposure",type="BASE",value=-25}}},[4]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={sourceOwned=true,type="Condition",varList={[1]="HitByFireDamage",[2]="HitByColdDamage"}},flags=0,keywordFlags=0,name="LightningExposure",type="BASE",value=-25}}}},nil} c["Hits that fail to Freeze due to insufficient Freeze Duration inflict Hoarfrost"]={{[1]={flags=0,keywordFlags=0,name="HitsCanInflictHoarfrost",type="FLAG",value=true}},nil} c["Hits that would Ignite instead Scorch"]={{[1]={flags=0,keywordFlags=0,name="IgniteCanScorch",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="CannotIgnite",type="FLAG",value=true}},nil} c["Hits with Melee Movement Skills have 40% chance to Fortify"]={nil,"Hits with Melee Movement Skills have 40% chance to Fortify "} @@ -17007,11 +17007,10 @@ c["If you've Consumed a corpse Recently, you and your Minions have 30% increased c["If you've Impaled an Enemy Recently, you"]={nil,"If you've Impaled an Enemy Recently, you "} c["If you've Impaled an Enemy Recently, you and nearby Allies have +1000 to Armour"]={{[1]={[1]={type="Condition",var="ImpaledRecently"},flags=0,keywordFlags=0,name="ExtraAura",type="LIST",value={mod={flags=0,keywordFlags=0,name="Armour",type="BASE",value=1000}}}},nil} c["If you've Warcried Recently, you and nearby allies have 20% increased Attack, Cast and Movement Speed"]={{[1]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="ExtraAura",type="LIST",value={mod={flags=0,keywordFlags=0,name="Speed",type="INC",value=20}}},[2]={[1]={type="Condition",var="UsedWarcryRecently"},flags=0,keywordFlags=0,name="ExtraAura",type="LIST",value={mod={flags=0,keywordFlags=0,name="MovementSpeed",type="INC",value=20}}}},nil} -c["If your Linked Mercenary dies, the Link owner does not also die"]={nil,"If your Linked Mercenary dies, the Link owner does not also die "} +c["If your Linked Mercenary dies, the Link owner does not also die"]={{},"If your Linked Mercenary dies, the Link owner does not also die"} c["If your Mercenary's Life is higher than your own, 20% of Damage from Hits is"]={nil,"If your Mercenary's Life is higher than your own, 20% of Damage from Hits is "} -c["If your Mercenary's Life is higher than your own, 20% of Damage from Hits is taken from your Mercenary's Life before you"]={nil,"If your Mercenary's Life is higher than your own, 20% of Damage from Hits is taken from your Mercenary's Life before you "} -c["If your Mercenary's Life is higher than your own, 20% of Damage from Hits is taken from your Mercenary's Life before you If your Mercenary's Life is lower than your own, 40% of Damage they take is Recouped as Life"]={nil,"If your Mercenary's Life is higher than your own, 20% of Damage from Hits is taken from your Mercenary's Life before you If your Mercenary's Life is lower than your own, 40% of Damage they take is Recouped as Life "} -c["If your Mercenary's Life is lower than your own, 40% of Damage they take is Recouped as Life"]={nil,"If your Mercenary's Life is lower than your own, 40% of Damage they take is Recouped as Life "} +c["If your Mercenary's Life is higher than your own, 20% of Damage from Hits is taken from your Mercenary's Life before you"]={{[1]={flags=0,keywordFlags=0,name="LoyalBodyguardRedirect",type="BASE",value=20}},nil} +c["If your Mercenary's Life is lower than your own, 40% of Damage they take is Recouped as Life"]={{[1]={flags=0,keywordFlags=0,name="MercenaryLifeRecoup",type="BASE",value=40}},nil} c["Ignited Enemies Burn 50% slower"]={{[1]={flags=0,keywordFlags=0,name="IgniteBurnSlower",type="INC",value=50}},nil} c["Ignited Enemies Burn 58% slower"]={{[1]={flags=0,keywordFlags=0,name="IgniteBurnSlower",type="INC",value=58}},nil} c["Ignited Enemies Burn 65% slower"]={{[1]={flags=0,keywordFlags=0,name="IgniteBurnSlower",type="INC",value=65}},nil} @@ -17134,7 +17133,7 @@ c["Increases and Reductions to Light Radius also apply to Accuracy"]={{[1]={flag c["Increases and Reductions to Light Radius also apply to Area of Effect at 50% of their value"]={{[1]={flags=0,keywordFlags=0,name="LightRadiusAppliesToAreaOfEffect",type="FLAG",value=true}},nil} c["Increases and Reductions to Light Radius also apply to Damage"]={{[1]={flags=0,keywordFlags=0,name="LightRadiusAppliesToDamage",type="FLAG",value=true}},nil} c["Increases and Reductions to Light Radius also apply to Effect"]={nil,"Increases and Reductions to Light Radius also apply to Effect "} -c["Increases and Reductions to Light Radius also apply to Effect of your Link Skill Buffs on your Mercenary"]={nil,"Increases and Reductions to Light Radius also apply to Effect of your Link Skill Buffs on your Mercenary "} +c["Increases and Reductions to Light Radius also apply to Effect of your Link Skill Buffs on your Mercenary"]={{[1]={flags=0,keywordFlags=0,name="LightRadiusAppliesToMercenaryLinkEffect",type="FLAG",value=true}},nil} c["Increases and Reductions to Lightning Damage also apply to Effect of"]={nil,"Increases and Reductions to Lightning Damage also apply to Effect of "} c["Increases and Reductions to Lightning Damage also apply to Effect of Auras from Lightning Skills at 13% of their value, up to a maximum of 150%"]={{[1]={flags=0,keywordFlags=0,name="LightningDamageAppliesToLightningAuraEffect",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ImprovedLightningDamageAppliesToLightningAuraEffect",type="BASE",value=13},[3]={flags=0,keywordFlags=0,name="LightningDamageAppliesToLightningAuraEffectLimit",type="MAX",value=150}},nil} c["Increases and Reductions to Lightning Damage also apply to Effect of Auras from Lightning Skills at 15% of their value, up to a maximum of 150%"]={{[1]={flags=0,keywordFlags=0,name="LightningDamageAppliesToLightningAuraEffect",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ImprovedLightningDamageAppliesToLightningAuraEffect",type="BASE",value=15},[3]={flags=0,keywordFlags=0,name="LightningDamageAppliesToLightningAuraEffectLimit",type="MAX",value=150}},nil} @@ -17440,7 +17439,7 @@ c["Link Skills have 20% increased Buff Effect if you have Linked to a target Rec c["Link Skills have 5% increased Buff Effect"]={{[1]={[1]={skillType=107,type="SkillType"},flags=0,keywordFlags=0,name="BuffEffect",type="INC",value=5}},nil} c["Link Skills have 50% increased range"]={{}," range "} c["Link Skills have 50% increased range Limited to 1 Runegraft of Connection"]={{}," range Limited to 1 Runegraft of Connection "} -c["Link Skills have infinite Attachment Duration"]={nil,"infinite Attachment Duration "} +c["Link Skills have infinite Attachment Duration"]={{},"Link Skills have infinite Attachment Duration"} c["Link Skills have infinite Attachment Duration If your Linked Mercenary dies, the Link owner does not also die"]={nil,"infinite Attachment Duration If your Linked Mercenary dies, the Link owner does not also die "} c["Linked Targets Cannot Die for 2 seconds after you Die"]={nil,"Linked Targets Cannot Die for 2 seconds after you Die "} c["Linked Targets Cannot Die for 2 seconds after you Die Lose no Experience when you die because a Linked target died"]={nil,"Linked Targets Cannot Die for 2 seconds after you Die Lose no Experience when you die because a Linked target died "} @@ -20007,8 +20006,8 @@ c["Skills Socketed in your Boots are Supported by level 20 High-Impact Mine"]={{ c["Skills Socketed in your Boots are Supported by level 20 Hypothermia"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportHypothermia"}}},nil} c["Skills Socketed in your Boots are Supported by level 20 Ice Bite"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIceBite"}}},nil} c["Skills Socketed in your Boots are Supported by level 20 Ignite Proliferation"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIgniteProliferation"}}},nil} -end)();(function() c["Skills Socketed in your Boots are Supported by level 20 Immolate"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportImmolate"}}},nil} +end)();(function() c["Skills Socketed in your Boots are Supported by level 20 Impale"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportImpale"}}},nil} c["Skills Socketed in your Boots are Supported by level 20 Increased Area of Effect"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIncreasedAreaOfEffect"}}},nil} c["Skills Socketed in your Boots are Supported by level 20 Increased Critical Damage"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIncreasedCriticalDamage"}}},nil} @@ -22777,7 +22776,7 @@ c["You can have an Offering of each type"]={nil,"You can have an Offering of eac c["You can have an Offering of each type Offering Skills have 50% reduced Duration"]={nil,"You can have an Offering of each type Offering Skills have 50% reduced Duration "} c["You can have an additional Brand Attached to an Enemy"]={{[1]={flags=0,keywordFlags=0,name="BrandsAttachedLimit",type="BASE",value=1}},nil} c["You can have an additional Tincture active"]={{[1]={flags=0,keywordFlags=0,name="TinctureLimit",type="BASE",value=1}},nil} -c["You can hire a Mercenary permanently"]={nil,"You can hire a Mercenary permanently "} +c["You can hire a Mercenary permanently"]={{[1]={flags=0,keywordFlags=0,name="CanHirePermanentMercenary",type="FLAG",value=true}},nil} c["You can inflict +1 Hallowing Flame on Enemies"]={{[1]={flags=0,keywordFlags=0,name="Multiplier:HallowingFlameMax",type="BASE",value=1}},nil} c["You can inflict Bleeding on an Enemy up to 8 times"]={{[1]={flags=0,keywordFlags=0,name="BleedStacksMax",type="OVERRIDE",value=8},[2]={flags=0,keywordFlags=0,name="Condition:HaveCrimsonDance",type="FLAG",value=true}},nil} c["You can inflict an additional Ignite on each Enemy"]={{[1]={flags=0,keywordFlags=0,name="IgniteCanStack",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="IgniteStacks",type="BASE",value=1}},nil} @@ -23084,23 +23083,19 @@ c["Your Maximum Resistances are 77%"]={{[1]={flags=0,keywordFlags=0,name="FireRe c["Your Maximum Resistances are 78%"]={{[1]={flags=0,keywordFlags=0,name="FireResistMax",type="OVERRIDE",value=78},[2]={flags=0,keywordFlags=0,name="ColdResistMax",type="OVERRIDE",value=78},[3]={flags=0,keywordFlags=0,name="LightningResistMax",type="OVERRIDE",value=78},[4]={flags=0,keywordFlags=0,name="ChaosResistMax",type="OVERRIDE",value=78}},nil} c["Your Maximum Resistances are 80%"]={{[1]={flags=0,keywordFlags=0,name="FireResistMax",type="OVERRIDE",value=80},[2]={flags=0,keywordFlags=0,name="ColdResistMax",type="OVERRIDE",value=80},[3]={flags=0,keywordFlags=0,name="LightningResistMax",type="OVERRIDE",value=80},[4]={flags=0,keywordFlags=0,name="ChaosResistMax",type="OVERRIDE",value=80}},nil} c["Your Melee Hits can't be Evaded while wielding a Sword"]={{[1]={[1]={type="Condition",var="UsingSword"},flags=260,keywordFlags=0,name="CannotBeEvaded",type="FLAG",value=true}},nil} -c["Your Mercenary Taunts on Hit"]={nil,"Your Mercenary Taunts on Hit "} -c["Your Mercenary Taunts on Hit Your Mercenary has 50% increased effect of Non-Curse Auras from Skills"]={nil,"Your Mercenary Taunts on Hit Your Mercenary has 50% increased effect of Non-Curse Auras from Skills "} -c["Your Mercenary and their Minions deal 15% increased Damage"]={nil,"Your Mercenary and their Minions deal 15% increased Damage "} -c["Your Mercenary and their Minions deal 15% increased Damage 5% increased Light Radius"]={nil,"Your Mercenary and their Minions deal 15% increased Damage 5% increased Light Radius "} +c["Your Mercenary Taunts on Hit"]={{[1]={flags=0,keywordFlags=0,name="MercenaryTauntsOnHit",type="FLAG",value=true}},nil} +c["Your Mercenary and their Minions deal 15% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="MercenaryModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=15}}},[2]={flags=0,keywordFlags=0,name="MercenaryMinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=15}}}},nil} c["Your Mercenary and their Minions deal 8% more Damage for"]={nil,"Your Mercenary and their Minions deal 8% more Damage for "} -c["Your Mercenary and their Minions deal 8% more Damage for each Unique item they have equipped"]={nil,"Your Mercenary and their Minions deal 8% more Damage for each Unique item they have equipped "} -c["Your Mercenary and their Minions have 15% increased maximum Life"]={nil,"Your Mercenary and their Minions have 15% increased maximum Life "} -c["Your Mercenary and their Minions have 15% increased maximum Life 5% increased Light Radius"]={nil,"Your Mercenary and their Minions have 15% increased maximum Life 5% increased Light Radius "} -c["Your Mercenary can equip Unique Amulets"]={nil,"Your Mercenary can equip Unique Amulets "} -c["Your Mercenary can equip Unique Belts"]={nil,"Your Mercenary can equip Unique Belts "} -c["Your Mercenary can equip Unique Boots"]={nil,"Your Mercenary can equip Unique Boots "} -c["Your Mercenary can equip Unique Gloves"]={nil,"Your Mercenary can equip Unique Gloves "} -c["Your Mercenary can equip Unique Helmets"]={nil,"Your Mercenary can equip Unique Helmets "} -c["Your Mercenary can equip Unique Rings"]={nil,"Your Mercenary can equip Unique Rings "} -c["Your Mercenary can equip Unique Weapons, Shields and Quivers"]={nil,"Your Mercenary can equip Unique Weapons, Shields and Quivers "} -c["Your Mercenary can equip Unique Weapons, Shields and Quivers Your Mercenary and their Minions deal 8% more Damage for\neach Unique item they have equipped"]={nil,"Your Mercenary can equip Unique Weapons, Shields and Quivers Your Mercenary and their Minions deal 8% more Damage for\neach Unique item they have equipped "} -c["Your Mercenary has 50% increased effect of Non-Curse Auras from Skills"]={nil,"Your Mercenary has 50% increased effect of Non-Curse Auras from Skills "} +c["Your Mercenary and their Minions deal 8% more Damage for each Unique item they have equipped"]={{[1]={flags=0,keywordFlags=0,name="MercenaryModifier",type="LIST",value={mod={[1]={type="Multiplier",var="UniqueItem"},flags=0,keywordFlags=0,name="Damage",type="MORE",value=8}}},[2]={flags=0,keywordFlags=0,name="MercenaryMinionModifier",type="LIST",value={mod={[1]={type="Multiplier",var="UniqueItem"},flags=0,keywordFlags=0,name="Damage",type="MORE",value=8}}}},nil} +c["Your Mercenary and their Minions have 15% increased maximum Life"]={{[1]={flags=0,keywordFlags=0,name="MercenaryModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Life",type="INC",value=15}}},[2]={flags=0,keywordFlags=0,name="MercenaryMinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Life",type="INC",value=15}}}},nil} +c["Your Mercenary can equip Unique Amulets"]={{[1]={flags=0,keywordFlags=0,name="MercenaryCanEquipUniqueAmulets",type="FLAG",value=true}},nil} +c["Your Mercenary can equip Unique Belts"]={{[1]={flags=0,keywordFlags=0,name="MercenaryCanEquipUniqueBelts",type="FLAG",value=true}},nil} +c["Your Mercenary can equip Unique Boots"]={{[1]={flags=0,keywordFlags=0,name="MercenaryCanEquipUniqueBoots",type="FLAG",value=true}},nil} +c["Your Mercenary can equip Unique Gloves"]={{[1]={flags=0,keywordFlags=0,name="MercenaryCanEquipUniqueGloves",type="FLAG",value=true}},nil} +c["Your Mercenary can equip Unique Helmets"]={{[1]={flags=0,keywordFlags=0,name="MercenaryCanEquipUniqueHelmets",type="FLAG",value=true}},nil} +c["Your Mercenary can equip Unique Rings"]={{[1]={flags=0,keywordFlags=0,name="MercenaryCanEquipUniqueRings",type="FLAG",value=true}},nil} +c["Your Mercenary can equip Unique Weapons, Shields and Quivers"]={{[1]={flags=0,keywordFlags=0,name="MercenaryCanEquipUniqueArms",type="FLAG",value=true}},nil} +c["Your Mercenary has 50% increased effect of Non-Curse Auras from Skills"]={{[1]={flags=0,keywordFlags=0,name="MercenaryModifier",type="LIST",value={mod={[1]={skillType=39,type="SkillType"},[2]={neg=true,skillType=69,type="SkillType"},flags=0,keywordFlags=0,name="AuraEffect",type="INC",value=50}}}},nil} c["Your Minions spread Burning Ground on Death, dealing 10% of their maximum Life as Fire Damage per second"]={{[1]={flags=0,keywordFlags=0,name="ExtraMinionSkill",type="LIST",value={skillId="ReplicaSiegebreakerBurningGround"}},[2]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Multiplier:SiegebreakerBurningGroundPercent",type="BASE",value=10}}}},nil} c["Your Minions spread Burning Ground on Death, dealing 20% of their maximum Life as Fire Damage per second"]={{[1]={flags=0,keywordFlags=0,name="ExtraMinionSkill",type="LIST",value={skillId="ReplicaSiegebreakerBurningGround"}},[2]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Multiplier:SiegebreakerBurningGroundPercent",type="BASE",value=20}}}},nil} c["Your Minions spread Caustic Ground on Death, dealing 20% of their maximum Life as Chaos Damage per second"]={{[1]={flags=0,keywordFlags=0,name="ExtraMinionSkill",type="LIST",value={skillId="SiegebreakerCausticGround"}},[2]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Multiplier:SiegebreakerCausticGroundPercent",type="BASE",value=20}}}},nil} @@ -23171,7 +23166,6 @@ c["and nearby Allies Regenerate 400 Life per second"]={{[1]={[1]={type="Conditio c["be inflicted on a nearby Minion instead"]={nil,"be inflicted on a nearby Minion instead "} c["be inflicted on a nearby Minion instead Limited to 1 Runegraft of Loyalty"]={nil,"be inflicted on a nearby Minion instead Limited to 1 Runegraft of Loyalty "} c["each Herald affecting you, up to a maximum of 40%"]={nil,"each Herald affecting you, up to a maximum of 40% "} -c["each Unique item they have equipped"]={nil,"each Unique item they have equipped "} c["each remaining Chain, up to a maximum of 100%"]={nil,"each remaining Chain, up to a maximum of 100% "} c["grant 100% increased Flask Charges"]={nil,"grant 100% increased Flask Charges "} c["has a 20% increased angle"]={nil,"has a 20% increased angle "} @@ -23184,7 +23178,6 @@ c["have fewer than 5 Poisons on you"]={nil,"fewer than 5 Poisons on you "} c["more than once every 0.3 seconds"]={nil,"more than once every 0.3 seconds "} c["more than once every 0.3 seconds Lose all Defiance when you reach 10 Defiance"]={nil,"more than once every 0.3 seconds Lose all Defiance when you reach 10 Defiance "} c["more than once every 0.3 seconds Lose all Defiance when you reach 10 Defiance Gain 3% of Missing Unreserved Life before being Hit by an Enemy Per Defiance"]={nil,"more than once every 0.3 seconds Lose all Defiance when you reach 10 Defiance Gain 3% of Missing Unreserved Life before being Hit by an Enemy Per Defiance "} -c["of your Link Skill Buffs on your Mercenary"]={nil,"of your Link Skill Buffs on your Mercenary "} c["of your Traps are Triggered by an Enemy"]={nil,"of your Traps are Triggered by an Enemy "} c["of your Traps are Triggered by an Enemy Skills which throw Traps Cost Life instead of Mana"]={nil,"of your Traps are Triggered by an Enemy Skills which throw Traps Cost Life instead of Mana "} c["per Tribe for which you have an allocated Tattoo"]={nil,"per Tribe for which you have an allocated Tattoo "} @@ -23192,8 +23185,6 @@ c["per Tribe for which you have an allocated Tattoo Limited to 1 Ancestral Tatto c["removed by Filling Unreserved Life"]={nil,"removed by Filling Unreserved Life "} c["removed by Filling Unreserved Life 10% chance to gain Onslaught for 4 Seconds when Leech is"]={nil,"removed by Filling Unreserved Life 10% chance to gain Onslaught for 4 Seconds when Leech is "} c["second, up to a maximum of 100%"]={nil,"second, up to a maximum of 100% "} -c["taken from your Mercenary's Life before you"]={nil,"taken from your Mercenary's Life before you "} -c["taken from your Mercenary's Life before you If your Mercenary's Life is lower than your own, 40% of Damage they take is Recouped as Life"]={nil,"taken from your Mercenary's Life before you If your Mercenary's Life is lower than your own, 40% of Damage they take is Recouped as Life "} c["to grant an Endurance Charge when you Stun an Enemy"]={nil,"to grant an Endurance Charge when you Stun an Enemy "} c["to grant an Endurance Charge when you Stun an Enemy With at least 40 Strength in Radius, Ground Slam"]={nil,"to grant an Endurance Charge when you Stun an Enemy With at least 40 Strength in Radius, Ground Slam "} c["to grant an Endurance Charge when you Stun an Enemy With at least 40 Strength in Radius, Ground Slam has a 35% chance"]={nil,"to grant an Endurance Charge when you Stun an Enemy With at least 40 Strength in Radius, Ground Slam has a 35% chance "} diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index 880e8c8e421..a5a2ea1762e 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -1896,6 +1896,9 @@ return { mod("TotemDuration", "BASE", nil), div = 1000 }, +["totem_ignores_cooldown"] = { + flag("TotemIgnoresCooldown"), +}, -- Minion ["minion_damage_+%"] = { mod("MinionModifier", "LIST", { mod = mod("Damage", "INC", nil) }), diff --git a/src/Data/Skills/mercenary.lua b/src/Data/Skills/mercenary.lua new file mode 100644 index 00000000000..0df1c665b7d --- /dev/null +++ b/src/Data/Skills/mercenary.lua @@ -0,0 +1,23827 @@ +-- This file is automatically generated, do not edit! +-- Mercenary skill data (c) Grinding Gear Games + +return function(skills, mod, flag, skill) +skills["ABTTArmourEleMercenary"] = { + name = "Prismplate", + hidden = true, + mercenary = true, + inheritedFrom = "ABTTAzmeriTurtleInvulnerability", + color = 4, + skillTypes = { [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 8000 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 15, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["ABTTExtraImpaleMercenary"] = { + name = "Brutal Teachings", + hidden = true, + mercenary = true, + inheritedFrom = "ABTTAzmeriTurtleInvulnerability", + color = 4, + skillTypes = { [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 8000 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 15, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["ABTTInvulnBubbleMercenary"] = { + name = "Impenetrable Bastion", + hidden = true, + mercenary = true, + inheritedFrom = "ABTTAzmeriTurtleInvulnerability", + color = 4, + skillTypes = { [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.25, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 30, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["ABTTPhysEnrageMercenary"] = { + name = "Bloodthirst", + hidden = true, + mercenary = true, + inheritedFrom = "ABTTAzmeriTurtleInvulnerability", + color = 4, + skillTypes = { [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 8000 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 15, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["AbsolutionMercenary"] = { + name = "Absolution", + hidden = true, + mercenary = true, + inheritedFrom = "Absolution", + color = 1, + baseEffectiveness = 2.8499999046326, + incrementalEffectiveness = 0.043200001120567, + description = "Damages enemies in an area, applying a debuff for a short duration. If a non-unique enemy dies while affected by the debuff, the corpse will be consumed to summon a Sentinel of Absolution for a secondary duration, or to refresh the duration and life of an existing one instead if you have the maximum number of them.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.Duration] = true, [SkillType.Physical] = true, [SkillType.Lightning] = true, [SkillType.MinionsCanExplode] = true, [SkillType.CreatesMinion] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.Triggerable] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesSentinelMinion] = true, }, + statDescriptionScope = "minion_spell_damage_skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "base_max_number_of_absolution_sentinels", 3 }, + { "base_secondary_skill_effect_duration", 10000 }, + { "absolution_blast_chance_to_summon_on_hitting_rare_or_unique_%", 25 }, + { "display_minion_monster_type", 19 }, + { "base_skill_effect_duration", 1000 }, + { "base_max_number_of_vaal_absolution_sentinels", 1 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_display_minion_actor_level", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 12, 0, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 12, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 15, 0, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 15, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 19, 1, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 19, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 23, 1, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 23, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 27, 1, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 27, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 31, 2, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 31, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 35, 2, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 35, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 38, 2, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 38, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 41, 3, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 41, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 44, 3, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 47, 3, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 47, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 50, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 50, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 53, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 53, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 56, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 59, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 59, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 62, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 62, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 64, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 66, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 66, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 68, 6, critChance = 6, damageEffectiveness = 2, levelRequirement = 68, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 70, 6, critChance = 6, damageEffectiveness = 2, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 72, 7, critChance = 6, damageEffectiveness = 2, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 74, 7, critChance = 6, damageEffectiveness = 2, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 76, 7, critChance = 6, damageEffectiveness = 2, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 78, 8, critChance = 6, damageEffectiveness = 2, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 80, 8, critChance = 6, damageEffectiveness = 2, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 82, 8, critChance = 6, damageEffectiveness = 2, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 84, 9, critChance = 6, damageEffectiveness = 2, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 86, 9, critChance = 6, damageEffectiveness = 2, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 88, 9, critChance = 6, damageEffectiveness = 2, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 90, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 91, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 92, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 93, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 94, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 95, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 96, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 97, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 98, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 99, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 100, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["AbsolutionMercenaryEncounter"] = { + name = "Absolution", + hidden = true, + mercenary = true, + inheritedFrom = "Absolution", + color = 1, + baseEffectiveness = 2.0499999523163, + incrementalEffectiveness = 0.042500000447035, + description = "Damages enemies in an area, applying a debuff for a short duration. If a non-unique enemy dies while affected by the debuff, the corpse will be consumed to summon a Sentinel of Absolution for a secondary duration, or to refresh the duration and life of an existing one instead if you have the maximum number of them.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.Duration] = true, [SkillType.Physical] = true, [SkillType.Lightning] = true, [SkillType.MinionsCanExplode] = true, [SkillType.CreatesMinion] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.Triggerable] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesSentinelMinion] = true, }, + statDescriptionScope = "minion_spell_damage_skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 60 }, + { "base_max_number_of_absolution_sentinels", 3 }, + { "base_secondary_skill_effect_duration", 10000 }, + { "absolution_blast_chance_to_summon_on_hitting_rare_or_unique_%", 25 }, + { "display_minion_monster_type", 19 }, + { "base_skill_effect_duration", 1000 }, + { "base_max_number_of_vaal_absolution_sentinels", 1 }, + { "active_skill_minion_damage_+%_final", -80 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_display_minion_actor_level", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 12, 0, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 12, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 15, 0, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 15, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 19, 1, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 19, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 23, 1, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 23, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 27, 1, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 27, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 31, 2, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 31, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 35, 2, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 35, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 38, 2, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 38, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 41, 3, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 41, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 44, 3, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 47, 3, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 47, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 50, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 50, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 53, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 53, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 56, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 59, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 59, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 62, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 62, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 64, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 66, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 66, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 68, 6, critChance = 6, damageEffectiveness = 2, levelRequirement = 68, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 70, 6, critChance = 6, damageEffectiveness = 2, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 72, 7, critChance = 6, damageEffectiveness = 2, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 74, 7, critChance = 6, damageEffectiveness = 2, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 76, 7, critChance = 6, damageEffectiveness = 2, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 78, 8, critChance = 6, damageEffectiveness = 2, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 80, 8, critChance = 6, damageEffectiveness = 2, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 82, 8, critChance = 6, damageEffectiveness = 2, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 84, 9, critChance = 6, damageEffectiveness = 2, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 86, 9, critChance = 6, damageEffectiveness = 2, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 88, 9, critChance = 6, damageEffectiveness = 2, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 90, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 91, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 92, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 93, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 94, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 95, 10, critChance = 6, damageEffectiveness = 2, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 96, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 97, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 98, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 99, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 100, 11, critChance = 6, damageEffectiveness = 2, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["AbyssalCryMercenary"] = { + name = "Abyssal Cry", + hidden = true, + mercenary = true, + color = 1, + description = "Performs a warcry, Hindering nearby enemies and causing them to explode when killed. The Hinder effect is proportional to the number of surrounding enemies. Taunts all nearby enemies to attack the user. Shares a cooldown with other Warcry skills.", + skillTypes = { [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Chaos] = true, [SkillType.Damage] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.25, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "abyssal_cry_%_max_life_as_chaos_on_death", 1 }, + { "base_skill_effect_duration", 4000 }, + }, + stats = { + "abyssal_cry_movement_velocity_+%_per_one_hundred_nearby_enemies", + "base_movement_velocity_+%", + }, + levels = { + [1] = { -60, -12, cooldown = 4, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { -62, -12, cooldown = 4, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { -62, -13, cooldown = 4, levelRequirement = 8, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { -64, -13, cooldown = 4, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { -66, -14, cooldown = 4, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { -68, -15, cooldown = 4, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { -69, -16, cooldown = 4, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { -70, -16, cooldown = 4, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { -71, -17, cooldown = 4, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { -72, -17, cooldown = 4, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { -73, -18, cooldown = 4, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { -74, -18, cooldown = 4, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { -75, -19, cooldown = 4, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { -76, -19, cooldown = 4, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { -77, -20, cooldown = 4, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { -78, -20, cooldown = 4, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { -79, -21, cooldown = 4, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { -80, -21, cooldown = 4, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { -81, -22, cooldown = 4, levelRequirement = 69, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { -82, -22, cooldown = 4, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { -83, -23, cooldown = 4, levelRequirement = 71, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { -84, -23, cooldown = 4, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { -85, -24, cooldown = 4, levelRequirement = 73, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { -86, -24, cooldown = 4, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { -87, -25, cooldown = 4, levelRequirement = 75, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { -88, -25, cooldown = 4, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { -89, -26, cooldown = 4, levelRequirement = 77, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { -90, -26, cooldown = 4, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { -91, -27, cooldown = 4, levelRequirement = 79, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { -92, -27, cooldown = 4, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { -93, -28, cooldown = 4, levelRequirement = 81, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { -94, -28, cooldown = 4, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["ActionSpeedAuraMercenary"] = { + name = "Trarthan Agility", + hidden = true, + mercenary = true, + inheritedFrom = "ABTTAzmeriTurtleInvulnerability", + color = 4, + skillTypes = { [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 8000 }, + { "action_speed_-%", -10 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 20, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["AlchemistsMarkMercenary"] = { + name = "Alchemist's Mark", + hidden = true, + mercenary = true, + inheritedFrom = "AlchemistsMark", + color = 2, + baseEffectiveness = 0, + description = "Curses a single enemy, granting flask charges when you hit them and creating Burning Ground under them if your hit Ignites them, and Caustic Ground if it Poisons them. Damage modifiers do not apply to these ground effects. You can only have one Mark at a time.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Mark] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.AreaSpell] = true, [SkillType.Fire] = true, [SkillType.Chaos] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "alchemists_mark_grant_attacker_x_flask_charges_when_hit_once_per_3s", 1 }, + { "base_skill_effect_duration", 4000 }, + }, + stats = { + "alchemists_mark_igniter_creates_burning_ground_%_ignite_damage", + "alchemists_mark_poisoner_creates_caustic_ground_%_poison_damage", + "base_deal_no_damage", + }, + levels = { + [1] = { 20, 60, cooldown = 6, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 20, 61, cooldown = 6, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 21, 62, cooldown = 6, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 21, 63, cooldown = 6, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 21, 64, cooldown = 6, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 22, 65, cooldown = 6, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 22, 66, cooldown = 6, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 22, 67, cooldown = 6, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 23, 68, cooldown = 6, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 23, 69, cooldown = 6, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 23, 70, cooldown = 6, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 24, 71, cooldown = 6, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 24, 72, cooldown = 6, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 24, 73, cooldown = 6, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 25, 74, cooldown = 6, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 25, 75, cooldown = 6, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 25, 76, cooldown = 6, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 26, 77, cooldown = 6, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 26, 78, cooldown = 6, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 26, 79, cooldown = 6, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 27, 80, cooldown = 6, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 27, 81, cooldown = 6, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 27, 82, cooldown = 6, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 28, 83, cooldown = 6, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 28, 84, cooldown = 6, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 28, 85, cooldown = 6, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 29, 86, cooldown = 6, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 29, 87, cooldown = 6, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 29, 88, cooldown = 6, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 30, 89, cooldown = 6, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 30, 90, cooldown = 6, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 30, 91, cooldown = 6, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 30, 92, cooldown = 6, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 30, 93, cooldown = 6, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 30, 94, cooldown = 6, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 31, 95, cooldown = 6, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 31, 96, cooldown = 6, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 31, 97, cooldown = 6, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 31, 98, cooldown = 6, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 31, 99, cooldown = 6, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["AngerMercenary"] = { + name = "Anger", + hidden = true, + mercenary = true, + inheritedFrom = "Anger", + color = 1, + baseEffectiveness = 2.25, + incrementalEffectiveness = 0.023000000044703, + description = "Casts an aura that adds fire damage to the attacks and spells of you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Fire] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "attack_minimum_added_fire_damage", + "attack_maximum_added_fire_damage", + "spell_minimum_added_fire_damage", + "spell_maximum_added_fire_damage", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [2] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [3] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [4] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [5] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [6] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [7] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [8] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [9] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [10] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [11] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [12] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [13] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [14] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [15] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [16] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [17] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [18] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [19] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [20] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [21] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [22] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [23] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [24] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [25] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [26] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [27] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [28] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [29] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [30] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [31] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [32] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [33] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [34] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [35] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [36] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [37] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [38] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [39] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [40] = { 0.34999999403954, 0.5, 0.34999999403954, 0.5, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + }, +} + +skills["ArcAltMercenary"] = { + name = "[DNT] Unused", + hidden = true, + mercenary = true, + inheritedFrom = "ArcAltX", + color = 3, + baseEffectiveness = 3.0499999523163, + incrementalEffectiveness = 0.039500001817942, + description = "An arc of lightning reaches from the caster to a targeted enemy and splits to simultaneously hit several other enemies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, [SkillType.ThresholdJewelChaining] = true, }, + statDescriptionScope = "beam_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + spell = true, + }, + constantStats = { + { "arc_chain_distance", 20 }, + { "arc_additional_delay_ms", 150 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "projectile_number_to_split", + "active_skill_beam_splits_instead_of_chaining", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, cost = { Mana = 8, }, }, + [2] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [3] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [4] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [5] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [6] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [7] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [8] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [9] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [10] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [11] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [12] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [13] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [14] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [15] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [16] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [17] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [18] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [19] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [20] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, cost = { Mana = 23, }, }, + [21] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [22] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [23] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [24] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [25] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [26] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [27] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [28] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [29] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [30] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [31] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [32] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [33] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [34] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [35] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [36] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [37] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [38] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [39] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [40] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, cost = { Mana = 31, }, }, + }, +} + +skills["ArcMercenary"] = { + name = "Arc", + hidden = true, + mercenary = true, + inheritedFrom = "Arc", + color = 3, + baseEffectiveness = 1.584900021553, + incrementalEffectiveness = 0.039500001817942, + description = "An arc of lightning reaches from the caster to a targeted enemy and chains to other enemies, but not immediately back. Each time the arc chains, it will also chain a secondary arc to another enemy that the main arc has not already hit, which cannot chain further.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Chains] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "beam_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + spell = true, + }, + constantStats = { + { "arc_damage_+%_final_for_each_remaining_chain", 15 }, + { "arc_chain_distance", 35 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "number_of_chains", + "arc_enhanced_behaviour", + "disable_visual_hit_effect", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, cost = { Mana = 8, }, }, + [2] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [3] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [4] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [5] = { 0.30000001192093, 1.7000000476837, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [6] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [7] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [8] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [9] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [10] = { 0.30000001192093, 1.7000000476837, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [11] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [12] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [13] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [14] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [15] = { 0.30000001192093, 1.7000000476837, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [16] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [17] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [18] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [19] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [20] = { 0.30000001192093, 1.7000000476837, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, cost = { Mana = 23, }, }, + [21] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [22] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [23] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [24] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [25] = { 0.30000001192093, 1.7000000476837, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [26] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [27] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [28] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [29] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [30] = { 0.30000001192093, 1.7000000476837, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [31] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [32] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [33] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [34] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [35] = { 0.30000001192093, 1.7000000476837, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [36] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [37] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [38] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [39] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [40] = { 0.30000001192093, 1.7000000476837, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, cost = { Mana = 31, }, }, + }, +} + +skills["ArcMercenaryEncounter"] = { + name = "Arc", + hidden = true, + mercenary = true, + inheritedFrom = "Arc", + color = 3, + incrementalEffectiveness = 0.050000000745058, + description = "An arc of lightning reaches from the caster to a targeted enemy and chains to other enemies, but not immediately back. Each time the arc chains, it will also chain a secondary arc to another enemy that the main arc has not already hit, which cannot chain further.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Chains] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "beam_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + spell = true, + }, + constantStats = { + { "arc_chain_distance", 20 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "number_of_chains", + "disable_visual_hit_effect", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, cost = { Mana = 8, }, }, + [2] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [3] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [4] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [5] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [6] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [7] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [8] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [9] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [10] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [11] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [12] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [13] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [14] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [15] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [16] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [17] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [18] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [19] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [20] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, cost = { Mana = 23, }, }, + [21] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [22] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [23] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [24] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [25] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [26] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [27] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [28] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [29] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [30] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [31] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [32] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [33] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [34] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [35] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, cost = { Mana = 29, }, }, + [36] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [37] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [38] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [39] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, cost = { Mana = 30, }, }, + [40] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, cost = { Mana = 31, }, }, + }, +} + +skills["ArcticArmourMercenary"] = { + name = "Arctic Armour", + hidden = true, + mercenary = true, + inheritedFrom = "ArcticArmour", + color = 2, + incrementalEffectiveness = 0.029999999329448, + description = "Conjures an icy barrier that chills enemies when they hit you. You drop chilled ground while moving, and take less Fire and Physical damage while stationary.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Totemable] = true, [SkillType.Duration] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Cold] = true, [SkillType.ElementalStatus] = true, [SkillType.Instant] = true, [SkillType.NonHitChill] = true, [SkillType.ChillingArea] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "arctic_armour_chill_when_hit_duration", 500 }, + { "ground_ice_art_variation", 6 }, + }, + stats = { + "new_arctic_armour_physical_damage_taken_when_hit_+%_final", + "new_arctic_armour_fire_damage_taken_when_hit_+%_final", + "base_skill_effect_duration", + "base_immune_to_freeze", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { -11, -11, 2500, cooldown = 1.2, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { -12, -11, 2600, cooldown = 1.2, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { -12, -12, 2700, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { -13, -12, 2800, cooldown = 1.2, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { -13, -13, 2900, cooldown = 1.2, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { -14, -13, 3000, cooldown = 1.2, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { -14, -14, 3100, cooldown = 1.2, levelRequirement = 37, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { -15, -14, 3200, cooldown = 1.2, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { -15, -15, 3300, cooldown = 1.2, levelRequirement = 43, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { -16, -15, 3400, cooldown = 1.2, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { -16, -16, 3500, cooldown = 1.2, levelRequirement = 49, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { -17, -16, 3600, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { -17, -17, 3700, cooldown = 1.2, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { -18, -17, 3800, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { -18, -18, 3900, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { -19, -18, 4000, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { -19, -19, 4100, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { -20, -19, 4200, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { -20, -20, 4300, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { -21, -20, 4400, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { -21, -21, 4500, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { -22, -21, 4600, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { -22, -22, 4700, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { -23, -22, 4800, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { -23, -23, 4900, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { -24, -23, 5000, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { -24, -24, 5100, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { -25, -24, 5200, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { -25, -25, 5300, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { -26, -25, 5400, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { -26, -25, 5450, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { -26, -26, 5500, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { -26, -26, 5550, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { -27, -26, 5600, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { -27, -26, 5650, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { -27, -27, 5700, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { -27, -27, 5750, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { -28, -27, 5800, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { -28, -27, 5850, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { -28, -28, 5900, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["ArtilleryBallistaMercenary"] = { + name = "Artillery Ballista", + hidden = true, + mercenary = true, + inheritedFrom = "ArtilleryBallista", + color = 2, + description = "Summons a ballista totem that propels a sequence of fiery arrows into the air. The arrows impact the ground in a line, each dealing area damage to enemies around it. Requires a Bow.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.SummonsTotem] = true, [SkillType.Area] = true, [SkillType.Fire] = true, [SkillType.ProjectileNumber] = true, [SkillType.ProjectileSpeed] = true, [SkillType.AttackInPlaceIsDefault] = true, [SkillType.TotemsAreBallistae] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 19, + castTime = 1, + baseFlags = { + area = true, + attack = true, + totem = true, + }, + constantStats = { + { "base_totem_range", 80 }, + { "base_totem_duration", 8000 }, + { "base_number_of_arrows", 6 }, + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + }, + stats = { + "attack_skills_additional_ballista_totems_allowed", + "base_is_projectile", + "base_skill_is_totemified", + "is_totem", + "skill_can_fire_arrows", + "is_area_damage", + "is_ranged_attack_totem", + "quality_display_base_additional_arrows_is_gem", + "totem_ignores_cooldown", + }, + levels = { + [1] = { 2, baseMultiplier = 0.5, cooldown = 4, damageEffectiveness = 0.5, levelRequirement = 28, storedUses = 2, statInterpolation = { 1, }, }, + [2] = { 2, baseMultiplier = 0.508, cooldown = 4, damageEffectiveness = 0.508, levelRequirement = 31, storedUses = 2, statInterpolation = { 1, }, }, + [3] = { 2, baseMultiplier = 0.516, cooldown = 4, damageEffectiveness = 0.516, levelRequirement = 34, storedUses = 2, statInterpolation = { 1, }, }, + [4] = { 2, baseMultiplier = 0.524, cooldown = 4, damageEffectiveness = 0.524, levelRequirement = 37, storedUses = 2, statInterpolation = { 1, }, }, + [5] = { 2, baseMultiplier = 0.532, cooldown = 4, damageEffectiveness = 0.532, levelRequirement = 40, storedUses = 2, statInterpolation = { 1, }, }, + [6] = { 2, baseMultiplier = 0.539, cooldown = 4, damageEffectiveness = 0.539, levelRequirement = 42, storedUses = 2, statInterpolation = { 1, }, }, + [7] = { 2, baseMultiplier = 0.547, cooldown = 4, damageEffectiveness = 0.547, levelRequirement = 44, storedUses = 2, statInterpolation = { 1, }, }, + [8] = { 2, baseMultiplier = 0.555, cooldown = 4, damageEffectiveness = 0.555, levelRequirement = 46, storedUses = 2, statInterpolation = { 1, }, }, + [9] = { 2, baseMultiplier = 0.563, cooldown = 4, damageEffectiveness = 0.563, levelRequirement = 48, storedUses = 2, statInterpolation = { 1, }, }, + [10] = { 2, baseMultiplier = 0.571, cooldown = 4, damageEffectiveness = 0.571, levelRequirement = 50, storedUses = 2, statInterpolation = { 1, }, }, + [11] = { 3, baseMultiplier = 0.579, cooldown = 4, damageEffectiveness = 0.579, levelRequirement = 52, storedUses = 2, statInterpolation = { 1, }, }, + [12] = { 3, baseMultiplier = 0.587, cooldown = 4, damageEffectiveness = 0.587, levelRequirement = 54, storedUses = 2, statInterpolation = { 1, }, }, + [13] = { 3, baseMultiplier = 0.595, cooldown = 4, damageEffectiveness = 0.595, levelRequirement = 56, storedUses = 2, statInterpolation = { 1, }, }, + [14] = { 3, baseMultiplier = 0.603, cooldown = 4, damageEffectiveness = 0.603, levelRequirement = 58, storedUses = 2, statInterpolation = { 1, }, }, + [15] = { 3, baseMultiplier = 0.611, cooldown = 4, damageEffectiveness = 0.611, levelRequirement = 60, storedUses = 2, statInterpolation = { 1, }, }, + [16] = { 3, baseMultiplier = 0.618, cooldown = 4, damageEffectiveness = 0.618, levelRequirement = 62, storedUses = 2, statInterpolation = { 1, }, }, + [17] = { 3, baseMultiplier = 0.626, cooldown = 4, damageEffectiveness = 0.626, levelRequirement = 64, storedUses = 2, statInterpolation = { 1, }, }, + [18] = { 3, baseMultiplier = 0.634, cooldown = 4, damageEffectiveness = 0.634, levelRequirement = 66, storedUses = 2, statInterpolation = { 1, }, }, + [19] = { 3, baseMultiplier = 0.642, cooldown = 4, damageEffectiveness = 0.642, levelRequirement = 68, storedUses = 2, statInterpolation = { 1, }, }, + [20] = { 3, baseMultiplier = 0.65, cooldown = 4, damageEffectiveness = 0.65, levelRequirement = 70, storedUses = 2, statInterpolation = { 1, }, }, + [21] = { 3, baseMultiplier = 0.658, cooldown = 4, damageEffectiveness = 0.658, levelRequirement = 72, storedUses = 2, statInterpolation = { 1, }, }, + [22] = { 4, baseMultiplier = 0.666, cooldown = 4, damageEffectiveness = 0.666, levelRequirement = 74, storedUses = 2, statInterpolation = { 1, }, }, + [23] = { 4, baseMultiplier = 0.674, cooldown = 4, damageEffectiveness = 0.674, levelRequirement = 76, storedUses = 2, statInterpolation = { 1, }, }, + [24] = { 4, baseMultiplier = 0.682, cooldown = 4, damageEffectiveness = 0.682, levelRequirement = 78, storedUses = 2, statInterpolation = { 1, }, }, + [25] = { 4, baseMultiplier = 0.689, cooldown = 4, damageEffectiveness = 0.689, levelRequirement = 80, storedUses = 2, statInterpolation = { 1, }, }, + [26] = { 4, baseMultiplier = 0.697, cooldown = 4, damageEffectiveness = 0.697, levelRequirement = 82, storedUses = 2, statInterpolation = { 1, }, }, + [27] = { 4, baseMultiplier = 0.705, cooldown = 4, damageEffectiveness = 0.705, levelRequirement = 84, storedUses = 2, statInterpolation = { 1, }, }, + [28] = { 4, baseMultiplier = 0.713, cooldown = 4, damageEffectiveness = 0.713, levelRequirement = 86, storedUses = 2, statInterpolation = { 1, }, }, + [29] = { 4, baseMultiplier = 0.721, cooldown = 4, damageEffectiveness = 0.721, levelRequirement = 88, storedUses = 2, statInterpolation = { 1, }, }, + [30] = { 4, baseMultiplier = 0.729, cooldown = 4, damageEffectiveness = 0.729, levelRequirement = 90, storedUses = 2, statInterpolation = { 1, }, }, + [31] = { 4, baseMultiplier = 0.733, cooldown = 4, damageEffectiveness = 0.733, levelRequirement = 91, storedUses = 2, statInterpolation = { 1, }, }, + [32] = { 4, baseMultiplier = 0.737, cooldown = 4, damageEffectiveness = 0.737, levelRequirement = 92, storedUses = 2, statInterpolation = { 1, }, }, + [33] = { 4, baseMultiplier = 0.741, cooldown = 4, damageEffectiveness = 0.741, levelRequirement = 93, storedUses = 2, statInterpolation = { 1, }, }, + [34] = { 4, baseMultiplier = 0.745, cooldown = 4, damageEffectiveness = 0.745, levelRequirement = 94, storedUses = 2, statInterpolation = { 1, }, }, + [35] = { 4, baseMultiplier = 0.749, cooldown = 4, damageEffectiveness = 0.749, levelRequirement = 95, storedUses = 2, statInterpolation = { 1, }, }, + [36] = { 4, baseMultiplier = 0.753, cooldown = 4, damageEffectiveness = 0.753, levelRequirement = 96, storedUses = 2, statInterpolation = { 1, }, }, + [37] = { 4, baseMultiplier = 0.757, cooldown = 4, damageEffectiveness = 0.757, levelRequirement = 97, storedUses = 2, statInterpolation = { 1, }, }, + [38] = { 4, baseMultiplier = 0.761, cooldown = 4, damageEffectiveness = 0.761, levelRequirement = 98, storedUses = 2, statInterpolation = { 1, }, }, + [39] = { 4, baseMultiplier = 0.764, cooldown = 4, damageEffectiveness = 0.764, levelRequirement = 99, storedUses = 2, statInterpolation = { 1, }, }, + [40] = { 4, baseMultiplier = 0.768, cooldown = 4, damageEffectiveness = 0.768, levelRequirement = 100, storedUses = 2, statInterpolation = { 1, }, }, + }, +} + +skills["AspectOfTheSpiderMercenary"] = { + name = "Aspect of the Spider", + hidden = true, + mercenary = true, + inheritedFrom = "AspectOfTheSpider", + color = 4, + description = "While active, periodically applies a Spider's Web debuff to nearby Enemies, and Hinders them. Each Spider's Web on an Enemy increases the Damage they take. Hinder reduces their movement speed.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Spell] = true, [SkillType.HasReservation] = true, [SkillType.Duration] = true, [SkillType.Instant] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_damage_taken_+%", 5 }, + { "base_skill_effect_duration", 6000 }, + { "spider_aspect_web_interval_ms", 1000 }, + }, + stats = { + "spider_aspect_max_web_count", + }, + levels = { + [1] = { 3, cooldown = 1.2, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["AssassinsMarkMercenary"] = { + name = "Assassin's Mark", + hidden = true, + mercenary = true, + inheritedFrom = "AssassinsMark", + color = 3, + baseEffectiveness = 0, + description = "Curses a single enemy, making them more vulnerable to Critical Strikes. Killing the cursed enemy will grant life and mana, and a power charge. You can only have one Mark at a time.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Mark] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + spell = true, + }, + constantStats = { + { "enemy_additional_critical_strike_chance_against_self", 150 }, + { "chance_to_grant_power_charge_on_death_%", 100 }, + }, + stats = { + "enemy_additional_critical_strike_multiplier_against_self", + "life_granted_when_killed", + "mana_granted_when_killed", + "base_deal_no_damage", + }, + levels = { + [1] = { 30, 65, 25, levelRequirement = 16, statInterpolation = { 1, 1, 1, }, }, + [2] = { 31, 99, 28, levelRequirement = 20, statInterpolation = { 1, 1, 1, }, }, + [3] = { 32, 134, 32, levelRequirement = 24, statInterpolation = { 1, 1, 1, }, }, + [4] = { 33, 169, 35, levelRequirement = 28, statInterpolation = { 1, 1, 1, }, }, + [5] = { 34, 204, 39, levelRequirement = 31, statInterpolation = { 1, 1, 1, }, }, + [6] = { 35, 239, 42, levelRequirement = 34, statInterpolation = { 1, 1, 1, }, }, + [7] = { 36, 274, 46, levelRequirement = 37, statInterpolation = { 1, 1, 1, }, }, + [8] = { 37, 309, 50, levelRequirement = 40, statInterpolation = { 1, 1, 1, }, }, + [9] = { 38, 344, 53, levelRequirement = 43, statInterpolation = { 1, 1, 1, }, }, + [10] = { 39, 367, 56, levelRequirement = 46, statInterpolation = { 1, 1, 1, }, }, + [11] = { 40, 390, 58, levelRequirement = 49, statInterpolation = { 1, 1, 1, }, }, + [12] = { 41, 413, 60, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [13] = { 42, 437, 63, levelRequirement = 55, statInterpolation = { 1, 1, 1, }, }, + [14] = { 43, 460, 65, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 44, 483, 68, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 45, 506, 70, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 46, 530, 72, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 47, 553, 75, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 48, 576, 77, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 49, 600, 80, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 50, 623, 82, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 51, 646, 84, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 52, 669, 87, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 53, 693, 89, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 54, 716, 91, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 55, 739, 94, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 56, 762, 96, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 57, 786, 99, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 58, 809, 101, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 59, 832, 103, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 59, 844, 105, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 60, 855, 106, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 60, 867, 107, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 61, 879, 108, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 61, 890, 109, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 62, 902, 111, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 62, 914, 112, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 63, 925, 113, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 63, 937, 114, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 64, 948, 115, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["BallLightningAltMercenary"] = { + name = "Ball Lightning of Static", + hidden = true, + mercenary = true, + inheritedFrom = "BallLightningAltY", + color = 3, + baseEffectiveness = 0.97000002861023, + incrementalEffectiveness = 0.044300001114607, + description = "Creates a ball of lightning at a location that damages each enemy in an area around it repeatedly with bolts of lightning. Cannot be supported by Spell Echo or used by Totems.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Orb] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 18 }, + { "number_of_projectiles_override", 1 }, + { "ball_lightning_projectile_speed_and_hit_frequency_+%_final", 33 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 28, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 12, }, }, + [2] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 31, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 13, }, }, + [3] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 34, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 14, }, }, + [4] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 37, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 15, }, }, + [5] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 40, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 15, }, }, + [6] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 42, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 16, }, }, + [7] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 44, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 16, }, }, + [8] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 46, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 17, }, }, + [9] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 48, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 17, }, }, + [10] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 50, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 18, }, }, + [11] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 52, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 18, }, }, + [12] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 54, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 19, }, }, + [13] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 56, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 19, }, }, + [14] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 58, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 20, }, }, + [15] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 60, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 20, }, }, + [16] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 62, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 21, }, }, + [17] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 64, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 21, }, }, + [18] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 66, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 22, }, }, + [19] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 68, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 22, }, }, + [20] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 70, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 23, }, }, + [21] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 72, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 24, }, }, + [22] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 74, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 24, }, }, + [23] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 76, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 25, }, }, + [24] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 78, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 25, }, }, + [25] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 80, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 26, }, }, + [26] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 82, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 26, }, }, + [27] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 84, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 27, }, }, + [28] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 86, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 27, }, }, + [29] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 88, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [30] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 90, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [31] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 91, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [32] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 92, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [33] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 93, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [34] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 94, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [35] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 95, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [36] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 96, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [37] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 97, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [38] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 98, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [39] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 99, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [40] = { 0.10000000149012, 1.8999999761581, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 100, storedUses = 3, statInterpolation = { 3, 3, }, cost = { Mana = 31, }, }, + }, +} + +skills["BallLightningAltMercenaryEncounter"] = { + name = "Ball Lightning of Static", + hidden = true, + mercenary = true, + inheritedFrom = "BallLightningAltY", + color = 3, + baseEffectiveness = 0.40000000596046, + incrementalEffectiveness = 0.044300001114607, + description = "Creates a ball of lightning at a location that damages each enemy in an area around it repeatedly with bolts of lightning. Cannot be supported by Spell Echo or used by Totems.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Orb] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 0 }, + { "number_of_projectiles_override", 1 }, + { "ball_lightning_projectile_speed_and_hit_frequency_+%_final", 0 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "cannot_stun", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 28, storedUses = 3, statInterpolation = { 3, 3, }, }, + [2] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 31, storedUses = 3, statInterpolation = { 3, 3, }, }, + [3] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 34, storedUses = 3, statInterpolation = { 3, 3, }, }, + [4] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 37, storedUses = 3, statInterpolation = { 3, 3, }, }, + [5] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 40, storedUses = 3, statInterpolation = { 3, 3, }, }, + [6] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 42, storedUses = 3, statInterpolation = { 3, 3, }, }, + [7] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 44, storedUses = 3, statInterpolation = { 3, 3, }, }, + [8] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 46, storedUses = 3, statInterpolation = { 3, 3, }, }, + [9] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 48, storedUses = 3, statInterpolation = { 3, 3, }, }, + [10] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 50, storedUses = 3, statInterpolation = { 3, 3, }, }, + [11] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 52, storedUses = 3, statInterpolation = { 3, 3, }, }, + [12] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 54, storedUses = 3, statInterpolation = { 3, 3, }, }, + [13] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 56, storedUses = 3, statInterpolation = { 3, 3, }, }, + [14] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 58, storedUses = 3, statInterpolation = { 3, 3, }, }, + [15] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 60, storedUses = 3, statInterpolation = { 3, 3, }, }, + [16] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 62, storedUses = 3, statInterpolation = { 3, 3, }, }, + [17] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 64, storedUses = 3, statInterpolation = { 3, 3, }, }, + [18] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 66, storedUses = 3, statInterpolation = { 3, 3, }, }, + [19] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 68, storedUses = 3, statInterpolation = { 3, 3, }, }, + [20] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 70, storedUses = 3, statInterpolation = { 3, 3, }, }, + [21] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 72, storedUses = 3, statInterpolation = { 3, 3, }, }, + [22] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 74, storedUses = 3, statInterpolation = { 3, 3, }, }, + [23] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 76, storedUses = 3, statInterpolation = { 3, 3, }, }, + [24] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 78, storedUses = 3, statInterpolation = { 3, 3, }, }, + [25] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 80, storedUses = 3, statInterpolation = { 3, 3, }, }, + [26] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 82, storedUses = 3, statInterpolation = { 3, 3, }, }, + [27] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 84, storedUses = 3, statInterpolation = { 3, 3, }, }, + [28] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 86, storedUses = 3, statInterpolation = { 3, 3, }, }, + [29] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 88, storedUses = 3, statInterpolation = { 3, 3, }, }, + [30] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 90, storedUses = 3, statInterpolation = { 3, 3, }, }, + [31] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 91, storedUses = 3, statInterpolation = { 3, 3, }, }, + [32] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 92, storedUses = 3, statInterpolation = { 3, 3, }, }, + [33] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 93, storedUses = 3, statInterpolation = { 3, 3, }, }, + [34] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 94, storedUses = 3, statInterpolation = { 3, 3, }, }, + [35] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 95, storedUses = 3, statInterpolation = { 3, 3, }, }, + [36] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 96, storedUses = 3, statInterpolation = { 3, 3, }, }, + [37] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 97, storedUses = 3, statInterpolation = { 3, 3, }, }, + [38] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 98, storedUses = 3, statInterpolation = { 3, 3, }, }, + [39] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 99, storedUses = 3, statInterpolation = { 3, 3, }, }, + [40] = { 0.5, 1.5, cooldown = 1.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 100, storedUses = 3, statInterpolation = { 3, 3, }, }, + }, +} + +skills["BallLightningAltTrapMercenary"] = { + name = "Ball Lightning of Orbiting Trap", + hidden = true, + mercenary = true, + inheritedFrom = "BallLightningAltX", + color = 3, + baseEffectiveness = 0.46999999880791, + incrementalEffectiveness = 0.044300001114607, + description = "Fires a single projectile which moves in a spiral while damaging each enemy in an area around it repeatedly with bolts of lightning.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.ProjectileSpiral] = true, [SkillType.ProjectilesNumberModifiersNotApplied] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 20 }, + { "active_skill_projectile_speed_+%_final", 100 }, + { "active_skill_projectile_speed_+%_variation_final", 30 }, + { "ball_lightning_projectile_speed_and_hit_frequency_+%_final", 33 }, + { "base_trap_duration", 4000 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "base_is_projectile", + "modifiers_to_projectile_count_do_not_apply", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.10000000149012, 1.8999999761581, critChance = 5, damageEffectiveness = 0.5, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["BaneMercenary"] = { + name = "Bane", + hidden = true, + mercenary = true, + inheritedFrom = "Bane", + color = 3, + baseEffectiveness = 6.3354997634888, + incrementalEffectiveness = 0.045299999415874, + description = "Applies a debuff to enemies in an area, which deals chaos damage over Time. Linked hex curses are also applied to those enemies. The debuff deals more damage and lasts longer for each hex applied this way. This skill cannot be used by Totems, Traps, or Mines.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.Triggerable] = true, [SkillType.DegenOnlySpellDamage] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "active_skill_base_area_of_effect_radius", 21 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "active_skill_base_area_of_effect_radius", + "dark_ritual_damage_+%_final_per_curse_applied", + "spell_damage_modifiers_apply_to_skill_dot", + }, + levels = { + [1] = { 16.666667039196, 0, 28, levelRequirement = 24, statInterpolation = { 3, 1, 1, }, }, + [2] = { 16.666667039196, 0, 28, levelRequirement = 27, statInterpolation = { 3, 1, 1, }, }, + [3] = { 16.666667039196, 0, 29, levelRequirement = 30, statInterpolation = { 3, 1, 1, }, }, + [4] = { 16.666667039196, 0, 30, levelRequirement = 33, statInterpolation = { 3, 1, 1, }, }, + [5] = { 16.666667039196, 0, 31, levelRequirement = 36, statInterpolation = { 3, 1, 1, }, }, + [6] = { 16.666667039196, 1, 31, levelRequirement = 39, statInterpolation = { 3, 1, 1, }, }, + [7] = { 16.666667039196, 1, 32, levelRequirement = 42, statInterpolation = { 3, 1, 1, }, }, + [8] = { 16.666667039196, 1, 33, levelRequirement = 45, statInterpolation = { 3, 1, 1, }, }, + [9] = { 16.666667039196, 1, 34, levelRequirement = 48, statInterpolation = { 3, 1, 1, }, }, + [10] = { 16.666667039196, 1, 34, levelRequirement = 50, statInterpolation = { 3, 1, 1, }, }, + [11] = { 16.666667039196, 2, 35, levelRequirement = 52, statInterpolation = { 3, 1, 1, }, }, + [12] = { 16.666667039196, 2, 36, levelRequirement = 54, statInterpolation = { 3, 1, 1, }, }, + [13] = { 16.666667039196, 2, 37, levelRequirement = 56, statInterpolation = { 3, 1, 1, }, }, + [14] = { 16.666667039196, 2, 37, levelRequirement = 58, statInterpolation = { 3, 1, 1, }, }, + [15] = { 16.666667039196, 2, 38, levelRequirement = 60, statInterpolation = { 3, 1, 1, }, }, + [16] = { 16.666667039196, 3, 39, levelRequirement = 62, statInterpolation = { 3, 1, 1, }, }, + [17] = { 16.666667039196, 3, 40, levelRequirement = 64, statInterpolation = { 3, 1, 1, }, }, + [18] = { 16.666667039196, 3, 40, levelRequirement = 66, statInterpolation = { 3, 1, 1, }, }, + [19] = { 16.666667039196, 3, 41, levelRequirement = 68, statInterpolation = { 3, 1, 1, }, }, + [20] = { 16.666667039196, 3, 42, levelRequirement = 70, statInterpolation = { 3, 1, 1, }, }, + [21] = { 16.666667039196, 4, 43, levelRequirement = 72, statInterpolation = { 3, 1, 1, }, }, + [22] = { 16.666667039196, 4, 43, levelRequirement = 74, statInterpolation = { 3, 1, 1, }, }, + [23] = { 16.666667039196, 4, 44, levelRequirement = 76, statInterpolation = { 3, 1, 1, }, }, + [24] = { 16.666667039196, 4, 45, levelRequirement = 78, statInterpolation = { 3, 1, 1, }, }, + [25] = { 16.666667039196, 4, 46, levelRequirement = 80, statInterpolation = { 3, 1, 1, }, }, + [26] = { 16.666667039196, 5, 46, levelRequirement = 82, statInterpolation = { 3, 1, 1, }, }, + [27] = { 16.666667039196, 5, 47, levelRequirement = 84, statInterpolation = { 3, 1, 1, }, }, + [28] = { 16.666667039196, 5, 48, levelRequirement = 86, statInterpolation = { 3, 1, 1, }, }, + [29] = { 16.666667039196, 5, 49, levelRequirement = 88, statInterpolation = { 3, 1, 1, }, }, + [30] = { 16.666667039196, 5, 49, levelRequirement = 90, statInterpolation = { 3, 1, 1, }, }, + [31] = { 16.666667039196, 5, 50, levelRequirement = 91, statInterpolation = { 3, 1, 1, }, }, + [32] = { 16.666667039196, 6, 50, levelRequirement = 92, statInterpolation = { 3, 1, 1, }, }, + [33] = { 16.666667039196, 6, 50, levelRequirement = 93, statInterpolation = { 3, 1, 1, }, }, + [34] = { 16.666667039196, 6, 51, levelRequirement = 94, statInterpolation = { 3, 1, 1, }, }, + [35] = { 16.666667039196, 6, 51, levelRequirement = 95, statInterpolation = { 3, 1, 1, }, }, + [36] = { 16.666667039196, 6, 52, levelRequirement = 96, statInterpolation = { 3, 1, 1, }, }, + [37] = { 16.666667039196, 6, 52, levelRequirement = 97, statInterpolation = { 3, 1, 1, }, }, + [38] = { 16.666667039196, 6, 52, levelRequirement = 98, statInterpolation = { 3, 1, 1, }, }, + [39] = { 16.666667039196, 6, 53, levelRequirement = 99, statInterpolation = { 3, 1, 1, }, }, + [40] = { 16.666667039196, 6, 53, levelRequirement = 100, statInterpolation = { 3, 1, 1, }, }, + }, +} + +skills["BaneMercenaryEncounter"] = { + name = "Bane", + hidden = true, + mercenary = true, + inheritedFrom = "Bane", + color = 3, + baseEffectiveness = 3.0999999046326, + incrementalEffectiveness = 0.04450000077486, + description = "Applies a debuff to enemies in an area, which deals chaos damage over Time. Linked hex curses are also applied to those enemies. The debuff deals more damage and lasts longer for each hex applied this way. This skill cannot be used by Totems, Traps, or Mines.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.Triggerable] = true, [SkillType.DegenOnlySpellDamage] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "active_skill_base_area_of_effect_radius", 21 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "active_skill_base_area_of_effect_radius", + "dark_ritual_damage_+%_final_per_curse_applied", + "spell_damage_modifiers_apply_to_skill_dot", + }, + levels = { + [1] = { 16.666667039196, 0, 20, levelRequirement = 24, statInterpolation = { 3, 1, 1, }, }, + [2] = { 16.666667039196, 0, 20, levelRequirement = 27, statInterpolation = { 3, 1, 1, }, }, + [3] = { 16.666667039196, 0, 20, levelRequirement = 30, statInterpolation = { 3, 1, 1, }, }, + [4] = { 16.666667039196, 0, 21, levelRequirement = 33, statInterpolation = { 3, 1, 1, }, }, + [5] = { 16.666667039196, 0, 21, levelRequirement = 36, statInterpolation = { 3, 1, 1, }, }, + [6] = { 16.666667039196, 1, 21, levelRequirement = 39, statInterpolation = { 3, 1, 1, }, }, + [7] = { 16.666667039196, 1, 22, levelRequirement = 42, statInterpolation = { 3, 1, 1, }, }, + [8] = { 16.666667039196, 1, 22, levelRequirement = 45, statInterpolation = { 3, 1, 1, }, }, + [9] = { 16.666667039196, 1, 22, levelRequirement = 48, statInterpolation = { 3, 1, 1, }, }, + [10] = { 16.666667039196, 1, 23, levelRequirement = 50, statInterpolation = { 3, 1, 1, }, }, + [11] = { 16.666667039196, 2, 23, levelRequirement = 52, statInterpolation = { 3, 1, 1, }, }, + [12] = { 16.666667039196, 2, 23, levelRequirement = 54, statInterpolation = { 3, 1, 1, }, }, + [13] = { 16.666667039196, 2, 24, levelRequirement = 56, statInterpolation = { 3, 1, 1, }, }, + [14] = { 16.666667039196, 2, 24, levelRequirement = 58, statInterpolation = { 3, 1, 1, }, }, + [15] = { 16.666667039196, 2, 24, levelRequirement = 60, statInterpolation = { 3, 1, 1, }, }, + [16] = { 16.666667039196, 3, 25, levelRequirement = 62, statInterpolation = { 3, 1, 1, }, }, + [17] = { 16.666667039196, 3, 25, levelRequirement = 64, statInterpolation = { 3, 1, 1, }, }, + [18] = { 16.666667039196, 3, 25, levelRequirement = 66, statInterpolation = { 3, 1, 1, }, }, + [19] = { 16.666667039196, 3, 26, levelRequirement = 68, statInterpolation = { 3, 1, 1, }, }, + [20] = { 16.666667039196, 3, 26, levelRequirement = 70, statInterpolation = { 3, 1, 1, }, }, + [21] = { 16.666667039196, 4, 26, levelRequirement = 72, statInterpolation = { 3, 1, 1, }, }, + [22] = { 16.666667039196, 4, 27, levelRequirement = 74, statInterpolation = { 3, 1, 1, }, }, + [23] = { 16.666667039196, 4, 27, levelRequirement = 76, statInterpolation = { 3, 1, 1, }, }, + [24] = { 16.666667039196, 4, 27, levelRequirement = 78, statInterpolation = { 3, 1, 1, }, }, + [25] = { 16.666667039196, 4, 28, levelRequirement = 80, statInterpolation = { 3, 1, 1, }, }, + [26] = { 16.666667039196, 5, 28, levelRequirement = 82, statInterpolation = { 3, 1, 1, }, }, + [27] = { 16.666667039196, 5, 28, levelRequirement = 84, statInterpolation = { 3, 1, 1, }, }, + [28] = { 16.666667039196, 5, 29, levelRequirement = 86, statInterpolation = { 3, 1, 1, }, }, + [29] = { 16.666667039196, 5, 29, levelRequirement = 88, statInterpolation = { 3, 1, 1, }, }, + [30] = { 16.666667039196, 5, 29, levelRequirement = 90, statInterpolation = { 3, 1, 1, }, }, + [31] = { 16.666667039196, 5, 30, levelRequirement = 91, statInterpolation = { 3, 1, 1, }, }, + [32] = { 16.666667039196, 6, 30, levelRequirement = 92, statInterpolation = { 3, 1, 1, }, }, + [33] = { 16.666667039196, 6, 30, levelRequirement = 93, statInterpolation = { 3, 1, 1, }, }, + [34] = { 16.666667039196, 6, 30, levelRequirement = 94, statInterpolation = { 3, 1, 1, }, }, + [35] = { 16.666667039196, 6, 30, levelRequirement = 95, statInterpolation = { 3, 1, 1, }, }, + [36] = { 16.666667039196, 6, 30, levelRequirement = 96, statInterpolation = { 3, 1, 1, }, }, + [37] = { 16.666667039196, 6, 30, levelRequirement = 97, statInterpolation = { 3, 1, 1, }, }, + [38] = { 16.666667039196, 6, 30, levelRequirement = 98, statInterpolation = { 3, 1, 1, }, }, + [39] = { 16.666667039196, 6, 30, levelRequirement = 99, statInterpolation = { 3, 1, 1, }, }, + [40] = { 16.666667039196, 6, 30, levelRequirement = 100, statInterpolation = { 3, 1, 1, }, }, + }, +} + +skills["BarrageAltMercenary"] = { + name = "Barrage of Volley Fire", + hidden = true, + mercenary = true, + inheritedFrom = "BarrageAltX", + color = 2, + description = "After a short preparation time, you fire projectiles repeatedly with a Bow or Wand. These projectiles have a small randomised spread. This skill cannot be Triggered.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.WandAttack] = true, }, + weaponTypes = { + ["Bow"] = true, + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "base_number_of_projectiles", 4 }, + { "barrage_final_volley_fires_x_additional_projectiles_simultaneously", 6 }, + }, + stats = { + "skill_can_fire_arrows", + "skill_can_fire_wand_projectiles", + "projectiles_barrage", + }, + levels = { + [1] = { baseMultiplier = 0.5, damageEffectiveness = 0.5, levelRequirement = 12, }, + [2] = { baseMultiplier = 0.505, damageEffectiveness = 0.505, levelRequirement = 15, }, + [3] = { baseMultiplier = 0.511, damageEffectiveness = 0.511, levelRequirement = 19, }, + [4] = { baseMultiplier = 0.516, damageEffectiveness = 0.516, levelRequirement = 23, }, + [5] = { baseMultiplier = 0.521, damageEffectiveness = 0.521, levelRequirement = 27, }, + [6] = { baseMultiplier = 0.526, damageEffectiveness = 0.526, levelRequirement = 31, }, + [7] = { baseMultiplier = 0.532, damageEffectiveness = 0.532, levelRequirement = 35, }, + [8] = { baseMultiplier = 0.537, damageEffectiveness = 0.537, levelRequirement = 38, }, + [9] = { baseMultiplier = 0.542, damageEffectiveness = 0.542, levelRequirement = 41, }, + [10] = { baseMultiplier = 0.547, damageEffectiveness = 0.547, levelRequirement = 44, }, + [11] = { baseMultiplier = 0.553, damageEffectiveness = 0.553, levelRequirement = 47, }, + [12] = { baseMultiplier = 0.558, damageEffectiveness = 0.558, levelRequirement = 50, }, + [13] = { baseMultiplier = 0.563, damageEffectiveness = 0.563, levelRequirement = 53, }, + [14] = { baseMultiplier = 0.568, damageEffectiveness = 0.568, levelRequirement = 56, }, + [15] = { baseMultiplier = 0.574, damageEffectiveness = 0.574, levelRequirement = 59, }, + [16] = { baseMultiplier = 0.579, damageEffectiveness = 0.579, levelRequirement = 62, }, + [17] = { baseMultiplier = 0.584, damageEffectiveness = 0.584, levelRequirement = 64, }, + [18] = { baseMultiplier = 0.589, damageEffectiveness = 0.589, levelRequirement = 66, }, + [19] = { baseMultiplier = 0.595, damageEffectiveness = 0.595, levelRequirement = 68, }, + [20] = { baseMultiplier = 0.6, damageEffectiveness = 0.6, levelRequirement = 70, }, + [21] = { baseMultiplier = 0.605, damageEffectiveness = 0.605, levelRequirement = 72, }, + [22] = { baseMultiplier = 0.611, damageEffectiveness = 0.611, levelRequirement = 74, }, + [23] = { baseMultiplier = 0.616, damageEffectiveness = 0.616, levelRequirement = 76, }, + [24] = { baseMultiplier = 0.621, damageEffectiveness = 0.621, levelRequirement = 78, }, + [25] = { baseMultiplier = 0.626, damageEffectiveness = 0.626, levelRequirement = 80, }, + [26] = { baseMultiplier = 0.632, damageEffectiveness = 0.632, levelRequirement = 82, }, + [27] = { baseMultiplier = 0.637, damageEffectiveness = 0.637, levelRequirement = 84, }, + [28] = { baseMultiplier = 0.642, damageEffectiveness = 0.642, levelRequirement = 86, }, + [29] = { baseMultiplier = 0.647, damageEffectiveness = 0.647, levelRequirement = 88, }, + [30] = { baseMultiplier = 0.653, damageEffectiveness = 0.653, levelRequirement = 90, }, + [31] = { baseMultiplier = 0.655, damageEffectiveness = 0.655, levelRequirement = 91, }, + [32] = { baseMultiplier = 0.658, damageEffectiveness = 0.658, levelRequirement = 92, }, + [33] = { baseMultiplier = 0.661, damageEffectiveness = 0.661, levelRequirement = 93, }, + [34] = { baseMultiplier = 0.663, damageEffectiveness = 0.663, levelRequirement = 94, }, + [35] = { baseMultiplier = 0.666, damageEffectiveness = 0.666, levelRequirement = 95, }, + [36] = { baseMultiplier = 0.668, damageEffectiveness = 0.668, levelRequirement = 96, }, + [37] = { baseMultiplier = 0.671, damageEffectiveness = 0.671, levelRequirement = 97, }, + [38] = { baseMultiplier = 0.674, damageEffectiveness = 0.674, levelRequirement = 98, }, + [39] = { baseMultiplier = 0.676, damageEffectiveness = 0.676, levelRequirement = 99, }, + [40] = { baseMultiplier = 0.679, damageEffectiveness = 0.679, levelRequirement = 100, }, + }, +} + +skills["BarrageMercenary"] = { + name = "Barrage", + hidden = true, + mercenary = true, + inheritedFrom = "Barrage", + color = 2, + description = "After a short preparation time, you fire individual projectiles repeatedly with a Bow or Wand. These projectiles have a small randomised spread. This skill cannot be Triggered.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.WandAttack] = true, }, + weaponTypes = { + ["Bow"] = true, + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "base_number_of_projectiles", 4 }, + }, + stats = { + "skill_can_fire_arrows", + "skill_can_fire_wand_projectiles", + "projectiles_barrage", + "no_barrage_projectile_spread", + }, + levels = { + [1] = { baseMultiplier = 0.47, damageEffectiveness = 0.47, levelRequirement = 12, }, + [2] = { baseMultiplier = 0.474, damageEffectiveness = 0.47, levelRequirement = 15, }, + [3] = { baseMultiplier = 0.478, damageEffectiveness = 0.48, levelRequirement = 19, }, + [4] = { baseMultiplier = 0.482, damageEffectiveness = 0.48, levelRequirement = 23, }, + [5] = { baseMultiplier = 0.486, damageEffectiveness = 0.49, levelRequirement = 27, }, + [6] = { baseMultiplier = 0.49, damageEffectiveness = 0.49, levelRequirement = 31, }, + [7] = { baseMultiplier = 0.494, damageEffectiveness = 0.49, levelRequirement = 35, }, + [8] = { baseMultiplier = 0.498, damageEffectiveness = 0.5, levelRequirement = 38, }, + [9] = { baseMultiplier = 0.502, damageEffectiveness = 0.5, levelRequirement = 41, }, + [10] = { baseMultiplier = 0.506, damageEffectiveness = 0.51, levelRequirement = 44, }, + [11] = { baseMultiplier = 0.51, damageEffectiveness = 0.51, levelRequirement = 47, }, + [12] = { baseMultiplier = 0.514, damageEffectiveness = 0.51, levelRequirement = 50, }, + [13] = { baseMultiplier = 0.518, damageEffectiveness = 0.52, levelRequirement = 53, }, + [14] = { baseMultiplier = 0.522, damageEffectiveness = 0.52, levelRequirement = 56, }, + [15] = { baseMultiplier = 0.526, damageEffectiveness = 0.53, levelRequirement = 59, }, + [16] = { baseMultiplier = 0.53, damageEffectiveness = 0.53, levelRequirement = 62, }, + [17] = { baseMultiplier = 0.534, damageEffectiveness = 0.53, levelRequirement = 64, }, + [18] = { baseMultiplier = 0.538, damageEffectiveness = 0.54, levelRequirement = 66, }, + [19] = { baseMultiplier = 0.542, damageEffectiveness = 0.54, levelRequirement = 68, }, + [20] = { baseMultiplier = 0.546, damageEffectiveness = 0.55, levelRequirement = 70, }, + [21] = { baseMultiplier = 0.55, damageEffectiveness = 0.55, levelRequirement = 72, }, + [22] = { baseMultiplier = 0.554, damageEffectiveness = 0.55, levelRequirement = 74, }, + [23] = { baseMultiplier = 0.558, damageEffectiveness = 0.56, levelRequirement = 76, }, + [24] = { baseMultiplier = 0.562, damageEffectiveness = 0.56, levelRequirement = 78, }, + [25] = { baseMultiplier = 0.566, damageEffectiveness = 0.57, levelRequirement = 80, }, + [26] = { baseMultiplier = 0.57, damageEffectiveness = 0.57, levelRequirement = 82, }, + [27] = { baseMultiplier = 0.574, damageEffectiveness = 0.57, levelRequirement = 84, }, + [28] = { baseMultiplier = 0.578, damageEffectiveness = 0.58, levelRequirement = 86, }, + [29] = { baseMultiplier = 0.582, damageEffectiveness = 0.58, levelRequirement = 88, }, + [30] = { baseMultiplier = 0.586, damageEffectiveness = 0.59, levelRequirement = 90, }, + [31] = { baseMultiplier = 0.588, damageEffectiveness = 0.59, levelRequirement = 91, }, + [32] = { baseMultiplier = 0.59, damageEffectiveness = 0.59, levelRequirement = 92, }, + [33] = { baseMultiplier = 0.592, damageEffectiveness = 0.59, levelRequirement = 93, }, + [34] = { baseMultiplier = 0.594, damageEffectiveness = 0.59, levelRequirement = 94, }, + [35] = { baseMultiplier = 0.596, damageEffectiveness = 0.6, levelRequirement = 95, }, + [36] = { baseMultiplier = 0.598, damageEffectiveness = 0.6, levelRequirement = 96, }, + [37] = { baseMultiplier = 0.6, damageEffectiveness = 0.6, levelRequirement = 97, }, + [38] = { baseMultiplier = 0.602, damageEffectiveness = 0.6, levelRequirement = 98, }, + [39] = { baseMultiplier = 0.604, damageEffectiveness = 0.6, levelRequirement = 99, }, + [40] = { baseMultiplier = 0.606, damageEffectiveness = 0.61, levelRequirement = 100, }, + }, +} + +skills["BattlemagesCryMercenary"] = { + name = "Battlemage's Cry", + hidden = true, + mercenary = true, + inheritedFrom = "BattlemagesCry", + color = 1, + description = "Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. The user and nearby allies gain a buff that boosts critical strike chance.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "skill_empowers_next_x_melee_attacks", 5 }, + { "divine_cry_additional_base_critical_strike_chance_per_5_power_up_to_cap", 50 }, + }, + stats = { + "warcry_speed_+%", + "base_skill_effect_duration", + "base_deal_no_attack_damage", + "base_deal_no_spell_damage", + "base_deal_no_secondary_damage", + "cannot_cancel_skill_before_contact_point", + "warcry_count_power_from_enemies", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 0, 2500, cooldown = 8, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 2, 2500, cooldown = 8, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 4, 2600, cooldown = 8, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 6, 2600, cooldown = 8, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 8, 2700, cooldown = 8, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 10, 2700, cooldown = 8, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 12, 2800, cooldown = 8, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 14, 2800, cooldown = 8, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 16, 2900, cooldown = 8, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 18, 2900, cooldown = 8, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 20, 3000, cooldown = 8, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 22, 3000, cooldown = 8, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 24, 3100, cooldown = 8, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 26, 3100, cooldown = 8, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 28, 3200, cooldown = 8, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 30, 3200, cooldown = 8, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 32, 3300, cooldown = 8, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 34, 3300, cooldown = 8, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 36, 3400, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 38, 3400, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 40, 3500, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 41, 3500, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 42, 3600, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 43, 3600, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 44, 3700, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 45, 3700, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 46, 3800, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 47, 3800, cooldown = 8, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 48, 3900, cooldown = 8, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 49, 3900, cooldown = 8, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 49, 3900, cooldown = 8, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 50, 4000, cooldown = 8, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 50, 4000, cooldown = 8, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 51, 4000, cooldown = 8, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 51, 4000, cooldown = 8, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 52, 4100, cooldown = 8, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 52, 4100, cooldown = 8, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 53, 4100, cooldown = 8, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 53, 4100, cooldown = 8, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 54, 4200, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["BearTrapMercenary"] = { + name = "Bear Trap", + hidden = true, + mercenary = true, + inheritedFrom = "BearTrap", + color = 2, + baseEffectiveness = 2.8499999046326, + incrementalEffectiveness = 0.042500000447035, + description = "Throws a trap that damages and immobilises a single enemy for a duration based on how much damage was dealt. After the immobilise expires, a debuff remains on the enemy for a duration, lowering their movement speed by an amount which lessens over time. The affected enemy will take increased damage from traps and mines until the debuff expires. Modifiers to spell damage do not affect this skill's damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Duration] = true, [SkillType.Mineable] = true, [SkillType.Trapped] = true, [SkillType.Damage] = true, [SkillType.Physical] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + duration = true, + spell = true, + trap = true, + }, + constantStats = { + { "base_trap_duration", 4000 }, + { "trap_override_pvp_scaling_time_ms", 750 }, + { "bear_trap_damage_taken_+%_from_traps_and_mines", 25 }, + { "bear_trap_movement_speed_+%_final", -80 }, + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "secondary_minimum_base_physical_damage", + "secondary_maximum_base_physical_damage", + "base_skill_is_trapped", + "display_skill_deals_secondary_damage", + "base_skill_show_average_damage_instead_of_dps", + "no_movement_speed", + "traps_do_not_explode_on_timeout", + "is_trap", + "quality_display_trap_duration_is_gem", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "secondary_minimum_base_physical_damage", + "secondary_maximum_base_physical_damage", + }, + levels = { + [1] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, 3, }, }, + [2] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 6, storedUses = 1, statInterpolation = { 3, 3, }, }, + [3] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 9, storedUses = 1, statInterpolation = { 3, 3, }, }, + [4] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, }, }, + [5] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, }, }, + [6] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, }, }, + [7] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, }, }, + [8] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, }, }, + [9] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, 3, }, }, + [10] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, }, }, + [11] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, }, }, + [12] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, }, }, + [13] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, }, }, + [14] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, }, }, + [15] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, }, }, + [16] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, }, }, + [17] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 61, storedUses = 1, statInterpolation = { 3, 3, }, }, + [18] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, }, }, + [19] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, }, }, + [20] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, }, }, + [21] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, }, }, + [22] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, }, }, + [23] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, }, }, + [24] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, }, }, + [25] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, }, }, + [26] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, }, }, + [27] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, }, }, + [28] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, }, }, + [29] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, }, }, + [30] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, }, }, + [31] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, }, }, + [32] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, }, }, + [33] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, }, }, + [34] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, }, }, + [35] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, }, }, + [36] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, }, }, + [37] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, }, }, + [38] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, }, }, + [39] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, }, }, + [40] = { 1, 1.3999999761581, cooldown = 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["BladeTrapMercenary"] = { + name = "Blade Trap", + hidden = true, + mercenary = true, + inheritedFrom = "BladeTrap", + color = 2, + description = "Throws a trap which, once triggered, swings two copies of your equipped Dagger, Claw or One Handed Sword around it in circles, each repeatedly damaging enemies it spins through.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Damage] = true, [SkillType.Mineable] = true, [SkillType.Area] = true, [SkillType.Trapped] = true, [SkillType.Area] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + trap = true, + }, + constantStats = { + { "base_trap_duration", 4000 }, + { "base_weapon_trap_total_rotation_%", 400 }, + { "weapon_trap_total_rotation_%_if_dual_wielding", 100 }, + { "weapon_trap_rotation_speed_+%_if_dual_wielding", 25 }, + { "trap_variation", 18 }, + { "active_skill_base_area_of_effect_radius", 16 }, + }, + stats = { + "active_skill_base_area_of_effect_radius", + "is_area_damage", + "attack_is_not_melee_override", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + levels = { + [1] = { 0, baseMultiplier = 0.76, damageEffectiveness = 0.76, levelRequirement = 12, statInterpolation = { 1, }, }, + [2] = { 0, baseMultiplier = 0.779, damageEffectiveness = 0.779, levelRequirement = 15, statInterpolation = { 1, }, }, + [3] = { 1, baseMultiplier = 0.798, damageEffectiveness = 0.798, levelRequirement = 19, statInterpolation = { 1, }, }, + [4] = { 1, baseMultiplier = 0.817, damageEffectiveness = 0.817, levelRequirement = 23, statInterpolation = { 1, }, }, + [5] = { 1, baseMultiplier = 0.836, damageEffectiveness = 0.836, levelRequirement = 27, statInterpolation = { 1, }, }, + [6] = { 2, baseMultiplier = 0.855, damageEffectiveness = 0.855, levelRequirement = 31, statInterpolation = { 1, }, }, + [7] = { 2, baseMultiplier = 0.874, damageEffectiveness = 0.874, levelRequirement = 35, statInterpolation = { 1, }, }, + [8] = { 2, baseMultiplier = 0.893, damageEffectiveness = 0.893, levelRequirement = 38, statInterpolation = { 1, }, }, + [9] = { 3, baseMultiplier = 0.912, damageEffectiveness = 0.912, levelRequirement = 41, statInterpolation = { 1, }, }, + [10] = { 3, baseMultiplier = 0.931, damageEffectiveness = 0.931, levelRequirement = 44, statInterpolation = { 1, }, }, + [11] = { 3, baseMultiplier = 0.949, damageEffectiveness = 0.949, levelRequirement = 47, statInterpolation = { 1, }, }, + [12] = { 4, baseMultiplier = 0.968, damageEffectiveness = 0.968, levelRequirement = 50, statInterpolation = { 1, }, }, + [13] = { 4, baseMultiplier = 0.987, damageEffectiveness = 0.987, levelRequirement = 53, statInterpolation = { 1, }, }, + [14] = { 4, baseMultiplier = 1.006, damageEffectiveness = 1.006, levelRequirement = 56, statInterpolation = { 1, }, }, + [15] = { 5, baseMultiplier = 1.025, damageEffectiveness = 1.025, levelRequirement = 59, statInterpolation = { 1, }, }, + [16] = { 5, baseMultiplier = 1.044, damageEffectiveness = 1.044, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 5, baseMultiplier = 1.063, damageEffectiveness = 1.063, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 6, baseMultiplier = 1.082, damageEffectiveness = 1.082, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 6, baseMultiplier = 1.101, damageEffectiveness = 1.101, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 6, baseMultiplier = 1.12, damageEffectiveness = 1.12, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 7, baseMultiplier = 1.139, damageEffectiveness = 1.139, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 7, baseMultiplier = 1.158, damageEffectiveness = 1.158, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 7, baseMultiplier = 1.177, damageEffectiveness = 1.177, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 8, baseMultiplier = 1.196, damageEffectiveness = 1.196, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 8, baseMultiplier = 1.215, damageEffectiveness = 1.215, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 8, baseMultiplier = 1.234, damageEffectiveness = 1.234, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 9, baseMultiplier = 1.253, damageEffectiveness = 1.253, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 9, baseMultiplier = 1.272, damageEffectiveness = 1.272, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 9, baseMultiplier = 1.291, damageEffectiveness = 1.291, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 10, baseMultiplier = 1.309, damageEffectiveness = 1.309, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 10, baseMultiplier = 1.319, damageEffectiveness = 1.319, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 10, baseMultiplier = 1.328, damageEffectiveness = 1.328, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 10, baseMultiplier = 1.338, damageEffectiveness = 1.338, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 10, baseMultiplier = 1.347, damageEffectiveness = 1.347, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 10, baseMultiplier = 1.357, damageEffectiveness = 1.357, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 11, baseMultiplier = 1.366, damageEffectiveness = 1.366, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 11, baseMultiplier = 1.376, damageEffectiveness = 1.376, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 11, baseMultiplier = 1.385, damageEffectiveness = 1.385, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 11, baseMultiplier = 1.395, damageEffectiveness = 1.395, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 11, baseMultiplier = 1.404, damageEffectiveness = 1.404, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["BladeVortexAltMercenary"] = { + name = "Corrupted Blade Vortex of the Scythe", + hidden = true, + mercenary = true, + inheritedFrom = "BladeVortexAltX", + color = 2, + baseEffectiveness = 2.1624999046326, + incrementalEffectiveness = 0.042899999767542, + description = "This spell creates a swarm of ethereal blades which briefly orbit in an area around you, dealing damage every 0.6 seconds to all enemies in their radius.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.TotemCastsAlone] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "maximum_number_of_spinning_blades", 1 }, + { "base_skill_effect_duration", 1500 }, + { "corrupted_blood_on_hit_num_stacks", 1 }, + { "corrupted_blood_on_hit_duration", 3000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + "corrupted_blood_on_hit_%_average_damage_to_deal_per_minute_per_stack", + "is_area_damage", + "damage_originates_from_initiator_location", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 10, 150, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 10, 162, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 15, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 11, 174, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 19, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 11, 186, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 23, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 12, 198, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 12, 210, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 13, 222, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 35, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 13, 234, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 14, 246, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 41, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 14, 258, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 15, 270, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 47, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 15, 282, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 16, 294, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 53, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 16, 306, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 17, 318, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 59, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 17, 330, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 18, 342, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 18, 354, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 19, 366, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 19, 378, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 20, 390, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 20, 402, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 21, 414, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 21, 426, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 22, 438, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 22, 450, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 23, 462, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 23, 474, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 24, 486, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 24, 498, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 25, 510, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 25, 522, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 25, 534, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 25, 546, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 26, 558, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 26, 570, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 26, 582, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 26, 594, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 27, 606, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 27, 618, cooldown = 1, critChance = 10, damageEffectiveness = 2, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["BladeVortexAltMercenaryEncounter"] = { + name = "Corrupted Blade Vortex of the Scythe", + hidden = true, + mercenary = true, + inheritedFrom = "BladeVortexAltX", + color = 2, + baseEffectiveness = 2.1500000953674, + incrementalEffectiveness = 0.030999999493361, + description = "This spell creates a swarm of ethereal blades which briefly orbit in an area around you, dealing damage every 0.6 seconds to all enemies in their radius.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.TotemCastsAlone] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "maximum_number_of_spinning_blades", 1 }, + { "base_skill_effect_duration", 1500 }, + { "corrupted_blood_on_hit_num_stacks", 1 }, + { "corrupted_blood_on_hit_duration", 3000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + "corrupted_blood_on_hit_%_average_damage_to_deal_per_minute_per_stack", + "is_area_damage", + "damage_originates_from_initiator_location", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 15, 10, cooldown = 1, critChance = 10, damageEffectiveness = 1.5, levelRequirement = 0, storedUses = 1, statInterpolation = { 3, 3, 2, 2, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 100, 65, cooldown = 1, critChance = 10, damageEffectiveness = 1.5, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 2, 2, }, }, + }, +} + +skills["BladeVortexMercenary"] = { + name = "Blade Vortex", + hidden = true, + mercenary = true, + inheritedFrom = "BladeVortex", + color = 2, + baseEffectiveness = 0.33660000562668, + incrementalEffectiveness = 0.042899999767542, + description = "This spell creates ethereal blades which orbit in an area around you, dealing damage every 0.6 seconds to all enemies in their radius. As more blades are added, the damage becomes greater and more frequent.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.TotemCastsAlone] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 4000 }, + { "maximum_number_of_spinning_blades", 10 }, + { "blade_vortex_hit_rate_+%_per_blade", 30 }, + { "blade_vortex_damage_+%_per_blade_final", 30 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + "is_area_damage", + "skill_can_add_multiple_charges_per_action", + "action_ignores_crit_tracking", + "base_skill_show_average_damage_instead_of_dps", + "damage_originates_from_initiator_location", + "skill_cannot_gain_repeat_bonuses", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 0, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 0, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 0, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 1, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 1, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 1, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 1, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 1, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 1, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 1, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 2, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 2, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 2, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 2, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 2, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 2, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 2, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 3, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 3, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 3, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 3, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 3, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 3, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 3, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 4, critChance = 10, damageEffectiveness = 0.3, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["BladefallAltMercenary"] = { + name = "Bladefall of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "BladefallAltZ", + color = 2, + baseEffectiveness = 0.72079998254776, + incrementalEffectiveness = 0.045499999076128, + description = "Once activated, continuously spends mana to cause volleys of ethereal weapons rain from the sky around you, dealing damage to enemies they impact. Each Blade will target a separate enemy in the volley area if possible. Each enemy can only be hit once by each volley, even if multiple blades land near them. This skill cannot be triggered or used by Totems, Traps, or Mines.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Physical] = true, [SkillType.Cooldown] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.Instant] = true, [SkillType.Arcane] = true, [SkillType.Duration] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.2, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "mana_degeneration_per_minute_%", 360 }, + { "bladefall_base_volley_frequency_ms", 700 }, + { "bladefall_volley_frequency_+%_per_100_maximum_mana", 2 }, + { "active_skill_base_area_of_effect_radius", 20 }, + { "active_skill_base_secondary_area_of_effect_radius", 8 }, + { "bladefall_create_X_lingering_blades_per_volley", 5 }, + { "base_skill_effect_duration", 6000 }, + { "maximum_number_of_blades_left_in_ground", 40 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_area_of_effect_radius", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 9, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 9, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 9, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 9, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 10, cooldown = 1.2, critChance = 10, damageEffectiveness = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["BladefallMercenary"] = { + name = "Bladefall", + hidden = true, + mercenary = true, + inheritedFrom = "Bladefall", + color = 2, + baseEffectiveness = 1.2013000249863, + incrementalEffectiveness = 0.045499999076128, + description = "Ethereal weapons rain from the sky, dealing damage to enemies in a sequence of volleys. Enemies can be hit multiple times where these overlap.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.Duration] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "bladefall_number_of_volleys", 5 }, + { "bladefall_blade_left_in_ground_for_every_X_volleys", 1 }, + { "maximum_number_of_blades_left_in_ground", 40 }, + { "base_skill_effect_duration", 6000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 10, damageEffectiveness = 1.4, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["BladestormMercenary"] = { + name = "Bladestorm", + hidden = true, + mercenary = true, + inheritedFrom = "Bladestorm", + color = 1, + description = "Perform a spinning attack, damaging enemies around you and creating a bladestorm matching your stance. The bladestorm repeatedly damages enemies, based on your weapon damage and attack time, for a duration. Blood bladestorms are stationary and cause Bleeding, while Sand bladestorms move slowly forwards and Blind enemies. Requires a Sword or Axe. You are in Blood Stance by default.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Multistrikeable] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "bladestorm_storm_damage_+%_final", -50 }, + { "bladestorm_maximum_number_of_storms_allowed", 3 }, + { "blind_art_variation", 1 }, + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "bladestorm_attack_speed_+%_final_while_in_bloodstorm", + "bladestorm_movement_speed_+%_while_in_sandstorm", + "active_skill_bleeding_damage_+%_final_in_blood_stance", + "is_area_damage", + "skill_can_add_multiple_charges_per_action", + }, + levels = { + [1] = { 10, 30, 70, baseMultiplier = 1.59, damageEffectiveness = 1.59, levelRequirement = 28, statInterpolation = { 1, 1, 1, }, }, + [2] = { 10, 30, 72, baseMultiplier = 1.643, damageEffectiveness = 1.643, levelRequirement = 31, statInterpolation = { 1, 1, 1, }, }, + [3] = { 10, 31, 74, baseMultiplier = 1.7, damageEffectiveness = 1.7, levelRequirement = 34, statInterpolation = { 1, 1, 1, }, }, + [4] = { 10, 31, 76, baseMultiplier = 1.758, damageEffectiveness = 1.758, levelRequirement = 37, statInterpolation = { 1, 1, 1, }, }, + [5] = { 10, 32, 78, baseMultiplier = 1.817, damageEffectiveness = 1.817, levelRequirement = 40, statInterpolation = { 1, 1, 1, }, }, + [6] = { 10, 32, 80, baseMultiplier = 1.875, damageEffectiveness = 1.875, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [7] = { 11, 32, 82, baseMultiplier = 1.936, damageEffectiveness = 1.936, levelRequirement = 44, statInterpolation = { 1, 1, 1, }, }, + [8] = { 11, 33, 84, baseMultiplier = 1.999, damageEffectiveness = 1.999, levelRequirement = 46, statInterpolation = { 1, 1, 1, }, }, + [9] = { 11, 33, 86, baseMultiplier = 2.062, damageEffectiveness = 2.062, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 11, 34, 88, baseMultiplier = 2.129, damageEffectiveness = 2.129, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 11, 34, 90, baseMultiplier = 2.197, damageEffectiveness = 2.197, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 11, 34, 92, baseMultiplier = 2.267, damageEffectiveness = 2.267, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 11, 35, 94, baseMultiplier = 2.34, damageEffectiveness = 2.34, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 12, 35, 96, baseMultiplier = 2.415, damageEffectiveness = 2.415, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 12, 36, 98, baseMultiplier = 2.493, damageEffectiveness = 2.493, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 12, 36, 100, baseMultiplier = 2.573, damageEffectiveness = 2.573, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 12, 36, 102, baseMultiplier = 2.656, damageEffectiveness = 2.656, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 12, 37, 104, baseMultiplier = 2.741, damageEffectiveness = 2.741, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 12, 37, 106, baseMultiplier = 2.829, damageEffectiveness = 2.829, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 12, 38, 108, baseMultiplier = 2.919, damageEffectiveness = 2.919, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 13, 38, 110, baseMultiplier = 3.013, damageEffectiveness = 3.013, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 13, 38, 112, baseMultiplier = 3.109, damageEffectiveness = 3.109, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 13, 39, 114, baseMultiplier = 3.209, damageEffectiveness = 3.209, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 13, 39, 116, baseMultiplier = 3.312, damageEffectiveness = 3.312, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 13, 40, 118, baseMultiplier = 3.418, damageEffectiveness = 3.418, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13, 40, 120, baseMultiplier = 3.527, damageEffectiveness = 3.527, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13, 40, 122, baseMultiplier = 3.639, damageEffectiveness = 3.639, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 14, 41, 124, baseMultiplier = 3.755, damageEffectiveness = 3.755, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 14, 41, 126, baseMultiplier = 3.875, damageEffectiveness = 3.875, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 14, 42, 128, baseMultiplier = 3.999, damageEffectiveness = 3.999, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 14, 42, 129, baseMultiplier = 4.18, damageEffectiveness = 4.18, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14, 42, 130, baseMultiplier = 4.246, damageEffectiveness = 4.246, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14, 42, 131, baseMultiplier = 4.313, damageEffectiveness = 4.313, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14, 42, 132, baseMultiplier = 4.382, damageEffectiveness = 4.382, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14, 43, 133, baseMultiplier = 4.453, damageEffectiveness = 4.453, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14, 43, 134, baseMultiplier = 4.523, damageEffectiveness = 4.523, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14, 43, 135, baseMultiplier = 4.595, damageEffectiveness = 4.595, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14, 43, 136, baseMultiplier = 4.668, damageEffectiveness = 4.668, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14, 43, 137, baseMultiplier = 4.743, damageEffectiveness = 4.743, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 15, 44, 138, baseMultiplier = 4.81, damageEffectiveness = 4.81, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["BlastRainAltMercenary"] = { + name = "Blast Rain of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "BlastRainAltX", + color = 2, + baseEffectiveness = 2.4500000476837, + incrementalEffectiveness = 0.054000001400709, + description = "Fires a single arrow up in the air, to rain down at a targeted location. The arrow deals area damage around where it lands, as well as releasing a wave of fire which will apply a burning debuff to enemies. The impact of the arrow will also inflict this debuff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Fire] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.ProjectileNumber] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, [SkillType.DamageOverTime] = true, [SkillType.CausesBurning] = true, [SkillType.Duration] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + { "base_number_of_arrows", 1 }, + { "blast_rain_arrow_delay_ms", 80 }, + { "active_skill_base_area_of_effect_radius", 10 }, + { "base_skill_effect_duration", 4000 }, + { "active_skill_base_secondary_area_of_effect_radius", 35 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + "projectile_damage_modifiers_apply_to_skill_dot", + "modifiers_to_projectile_count_do_not_apply", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.9, damageEffectiveness = 0.9, levelRequirement = 28, statInterpolation = { 3, }, }, + [2] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.908, damageEffectiveness = 0.908, levelRequirement = 31, statInterpolation = { 3, }, }, + [3] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.916, damageEffectiveness = 0.916, levelRequirement = 34, statInterpolation = { 3, }, }, + [4] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.924, damageEffectiveness = 0.924, levelRequirement = 37, statInterpolation = { 3, }, }, + [5] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.932, damageEffectiveness = 0.932, levelRequirement = 40, statInterpolation = { 3, }, }, + [6] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.939, damageEffectiveness = 0.939, levelRequirement = 42, statInterpolation = { 3, }, }, + [7] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.947, damageEffectiveness = 0.947, levelRequirement = 44, statInterpolation = { 3, }, }, + [8] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.955, damageEffectiveness = 0.955, levelRequirement = 46, statInterpolation = { 3, }, }, + [9] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.963, damageEffectiveness = 0.963, levelRequirement = 48, statInterpolation = { 3, }, }, + [10] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.971, damageEffectiveness = 0.971, levelRequirement = 50, statInterpolation = { 3, }, }, + [11] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.979, damageEffectiveness = 0.979, levelRequirement = 52, statInterpolation = { 3, }, }, + [12] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.987, damageEffectiveness = 0.987, levelRequirement = 54, statInterpolation = { 3, }, }, + [13] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 0.995, damageEffectiveness = 0.995, levelRequirement = 56, statInterpolation = { 3, }, }, + [14] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.003, damageEffectiveness = 1.003, levelRequirement = 58, statInterpolation = { 3, }, }, + [15] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.011, damageEffectiveness = 1.011, levelRequirement = 60, statInterpolation = { 3, }, }, + [16] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.018, damageEffectiveness = 1.018, levelRequirement = 62, statInterpolation = { 3, }, }, + [17] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.026, damageEffectiveness = 1.026, levelRequirement = 64, statInterpolation = { 3, }, }, + [18] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.034, damageEffectiveness = 1.034, levelRequirement = 66, statInterpolation = { 3, }, }, + [19] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.042, damageEffectiveness = 1.042, levelRequirement = 68, statInterpolation = { 3, }, }, + [20] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.05, damageEffectiveness = 1.05, levelRequirement = 70, statInterpolation = { 3, }, }, + [21] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.058, damageEffectiveness = 1.058, levelRequirement = 72, statInterpolation = { 3, }, }, + [22] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.066, damageEffectiveness = 1.066, levelRequirement = 74, statInterpolation = { 3, }, }, + [23] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.074, damageEffectiveness = 1.074, levelRequirement = 76, statInterpolation = { 3, }, }, + [24] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.082, damageEffectiveness = 1.082, levelRequirement = 78, statInterpolation = { 3, }, }, + [25] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.089, damageEffectiveness = 1.089, levelRequirement = 80, statInterpolation = { 3, }, }, + [26] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.097, damageEffectiveness = 1.097, levelRequirement = 82, statInterpolation = { 3, }, }, + [27] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.105, damageEffectiveness = 1.105, levelRequirement = 84, statInterpolation = { 3, }, }, + [28] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.113, damageEffectiveness = 1.113, levelRequirement = 86, statInterpolation = { 3, }, }, + [29] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.121, damageEffectiveness = 1.121, levelRequirement = 88, statInterpolation = { 3, }, }, + [30] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.129, damageEffectiveness = 1.129, levelRequirement = 90, statInterpolation = { 3, }, }, + [31] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.133, damageEffectiveness = 1.133, levelRequirement = 91, statInterpolation = { 3, }, }, + [32] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.137, damageEffectiveness = 1.137, levelRequirement = 92, statInterpolation = { 3, }, }, + [33] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.141, damageEffectiveness = 1.141, levelRequirement = 93, statInterpolation = { 3, }, }, + [34] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.145, damageEffectiveness = 1.145, levelRequirement = 94, statInterpolation = { 3, }, }, + [35] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.149, damageEffectiveness = 1.149, levelRequirement = 95, statInterpolation = { 3, }, }, + [36] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.153, damageEffectiveness = 1.153, levelRequirement = 96, statInterpolation = { 3, }, }, + [37] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.157, damageEffectiveness = 1.157, levelRequirement = 97, statInterpolation = { 3, }, }, + [38] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.161, damageEffectiveness = 1.161, levelRequirement = 98, statInterpolation = { 3, }, }, + [39] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.164, damageEffectiveness = 1.164, levelRequirement = 99, statInterpolation = { 3, }, }, + [40] = { 80.833333550642, attackSpeedMultiplier = -20, baseMultiplier = 1.168, damageEffectiveness = 1.168, levelRequirement = 100, statInterpolation = { 3, }, }, + }, +} + +skills["BlastRainAltMercenaryEncounter"] = { + name = "Blast Rain of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "BlastRainAltX", + color = 2, + baseEffectiveness = 2.2000000476837, + incrementalEffectiveness = 0.03999999910593, + description = "Fires a single arrow up in the air, to rain down at a targeted location. The arrow deals area damage around where it lands, as well as releasing a wave of fire which will apply a burning debuff to enemies. The impact of the arrow will also inflict this debuff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Fire] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.ProjectileNumber] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, [SkillType.DamageOverTime] = true, [SkillType.CausesBurning] = true, [SkillType.Duration] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + { "base_number_of_arrows", 1 }, + { "blast_rain_arrow_delay_ms", 80 }, + { "active_skill_base_area_of_effect_radius", 10 }, + { "base_skill_effect_duration", 4000 }, + { "active_skill_base_secondary_area_of_effect_radius", 35 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + "projectile_damage_modifiers_apply_to_skill_dot", + "modifiers_to_projectile_count_do_not_apply", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.9, damageEffectiveness = 0.9, levelRequirement = 28, statInterpolation = { 3, }, }, + [2] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.908, damageEffectiveness = 0.908, levelRequirement = 31, statInterpolation = { 3, }, }, + [3] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.916, damageEffectiveness = 0.916, levelRequirement = 34, statInterpolation = { 3, }, }, + [4] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.924, damageEffectiveness = 0.924, levelRequirement = 37, statInterpolation = { 3, }, }, + [5] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.932, damageEffectiveness = 0.932, levelRequirement = 40, statInterpolation = { 3, }, }, + [6] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.939, damageEffectiveness = 0.939, levelRequirement = 42, statInterpolation = { 3, }, }, + [7] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.947, damageEffectiveness = 0.947, levelRequirement = 44, statInterpolation = { 3, }, }, + [8] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.955, damageEffectiveness = 0.955, levelRequirement = 46, statInterpolation = { 3, }, }, + [9] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.963, damageEffectiveness = 0.963, levelRequirement = 48, statInterpolation = { 3, }, }, + [10] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.971, damageEffectiveness = 0.971, levelRequirement = 50, statInterpolation = { 3, }, }, + [11] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.979, damageEffectiveness = 0.979, levelRequirement = 52, statInterpolation = { 3, }, }, + [12] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.987, damageEffectiveness = 0.987, levelRequirement = 54, statInterpolation = { 3, }, }, + [13] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 0.995, damageEffectiveness = 0.995, levelRequirement = 56, statInterpolation = { 3, }, }, + [14] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.003, damageEffectiveness = 1.003, levelRequirement = 58, statInterpolation = { 3, }, }, + [15] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.011, damageEffectiveness = 1.011, levelRequirement = 60, statInterpolation = { 3, }, }, + [16] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.018, damageEffectiveness = 1.018, levelRequirement = 62, statInterpolation = { 3, }, }, + [17] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.026, damageEffectiveness = 1.026, levelRequirement = 64, statInterpolation = { 3, }, }, + [18] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.034, damageEffectiveness = 1.034, levelRequirement = 66, statInterpolation = { 3, }, }, + [19] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.042, damageEffectiveness = 1.042, levelRequirement = 68, statInterpolation = { 3, }, }, + [20] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.05, damageEffectiveness = 1.05, levelRequirement = 70, statInterpolation = { 3, }, }, + [21] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.058, damageEffectiveness = 1.058, levelRequirement = 72, statInterpolation = { 3, }, }, + [22] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.066, damageEffectiveness = 1.066, levelRequirement = 74, statInterpolation = { 3, }, }, + [23] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.074, damageEffectiveness = 1.074, levelRequirement = 76, statInterpolation = { 3, }, }, + [24] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.082, damageEffectiveness = 1.082, levelRequirement = 78, statInterpolation = { 3, }, }, + [25] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.089, damageEffectiveness = 1.089, levelRequirement = 80, statInterpolation = { 3, }, }, + [26] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.097, damageEffectiveness = 1.097, levelRequirement = 82, statInterpolation = { 3, }, }, + [27] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.105, damageEffectiveness = 1.105, levelRequirement = 84, statInterpolation = { 3, }, }, + [28] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.113, damageEffectiveness = 1.113, levelRequirement = 86, statInterpolation = { 3, }, }, + [29] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.121, damageEffectiveness = 1.121, levelRequirement = 88, statInterpolation = { 3, }, }, + [30] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.129, damageEffectiveness = 1.129, levelRequirement = 90, statInterpolation = { 3, }, }, + [31] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.133, damageEffectiveness = 1.133, levelRequirement = 91, statInterpolation = { 3, }, }, + [32] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.137, damageEffectiveness = 1.137, levelRequirement = 92, statInterpolation = { 3, }, }, + [33] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.141, damageEffectiveness = 1.141, levelRequirement = 93, statInterpolation = { 3, }, }, + [34] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.145, damageEffectiveness = 1.145, levelRequirement = 94, statInterpolation = { 3, }, }, + [35] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.149, damageEffectiveness = 1.149, levelRequirement = 95, statInterpolation = { 3, }, }, + [36] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.153, damageEffectiveness = 1.153, levelRequirement = 96, statInterpolation = { 3, }, }, + [37] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.157, damageEffectiveness = 1.157, levelRequirement = 97, statInterpolation = { 3, }, }, + [38] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.161, damageEffectiveness = 1.161, levelRequirement = 98, statInterpolation = { 3, }, }, + [39] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.164, damageEffectiveness = 1.164, levelRequirement = 99, statInterpolation = { 3, }, }, + [40] = { 16.666667039196, attackSpeedMultiplier = -20, baseMultiplier = 1.168, damageEffectiveness = 1.168, levelRequirement = 100, statInterpolation = { 3, }, }, + }, +} + +skills["BlastRainColdMercenary"] = { + name = "Icicle Rain", + hidden = true, + mercenary = true, + inheritedFrom = "BlastRain", + color = 2, + description = "Fires arrows up in the air, to rain down in an area. Each arrow deals area damage around where it lands, and they will all overlap on the targeted location.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Fire] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.ProjectileNumber] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + }, + constantStats = { + { "base_number_of_arrows", 6 }, + { "blast_rain_arrow_delay_ms", 80 }, + { "skill_physical_damage_%_to_convert_to_cold", 100 }, + }, + stats = { + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + }, + levels = { + [1] = { baseMultiplier = 0.3, damageEffectiveness = 0.3, levelRequirement = 28, }, + [2] = { baseMultiplier = 0.303, damageEffectiveness = 0.3, levelRequirement = 31, }, + [3] = { baseMultiplier = 0.306, damageEffectiveness = 0.31, levelRequirement = 34, }, + [4] = { baseMultiplier = 0.309, damageEffectiveness = 0.31, levelRequirement = 37, }, + [5] = { baseMultiplier = 0.312, damageEffectiveness = 0.31, levelRequirement = 40, }, + [6] = { baseMultiplier = 0.315, damageEffectiveness = 0.31, levelRequirement = 42, }, + [7] = { baseMultiplier = 0.318, damageEffectiveness = 0.32, levelRequirement = 44, }, + [8] = { baseMultiplier = 0.321, damageEffectiveness = 0.32, levelRequirement = 46, }, + [9] = { baseMultiplier = 0.324, damageEffectiveness = 0.32, levelRequirement = 48, }, + [10] = { baseMultiplier = 0.327, damageEffectiveness = 0.33, levelRequirement = 50, }, + [11] = { baseMultiplier = 0.329, damageEffectiveness = 0.33, levelRequirement = 52, }, + [12] = { baseMultiplier = 0.332, damageEffectiveness = 0.33, levelRequirement = 54, }, + [13] = { baseMultiplier = 0.335, damageEffectiveness = 0.34, levelRequirement = 56, }, + [14] = { baseMultiplier = 0.338, damageEffectiveness = 0.34, levelRequirement = 58, }, + [15] = { baseMultiplier = 0.341, damageEffectiveness = 0.34, levelRequirement = 60, }, + [16] = { baseMultiplier = 0.344, damageEffectiveness = 0.34, levelRequirement = 62, }, + [17] = { baseMultiplier = 0.347, damageEffectiveness = 0.35, levelRequirement = 64, }, + [18] = { baseMultiplier = 0.35, damageEffectiveness = 0.35, levelRequirement = 66, }, + [19] = { baseMultiplier = 0.353, damageEffectiveness = 0.35, levelRequirement = 68, }, + [20] = { baseMultiplier = 0.356, damageEffectiveness = 0.36, levelRequirement = 70, }, + [21] = { baseMultiplier = 0.359, damageEffectiveness = 0.36, levelRequirement = 72, }, + [22] = { baseMultiplier = 0.362, damageEffectiveness = 0.36, levelRequirement = 74, }, + [23] = { baseMultiplier = 0.365, damageEffectiveness = 0.36, levelRequirement = 76, }, + [24] = { baseMultiplier = 0.368, damageEffectiveness = 0.37, levelRequirement = 78, }, + [25] = { baseMultiplier = 0.371, damageEffectiveness = 0.37, levelRequirement = 80, }, + [26] = { baseMultiplier = 0.374, damageEffectiveness = 0.37, levelRequirement = 82, }, + [27] = { baseMultiplier = 0.377, damageEffectiveness = 0.38, levelRequirement = 84, }, + [28] = { baseMultiplier = 0.38, damageEffectiveness = 0.38, levelRequirement = 86, }, + [29] = { baseMultiplier = 0.383, damageEffectiveness = 0.38, levelRequirement = 88, }, + [30] = { baseMultiplier = 0.385, damageEffectiveness = 0.39, levelRequirement = 90, }, + [31] = { baseMultiplier = 0.387, damageEffectiveness = 0.39, levelRequirement = 91, }, + [32] = { baseMultiplier = 0.388, damageEffectiveness = 0.39, levelRequirement = 92, }, + [33] = { baseMultiplier = 0.39, damageEffectiveness = 0.39, levelRequirement = 93, }, + [34] = { baseMultiplier = 0.391, damageEffectiveness = 0.39, levelRequirement = 94, }, + [35] = { baseMultiplier = 0.393, damageEffectiveness = 0.39, levelRequirement = 95, }, + [36] = { baseMultiplier = 0.394, damageEffectiveness = 0.39, levelRequirement = 96, }, + [37] = { baseMultiplier = 0.396, damageEffectiveness = 0.4, levelRequirement = 97, }, + [38] = { baseMultiplier = 0.397, damageEffectiveness = 0.4, levelRequirement = 98, }, + [39] = { baseMultiplier = 0.399, damageEffectiveness = 0.4, levelRequirement = 99, }, + [40] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 100, }, + }, +} + +skills["BlightMercenary"] = { + name = "Blight", + hidden = true, + mercenary = true, + inheritedFrom = "Blight", + color = 3, + baseEffectiveness = 5.4704999923706, + incrementalEffectiveness = 0.033399999141693, + description = "Apply a debuff to enemies in front of you which deals chaos damage over time. Enemies who aren't already debuffed by Blight are also hindered for a shorter secondary duration, slowing their movement. Continued channelling adds layers of damage to the debuff, each with their own duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Chaos] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Channel] = true, [SkillType.Duration] = true, [SkillType.DamageOverTime] = true, [SkillType.DegenOnlySpellDamage] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "base_secondary_skill_effect_duration", 1000 }, + { "base_movement_velocity_+%", -80 }, + { "display_max_blight_stacks", 20 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "active_skill_base_radius_+", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 16.666667039196, 0, levelRequirement = 1, statInterpolation = { 3, 1, }, }, + [2] = { 16.666667039196, 0, levelRequirement = 2, statInterpolation = { 3, 1, }, }, + [3] = { 16.666667039196, 1, levelRequirement = 4, statInterpolation = { 3, 1, }, }, + [4] = { 16.666667039196, 1, levelRequirement = 7, statInterpolation = { 3, 1, }, }, + [5] = { 16.666667039196, 1, levelRequirement = 11, statInterpolation = { 3, 1, }, }, + [6] = { 16.666667039196, 2, levelRequirement = 16, statInterpolation = { 3, 1, }, }, + [7] = { 16.666667039196, 2, levelRequirement = 20, statInterpolation = { 3, 1, }, }, + [8] = { 16.666667039196, 2, levelRequirement = 24, statInterpolation = { 3, 1, }, }, + [9] = { 16.666667039196, 3, levelRequirement = 28, statInterpolation = { 3, 1, }, }, + [10] = { 16.666667039196, 3, levelRequirement = 32, statInterpolation = { 3, 1, }, }, + [11] = { 16.666667039196, 3, levelRequirement = 36, statInterpolation = { 3, 1, }, }, + [12] = { 16.666667039196, 4, levelRequirement = 40, statInterpolation = { 3, 1, }, }, + [13] = { 16.666667039196, 4, levelRequirement = 44, statInterpolation = { 3, 1, }, }, + [14] = { 16.666667039196, 4, levelRequirement = 48, statInterpolation = { 3, 1, }, }, + [15] = { 16.666667039196, 5, levelRequirement = 52, statInterpolation = { 3, 1, }, }, + [16] = { 16.666667039196, 5, levelRequirement = 56, statInterpolation = { 3, 1, }, }, + [17] = { 16.666667039196, 5, levelRequirement = 60, statInterpolation = { 3, 1, }, }, + [18] = { 16.666667039196, 6, levelRequirement = 64, statInterpolation = { 3, 1, }, }, + [19] = { 16.666667039196, 6, levelRequirement = 67, statInterpolation = { 3, 1, }, }, + [20] = { 16.666667039196, 6, levelRequirement = 70, statInterpolation = { 3, 1, }, }, + [21] = { 16.666667039196, 7, levelRequirement = 72, statInterpolation = { 3, 1, }, }, + [22] = { 16.666667039196, 7, levelRequirement = 74, statInterpolation = { 3, 1, }, }, + [23] = { 16.666667039196, 7, levelRequirement = 76, statInterpolation = { 3, 1, }, }, + [24] = { 16.666667039196, 8, levelRequirement = 78, statInterpolation = { 3, 1, }, }, + [25] = { 16.666667039196, 8, levelRequirement = 80, statInterpolation = { 3, 1, }, }, + [26] = { 16.666667039196, 8, levelRequirement = 82, statInterpolation = { 3, 1, }, }, + [27] = { 16.666667039196, 9, levelRequirement = 84, statInterpolation = { 3, 1, }, }, + [28] = { 16.666667039196, 9, levelRequirement = 86, statInterpolation = { 3, 1, }, }, + [29] = { 16.666667039196, 9, levelRequirement = 88, statInterpolation = { 3, 1, }, }, + [30] = { 16.666667039196, 10, levelRequirement = 90, statInterpolation = { 3, 1, }, }, + [31] = { 16.666667039196, 10, levelRequirement = 91, statInterpolation = { 3, 1, }, }, + [32] = { 16.666667039196, 10, levelRequirement = 92, statInterpolation = { 3, 1, }, }, + [33] = { 16.666667039196, 10, levelRequirement = 93, statInterpolation = { 3, 1, }, }, + [34] = { 16.666667039196, 10, levelRequirement = 94, statInterpolation = { 3, 1, }, }, + [35] = { 16.666667039196, 10, levelRequirement = 95, statInterpolation = { 3, 1, }, }, + [36] = { 16.666667039196, 11, levelRequirement = 96, statInterpolation = { 3, 1, }, }, + [37] = { 16.666667039196, 11, levelRequirement = 97, statInterpolation = { 3, 1, }, }, + [38] = { 16.666667039196, 11, levelRequirement = 98, statInterpolation = { 3, 1, }, }, + [39] = { 16.666667039196, 11, levelRequirement = 99, statInterpolation = { 3, 1, }, }, + [40] = { 16.666667039196, 11, levelRequirement = 100, statInterpolation = { 3, 1, }, }, + }, +} + +skills["BlightMercenaryEncounter"] = { + name = "Blight", + hidden = true, + mercenary = true, + inheritedFrom = "Blight", + color = 3, + baseEffectiveness = 2.25, + incrementalEffectiveness = 0.027499999850988, + description = "Apply a debuff to enemies in front of you which deals chaos damage over time. Enemies who aren't already debuffed by Blight are also hindered for a shorter secondary duration, slowing their movement. Continued channelling adds layers of damage to the debuff, each with their own duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Chaos] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Channel] = true, [SkillType.Duration] = true, [SkillType.DamageOverTime] = true, [SkillType.DegenOnlySpellDamage] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "base_secondary_skill_effect_duration", 1000 }, + { "base_movement_velocity_+%", -80 }, + { "display_max_blight_stacks", 20 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "active_skill_base_radius_+", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 16.666667039196, 0, levelRequirement = 1, statInterpolation = { 3, 1, }, }, + [2] = { 16.666667039196, 0, levelRequirement = 2, statInterpolation = { 3, 1, }, }, + [3] = { 16.666667039196, 0, levelRequirement = 4, statInterpolation = { 3, 1, }, }, + [4] = { 16.666667039196, 0, levelRequirement = 7, statInterpolation = { 3, 1, }, }, + [5] = { 16.666667039196, 1, levelRequirement = 11, statInterpolation = { 3, 1, }, }, + [6] = { 16.666667039196, 1, levelRequirement = 16, statInterpolation = { 3, 1, }, }, + [7] = { 16.666667039196, 1, levelRequirement = 20, statInterpolation = { 3, 1, }, }, + [8] = { 16.666667039196, 1, levelRequirement = 24, statInterpolation = { 3, 1, }, }, + [9] = { 16.666667039196, 2, levelRequirement = 28, statInterpolation = { 3, 1, }, }, + [10] = { 16.666667039196, 2, levelRequirement = 32, statInterpolation = { 3, 1, }, }, + [11] = { 16.666667039196, 2, levelRequirement = 36, statInterpolation = { 3, 1, }, }, + [12] = { 16.666667039196, 2, levelRequirement = 40, statInterpolation = { 3, 1, }, }, + [13] = { 16.666667039196, 3, levelRequirement = 44, statInterpolation = { 3, 1, }, }, + [14] = { 16.666667039196, 3, levelRequirement = 48, statInterpolation = { 3, 1, }, }, + [15] = { 16.666667039196, 3, levelRequirement = 52, statInterpolation = { 3, 1, }, }, + [16] = { 16.666667039196, 3, levelRequirement = 56, statInterpolation = { 3, 1, }, }, + [17] = { 16.666667039196, 4, levelRequirement = 60, statInterpolation = { 3, 1, }, }, + [18] = { 16.666667039196, 4, levelRequirement = 64, statInterpolation = { 3, 1, }, }, + [19] = { 16.666667039196, 4, levelRequirement = 67, statInterpolation = { 3, 1, }, }, + [20] = { 16.666667039196, 4, levelRequirement = 70, statInterpolation = { 3, 1, }, }, + [21] = { 16.666667039196, 5, levelRequirement = 72, statInterpolation = { 3, 1, }, }, + [22] = { 16.666667039196, 5, levelRequirement = 74, statInterpolation = { 3, 1, }, }, + [23] = { 16.666667039196, 5, levelRequirement = 76, statInterpolation = { 3, 1, }, }, + [24] = { 16.666667039196, 5, levelRequirement = 78, statInterpolation = { 3, 1, }, }, + [25] = { 16.666667039196, 6, levelRequirement = 80, statInterpolation = { 3, 1, }, }, + [26] = { 16.666667039196, 6, levelRequirement = 82, statInterpolation = { 3, 1, }, }, + [27] = { 16.666667039196, 6, levelRequirement = 84, statInterpolation = { 3, 1, }, }, + [28] = { 16.666667039196, 6, levelRequirement = 86, statInterpolation = { 3, 1, }, }, + [29] = { 16.666667039196, 7, levelRequirement = 88, statInterpolation = { 3, 1, }, }, + [30] = { 16.666667039196, 7, levelRequirement = 90, statInterpolation = { 3, 1, }, }, + [31] = { 16.666667039196, 7, levelRequirement = 91, statInterpolation = { 3, 1, }, }, + [32] = { 16.666667039196, 7, levelRequirement = 92, statInterpolation = { 3, 1, }, }, + [33] = { 16.666667039196, 8, levelRequirement = 93, statInterpolation = { 3, 1, }, }, + [34] = { 16.666667039196, 8, levelRequirement = 94, statInterpolation = { 3, 1, }, }, + [35] = { 16.666667039196, 8, levelRequirement = 95, statInterpolation = { 3, 1, }, }, + [36] = { 16.666667039196, 8, levelRequirement = 96, statInterpolation = { 3, 1, }, }, + [37] = { 16.666667039196, 9, levelRequirement = 97, statInterpolation = { 3, 1, }, }, + [38] = { 16.666667039196, 9, levelRequirement = 98, statInterpolation = { 3, 1, }, }, + [39] = { 16.666667039196, 9, levelRequirement = 99, statInterpolation = { 3, 1, }, }, + [40] = { 16.666667039196, 9, levelRequirement = 100, statInterpolation = { 3, 1, }, }, + }, +} + +skills["BlinkArrowMercenary"] = { + name = "Blink Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "BlinkArrow", + color = 2, + description = "Fires an arrow at the target destination. When the arrow lands, you are teleported to it and a clone is summoned at your old location. The clone is a minion that uses your bow and quiver.", + skillTypes = { [SkillType.ProjectileSpeed] = true, [SkillType.Attack] = true, [SkillType.Minion] = true, [SkillType.RangedAttack] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Movement] = true, [SkillType.Triggerable] = true, [SkillType.CreatesMinion] = true, [SkillType.Travel] = true, [SkillType.Cooldown] = true, [SkillType.Rain] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesFromUser] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "minion_attack_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + minion = true, + movement = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "number_of_monsters_to_summon", 1 }, + { "display_minion_monster_type", 25 }, + }, + stats = { + "base_display_minion_actor_level", + "base_cooldown_speed_+%", + "active_skill_minion_damage_+%_final", + "base_is_projectile", + "base_skill_show_average_damage_instead_of_dps", + "minion_dies_when_parent_dies", + }, + notMinionStat = { + "base_cooldown_speed_+%", + "active_skill_minion_damage_+%_final", + }, + levels = { + [1] = { 10, 0, 0, cooldown = 3, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 13, 2, 3, cooldown = 3, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 17, 5, 6, cooldown = 3, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 21, 7, 9, cooldown = 3, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 25, 10, 12, cooldown = 3, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 29, 12, 15, cooldown = 3, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 33, 15, 18, cooldown = 3, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 36, 17, 21, cooldown = 3, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 39, 20, 24, cooldown = 3, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 42, 22, 27, cooldown = 3, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 45, 25, 30, cooldown = 3, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 48, 27, 33, cooldown = 3, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 51, 30, 36, cooldown = 3, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 54, 32, 39, cooldown = 3, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 57, 35, 42, cooldown = 3, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 60, 37, 45, cooldown = 3, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 63, 40, 48, cooldown = 3, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 66, 42, 51, cooldown = 3, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 68, 45, 54, cooldown = 3, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 70, 47, 57, cooldown = 3, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 72, 50, 60, cooldown = 3, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 74, 52, 63, cooldown = 3, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 76, 55, 66, cooldown = 3, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 78, 57, 69, cooldown = 3, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 80, 60, 72, cooldown = 3, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 82, 62, 75, cooldown = 3, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 84, 65, 78, cooldown = 3, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 86, 67, 81, cooldown = 3, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 88, 70, 84, cooldown = 3, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 90, 72, 87, cooldown = 3, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 91, 73, 88, cooldown = 3, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 92, 75, 90, cooldown = 3, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 93, 76, 91, cooldown = 3, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 94, 77, 93, cooldown = 3, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 95, 78, 94, cooldown = 3, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 96, 80, 96, cooldown = 3, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 97, 81, 97, cooldown = 3, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 98, 82, 99, cooldown = 3, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 99, 83, 100, cooldown = 3, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 100, 85, 102, cooldown = 3, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["BloodMortarMercenary"] = { + name = "Blood Mortar", + hidden = true, + mercenary = true, + inheritedFrom = "BirdmanBloodProjectileMortar", + color = 4, + description = "Generic monster mortar skill. Like Monster Projectile but has an impact effect.", + skillTypes = { [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Attack] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "attack_speed_+%", 100 }, + { "active_skill_damage_+%_final", 10 }, + { "projectile_spread_radius", 15 }, + { "active_skill_area_of_effect_radius_+%_final", 20 }, + { "bleed_on_hit_with_attacks_%", 25 }, + }, + stats = { + "base_is_projectile", + "projectile_uses_contact_position", + }, + levels = { + [1] = { levelRequirement = 1, }, + }, +} + +skills["BodyswapMercenary"] = { + name = "Bodyswap", + hidden = true, + mercenary = true, + inheritedFrom = "Bodyswap", + color = 3, + baseEffectiveness = 0.40259999036789, + incrementalEffectiveness = 0.046300001442432, + description = "Violently destroys your body and recreates it at the location of a targeted enemy or corpse, dealing spell damage in an area at both locations. If there is no specific target, it will prioritise corpses over enemies. If targeting a corpse, the corpse will also explode, dealing damage around it that is not affected by modifiers to spell damage, and cannot be reflected. This spell cannot be repeated.", + skillTypes = { [SkillType.Movement] = true, [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Trappable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.AreaSpell] = true, [SkillType.Travel] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + movement = true, + spell = true, + }, + constantStats = { + { "corpse_warp_area_of_effect_+%_final_when_consuming_corpse", 200 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "corpse_explosion_monster_life_permillage_fire", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 60, 0, critChance = 6, levelRequirement = 10, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 61, 0, critChance = 6, levelRequirement = 13, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 62, 0, critChance = 6, levelRequirement = 17, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 63, 0, critChance = 6, levelRequirement = 21, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 64, 1, critChance = 6, levelRequirement = 25, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 65, 1, critChance = 6, levelRequirement = 29, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 66, 1, critChance = 6, levelRequirement = 33, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 67, 1, critChance = 6, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 68, 1, critChance = 6, levelRequirement = 39, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 69, 1, critChance = 6, levelRequirement = 42, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 70, 1, critChance = 6, levelRequirement = 45, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 71, 1, critChance = 6, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 72, 2, critChance = 6, levelRequirement = 51, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 73, 2, critChance = 6, levelRequirement = 54, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 74, 2, critChance = 6, levelRequirement = 57, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 75, 2, critChance = 6, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 76, 2, critChance = 6, levelRequirement = 63, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 77, 2, critChance = 6, levelRequirement = 66, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 78, 2, critChance = 6, levelRequirement = 68, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 79, 2, critChance = 6, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 80, 3, critChance = 6, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 81, 3, critChance = 6, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 82, 3, critChance = 6, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 83, 3, critChance = 6, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 84, 3, critChance = 6, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 85, 3, critChance = 6, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 86, 3, critChance = 6, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 87, 3, critChance = 6, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 88, 4, critChance = 6, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 89, 4, critChance = 6, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 89, 4, critChance = 6, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 90, 4, critChance = 6, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 90, 4, critChance = 6, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 91, 4, critChance = 6, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 91, 4, critChance = 6, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 92, 4, critChance = 6, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 92, 4, critChance = 6, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 93, 4, critChance = 6, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 93, 4, critChance = 6, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 94, 4, critChance = 6, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["BoneOfferingMercenary"] = { + name = "Bone Offering", + hidden = true, + mercenary = true, + inheritedFrom = "BoneOffering", + color = 3, + description = "Consumes a corpse, granting all of your minions the power to block both attacks and spells. The skill consumes other nearby corpses, increasing the duration for each corpse consumed.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Triggerable] = true, [SkillType.Minion] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Offering] = true, }, + statDescriptionScope = "offering_skill_stat_descriptions", + castTime = 1, + baseFlags = { + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 5000 }, + { "offering_skill_effect_duration_per_corpse", 1000 }, + { "minion_life_regeneration_rate_per_minute_%_if_blocked_recently", 240 }, + }, + stats = { + "monster_base_block_%", + "base_spell_block_%", + "base_deal_no_damage", + }, + levels = { + [1] = { 25, 25, cooldown = 10, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 26, 25, cooldown = 10, levelRequirement = 15, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 26, 26, cooldown = 10, levelRequirement = 19, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 27, 26, cooldown = 10, levelRequirement = 23, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 27, 27, cooldown = 10, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 28, 27, cooldown = 10, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 28, 28, cooldown = 10, levelRequirement = 35, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 29, 28, cooldown = 10, levelRequirement = 38, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 29, 29, cooldown = 10, levelRequirement = 41, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 30, 29, cooldown = 10, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 30, 30, cooldown = 10, levelRequirement = 47, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 31, 30, cooldown = 10, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 31, 31, cooldown = 10, levelRequirement = 53, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 32, 31, cooldown = 10, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 32, 32, cooldown = 10, levelRequirement = 59, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 33, 32, cooldown = 10, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 33, 33, cooldown = 10, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 34, 33, cooldown = 10, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 34, 34, cooldown = 10, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 35, 34, cooldown = 10, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 35, 35, cooldown = 10, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 36, 35, cooldown = 10, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 36, 36, cooldown = 10, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 37, 36, cooldown = 10, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 37, 37, cooldown = 10, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 38, 37, cooldown = 10, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 38, 38, cooldown = 10, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 39, 38, cooldown = 10, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 39, 39, cooldown = 10, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 40, 39, cooldown = 10, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 40, 39, cooldown = 10, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 40, 40, cooldown = 10, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 40, 40, cooldown = 10, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 41, 40, cooldown = 10, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 41, 40, cooldown = 10, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 41, 41, cooldown = 10, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 41, 41, cooldown = 10, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 42, 41, cooldown = 10, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 42, 41, cooldown = 10, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 42, 42, cooldown = 10, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["BonePrison"] = { + name = "BonePrison", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "wall_maximum_length", 315 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 10, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["BoneshatterMercenary"] = { + name = "Boneshatter", + hidden = true, + mercenary = true, + inheritedFrom = "Boneshatter", + color = 1, + baseEffectiveness = 0.18279999494553, + incrementalEffectiveness = 0.053700000047684, + description = "Attack enemies with a forceful melee strike that also hurts you. Successive uses will raise the damage dealt both to enemies and you. Stunning an enemy with the strike releases a damaging pulse. Requires a Mace, Sceptre, Axe or Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Physical] = true, [SkillType.InnateTrauma] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "trauma_strike_shockwave_area_of_effect_+%_per_100ms_stun_duration_up_to_400%", 15 }, + { "boneshatter_trauma_base_duration_ms", 6000 }, + }, + stats = { + "trauma_strike_self_damage_per_trauma", + "attack_minimum_added_physical_damage", + "attack_maximum_added_physical_damage", + "trauma_strike_damage_+%_final_per_trauma", + }, + notMinionStat = { + "trauma_strike_self_damage_per_trauma", + }, + levels = { + [1] = { 0.60000002384186, 1.1200000047684, 1.6799999475479, 3, baseMultiplier = 2.31, damageEffectiveness = 2.31, levelRequirement = 28, statInterpolation = { 3, 3, 3, 1, }, }, + [2] = { 0.60000002384186, 1.1039999723434, 1.6560000181198, 3, baseMultiplier = 2.366, damageEffectiveness = 2.366, levelRequirement = 31, statInterpolation = { 3, 3, 3, 1, }, }, + [3] = { 0.60000002384186, 1.0880000591278, 1.6319999694824, 3, baseMultiplier = 2.423, damageEffectiveness = 2.423, levelRequirement = 34, statInterpolation = { 3, 3, 3, 1, }, }, + [4] = { 0.60000002384186, 1.0720000267029, 1.6080000400543, 3, baseMultiplier = 2.481, damageEffectiveness = 2.481, levelRequirement = 37, statInterpolation = { 3, 3, 3, 1, }, }, + [5] = { 0.60000002384186, 1.055999994278, 1.5839999914169, 4, baseMultiplier = 2.539, damageEffectiveness = 2.539, levelRequirement = 40, statInterpolation = { 3, 3, 3, 1, }, }, + [6] = { 0.60000002384186, 1.039999961853, 1.5599999427795, 4, baseMultiplier = 2.594, damageEffectiveness = 2.594, levelRequirement = 42, statInterpolation = { 3, 3, 3, 1, }, }, + [7] = { 0.60000002384186, 1.0240000486374, 1.5360000133514, 4, baseMultiplier = 2.648, damageEffectiveness = 2.648, levelRequirement = 44, statInterpolation = { 3, 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.0080000162125, 1.5119999647141, 4, baseMultiplier = 2.703, damageEffectiveness = 2.703, levelRequirement = 46, statInterpolation = { 3, 3, 3, 1, }, }, + [9] = { 0.80000001192093, 0.99199998378754, 1.4880000352859, 4, baseMultiplier = 2.758, damageEffectiveness = 2.758, levelRequirement = 48, statInterpolation = { 3, 3, 3, 1, }, }, + [10] = { 0.80000001192093, 0.97600001096725, 1.4639999866486, 4, baseMultiplier = 2.813, damageEffectiveness = 2.813, levelRequirement = 50, statInterpolation = { 3, 3, 3, 1, }, }, + [11] = { 0.80000001192093, 0.95999997854233, 1.4400000572205, 5, baseMultiplier = 2.868, damageEffectiveness = 2.868, levelRequirement = 52, statInterpolation = { 3, 3, 3, 1, }, }, + [12] = { 0.80000001192093, 0.94400000572205, 1.4160000085831, 5, baseMultiplier = 2.924, damageEffectiveness = 2.924, levelRequirement = 54, statInterpolation = { 3, 3, 3, 1, }, }, + [13] = { 0.80000001192093, 0.92799997329712, 1.3919999599457, 5, baseMultiplier = 2.98, damageEffectiveness = 2.98, levelRequirement = 56, statInterpolation = { 3, 3, 3, 1, }, }, + [14] = { 0.80000001192093, 0.91200000047684, 1.3680000305176, 5, baseMultiplier = 3.037, damageEffectiveness = 3.037, levelRequirement = 58, statInterpolation = { 3, 3, 3, 1, }, }, + [15] = { 0.80000001192093, 0.89600002765656, 1.3439999818802, 5, baseMultiplier = 3.093, damageEffectiveness = 3.093, levelRequirement = 60, statInterpolation = { 3, 3, 3, 1, }, }, + [16] = { 0.80000001192093, 0.87999999523163, 1.3200000524521, 5, baseMultiplier = 3.152, damageEffectiveness = 3.152, levelRequirement = 62, statInterpolation = { 3, 3, 3, 1, }, }, + [17] = { 0.80000001192093, 0.86400002241135, 1.2960000038147, 6, baseMultiplier = 3.209, damageEffectiveness = 3.209, levelRequirement = 64, statInterpolation = { 3, 3, 3, 1, }, }, + [18] = { 0.80000001192093, 0.84799998998642, 1.2719999551773, 6, baseMultiplier = 3.267, damageEffectiveness = 3.267, levelRequirement = 66, statInterpolation = { 3, 3, 3, 1, }, }, + [19] = { 0.80000001192093, 0.83200001716614, 1.2480000257492, 6, baseMultiplier = 3.325, damageEffectiveness = 3.325, levelRequirement = 68, statInterpolation = { 3, 3, 3, 1, }, }, + [20] = { 1, 0.81599998474121, 1.2239999771118, 6, baseMultiplier = 3.383, damageEffectiveness = 3.383, levelRequirement = 70, statInterpolation = { 3, 3, 3, 1, }, }, + [21] = { 1, 0.80000001192093, 1.2000000476837, 6, baseMultiplier = 3.442, damageEffectiveness = 3.442, levelRequirement = 72, statInterpolation = { 3, 3, 3, 1, }, }, + [22] = { 1, 0.783999979496, 1.1759999990463, 6, baseMultiplier = 3.5, damageEffectiveness = 3.5, levelRequirement = 74, statInterpolation = { 3, 3, 3, 1, }, }, + [23] = { 1, 0.76800000667572, 1.1519999504089, 6, baseMultiplier = 3.56, damageEffectiveness = 3.56, levelRequirement = 76, statInterpolation = { 3, 3, 3, 1, }, }, + [24] = { 1, 0.75199997425079, 1.1280000209808, 7, baseMultiplier = 3.619, damageEffectiveness = 3.619, levelRequirement = 78, statInterpolation = { 3, 3, 3, 1, }, }, + [25] = { 1, 0.73600000143051, 1.1039999723434, 7, baseMultiplier = 3.68, damageEffectiveness = 3.68, levelRequirement = 80, statInterpolation = { 3, 3, 3, 1, }, }, + [26] = { 1, 0.72000002861023, 1.0800000429153, 7, baseMultiplier = 3.74, damageEffectiveness = 3.74, levelRequirement = 82, statInterpolation = { 3, 3, 3, 1, }, }, + [27] = { 1, 0.7039999961853, 1.055999994278, 7, baseMultiplier = 3.801, damageEffectiveness = 3.801, levelRequirement = 84, statInterpolation = { 3, 3, 3, 1, }, }, + [28] = { 1, 0.68800002336502, 1.0319999456406, 7, baseMultiplier = 3.862, damageEffectiveness = 3.862, levelRequirement = 86, statInterpolation = { 3, 3, 3, 1, }, }, + [29] = { 1, 0.67199999094009, 1.0080000162125, 7, baseMultiplier = 3.923, damageEffectiveness = 3.923, levelRequirement = 88, statInterpolation = { 3, 3, 3, 1, }, }, + [30] = { 1, 0.65600001811981, 0.98400002717972, 8, baseMultiplier = 3.984, damageEffectiveness = 3.984, levelRequirement = 90, statInterpolation = { 3, 3, 3, 1, }, }, + [31] = { 1, 0.64800000190735, 0.97200000286102, 8, baseMultiplier = 4.015, damageEffectiveness = 4.015, levelRequirement = 91, statInterpolation = { 3, 3, 3, 1, }, }, + [32] = { 1, 0.63999998569489, 0.95999997854233, 8, baseMultiplier = 4.046, damageEffectiveness = 4.046, levelRequirement = 92, statInterpolation = { 3, 3, 3, 1, }, }, + [33] = { 1, 0.63200002908707, 0.94800001382828, 8, baseMultiplier = 4.077, damageEffectiveness = 4.077, levelRequirement = 93, statInterpolation = { 3, 3, 3, 1, }, }, + [34] = { 1, 0.6240000128746, 0.93599998950958, 8, baseMultiplier = 4.108, damageEffectiveness = 4.108, levelRequirement = 94, statInterpolation = { 3, 3, 3, 1, }, }, + [35] = { 1, 0.61599999666214, 0.92400002479553, 8, baseMultiplier = 4.139, damageEffectiveness = 4.139, levelRequirement = 95, statInterpolation = { 3, 3, 3, 1, }, }, + [36] = { 1.2000000476837, 0.60799998044968, 0.91200000047684, 8, baseMultiplier = 4.17, damageEffectiveness = 4.17, levelRequirement = 96, statInterpolation = { 3, 3, 3, 1, }, }, + [37] = { 1.2000000476837, 0.60000002384186, 0.89999997615814, 8, baseMultiplier = 4.202, damageEffectiveness = 4.202, levelRequirement = 97, statInterpolation = { 3, 3, 3, 1, }, }, + [38] = { 1.2000000476837, 0.59200000762939, 0.88800001144409, 8, baseMultiplier = 4.233, damageEffectiveness = 4.233, levelRequirement = 98, statInterpolation = { 3, 3, 3, 1, }, }, + [39] = { 1.2000000476837, 0.58399999141693, 0.8759999871254, 8, baseMultiplier = 4.266, damageEffectiveness = 4.266, levelRequirement = 99, statInterpolation = { 3, 3, 3, 1, }, }, + [40] = { 1.2000000476837, 0.57599997520447, 0.86400002241135, 8, baseMultiplier = 4.297, damageEffectiveness = 4.297, levelRequirement = 100, statInterpolation = { 3, 3, 3, 1, }, }, + }, +} + +skills["BurningArrowMercenary"] = { + name = "Burning Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "BurningArrow", + color = 2, + description = "Fires a burning arrow that deals fire damage and has a chance to ignite.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Fire] = true, [SkillType.ThresholdJewelArea] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "base_chance_to_ignite_%", 25 }, + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + }, + stats = { + "skill_can_fire_arrows", + }, + levels = { + [1] = { baseMultiplier = 2.8, damageEffectiveness = 2.8, levelRequirement = 1, }, + [2] = { baseMultiplier = 2.874, damageEffectiveness = 2.874, levelRequirement = 2, }, + [3] = { baseMultiplier = 2.947, damageEffectiveness = 2.947, levelRequirement = 4, }, + [4] = { baseMultiplier = 3.021, damageEffectiveness = 3.021, levelRequirement = 7, }, + [5] = { baseMultiplier = 3.095, damageEffectiveness = 3.095, levelRequirement = 11, }, + [6] = { baseMultiplier = 3.168, damageEffectiveness = 3.168, levelRequirement = 16, }, + [7] = { baseMultiplier = 3.242, damageEffectiveness = 3.242, levelRequirement = 20, }, + [8] = { baseMultiplier = 3.316, damageEffectiveness = 3.316, levelRequirement = 24, }, + [9] = { baseMultiplier = 3.389, damageEffectiveness = 3.389, levelRequirement = 28, }, + [10] = { baseMultiplier = 3.463, damageEffectiveness = 3.463, levelRequirement = 32, }, + [11] = { baseMultiplier = 3.537, damageEffectiveness = 3.537, levelRequirement = 36, }, + [12] = { baseMultiplier = 3.611, damageEffectiveness = 3.611, levelRequirement = 40, }, + [13] = { baseMultiplier = 3.684, damageEffectiveness = 3.684, levelRequirement = 44, }, + [14] = { baseMultiplier = 3.758, damageEffectiveness = 3.758, levelRequirement = 48, }, + [15] = { baseMultiplier = 3.832, damageEffectiveness = 3.832, levelRequirement = 52, }, + [16] = { baseMultiplier = 3.905, damageEffectiveness = 3.905, levelRequirement = 56, }, + [17] = { baseMultiplier = 3.979, damageEffectiveness = 3.979, levelRequirement = 60, }, + [18] = { baseMultiplier = 4.053, damageEffectiveness = 4.053, levelRequirement = 64, }, + [19] = { baseMultiplier = 4.126, damageEffectiveness = 4.126, levelRequirement = 67, }, + [20] = { baseMultiplier = 4.2, damageEffectiveness = 4.2, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.274, damageEffectiveness = 4.274, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.347, damageEffectiveness = 4.347, levelRequirement = 74, }, + [23] = { baseMultiplier = 4.421, damageEffectiveness = 4.421, levelRequirement = 76, }, + [24] = { baseMultiplier = 4.495, damageEffectiveness = 4.495, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.568, damageEffectiveness = 4.568, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.642, damageEffectiveness = 4.642, levelRequirement = 82, }, + [27] = { baseMultiplier = 4.716, damageEffectiveness = 4.716, levelRequirement = 84, }, + [28] = { baseMultiplier = 4.789, damageEffectiveness = 4.789, levelRequirement = 86, }, + [29] = { baseMultiplier = 4.863, damageEffectiveness = 4.863, levelRequirement = 88, }, + [30] = { baseMultiplier = 4.937, damageEffectiveness = 4.937, levelRequirement = 90, }, + [31] = { baseMultiplier = 4.974, damageEffectiveness = 4.974, levelRequirement = 91, }, + [32] = { baseMultiplier = 5.011, damageEffectiveness = 5.011, levelRequirement = 92, }, + [33] = { baseMultiplier = 5.047, damageEffectiveness = 5.047, levelRequirement = 93, }, + [34] = { baseMultiplier = 5.084, damageEffectiveness = 5.084, levelRequirement = 94, }, + [35] = { baseMultiplier = 5.121, damageEffectiveness = 5.121, levelRequirement = 95, }, + [36] = { baseMultiplier = 5.158, damageEffectiveness = 5.158, levelRequirement = 96, }, + [37] = { baseMultiplier = 5.195, damageEffectiveness = 5.195, levelRequirement = 97, }, + [38] = { baseMultiplier = 5.232, damageEffectiveness = 5.232, levelRequirement = 98, }, + [39] = { baseMultiplier = 5.268, damageEffectiveness = 5.268, levelRequirement = 99, }, + [40] = { baseMultiplier = 5.305, damageEffectiveness = 5.305, levelRequirement = 100, }, + }, +} + +skills["BurningArrowMercenaryEncounter"] = { + name = "Burning Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "BurningArrow", + color = 2, + description = "Fires a burning arrow that deals fire damage and has a chance to ignite.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Fire] = true, [SkillType.ThresholdJewelArea] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "base_chance_to_ignite_%", 25 }, + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + }, + stats = { + "skill_can_fire_arrows", + }, + levels = { + [1] = { baseMultiplier = 2.25, damageEffectiveness = 2.25, levelRequirement = 0, }, + }, +} + +skills["BurrowMercenary"] = { + name = "Burrow", + hidden = true, + mercenary = true, + color = 1, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { cooldown = 5, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["CGEBloodGroundMercenary"] = { + name = "Boiling Blood", + hidden = true, + mercenary = true, + inheritedFrom = "CGEFaridunWarlockSwarmGround", + color = 4, + baseEffectiveness = 1.6599999666214, + incrementalEffectiveness = 0.036660000681877, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "ground_blood_art_variation", 8 }, + { "active_skill_area_of_effect_radius_+%_final", -25 }, + { "base_skill_effect_duration", 2000 }, + }, + stats = { + "base_physical_damage_to_deal_per_minute", + }, + levels = { + [1] = { 25.000000558794, levelRequirement = 0, statInterpolation = { 3, }, }, + }, +} + +skills["CGEOilGroundSlowMercenary"] = { + name = "Oil Slick", + hidden = true, + mercenary = true, + inheritedFrom = "CGEFaridunWarlockSwarmGround", + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + { "base_movement_velocity_+%", -20 }, + { "active_skill_area_of_effect_radius_+%_final", 50 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 5, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["CallOfSteelMercenary"] = { + name = "Call of Steel", + hidden = true, + mercenary = true, + inheritedFrom = "CallOfSteel", + color = 1, + description = "Calls impale debuffs from enemies, alive or dead, in a large area around you to gain steel shards. Deals reflected damage in a smaller area around each such enemy based on the impales removed from them. Continues to grant shards over time until you reach maximum or spend them.", + skillTypes = { [SkillType.Cooldown] = true, [SkillType.Area] = true, [SkillType.Steel] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.4, + baseFlags = { + area = true, + }, + constantStats = { + { "call_of_steel_reload_amount", 4 }, + { "call_of_steel_reload_time", 500 }, + }, + stats = { + "skill_is_steel_skill_reload", + }, + levels = { + [1] = { baseMultiplier = 1.3, damageEffectiveness = 1.3, levelRequirement = 1, }, + }, +} + +skills["CausticArrowMercenary"] = { + name = "Caustic Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "CausticArrow", + color = 2, + baseEffectiveness = 8.1670999526978, + incrementalEffectiveness = 0.050299998372793, + description = "Fires an arrow which deals chaos damage in an area on impact, and spreads caustic ground. Enemies standing on the caustic ground take chaos damage over time.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "caustic_arrow_explode_on_hit_base_area_of_effect_radius", 12 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "active_skill_base_radius_+", + "skill_can_fire_arrows", + "projectile_damage_modifiers_apply_to_skill_dot", + "visual_hit_effect_chaos_is_green", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 16.666667039196, 0, baseMultiplier = 0.55, damageEffectiveness = 0.55, levelRequirement = 1, statInterpolation = { 3, 1, }, }, + [2] = { 16.666667039196, 0, baseMultiplier = 0.555, damageEffectiveness = 0.55, levelRequirement = 2, statInterpolation = { 3, 1, }, }, + [3] = { 16.666667039196, 1, baseMultiplier = 0.56, damageEffectiveness = 0.56, levelRequirement = 4, statInterpolation = { 3, 1, }, }, + [4] = { 16.666667039196, 1, baseMultiplier = 0.565, damageEffectiveness = 0.56, levelRequirement = 7, statInterpolation = { 3, 1, }, }, + [5] = { 16.666667039196, 1, baseMultiplier = 0.57, damageEffectiveness = 0.57, levelRequirement = 11, statInterpolation = { 3, 1, }, }, + [6] = { 16.666667039196, 2, baseMultiplier = 0.575, damageEffectiveness = 0.57, levelRequirement = 16, statInterpolation = { 3, 1, }, }, + [7] = { 16.666667039196, 2, baseMultiplier = 0.58, damageEffectiveness = 0.58, levelRequirement = 20, statInterpolation = { 3, 1, }, }, + [8] = { 16.666667039196, 2, baseMultiplier = 0.585, damageEffectiveness = 0.58, levelRequirement = 24, statInterpolation = { 3, 1, }, }, + [9] = { 16.666667039196, 3, baseMultiplier = 0.59, damageEffectiveness = 0.59, levelRequirement = 28, statInterpolation = { 3, 1, }, }, + [10] = { 16.666667039196, 3, baseMultiplier = 0.595, damageEffectiveness = 0.59, levelRequirement = 32, statInterpolation = { 3, 1, }, }, + [11] = { 16.666667039196, 3, baseMultiplier = 0.599, damageEffectiveness = 0.6, levelRequirement = 36, statInterpolation = { 3, 1, }, }, + [12] = { 16.666667039196, 3, baseMultiplier = 0.604, damageEffectiveness = 0.6, levelRequirement = 40, statInterpolation = { 3, 1, }, }, + [13] = { 16.666667039196, 4, baseMultiplier = 0.609, damageEffectiveness = 0.61, levelRequirement = 44, statInterpolation = { 3, 1, }, }, + [14] = { 16.666667039196, 4, baseMultiplier = 0.614, damageEffectiveness = 0.61, levelRequirement = 48, statInterpolation = { 3, 1, }, }, + [15] = { 16.666667039196, 4, baseMultiplier = 0.619, damageEffectiveness = 0.62, levelRequirement = 52, statInterpolation = { 3, 1, }, }, + [16] = { 16.666667039196, 5, baseMultiplier = 0.624, damageEffectiveness = 0.62, levelRequirement = 56, statInterpolation = { 3, 1, }, }, + [17] = { 16.666667039196, 5, baseMultiplier = 0.629, damageEffectiveness = 0.63, levelRequirement = 60, statInterpolation = { 3, 1, }, }, + [18] = { 16.666667039196, 5, baseMultiplier = 0.634, damageEffectiveness = 0.63, levelRequirement = 64, statInterpolation = { 3, 1, }, }, + [19] = { 16.666667039196, 6, baseMultiplier = 0.639, damageEffectiveness = 0.64, levelRequirement = 67, statInterpolation = { 3, 1, }, }, + [20] = { 16.666667039196, 6, baseMultiplier = 0.644, damageEffectiveness = 0.64, levelRequirement = 70, statInterpolation = { 3, 1, }, }, + [21] = { 16.666667039196, 6, baseMultiplier = 0.649, damageEffectiveness = 0.65, levelRequirement = 72, statInterpolation = { 3, 1, }, }, + [22] = { 16.666667039196, 7, baseMultiplier = 0.654, damageEffectiveness = 0.65, levelRequirement = 74, statInterpolation = { 3, 1, }, }, + [23] = { 16.666667039196, 7, baseMultiplier = 0.659, damageEffectiveness = 0.66, levelRequirement = 76, statInterpolation = { 3, 1, }, }, + [24] = { 16.666667039196, 7, baseMultiplier = 0.664, damageEffectiveness = 0.66, levelRequirement = 78, statInterpolation = { 3, 1, }, }, + [25] = { 16.666667039196, 8, baseMultiplier = 0.669, damageEffectiveness = 0.67, levelRequirement = 80, statInterpolation = { 3, 1, }, }, + [26] = { 16.666667039196, 8, baseMultiplier = 0.674, damageEffectiveness = 0.67, levelRequirement = 82, statInterpolation = { 3, 1, }, }, + [27] = { 16.666667039196, 8, baseMultiplier = 0.679, damageEffectiveness = 0.68, levelRequirement = 84, statInterpolation = { 3, 1, }, }, + [28] = { 16.666667039196, 9, baseMultiplier = 0.684, damageEffectiveness = 0.68, levelRequirement = 86, statInterpolation = { 3, 1, }, }, + [29] = { 16.666667039196, 9, baseMultiplier = 0.689, damageEffectiveness = 0.69, levelRequirement = 88, statInterpolation = { 3, 1, }, }, + [30] = { 16.666667039196, 9, baseMultiplier = 0.694, damageEffectiveness = 0.69, levelRequirement = 90, statInterpolation = { 3, 1, }, }, + [31] = { 16.666667039196, 9, baseMultiplier = 0.698, damageEffectiveness = 0.7, levelRequirement = 91, statInterpolation = { 3, 1, }, }, + [32] = { 16.666667039196, 10, baseMultiplier = 0.703, damageEffectiveness = 0.7, levelRequirement = 92, statInterpolation = { 3, 1, }, }, + [33] = { 16.666667039196, 10, baseMultiplier = 0.708, damageEffectiveness = 0.71, levelRequirement = 93, statInterpolation = { 3, 1, }, }, + [34] = { 16.666667039196, 10, baseMultiplier = 0.713, damageEffectiveness = 0.71, levelRequirement = 94, statInterpolation = { 3, 1, }, }, + [35] = { 16.666667039196, 11, baseMultiplier = 0.718, damageEffectiveness = 0.72, levelRequirement = 95, statInterpolation = { 3, 1, }, }, + [36] = { 16.666667039196, 11, baseMultiplier = 0.723, damageEffectiveness = 0.72, levelRequirement = 96, statInterpolation = { 3, 1, }, }, + [37] = { 16.666667039196, 11, baseMultiplier = 0.728, damageEffectiveness = 0.73, levelRequirement = 97, statInterpolation = { 3, 1, }, }, + [38] = { 16.666667039196, 12, baseMultiplier = 0.733, damageEffectiveness = 0.73, levelRequirement = 98, statInterpolation = { 3, 1, }, }, + [39] = { 16.666667039196, 12, baseMultiplier = 0.738, damageEffectiveness = 0.74, levelRequirement = 99, statInterpolation = { 3, 1, }, }, + [40] = { 16.666667039196, 12, baseMultiplier = 0.743, damageEffectiveness = 0.74, levelRequirement = 100, statInterpolation = { 3, 1, }, }, + }, +} + +skills["CausticArrowMercenaryEncounter"] = { + name = "Caustic Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "CausticArrow", + color = 2, + baseEffectiveness = 4, + incrementalEffectiveness = 0.050000000745058, + description = "Fires an arrow which deals chaos damage in an area on impact, and spreads caustic ground. Enemies standing on the caustic ground take chaos damage over time.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "caustic_arrow_explode_on_hit_base_area_of_effect_radius", 12 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "active_skill_base_radius_+", + "skill_can_fire_arrows", + "projectile_damage_modifiers_apply_to_skill_dot", + "visual_hit_effect_chaos_is_green", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 12.500000279397, 0, baseMultiplier = 0.55, damageEffectiveness = 0.55, levelRequirement = 1, statInterpolation = { 3, 1, }, }, + [2] = { 12.500000279397, 0, baseMultiplier = 0.555, damageEffectiveness = 0.55, levelRequirement = 2, statInterpolation = { 3, 1, }, }, + [3] = { 12.500000279397, 1, baseMultiplier = 0.56, damageEffectiveness = 0.56, levelRequirement = 4, statInterpolation = { 3, 1, }, }, + [4] = { 12.500000279397, 1, baseMultiplier = 0.565, damageEffectiveness = 0.56, levelRequirement = 7, statInterpolation = { 3, 1, }, }, + [5] = { 12.500000279397, 1, baseMultiplier = 0.57, damageEffectiveness = 0.57, levelRequirement = 11, statInterpolation = { 3, 1, }, }, + [6] = { 12.500000279397, 2, baseMultiplier = 0.575, damageEffectiveness = 0.57, levelRequirement = 16, statInterpolation = { 3, 1, }, }, + [7] = { 12.500000279397, 2, baseMultiplier = 0.58, damageEffectiveness = 0.58, levelRequirement = 20, statInterpolation = { 3, 1, }, }, + [8] = { 12.500000279397, 2, baseMultiplier = 0.585, damageEffectiveness = 0.58, levelRequirement = 24, statInterpolation = { 3, 1, }, }, + [9] = { 12.500000279397, 3, baseMultiplier = 0.59, damageEffectiveness = 0.59, levelRequirement = 28, statInterpolation = { 3, 1, }, }, + [10] = { 12.500000279397, 3, baseMultiplier = 0.595, damageEffectiveness = 0.59, levelRequirement = 32, statInterpolation = { 3, 1, }, }, + [11] = { 12.500000279397, 3, baseMultiplier = 0.599, damageEffectiveness = 0.6, levelRequirement = 36, statInterpolation = { 3, 1, }, }, + [12] = { 12.500000279397, 3, baseMultiplier = 0.604, damageEffectiveness = 0.6, levelRequirement = 40, statInterpolation = { 3, 1, }, }, + [13] = { 12.500000279397, 4, baseMultiplier = 0.609, damageEffectiveness = 0.61, levelRequirement = 44, statInterpolation = { 3, 1, }, }, + [14] = { 12.500000279397, 4, baseMultiplier = 0.614, damageEffectiveness = 0.61, levelRequirement = 48, statInterpolation = { 3, 1, }, }, + [15] = { 12.500000279397, 4, baseMultiplier = 0.619, damageEffectiveness = 0.62, levelRequirement = 52, statInterpolation = { 3, 1, }, }, + [16] = { 12.500000279397, 5, baseMultiplier = 0.624, damageEffectiveness = 0.62, levelRequirement = 56, statInterpolation = { 3, 1, }, }, + [17] = { 12.500000279397, 5, baseMultiplier = 0.629, damageEffectiveness = 0.63, levelRequirement = 60, statInterpolation = { 3, 1, }, }, + [18] = { 12.500000279397, 5, baseMultiplier = 0.634, damageEffectiveness = 0.63, levelRequirement = 64, statInterpolation = { 3, 1, }, }, + [19] = { 12.500000279397, 6, baseMultiplier = 0.639, damageEffectiveness = 0.64, levelRequirement = 67, statInterpolation = { 3, 1, }, }, + [20] = { 12.500000279397, 6, baseMultiplier = 0.644, damageEffectiveness = 0.64, levelRequirement = 70, statInterpolation = { 3, 1, }, }, + [21] = { 12.500000279397, 6, baseMultiplier = 0.649, damageEffectiveness = 0.65, levelRequirement = 72, statInterpolation = { 3, 1, }, }, + [22] = { 12.500000279397, 7, baseMultiplier = 0.654, damageEffectiveness = 0.65, levelRequirement = 74, statInterpolation = { 3, 1, }, }, + [23] = { 12.500000279397, 7, baseMultiplier = 0.659, damageEffectiveness = 0.66, levelRequirement = 76, statInterpolation = { 3, 1, }, }, + [24] = { 12.500000279397, 7, baseMultiplier = 0.664, damageEffectiveness = 0.66, levelRequirement = 78, statInterpolation = { 3, 1, }, }, + [25] = { 12.500000279397, 8, baseMultiplier = 0.669, damageEffectiveness = 0.67, levelRequirement = 80, statInterpolation = { 3, 1, }, }, + [26] = { 12.500000279397, 8, baseMultiplier = 0.674, damageEffectiveness = 0.67, levelRequirement = 82, statInterpolation = { 3, 1, }, }, + [27] = { 12.500000279397, 8, baseMultiplier = 0.679, damageEffectiveness = 0.68, levelRequirement = 84, statInterpolation = { 3, 1, }, }, + [28] = { 12.500000279397, 9, baseMultiplier = 0.684, damageEffectiveness = 0.68, levelRequirement = 86, statInterpolation = { 3, 1, }, }, + [29] = { 12.500000279397, 9, baseMultiplier = 0.689, damageEffectiveness = 0.69, levelRequirement = 88, statInterpolation = { 3, 1, }, }, + [30] = { 12.500000279397, 9, baseMultiplier = 0.694, damageEffectiveness = 0.69, levelRequirement = 90, statInterpolation = { 3, 1, }, }, + [31] = { 12.500000279397, 9, baseMultiplier = 0.698, damageEffectiveness = 0.7, levelRequirement = 91, statInterpolation = { 3, 1, }, }, + [32] = { 12.500000279397, 10, baseMultiplier = 0.703, damageEffectiveness = 0.7, levelRequirement = 92, statInterpolation = { 3, 1, }, }, + [33] = { 12.500000279397, 10, baseMultiplier = 0.708, damageEffectiveness = 0.71, levelRequirement = 93, statInterpolation = { 3, 1, }, }, + [34] = { 12.500000279397, 10, baseMultiplier = 0.713, damageEffectiveness = 0.71, levelRequirement = 94, statInterpolation = { 3, 1, }, }, + [35] = { 12.500000279397, 11, baseMultiplier = 0.718, damageEffectiveness = 0.72, levelRequirement = 95, statInterpolation = { 3, 1, }, }, + [36] = { 12.500000279397, 11, baseMultiplier = 0.723, damageEffectiveness = 0.72, levelRequirement = 96, statInterpolation = { 3, 1, }, }, + [37] = { 12.500000279397, 11, baseMultiplier = 0.728, damageEffectiveness = 0.73, levelRequirement = 97, statInterpolation = { 3, 1, }, }, + [38] = { 12.500000279397, 12, baseMultiplier = 0.733, damageEffectiveness = 0.73, levelRequirement = 98, statInterpolation = { 3, 1, }, }, + [39] = { 12.500000279397, 12, baseMultiplier = 0.738, damageEffectiveness = 0.74, levelRequirement = 99, statInterpolation = { 3, 1, }, }, + [40] = { 12.500000279397, 12, baseMultiplier = 0.743, damageEffectiveness = 0.74, levelRequirement = 100, statInterpolation = { 3, 1, }, }, + }, +} + +skills["ChainHookAltMercenary"] = { + name = "Chain Hook of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "ChainHookAltY", + color = 1, + description = "Throws chains ahead of you, attaching them to targets hit. Enemies chained to you will grant rage when hit. When chains are broken, they snap and deal attack damage in an area around the target they were attached to. Requires a One Handed Mace, Sceptre, Sword or Axe.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Melee] = true, [SkillType.Multistrikeable] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Thrusting One Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "chain_hook_attaches_to_X_targets", 4 }, + { "chain_hook_attachment_range", 60 }, + { "chain_hook_attachment_rage_to_gain_per_hit", 1 }, + { "chain_hook_max_attached_targets", 8 }, + { "chain_strike_cone_radius_+_per_x_rage", 5 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 1.711, damageEffectiveness = 1.711, levelRequirement = 12, }, + [2] = { baseMultiplier = 1.788, damageEffectiveness = 1.788, levelRequirement = 15, }, + [3] = { baseMultiplier = 1.871, damageEffectiveness = 1.871, levelRequirement = 19, }, + [4] = { baseMultiplier = 1.959, damageEffectiveness = 1.959, levelRequirement = 23, }, + [5] = { baseMultiplier = 2.05, damageEffectiveness = 2.05, levelRequirement = 27, }, + [6] = { baseMultiplier = 2.146, damageEffectiveness = 2.146, levelRequirement = 31, }, + [7] = { baseMultiplier = 2.246, damageEffectiveness = 2.246, levelRequirement = 35, }, + [8] = { baseMultiplier = 2.346, damageEffectiveness = 2.346, levelRequirement = 38, }, + [9] = { baseMultiplier = 2.451, damageEffectiveness = 2.451, levelRequirement = 41, }, + [10] = { baseMultiplier = 2.561, damageEffectiveness = 2.561, levelRequirement = 44, }, + [11] = { baseMultiplier = 2.675, damageEffectiveness = 2.675, levelRequirement = 47, }, + [12] = { baseMultiplier = 2.794, damageEffectiveness = 2.794, levelRequirement = 50, }, + [13] = { baseMultiplier = 2.918, damageEffectiveness = 2.918, levelRequirement = 53, }, + [14] = { baseMultiplier = 3.049, damageEffectiveness = 3.049, levelRequirement = 56, }, + [15] = { baseMultiplier = 3.185, damageEffectiveness = 3.185, levelRequirement = 59, }, + [16] = { baseMultiplier = 3.325, damageEffectiveness = 3.325, levelRequirement = 62, }, + [17] = { baseMultiplier = 3.468, damageEffectiveness = 3.468, levelRequirement = 64, }, + [18] = { baseMultiplier = 3.616, damageEffectiveness = 3.616, levelRequirement = 66, }, + [19] = { baseMultiplier = 3.771, damageEffectiveness = 3.771, levelRequirement = 68, }, + [20] = { baseMultiplier = 3.931, damageEffectiveness = 3.931, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.099, damageEffectiveness = 4.099, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.273, damageEffectiveness = 4.273, levelRequirement = 74, }, + [23] = { baseMultiplier = 4.456, damageEffectiveness = 4.456, levelRequirement = 76, }, + [24] = { baseMultiplier = 4.646, damageEffectiveness = 4.646, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.845, damageEffectiveness = 4.845, levelRequirement = 80, }, + [26] = { baseMultiplier = 5.051, damageEffectiveness = 5.051, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.266, damageEffectiveness = 5.266, levelRequirement = 84, }, + [28] = { baseMultiplier = 5.49, damageEffectiveness = 5.49, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.725, damageEffectiveness = 5.725, levelRequirement = 88, }, + [30] = { baseMultiplier = 5.968, damageEffectiveness = 5.968, levelRequirement = 90, }, + [31] = { baseMultiplier = 6.334, damageEffectiveness = 6.334, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.469, damageEffectiveness = 6.469, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.607, damageEffectiveness = 6.607, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.746, damageEffectiveness = 6.746, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.89, damageEffectiveness = 6.89, levelRequirement = 95, }, + [36] = { baseMultiplier = 7.037, damageEffectiveness = 7.037, levelRequirement = 96, }, + [37] = { baseMultiplier = 7.186, damageEffectiveness = 7.186, levelRequirement = 97, }, + [38] = { baseMultiplier = 7.339, damageEffectiveness = 7.339, levelRequirement = 98, }, + [39] = { baseMultiplier = 7.494, damageEffectiveness = 7.494, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.654, damageEffectiveness = 7.654, levelRequirement = 100, }, + }, +} + +skills["ChaosGlacialCascadeMercenary"] = { + name = "Profane Cascade", + hidden = true, + mercenary = true, + inheritedFrom = "GlacialCascade", + color = 3, + baseEffectiveness = 0.57099997997284, + incrementalEffectiveness = 0.046399999409914, + description = "Icicles emerge from the ground in a series of small bursts, each damaging enemies caught in the area.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.Physical] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "upheaval_number_of_spikes", 4 }, + { "glacial_cascade_final_spike_damage_+%_final", 200 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + "global_knockback", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.60000002384186, 1, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["ChargedDashSpellScalingMercenary"] = { + name = "Charged Dash of the Arcane", + hidden = true, + mercenary = true, + inheritedFrom = "ChargedDash", + color = 2, + description = "Channel to project an illusion which you steer. You gain stages while it moves, until it stops at a maximum total distance. Waves of area damage frequently pulse along its path, based on your attack speed. Stop channelling to teleport to the illusion, dealing a final wave of damage. Requires a Melee Weapon.", + skillTypes = { [SkillType.Movement] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Channel] = true, [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.Lightning] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + movement = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "charged_dash_damage_+%_final", -100 }, + { "charged_dash_damage_+%_final_per_stack", 75 }, + { "charged_dash_channelling_damage_at_full_stacks_+%_final", 150 }, + { "charged_dash_skill_inherent_movement_speed_+%_final", 30 }, + { "active_skill_attack_speed_+%_final", 75 }, + }, + stats = { + "is_area_damage", + "skill_can_add_multiple_charges_per_action", + "spell_damage_modifiers_apply_to_attack_damage", + }, + levels = { + [1] = { baseMultiplier = 1.437, cooldown = 5, damageEffectiveness = 1.437, levelRequirement = 28, storedUses = 1, }, + [2] = { baseMultiplier = 1.487, cooldown = 5, damageEffectiveness = 1.487, levelRequirement = 31, storedUses = 1, }, + [3] = { baseMultiplier = 1.537, cooldown = 5, damageEffectiveness = 1.537, levelRequirement = 34, storedUses = 1, }, + [4] = { baseMultiplier = 1.59, cooldown = 5, damageEffectiveness = 1.59, levelRequirement = 37, storedUses = 1, }, + [5] = { baseMultiplier = 1.644, cooldown = 5, damageEffectiveness = 1.644, levelRequirement = 40, storedUses = 1, }, + [6] = { baseMultiplier = 1.697, cooldown = 5, damageEffectiveness = 1.697, levelRequirement = 42, storedUses = 1, }, + [7] = { baseMultiplier = 1.751, cooldown = 5, damageEffectiveness = 1.751, levelRequirement = 44, storedUses = 1, }, + [8] = { baseMultiplier = 1.808, cooldown = 5, damageEffectiveness = 1.808, levelRequirement = 46, storedUses = 1, }, + [9] = { baseMultiplier = 1.866, cooldown = 5, damageEffectiveness = 1.866, levelRequirement = 48, storedUses = 1, }, + [10] = { baseMultiplier = 1.926, cooldown = 5, damageEffectiveness = 1.926, levelRequirement = 50, storedUses = 1, }, + [11] = { baseMultiplier = 1.988, cooldown = 5, damageEffectiveness = 1.988, levelRequirement = 52, storedUses = 1, }, + [12] = { baseMultiplier = 2.052, cooldown = 5, damageEffectiveness = 2.052, levelRequirement = 54, storedUses = 1, }, + [13] = { baseMultiplier = 2.118, cooldown = 5, damageEffectiveness = 2.118, levelRequirement = 56, storedUses = 1, }, + [14] = { baseMultiplier = 2.185, cooldown = 5, damageEffectiveness = 2.185, levelRequirement = 58, storedUses = 1, }, + [15] = { baseMultiplier = 2.256, cooldown = 5, damageEffectiveness = 2.256, levelRequirement = 60, storedUses = 1, }, + [16] = { baseMultiplier = 2.328, cooldown = 5, damageEffectiveness = 2.328, levelRequirement = 62, storedUses = 1, }, + [17] = { baseMultiplier = 2.403, cooldown = 5, damageEffectiveness = 2.403, levelRequirement = 64, storedUses = 1, }, + [18] = { baseMultiplier = 2.48, cooldown = 5, damageEffectiveness = 2.48, levelRequirement = 66, storedUses = 1, }, + [19] = { baseMultiplier = 2.559, cooldown = 5, damageEffectiveness = 2.559, levelRequirement = 68, storedUses = 1, }, + [20] = { baseMultiplier = 2.641, cooldown = 5, damageEffectiveness = 2.641, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 2.725, cooldown = 5, damageEffectiveness = 2.725, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 2.813, cooldown = 5, damageEffectiveness = 2.813, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 2.903, cooldown = 5, damageEffectiveness = 2.903, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 2.996, cooldown = 5, damageEffectiveness = 2.996, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 3.092, cooldown = 5, damageEffectiveness = 3.092, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 3.191, cooldown = 5, damageEffectiveness = 3.191, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 3.292, cooldown = 5, damageEffectiveness = 3.292, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 3.398, cooldown = 5, damageEffectiveness = 3.398, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 3.506, cooldown = 5, damageEffectiveness = 3.506, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 3.619, cooldown = 5, damageEffectiveness = 3.619, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 3.782, cooldown = 5, damageEffectiveness = 3.782, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 3.842, cooldown = 5, damageEffectiveness = 3.842, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 3.903, cooldown = 5, damageEffectiveness = 3.903, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 3.965, cooldown = 5, damageEffectiveness = 3.965, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 4.028, cooldown = 5, damageEffectiveness = 4.028, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 4.093, cooldown = 5, damageEffectiveness = 4.093, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 4.157, cooldown = 5, damageEffectiveness = 4.157, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 4.224, cooldown = 5, damageEffectiveness = 4.224, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 4.29, cooldown = 5, damageEffectiveness = 4.29, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 4.359, cooldown = 5, damageEffectiveness = 4.359, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["ClarityMercenary"] = { + name = "Clarity", + hidden = true, + mercenary = true, + inheritedFrom = "Clarity", + color = 3, + description = "Casts an aura that grants mana regeneration to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "base_mana_regeneration_rate_per_minute", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 176, 0, cooldown = 1.2, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 266, 1, cooldown = 1.2, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 387, 2, cooldown = 1.2, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 507, 3, cooldown = 1.2, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 627, 4, cooldown = 1.2, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 748, 5, cooldown = 1.2, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 868, 6, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 958, 7, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 1049, 8, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 1139, 9, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 1229, 10, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 1320, 11, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 1410, 12, cooldown = 1.2, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 1500, 13, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 1590, 14, cooldown = 1.2, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 1681, 15, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 1771, 16, cooldown = 1.2, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 1861, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 1921, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 1982, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 2042, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 2102, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 2162, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 2222, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 2283, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 2343, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 2403, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 2463, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 2523, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 2584, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 2614, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 2644, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 2674, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 2704, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 2734, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 2764, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 2794, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 2824, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 2854, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 2884, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["CleaveMercenary"] = { + name = "Cleave", + hidden = true, + mercenary = true, + inheritedFrom = "Cleave", + color = 1, + description = "The character swings their weapon (or both weapons if dual wielding) in an arc, damaging monsters in an area in front of them. Only works with Axes and Swords.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.ThresholdJewelArea] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "active_skill_merged_damage_+%_final_while_dual_wielding", -40 }, + }, + stats = { + "active_skill_base_radius_+", + "is_area_damage", + "skill_double_hits_when_dual_wielding", + "console_skill_dont_chase", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, baseMultiplier = 2.1116, damageEffectiveness = 2.1116, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 1, baseMultiplier = 2.2418, damageEffectiveness = 2.2418, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 1, baseMultiplier = 2.3846, damageEffectiveness = 2.3846, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 2, baseMultiplier = 2.54, damageEffectiveness = 2.54, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 2, baseMultiplier = 2.7094, damageEffectiveness = 2.7094, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 3, baseMultiplier = 2.8956, damageEffectiveness = 2.8956, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 3, baseMultiplier = 3.0846, damageEffectiveness = 3.0846, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 4, baseMultiplier = 3.2834, damageEffectiveness = 3.2834, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 4, baseMultiplier = 3.4962, damageEffectiveness = 3.4962, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 5, baseMultiplier = 3.7202, damageEffectiveness = 3.7202, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 5, baseMultiplier = 3.9554, damageEffectiveness = 3.9554, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 6, baseMultiplier = 4.2046, damageEffectiveness = 4.2046, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 6, baseMultiplier = 4.4692, damageEffectiveness = 4.4692, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 7, baseMultiplier = 4.7478, damageEffectiveness = 4.7478, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 7, baseMultiplier = 5.0418, damageEffectiveness = 5.0418, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 8, baseMultiplier = 5.354, damageEffectiveness = 5.354, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 8, baseMultiplier = 5.6802, damageEffectiveness = 5.6802, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 9, baseMultiplier = 6.0274, damageEffectiveness = 6.0274, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 9, baseMultiplier = 6.3816, damageEffectiveness = 6.3816, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 10, baseMultiplier = 6.7568, damageEffectiveness = 6.7568, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 10, baseMultiplier = 7.139, damageEffectiveness = 7.139, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 11, baseMultiplier = 7.5422, damageEffectiveness = 7.5422, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 11, baseMultiplier = 7.9664, damageEffectiveness = 7.9664, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 12, baseMultiplier = 8.413, damageEffectiveness = 8.413, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 12, baseMultiplier = 8.8848, damageEffectiveness = 8.8848, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 13, baseMultiplier = 9.379, damageEffectiveness = 9.379, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 13, baseMultiplier = 9.9012, damageEffectiveness = 9.9012, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 14, baseMultiplier = 10.4514, damageEffectiveness = 10.4514, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 14, baseMultiplier = 11.031, damageEffectiveness = 11.031, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 15, baseMultiplier = 11.64, damageEffectiveness = 11.64, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 15, baseMultiplier = 12.578, damageEffectiveness = 12.578, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 15, baseMultiplier = 12.9238, damageEffectiveness = 12.9238, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 16, baseMultiplier = 13.2794, damageEffectiveness = 13.2794, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 16, baseMultiplier = 13.642, damageEffectiveness = 13.642, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 16, baseMultiplier = 14.0158, damageEffectiveness = 14.0158, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 17, baseMultiplier = 14.4008, damageEffectiveness = 14.4008, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 17, baseMultiplier = 14.7956, damageEffectiveness = 14.7956, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 17, baseMultiplier = 15.1988, damageEffectiveness = 15.1988, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 18, baseMultiplier = 15.6146, damageEffectiveness = 15.6146, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 18, baseMultiplier = 16.0402, damageEffectiveness = 16.0402, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["CleaveMercenaryEncounter"] = { + name = "Cleave", + hidden = true, + mercenary = true, + inheritedFrom = "Cleave", + color = 1, + description = "The character swings their weapon (or both weapons if dual wielding) in an arc, damaging monsters in an area in front of them. Only works with Axes and Swords.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.ThresholdJewelArea] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "active_skill_merged_damage_+%_final_while_dual_wielding", -40 }, + }, + stats = { + "active_skill_base_radius_+", + "is_area_damage", + "skill_double_hits_when_dual_wielding", + "console_skill_dont_chase", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, baseMultiplier = 1.794, damageEffectiveness = 1.794, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 1, baseMultiplier = 1.887, damageEffectiveness = 1.887, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 1, baseMultiplier = 1.989, damageEffectiveness = 1.989, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 2, baseMultiplier = 2.1, damageEffectiveness = 2.1, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 2, baseMultiplier = 2.221, damageEffectiveness = 2.221, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 3, baseMultiplier = 2.354, damageEffectiveness = 2.354, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 3, baseMultiplier = 2.489, damageEffectiveness = 2.489, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 4, baseMultiplier = 2.631, damageEffectiveness = 2.631, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 4, baseMultiplier = 2.783, damageEffectiveness = 2.783, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 5, baseMultiplier = 2.943, damageEffectiveness = 2.943, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 5, baseMultiplier = 3.111, damageEffectiveness = 3.111, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 6, baseMultiplier = 3.289, damageEffectiveness = 3.289, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 6, baseMultiplier = 3.478, damageEffectiveness = 3.478, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 7, baseMultiplier = 3.677, damageEffectiveness = 3.677, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 7, baseMultiplier = 3.887, damageEffectiveness = 3.887, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 8, baseMultiplier = 4.11, damageEffectiveness = 4.11, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 8, baseMultiplier = 4.343, damageEffectiveness = 4.343, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 9, baseMultiplier = 4.591, damageEffectiveness = 4.591, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 9, baseMultiplier = 4.844, damageEffectiveness = 4.844, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 10, baseMultiplier = 5.112, damageEffectiveness = 5.112, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 10, baseMultiplier = 5.385, damageEffectiveness = 5.385, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 11, baseMultiplier = 5.673, damageEffectiveness = 5.673, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 11, baseMultiplier = 5.976, damageEffectiveness = 5.976, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 12, baseMultiplier = 6.295, damageEffectiveness = 6.295, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 12, baseMultiplier = 6.632, damageEffectiveness = 6.632, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 13, baseMultiplier = 6.985, damageEffectiveness = 6.985, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 13, baseMultiplier = 7.358, damageEffectiveness = 7.358, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 14, baseMultiplier = 7.751, damageEffectiveness = 7.751, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 14, baseMultiplier = 8.165, damageEffectiveness = 8.165, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 15, baseMultiplier = 8.6, damageEffectiveness = 8.6, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 15, baseMultiplier = 9.27, damageEffectiveness = 9.27, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 15, baseMultiplier = 9.517, damageEffectiveness = 9.517, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 16, baseMultiplier = 9.771, damageEffectiveness = 9.771, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 16, baseMultiplier = 10.03, damageEffectiveness = 10.03, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 16, baseMultiplier = 10.297, damageEffectiveness = 10.297, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 17, baseMultiplier = 10.572, damageEffectiveness = 10.572, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 17, baseMultiplier = 10.854, damageEffectiveness = 10.854, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 17, baseMultiplier = 11.142, damageEffectiveness = 11.142, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 18, baseMultiplier = 11.439, damageEffectiveness = 11.439, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 18, baseMultiplier = 11.743, damageEffectiveness = 11.743, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["CobraLashMercenary"] = { + name = "Cobra Lash", + hidden = true, + mercenary = true, + inheritedFrom = "CobraLash", + color = 2, + description = "Fires a poisonous projectile based on your weapon that will chain between enemies. Requires a Dagger or Claw.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, [SkillType.Chaos] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "projectile_speed_variation_+%", 15 }, + { "projectile_angle_variance", 8 }, + { "base_chance_to_poison_on_hit_%", 40 }, + { "cobra_lash_hit_and_ailment_damage_+%_final_for_each_remaining_chain", 8 }, + }, + stats = { + "number_of_chains", + "base_is_projectile", + "console_skill_dont_chase", + "visual_hit_effect_chaos_is_green", + }, + levels = { + [1] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.25, damageEffectiveness = 1.25, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.292, damageEffectiveness = 1.292, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.334, damageEffectiveness = 1.334, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.376, damageEffectiveness = 1.376, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.418, damageEffectiveness = 1.418, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.461, damageEffectiveness = 1.461, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.503, damageEffectiveness = 1.503, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 3, attackSpeedMultiplier = 20, baseMultiplier = 1.545, damageEffectiveness = 1.545, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.587, damageEffectiveness = 1.587, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.629, damageEffectiveness = 1.629, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.671, damageEffectiveness = 1.671, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.713, damageEffectiveness = 1.713, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.755, damageEffectiveness = 1.755, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.797, damageEffectiveness = 1.797, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.839, damageEffectiveness = 1.839, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 4, attackSpeedMultiplier = 20, baseMultiplier = 1.882, damageEffectiveness = 1.882, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 1.924, damageEffectiveness = 1.924, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 1.966, damageEffectiveness = 1.966, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 2.008, damageEffectiveness = 2.008, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 2.05, damageEffectiveness = 2.05, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 2.092, damageEffectiveness = 2.092, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 2.134, damageEffectiveness = 2.134, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 2.176, damageEffectiveness = 2.176, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 5, attackSpeedMultiplier = 20, baseMultiplier = 2.218, damageEffectiveness = 2.218, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.261, damageEffectiveness = 2.261, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.303, damageEffectiveness = 2.303, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.345, damageEffectiveness = 2.345, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.387, damageEffectiveness = 2.387, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.429, damageEffectiveness = 2.429, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.471, damageEffectiveness = 2.471, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.492, damageEffectiveness = 2.492, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 6, attackSpeedMultiplier = 20, baseMultiplier = 2.513, damageEffectiveness = 2.513, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.534, damageEffectiveness = 2.534, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.555, damageEffectiveness = 2.555, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.576, damageEffectiveness = 2.576, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.597, damageEffectiveness = 2.597, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.618, damageEffectiveness = 2.618, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.639, damageEffectiveness = 2.639, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.661, damageEffectiveness = 2.661, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 7, attackSpeedMultiplier = 20, baseMultiplier = 2.682, damageEffectiveness = 2.682, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["ConductivityMercenary"] = { + name = "Conductivity", + hidden = true, + mercenary = true, + inheritedFrom = "Conductivity", + color = 3, + description = "Curses all targets in an area, lowering their lightning resistance and giving them a chance to be shocked when hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "chance_to_be_shocked_%", 25 }, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "base_lightning_damage_resistance_%", + "base_deal_no_damage", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, -17, cooldown = 10, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 8200, 1, -18, cooldown = 10, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 8400, 1, -19, cooldown = 10, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 8600, 2, -20, cooldown = 10, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8800, 2, -21, cooldown = 10, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 9000, 3, -22, cooldown = 10, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 9200, 3, -23, cooldown = 10, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 9400, 4, -24, cooldown = 10, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 9600, 4, -25, cooldown = 10, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9800, 5, -26, cooldown = 10, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10000, 5, -27, cooldown = 10, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 10200, 6, -28, cooldown = 10, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 10400, 6, -29, cooldown = 10, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 10600, 7, -30, cooldown = 10, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 10800, 7, -31, cooldown = 10, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 11000, 8, -32, cooldown = 10, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 11200, 8, -33, cooldown = 10, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 11400, 9, -34, cooldown = 10, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 11600, 9, -35, cooldown = 10, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 11800, 10, -36, cooldown = 10, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 12000, 10, -37, cooldown = 10, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 12200, 11, -38, cooldown = 10, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 12400, 11, -39, cooldown = 10, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 12600, 12, -40, cooldown = 10, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 12800, 12, -41, cooldown = 10, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13000, 13, -42, cooldown = 10, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13200, 13, -43, cooldown = 10, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 13400, 14, -44, cooldown = 10, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 13600, 14, -45, cooldown = 10, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 13800, 15, -46, cooldown = 10, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 13900, 15, -46, cooldown = 10, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14000, 15, -47, cooldown = 10, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14100, 15, -47, cooldown = 10, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14200, 16, -48, cooldown = 10, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14300, 16, -48, cooldown = 10, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14400, 16, -49, cooldown = 10, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14500, 16, -49, cooldown = 10, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14600, 17, -50, cooldown = 10, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14700, 17, -50, cooldown = 10, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 14800, 17, -51, cooldown = 10, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["ConflagrationMercenary"] = { + name = "Conflagration", + hidden = true, + mercenary = true, + inheritedFrom = "Conflagration", + color = 2, + baseEffectiveness = 3.3840000629425, + incrementalEffectiveness = 0.054000001400709, + description = "Fire arrows into the air that rain down around the targeted area, dealing area damage on impact and leaving the arrows stuck in the ground for a duration. If you move close to a stuck arrow, it will explode, dealing area damage and applying a fire damage over time debuff, as well as causing other stuck arrows in range to also explode.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Fire] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.ProjectileNumber] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, [SkillType.Duration] = true, [SkillType.DamageOverTime] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "secondary_debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + { "active_skill_area_of_effect_description_mode", 7 }, + { "active_skill_base_area_of_effect_radius", 30 }, + { "active_skill_secondary_area_of_effect_description_mode", 7 }, + { "active_skill_base_secondary_area_of_effect_radius", 10 }, + { "active_skill_tertiary_area_of_effect_description_mode", 1 }, + { "napalm_arrow_detonation_hit_damage_+%_final", 50 }, + { "napalm_arrow_maximum_number_of_unprimed_arrows_allowed", 20 }, + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + { "base_secondary_skill_effect_duration", 4000 }, + { "blast_rain_arrow_delay_ms", 90 }, + { "base_number_of_projectiles", 3 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "active_skill_base_tertiary_area_of_effect_radius", + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + "base_skill_show_average_damage_instead_of_dps", + "quality_display_base_number_of_projectiles_is_gem", + "projectile_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 49.500001583248, 15, baseMultiplier = 0.3, damageEffectiveness = 0.3, levelRequirement = 28, statInterpolation = { 3, 1, }, }, + [2] = { 49.500001583248, 15, baseMultiplier = 0.303, damageEffectiveness = 0.3, levelRequirement = 31, statInterpolation = { 3, 1, }, }, + [3] = { 49.500001583248, 16, baseMultiplier = 0.306, damageEffectiveness = 0.31, levelRequirement = 34, statInterpolation = { 3, 1, }, }, + [4] = { 49.500001583248, 16, baseMultiplier = 0.309, damageEffectiveness = 0.31, levelRequirement = 37, statInterpolation = { 3, 1, }, }, + [5] = { 49.500001583248, 16, baseMultiplier = 0.312, damageEffectiveness = 0.31, levelRequirement = 40, statInterpolation = { 3, 1, }, }, + [6] = { 49.500001583248, 16, baseMultiplier = 0.315, damageEffectiveness = 0.31, levelRequirement = 42, statInterpolation = { 3, 1, }, }, + [7] = { 49.500001583248, 17, baseMultiplier = 0.318, damageEffectiveness = 0.32, levelRequirement = 44, statInterpolation = { 3, 1, }, }, + [8] = { 49.500001583248, 17, baseMultiplier = 0.321, damageEffectiveness = 0.32, levelRequirement = 46, statInterpolation = { 3, 1, }, }, + [9] = { 49.500001583248, 17, baseMultiplier = 0.324, damageEffectiveness = 0.32, levelRequirement = 48, statInterpolation = { 3, 1, }, }, + [10] = { 49.500001583248, 17, baseMultiplier = 0.327, damageEffectiveness = 0.33, levelRequirement = 50, statInterpolation = { 3, 1, }, }, + [11] = { 49.500001583248, 18, baseMultiplier = 0.329, damageEffectiveness = 0.33, levelRequirement = 52, statInterpolation = { 3, 1, }, }, + [12] = { 49.500001583248, 18, baseMultiplier = 0.332, damageEffectiveness = 0.33, levelRequirement = 54, statInterpolation = { 3, 1, }, }, + [13] = { 49.500001583248, 18, baseMultiplier = 0.335, damageEffectiveness = 0.34, levelRequirement = 56, statInterpolation = { 3, 1, }, }, + [14] = { 49.500001583248, 18, baseMultiplier = 0.338, damageEffectiveness = 0.34, levelRequirement = 58, statInterpolation = { 3, 1, }, }, + [15] = { 49.500001583248, 19, baseMultiplier = 0.341, damageEffectiveness = 0.34, levelRequirement = 60, statInterpolation = { 3, 1, }, }, + [16] = { 49.500001583248, 19, baseMultiplier = 0.344, damageEffectiveness = 0.34, levelRequirement = 62, statInterpolation = { 3, 1, }, }, + [17] = { 49.500001583248, 19, baseMultiplier = 0.347, damageEffectiveness = 0.35, levelRequirement = 64, statInterpolation = { 3, 1, }, }, + [18] = { 49.500001583248, 19, baseMultiplier = 0.35, damageEffectiveness = 0.35, levelRequirement = 66, statInterpolation = { 3, 1, }, }, + [19] = { 49.500001583248, 20, baseMultiplier = 0.353, damageEffectiveness = 0.35, levelRequirement = 68, statInterpolation = { 3, 1, }, }, + [20] = { 49.500001583248, 20, baseMultiplier = 0.356, damageEffectiveness = 0.36, levelRequirement = 70, statInterpolation = { 3, 1, }, }, + [21] = { 49.500001583248, 20, baseMultiplier = 0.359, damageEffectiveness = 0.36, levelRequirement = 72, statInterpolation = { 3, 1, }, }, + [22] = { 49.500001583248, 20, baseMultiplier = 0.362, damageEffectiveness = 0.36, levelRequirement = 74, statInterpolation = { 3, 1, }, }, + [23] = { 49.500001583248, 21, baseMultiplier = 0.365, damageEffectiveness = 0.36, levelRequirement = 76, statInterpolation = { 3, 1, }, }, + [24] = { 49.500001583248, 21, baseMultiplier = 0.368, damageEffectiveness = 0.37, levelRequirement = 78, statInterpolation = { 3, 1, }, }, + [25] = { 49.500001583248, 21, baseMultiplier = 0.371, damageEffectiveness = 0.37, levelRequirement = 80, statInterpolation = { 3, 1, }, }, + [26] = { 49.500001583248, 21, baseMultiplier = 0.374, damageEffectiveness = 0.37, levelRequirement = 82, statInterpolation = { 3, 1, }, }, + [27] = { 49.500001583248, 22, baseMultiplier = 0.377, damageEffectiveness = 0.38, levelRequirement = 84, statInterpolation = { 3, 1, }, }, + [28] = { 49.500001583248, 22, baseMultiplier = 0.38, damageEffectiveness = 0.38, levelRequirement = 86, statInterpolation = { 3, 1, }, }, + [29] = { 49.500001583248, 22, baseMultiplier = 0.383, damageEffectiveness = 0.38, levelRequirement = 88, statInterpolation = { 3, 1, }, }, + [30] = { 49.500001583248, 22, baseMultiplier = 0.385, damageEffectiveness = 0.39, levelRequirement = 90, statInterpolation = { 3, 1, }, }, + [31] = { 49.500001583248, 23, baseMultiplier = 0.387, damageEffectiveness = 0.39, levelRequirement = 91, statInterpolation = { 3, 1, }, }, + [32] = { 49.500001583248, 23, baseMultiplier = 0.388, damageEffectiveness = 0.39, levelRequirement = 92, statInterpolation = { 3, 1, }, }, + [33] = { 49.500001583248, 23, baseMultiplier = 0.39, damageEffectiveness = 0.39, levelRequirement = 93, statInterpolation = { 3, 1, }, }, + [34] = { 49.500001583248, 23, baseMultiplier = 0.391, damageEffectiveness = 0.39, levelRequirement = 94, statInterpolation = { 3, 1, }, }, + [35] = { 49.500001583248, 24, baseMultiplier = 0.393, damageEffectiveness = 0.39, levelRequirement = 95, statInterpolation = { 3, 1, }, }, + [36] = { 49.500001583248, 24, baseMultiplier = 0.394, damageEffectiveness = 0.39, levelRequirement = 96, statInterpolation = { 3, 1, }, }, + [37] = { 49.500001583248, 24, baseMultiplier = 0.396, damageEffectiveness = 0.4, levelRequirement = 97, statInterpolation = { 3, 1, }, }, + [38] = { 49.500001583248, 24, baseMultiplier = 0.397, damageEffectiveness = 0.4, levelRequirement = 98, statInterpolation = { 3, 1, }, }, + [39] = { 49.500001583248, 25, baseMultiplier = 0.399, damageEffectiveness = 0.4, levelRequirement = 99, statInterpolation = { 3, 1, }, }, + [40] = { 49.500001583248, 25, baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 100, statInterpolation = { 3, 1, }, }, + }, +} + +skills["ConflagrationMercenaryEncounter"] = { + name = "Conflagration", + hidden = true, + mercenary = true, + inheritedFrom = "Conflagration", + color = 2, + baseEffectiveness = 2.5, + incrementalEffectiveness = 0.028500000014901, + description = "Fire arrows into the air that rain down around the targeted area, dealing area damage on impact and leaving the arrows stuck in the ground for a duration. If you move close to a stuck arrow, it will explode, dealing area damage and applying a fire damage over time debuff, as well as causing other stuck arrows in range to also explode.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Fire] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.ProjectileNumber] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, [SkillType.Duration] = true, [SkillType.DamageOverTime] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "secondary_debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + { "active_skill_area_of_effect_description_mode", 7 }, + { "active_skill_base_area_of_effect_radius", 30 }, + { "active_skill_secondary_area_of_effect_description_mode", 7 }, + { "active_skill_base_secondary_area_of_effect_radius", 10 }, + { "active_skill_tertiary_area_of_effect_description_mode", 1 }, + { "napalm_arrow_detonation_hit_damage_+%_final", 50 }, + { "napalm_arrow_maximum_number_of_unprimed_arrows_allowed", 20 }, + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + { "base_secondary_skill_effect_duration", 2000 }, + { "blast_rain_arrow_delay_ms", 90 }, + { "base_number_of_projectiles", 3 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "active_skill_base_tertiary_area_of_effect_radius", + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + "base_skill_show_average_damage_instead_of_dps", + "quality_display_base_number_of_projectiles_is_gem", + "projectile_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 49.500001583248, 15, baseMultiplier = 0.3, damageEffectiveness = 0.3, levelRequirement = 28, statInterpolation = { 3, 1, }, }, + [2] = { 49.500001583248, 15, baseMultiplier = 0.303, damageEffectiveness = 0.3, levelRequirement = 31, statInterpolation = { 3, 1, }, }, + [3] = { 49.500001583248, 16, baseMultiplier = 0.306, damageEffectiveness = 0.31, levelRequirement = 34, statInterpolation = { 3, 1, }, }, + [4] = { 49.500001583248, 16, baseMultiplier = 0.309, damageEffectiveness = 0.31, levelRequirement = 37, statInterpolation = { 3, 1, }, }, + [5] = { 49.500001583248, 16, baseMultiplier = 0.312, damageEffectiveness = 0.31, levelRequirement = 40, statInterpolation = { 3, 1, }, }, + [6] = { 49.500001583248, 16, baseMultiplier = 0.315, damageEffectiveness = 0.31, levelRequirement = 42, statInterpolation = { 3, 1, }, }, + [7] = { 49.500001583248, 17, baseMultiplier = 0.318, damageEffectiveness = 0.32, levelRequirement = 44, statInterpolation = { 3, 1, }, }, + [8] = { 49.500001583248, 17, baseMultiplier = 0.321, damageEffectiveness = 0.32, levelRequirement = 46, statInterpolation = { 3, 1, }, }, + [9] = { 49.500001583248, 17, baseMultiplier = 0.324, damageEffectiveness = 0.32, levelRequirement = 48, statInterpolation = { 3, 1, }, }, + [10] = { 49.500001583248, 17, baseMultiplier = 0.327, damageEffectiveness = 0.33, levelRequirement = 50, statInterpolation = { 3, 1, }, }, + [11] = { 49.500001583248, 18, baseMultiplier = 0.329, damageEffectiveness = 0.33, levelRequirement = 52, statInterpolation = { 3, 1, }, }, + [12] = { 49.500001583248, 18, baseMultiplier = 0.332, damageEffectiveness = 0.33, levelRequirement = 54, statInterpolation = { 3, 1, }, }, + [13] = { 49.500001583248, 18, baseMultiplier = 0.335, damageEffectiveness = 0.34, levelRequirement = 56, statInterpolation = { 3, 1, }, }, + [14] = { 49.500001583248, 18, baseMultiplier = 0.338, damageEffectiveness = 0.34, levelRequirement = 58, statInterpolation = { 3, 1, }, }, + [15] = { 49.500001583248, 19, baseMultiplier = 0.341, damageEffectiveness = 0.34, levelRequirement = 60, statInterpolation = { 3, 1, }, }, + [16] = { 49.500001583248, 19, baseMultiplier = 0.344, damageEffectiveness = 0.34, levelRequirement = 62, statInterpolation = { 3, 1, }, }, + [17] = { 49.500001583248, 19, baseMultiplier = 0.347, damageEffectiveness = 0.35, levelRequirement = 64, statInterpolation = { 3, 1, }, }, + [18] = { 49.500001583248, 19, baseMultiplier = 0.35, damageEffectiveness = 0.35, levelRequirement = 66, statInterpolation = { 3, 1, }, }, + [19] = { 49.500001583248, 20, baseMultiplier = 0.353, damageEffectiveness = 0.35, levelRequirement = 68, statInterpolation = { 3, 1, }, }, + [20] = { 49.500001583248, 20, baseMultiplier = 0.356, damageEffectiveness = 0.36, levelRequirement = 70, statInterpolation = { 3, 1, }, }, + [21] = { 49.500001583248, 20, baseMultiplier = 0.359, damageEffectiveness = 0.36, levelRequirement = 72, statInterpolation = { 3, 1, }, }, + [22] = { 49.500001583248, 20, baseMultiplier = 0.362, damageEffectiveness = 0.36, levelRequirement = 74, statInterpolation = { 3, 1, }, }, + [23] = { 49.500001583248, 21, baseMultiplier = 0.365, damageEffectiveness = 0.36, levelRequirement = 76, statInterpolation = { 3, 1, }, }, + [24] = { 49.500001583248, 21, baseMultiplier = 0.368, damageEffectiveness = 0.37, levelRequirement = 78, statInterpolation = { 3, 1, }, }, + [25] = { 49.500001583248, 21, baseMultiplier = 0.371, damageEffectiveness = 0.37, levelRequirement = 80, statInterpolation = { 3, 1, }, }, + [26] = { 49.500001583248, 21, baseMultiplier = 0.374, damageEffectiveness = 0.37, levelRequirement = 82, statInterpolation = { 3, 1, }, }, + [27] = { 49.500001583248, 22, baseMultiplier = 0.377, damageEffectiveness = 0.38, levelRequirement = 84, statInterpolation = { 3, 1, }, }, + [28] = { 49.500001583248, 22, baseMultiplier = 0.38, damageEffectiveness = 0.38, levelRequirement = 86, statInterpolation = { 3, 1, }, }, + [29] = { 49.500001583248, 22, baseMultiplier = 0.383, damageEffectiveness = 0.38, levelRequirement = 88, statInterpolation = { 3, 1, }, }, + [30] = { 49.500001583248, 22, baseMultiplier = 0.385, damageEffectiveness = 0.39, levelRequirement = 90, statInterpolation = { 3, 1, }, }, + [31] = { 49.500001583248, 23, baseMultiplier = 0.387, damageEffectiveness = 0.39, levelRequirement = 91, statInterpolation = { 3, 1, }, }, + [32] = { 49.500001583248, 23, baseMultiplier = 0.388, damageEffectiveness = 0.39, levelRequirement = 92, statInterpolation = { 3, 1, }, }, + [33] = { 49.500001583248, 23, baseMultiplier = 0.39, damageEffectiveness = 0.39, levelRequirement = 93, statInterpolation = { 3, 1, }, }, + [34] = { 49.500001583248, 23, baseMultiplier = 0.391, damageEffectiveness = 0.39, levelRequirement = 94, statInterpolation = { 3, 1, }, }, + [35] = { 49.500001583248, 24, baseMultiplier = 0.393, damageEffectiveness = 0.39, levelRequirement = 95, statInterpolation = { 3, 1, }, }, + [36] = { 49.500001583248, 24, baseMultiplier = 0.394, damageEffectiveness = 0.39, levelRequirement = 96, statInterpolation = { 3, 1, }, }, + [37] = { 49.500001583248, 24, baseMultiplier = 0.396, damageEffectiveness = 0.4, levelRequirement = 97, statInterpolation = { 3, 1, }, }, + [38] = { 49.500001583248, 24, baseMultiplier = 0.397, damageEffectiveness = 0.4, levelRequirement = 98, statInterpolation = { 3, 1, }, }, + [39] = { 49.500001583248, 25, baseMultiplier = 0.399, damageEffectiveness = 0.4, levelRequirement = 99, statInterpolation = { 3, 1, }, }, + [40] = { 49.500001583248, 25, baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 100, statInterpolation = { 3, 1, }, }, + }, +} + +skills["ConsecratedPathMercenary"] = { + name = "Consecrated Path", + hidden = true, + mercenary = true, + inheritedFrom = "ConsecratedPath", + color = 1, + description = "Slams the ground at a targeted location. If an enemy is near where you target, you'll teleport to it from a short distance away, slam, and create an area of consecrated ground. Can't be supported by Multistrike, and requires a Sword, Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Melee] = true, [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Movement] = true, [SkillType.Triggerable] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Fire] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + movement = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 50 }, + { "base_skill_effect_duration", 4000 }, + { "groundslam_damage_to_close_targets_+%_final", 20 }, + { "ignite_art_variation", 7 }, + }, + stats = { + "is_area_damage", + "visual_hit_effect_elemental_is_holy", + }, + levels = { + [1] = { baseMultiplier = 2.27, damageEffectiveness = 2.27, levelRequirement = 28, }, + [2] = { baseMultiplier = 2.347, damageEffectiveness = 2.347, levelRequirement = 31, }, + [3] = { baseMultiplier = 2.428, damageEffectiveness = 2.428, levelRequirement = 34, }, + [4] = { baseMultiplier = 2.511, damageEffectiveness = 2.511, levelRequirement = 37, }, + [5] = { baseMultiplier = 2.596, damageEffectiveness = 2.596, levelRequirement = 40, }, + [6] = { baseMultiplier = 2.679, damageEffectiveness = 2.679, levelRequirement = 42, }, + [7] = { baseMultiplier = 2.766, damageEffectiveness = 2.766, levelRequirement = 44, }, + [8] = { baseMultiplier = 2.854, damageEffectiveness = 2.854, levelRequirement = 46, }, + [9] = { baseMultiplier = 2.947, damageEffectiveness = 2.947, levelRequirement = 48, }, + [10] = { baseMultiplier = 3.041, damageEffectiveness = 3.041, levelRequirement = 50, }, + [11] = { baseMultiplier = 3.139, damageEffectiveness = 3.139, levelRequirement = 52, }, + [12] = { baseMultiplier = 3.239, damageEffectiveness = 3.239, levelRequirement = 54, }, + [13] = { baseMultiplier = 3.344, damageEffectiveness = 3.344, levelRequirement = 56, }, + [14] = { baseMultiplier = 3.451, damageEffectiveness = 3.451, levelRequirement = 58, }, + [15] = { baseMultiplier = 3.561, damageEffectiveness = 3.561, levelRequirement = 60, }, + [16] = { baseMultiplier = 3.676, damageEffectiveness = 3.676, levelRequirement = 62, }, + [17] = { baseMultiplier = 3.794, damageEffectiveness = 3.794, levelRequirement = 64, }, + [18] = { baseMultiplier = 3.915, damageEffectiveness = 3.915, levelRequirement = 66, }, + [19] = { baseMultiplier = 4.041, damageEffectiveness = 4.041, levelRequirement = 68, }, + [20] = { baseMultiplier = 4.17, damageEffectiveness = 4.17, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.304, damageEffectiveness = 4.304, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.441, damageEffectiveness = 4.441, levelRequirement = 74, }, + [23] = { baseMultiplier = 4.583, damageEffectiveness = 4.583, levelRequirement = 76, }, + [24] = { baseMultiplier = 4.731, damageEffectiveness = 4.731, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.881, damageEffectiveness = 4.881, levelRequirement = 80, }, + [26] = { baseMultiplier = 5.037, damageEffectiveness = 5.037, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.199, damageEffectiveness = 5.199, levelRequirement = 84, }, + [28] = { baseMultiplier = 5.365, damageEffectiveness = 5.365, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.537, damageEffectiveness = 5.537, levelRequirement = 88, }, + [30] = { baseMultiplier = 5.714, damageEffectiveness = 5.714, levelRequirement = 90, }, + [31] = { baseMultiplier = 5.97, damageEffectiveness = 5.97, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.066, damageEffectiveness = 6.066, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.162, damageEffectiveness = 6.162, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.26, damageEffectiveness = 6.26, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.36, damageEffectiveness = 6.36, levelRequirement = 95, }, + [36] = { baseMultiplier = 6.462, damageEffectiveness = 6.462, levelRequirement = 96, }, + [37] = { baseMultiplier = 6.564, damageEffectiveness = 6.564, levelRequirement = 97, }, + [38] = { baseMultiplier = 6.669, damageEffectiveness = 6.669, levelRequirement = 98, }, + [39] = { baseMultiplier = 6.775, damageEffectiveness = 6.775, levelRequirement = 99, }, + [40] = { baseMultiplier = 6.882, damageEffectiveness = 6.882, levelRequirement = 100, }, + }, +} + +skills["CreepingFrostTrapMercenary"] = { + name = "Creeping Frost Trap", + hidden = true, + mercenary = true, + inheritedFrom = "CreepingFrost", + color = 3, + baseEffectiveness = 1.1953999996185, + incrementalEffectiveness = 0.047100000083447, + description = "Fire an icy projectile that bursts on impact or when reaching the targeted area, dealing area damage and creating a chilling area that deals cold damage over time. This area will creep across the ground towards nearby enemies until its duration expires.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Duration] = true, [SkillType.Area] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.ChillingArea] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "arctic_breath_maximum_number_of_skulls_allowed", 10 }, + { "total_projectile_spread_angle_override", 200 }, + { "active_skill_projectile_speed_+%_variation_final", 60 }, + { "base_skill_effect_duration", 5000 }, + { "active_skill_base_area_of_effect_radius", 15 }, + { "active_skill_base_secondary_area_of_effect_radius", 18 }, + { "base_trap_duration", 4000 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_cold_damage_to_deal_per_minute", + "spell_damage_modifiers_apply_to_skill_dot", + "base_is_projectile", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.68999999761581, 1.0299999713898, 70.833334916582, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 12, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.68999999761581, 1.0299999713898, 76.166671230147, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 15, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.68999999761581, 1.0299999713898, 81.333337058624, critChance = 6, levelRequirement = 19, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.68999999761581, 1.0299999713898, 86.666665424903, critChance = 6, levelRequirement = 23, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.68999999761581, 1.0299999713898, 91.666668715576, critChance = 6, levelRequirement = 27, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.68999999761581, 1.0299999713898, 96.66667200625, critChance = 6, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.68999999761581, 1.0299999713898, 101.83333783473, critChance = 6, levelRequirement = 35, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.68999999761581, 1.0299999713898, 106.83333317811, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 38, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.68999999761581, 1.0299999713898, 111.6666659837, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 41, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.68999999761581, 1.0299999713898, 116.49999878928, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.68999999761581, 1.0299999713898, 121.50000207995, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 47, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.68999999761581, 1.0299999713898, 126.00000186265, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.68999999761581, 1.0299999713898, 130.66667213043, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 53, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.68999999761581, 1.0299999713898, 135.33333445092, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.68999999761581, 1.0299999713898, 139.99999677141, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 59, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.68999999761581, 1.0299999713898, 144.3333340163, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.68999999761581, 1.0299999713898, 148.83334174628, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.68999999761581, 1.0299999713898, 153.33333358169, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.68999999761581, 1.0299999713898, 157.99999590218, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.68999999761581, 1.0299999713898, 162.33333314707, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.68999999761581, 1.0299999713898, 166.66667039196, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.68999999761581, 1.0299999713898, 171.16667812193, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.68999999761581, 1.0299999713898, 175.33334488173, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.68999999761581, 1.0299999713898, 179.50001164153, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.68999999761581, 1.0299999713898, 183.66667840133, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.68999999761581, 1.0299999713898, 187.99999975165, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.68999999761581, 1.0299999713898, 192.16666651145, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.68999999761581, 1.0299999713898, 196.00000819564, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.68999999761581, 1.0299999713898, 200.00000447035, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.68999999761581, 1.0299999713898, 204.16667123015, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.68999999761581, 1.0299999713898, 205.99999888241, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.68999999761581, 1.0299999713898, 207.83334242925, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.68999999761581, 1.0299999713898, 209.83334056661, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.68999999761581, 1.0299999713898, 211.83333870396, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.68999999761581, 1.0299999713898, 213.66666635623, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.68999999761581, 1.0299999713898, 215.50000990306, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.68999999761581, 1.0299999713898, 217.50000804042, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.68999999761581, 1.0299999713898, 219.33333569268, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.68999999761581, 1.0299999713898, 221.16667923952, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.68999999761581, 1.0299999713898, 223.00000689179, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["CreepingFrostTrapMercenaryEncounter"] = { + name = "Creeping Frost Trap", + hidden = true, + mercenary = true, + inheritedFrom = "CreepingFrost", + color = 3, + baseEffectiveness = 1.1000000238419, + incrementalEffectiveness = 0.03999999910593, + description = "Fire an icy projectile that bursts on impact or when reaching the targeted area, dealing area damage and creating a chilling area that deals cold damage over time. This area will creep across the ground towards nearby enemies until its duration expires.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Duration] = true, [SkillType.Area] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.ChillingArea] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "arctic_breath_maximum_number_of_skulls_allowed", 10 }, + { "total_projectile_spread_angle_override", 200 }, + { "active_skill_projectile_speed_+%_variation_final", 60 }, + { "base_skill_effect_duration", 5000 }, + { "active_skill_base_area_of_effect_radius", 15 }, + { "active_skill_base_secondary_area_of_effect_radius", 18 }, + { "base_trap_duration", 4000 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_cold_damage_to_deal_per_minute", + "spell_damage_modifiers_apply_to_skill_dot", + "base_is_projectile", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 12, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 15, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 19, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 23, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 27, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 35, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 38, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 41, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 47, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 53, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 59, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 66.666668156783, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["CurseNova"] = { + name = "Elemental Warding", + hidden = true, + mercenary = true, + inheritedFrom = "ElementalWarding", + color = 4, + baseEffectiveness = 4.6556000709534, + incrementalEffectiveness = 0.050000000745058, + description = "Fires projectiles in all directions, converting all their physical damage to a random element, and grants a buff which makes you unaffected by curses for a duration. Removes curses on you when used.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, [SkillType.Triggered] = true, [SkillType.InbuiltTrigger] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Fire] = true, [SkillType.Cold] = true, [SkillType.Lightning] = true, [SkillType.Duration] = true, [SkillType.Buff] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 2, + baseFlags = { + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "number_of_additional_projectiles", 16 }, + { "curse_nova_damage_+%_final_per_curse_removed", 25 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "base_is_projectile", + "projectiles_nova", + "always_pierce", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0.64999997615814, 0.98000001907349, 0.89999997615814, 1.3500000238419, cooldown = 10, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 3, 3, }, }, + }, +} + +skills["CycloneReverseKnockbackMercenary"] = { + name = "Cyclone of the Empire", + hidden = true, + mercenary = true, + inheritedFrom = "Cyclone", + color = 2, + description = "Channel this skill to move towards a targeted location while spinning constantly attacking enemies in an area around you. While channelling this skill, you cannot be knocked back.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Movement] = true, [SkillType.Channel] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + movement = true, + }, + constantStats = { + { "cyclone_movement_speed_+%_final", -30 }, + { "cyclone_area_of_effect_+%_per_additional_melee_range", 10 }, + { "add_frenzy_charge_on_skill_hit_%", 50 }, + }, + stats = { + "is_area_damage", + "skill_can_add_multiple_charges_per_action", + "enemy_knockback_direction_is_reversed", + "global_knockback", + }, + levels = { + [1] = { baseMultiplier = 0.606, damageEffectiveness = 0.606, levelRequirement = 28, }, + [2] = { baseMultiplier = 0.626, damageEffectiveness = 0.626, levelRequirement = 31, }, + [3] = { baseMultiplier = 0.647, damageEffectiveness = 0.647, levelRequirement = 34, }, + [4] = { baseMultiplier = 0.67, damageEffectiveness = 0.67, levelRequirement = 37, }, + [5] = { baseMultiplier = 0.693, damageEffectiveness = 0.693, levelRequirement = 40, }, + [6] = { baseMultiplier = 0.714, damageEffectiveness = 0.714, levelRequirement = 42, }, + [7] = { baseMultiplier = 0.737, damageEffectiveness = 0.737, levelRequirement = 44, }, + [8] = { baseMultiplier = 0.762, damageEffectiveness = 0.762, levelRequirement = 46, }, + [9] = { baseMultiplier = 0.786, damageEffectiveness = 0.786, levelRequirement = 48, }, + [10] = { baseMultiplier = 0.811, damageEffectiveness = 0.811, levelRequirement = 50, }, + [11] = { baseMultiplier = 0.837, damageEffectiveness = 0.837, levelRequirement = 52, }, + [12] = { baseMultiplier = 0.864, damageEffectiveness = 0.864, levelRequirement = 54, }, + [13] = { baseMultiplier = 0.891, damageEffectiveness = 0.891, levelRequirement = 56, }, + [14] = { baseMultiplier = 0.92, damageEffectiveness = 0.92, levelRequirement = 58, }, + [15] = { baseMultiplier = 0.949, damageEffectiveness = 0.949, levelRequirement = 60, }, + [16] = { baseMultiplier = 0.98, damageEffectiveness = 0.98, levelRequirement = 62, }, + [17] = { baseMultiplier = 1.012, damageEffectiveness = 1.012, levelRequirement = 64, }, + [18] = { baseMultiplier = 1.044, damageEffectiveness = 1.044, levelRequirement = 66, }, + [19] = { baseMultiplier = 1.078, damageEffectiveness = 1.078, levelRequirement = 68, }, + [20] = { baseMultiplier = 1.112, damageEffectiveness = 1.112, levelRequirement = 70, }, + [21] = { baseMultiplier = 1.147, damageEffectiveness = 1.147, levelRequirement = 72, }, + [22] = { baseMultiplier = 1.185, damageEffectiveness = 1.185, levelRequirement = 74, }, + [23] = { baseMultiplier = 1.222, damageEffectiveness = 1.222, levelRequirement = 76, }, + [24] = { baseMultiplier = 1.261, damageEffectiveness = 1.261, levelRequirement = 78, }, + [25] = { baseMultiplier = 1.302, damageEffectiveness = 1.302, levelRequirement = 80, }, + [26] = { baseMultiplier = 1.343, damageEffectiveness = 1.343, levelRequirement = 82, }, + [27] = { baseMultiplier = 1.387, damageEffectiveness = 1.387, levelRequirement = 84, }, + [28] = { baseMultiplier = 1.43, damageEffectiveness = 1.43, levelRequirement = 86, }, + [29] = { baseMultiplier = 1.477, damageEffectiveness = 1.477, levelRequirement = 88, }, + [30] = { baseMultiplier = 1.523, damageEffectiveness = 1.523, levelRequirement = 90, }, + [31] = { baseMultiplier = 1.592, damageEffectiveness = 1.592, levelRequirement = 91, }, + [32] = { baseMultiplier = 1.617, damageEffectiveness = 1.617, levelRequirement = 92, }, + [33] = { baseMultiplier = 1.643, damageEffectiveness = 1.643, levelRequirement = 93, }, + [34] = { baseMultiplier = 1.669, damageEffectiveness = 1.669, levelRequirement = 94, }, + [35] = { baseMultiplier = 1.696, damageEffectiveness = 1.696, levelRequirement = 95, }, + [36] = { baseMultiplier = 1.722, damageEffectiveness = 1.722, levelRequirement = 96, }, + [37] = { baseMultiplier = 1.75, damageEffectiveness = 1.75, levelRequirement = 97, }, + [38] = { baseMultiplier = 1.779, damageEffectiveness = 1.779, levelRequirement = 98, }, + [39] = { baseMultiplier = 1.806, damageEffectiveness = 1.806, levelRequirement = 99, }, + [40] = { baseMultiplier = 1.835, damageEffectiveness = 1.835, levelRequirement = 100, }, + }, +} + +skills["DarkPactMercenary"] = { + name = "Dark Bargain", + hidden = true, + mercenary = true, + inheritedFrom = "DarkPact", + color = 3, + baseEffectiveness = 1.6000000238419, + incrementalEffectiveness = 0.035000000149012, + description = "This spell removes some life from one of your Skeleton minions near you or the targeted location to deal chaos damage in an area around it. This effect will chain to your other nearby skeletons. If you have no skeletons near you or the targeted location, it will sacrifice your own life to deal damage instead.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Chains] = true, [SkillType.Chaos] = true, [SkillType.Minion] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + minion = true, + spell = true, + }, + constantStats = { + { "skeletal_chains_aoe_%_health_dealt_as_chaos_damage", 0 }, + { "active_skill_area_of_effect_radius_+%_final", 50 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "is_area_damage", + "skeletal_chains_no_minions_targets_self", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 7, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["DashMercenary"] = { + name = "Dash", + hidden = true, + mercenary = true, + inheritedFrom = "Dash", + color = 2, + description = "Performs a series of quick teleports towards a targeted location. If using the \"Attack in Place\" option, the direction is reversed. Shares a cooldown with other Blink skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Movement] = true, [SkillType.Travel] = true, [SkillType.Blink] = true, [SkillType.Cooldown] = true, [SkillType.FixedCastTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.15, + baseFlags = { + movement = true, + spell = true, + }, + stats = { + "base_cooldown_speed_+%", + "skill_travel_distance_+%", + "base_deal_no_damage", + "skill_cannot_be_interrupted", + "skill_cannot_be_knocked_back", + "skill_cannot_be_stunned", + "spell_cast_time_cannot_be_modified", + }, + notMinionStat = { + "base_cooldown_speed_+%", + }, + levels = { + [1] = { 0, 0, cooldown = 2.5, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 1, 3, cooldown = 2.5, levelRequirement = 6, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 2, 6, cooldown = 2.5, levelRequirement = 9, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 3, 9, cooldown = 2.5, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 4, 12, cooldown = 2.5, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 5, 15, cooldown = 2.5, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 6, 18, cooldown = 2.5, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 7, 21, cooldown = 2.5, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 8, 24, cooldown = 2.5, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 9, 27, cooldown = 2.5, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 10, 30, cooldown = 2.5, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 11, 33, cooldown = 2.5, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 12, 36, cooldown = 2.5, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 13, 39, cooldown = 2.5, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 14, 42, cooldown = 2.5, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 15, 45, cooldown = 2.5, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 16, 48, cooldown = 2.5, levelRequirement = 61, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 17, 51, cooldown = 2.5, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 18, 54, cooldown = 2.5, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 19, 57, cooldown = 2.5, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 20, 60, cooldown = 2.5, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 21, 63, cooldown = 2.5, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 22, 66, cooldown = 2.5, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 23, 69, cooldown = 2.5, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 24, 72, cooldown = 2.5, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 25, 75, cooldown = 2.5, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 26, 78, cooldown = 2.5, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 27, 81, cooldown = 2.5, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 28, 84, cooldown = 2.5, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 29, 87, cooldown = 2.5, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 29, 88, cooldown = 2.5, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 30, 90, cooldown = 2.5, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 30, 91, cooldown = 2.5, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 31, 93, cooldown = 2.5, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 31, 94, cooldown = 2.5, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 32, 96, cooldown = 2.5, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 32, 97, cooldown = 2.5, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 33, 99, cooldown = 2.5, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 33, 100, cooldown = 2.5, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 34, 102, cooldown = 2.5, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["DeceleratingProjectileMercenary"] = { + name = "Chaotic Shot", + hidden = true, + mercenary = true, + inheritedFrom = "DeceleratingProjectileAzmeriCasterDemon", + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + projectile = true, + spell = true, + }, + constantStats = { + { "decelerating_projectile_speed_variation_+%", 150 }, + { "skill_physical_damage_%_to_convert_to_chaos", 20 }, + { "number_of_projectiles_override", 1 }, + }, + stats = { + "active_skill_damage_+%_final", + "base_is_projectile", + "global_poison_on_hit", + "visual_hit_effect_chaos_is_green", + "skill_can_fire_arrows", + }, + notMinionStat = { + "active_skill_damage_+%_final", + }, + levels = { + [1] = { 1, baseMultiplier = 1.25, damageEffectiveness = 1.25, levelRequirement = 1, statInterpolation = { 2, }, }, + [84] = { 100, baseMultiplier = 1.25, damageEffectiveness = 1.25, levelRequirement = 84, statInterpolation = { 2, }, }, + }, +} + +skills["DeceleratingProjectileMercenaryExplode"] = { + name = "Chaotic Burst", + hidden = true, + mercenary = true, + inheritedFrom = "AfflictionMinionPhysSlamCircleBig", + color = 4, + baseEffectiveness = 1.75, + incrementalEffectiveness = 0.029999999329448, + skillTypes = { [SkillType.Triggerable] = true, [SkillType.Attack] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_chaos", 50 }, + }, + stats = { + "active_skill_damage_+%_final", + "is_area_damage", + "visual_hit_effect_chaos_is_green", + }, + notMinionStat = { + "active_skill_damage_+%_final", + }, + levels = { + [1] = { 1, baseMultiplier = 1.6, damageEffectiveness = 1.6, levelRequirement = 1, statInterpolation = { 2, }, }, + [84] = { 50, baseMultiplier = 1.6, damageEffectiveness = 1.6, levelRequirement = 84, statInterpolation = { 2, }, }, + }, +} + +skills["DecoyTotemMercenary"] = { + name = "Decoy Totem", + hidden = true, + mercenary = true, + inheritedFrom = "DecoyTotem", + color = 1, + description = "Summons a totem that taunts nearby monsters to attack it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Area] = true, [SkillType.SummonsTotem] = true, [SkillType.Multicastable] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 6, + castTime = 1, + baseFlags = { + area = true, + spell = true, + totem = true, + }, + constantStats = { + { "base_totem_duration", 8000 }, + { "base_totem_range", 60 }, + }, + stats = { + "totem_life_+%", + "base_skill_is_totemified", + "base_deal_no_damage", + "totems_cannot_evade", + "totem_ignores_cooldown", + "is_totem", + }, + levels = { + [1] = { 0, cooldown = 26, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 4, cooldown = 24, levelRequirement = 6, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 8, cooldown = 22, levelRequirement = 9, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 12, cooldown = 20, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 16, cooldown = 18, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 20, cooldown = 16, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 24, cooldown = 14, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 28, cooldown = 12, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 32, cooldown = 10, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 36, cooldown = 8, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 40, cooldown = 8, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 44, cooldown = 8, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 48, cooldown = 8, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 52, cooldown = 8, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 56, cooldown = 8, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 60, cooldown = 8, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 64, cooldown = 8, levelRequirement = 61, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 68, cooldown = 8, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 72, cooldown = 8, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 76, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 80, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 84, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 88, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 92, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 96, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 100, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 104, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 108, cooldown = 8, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 112, cooldown = 8, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 116, cooldown = 8, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 118, cooldown = 8, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 120, cooldown = 8, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 122, cooldown = 8, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 124, cooldown = 8, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 126, cooldown = 8, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 128, cooldown = 8, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 130, cooldown = 8, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 132, cooldown = 8, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 134, cooldown = 8, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 136, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["DesecrateMercenary"] = { + name = "Desecrate", + hidden = true, + mercenary = true, + inheritedFrom = "Desecrate", + color = 2, + baseEffectiveness = 1.6000000238419, + incrementalEffectiveness = 0.046500001102686, + description = "Desecrates the ground, spawning corpses based on monsters in the current area and dealing chaos damage over time to enemies. If you are using the Raise Spectre skill there is a chance to spawn spectral corpses matching your most recently raised Spectres. Spectral corpses cannot be interacted with except by Minion skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.DamageOverTime] = true, [SkillType.Multicastable] = true, [SkillType.Chaos] = true, [SkillType.Cascadable] = true, [SkillType.AreaSpell] = true, [SkillType.CreatesCorpse] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 4000 }, + { "desecrate_number_of_corpses_to_create", 5 }, + { "desecrate_maximum_number_of_corpses", 10 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "desecrate_corpse_level", + "is_area_damage", + "pact_of_ghorr_can_modify_damage_over_time_of_skill", + }, + levels = { + [1] = { 16.666667039196, 20, cooldown = 3, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 1, }, }, + [2] = { 16.666667039196, 24, cooldown = 3, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 1, }, }, + [3] = { 16.666667039196, 28, cooldown = 3, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 1, }, }, + [4] = { 16.666667039196, 32, cooldown = 3, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 1, }, }, + [5] = { 16.666667039196, 35, cooldown = 3, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 1, }, }, + [6] = { 16.666667039196, 38, cooldown = 3, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 1, }, }, + [7] = { 16.666667039196, 41, cooldown = 3, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 1, }, }, + [8] = { 16.666667039196, 44, cooldown = 3, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 1, }, }, + [9] = { 16.666667039196, 47, cooldown = 3, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 1, }, }, + [10] = { 16.666667039196, 50, cooldown = 3, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 1, }, }, + [11] = { 16.666667039196, 53, cooldown = 3, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 1, }, }, + [12] = { 16.666667039196, 56, cooldown = 3, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 1, }, }, + [13] = { 16.666667039196, 59, cooldown = 3, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 1, }, }, + [14] = { 16.666667039196, 62, cooldown = 3, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 1, }, }, + [15] = { 16.666667039196, 65, cooldown = 3, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 1, }, }, + [16] = { 16.666667039196, 68, cooldown = 3, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 1, }, }, + [17] = { 16.666667039196, 71, cooldown = 3, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 1, }, }, + [18] = { 16.666667039196, 74, cooldown = 3, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 1, }, }, + [19] = { 16.666667039196, 77, cooldown = 3, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 1, }, }, + [20] = { 16.666667039196, 80, cooldown = 3, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 1, }, }, + [21] = { 16.666667039196, 81, cooldown = 3, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 1, }, }, + [22] = { 16.666667039196, 82, cooldown = 3, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 1, }, }, + [23] = { 16.666667039196, 83, cooldown = 3, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 1, }, }, + [24] = { 16.666667039196, 84, cooldown = 3, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 1, }, }, + [25] = { 16.666667039196, 85, cooldown = 3, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 1, }, }, + [26] = { 16.666667039196, 86, cooldown = 3, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 1, }, }, + [27] = { 16.666667039196, 87, cooldown = 3, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 1, }, }, + [28] = { 16.666667039196, 88, cooldown = 3, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 1, }, }, + [29] = { 16.666667039196, 89, cooldown = 3, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 1, }, }, + [30] = { 16.666667039196, 90, cooldown = 3, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 1, }, }, + [31] = { 16.666667039196, 91, cooldown = 3, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 1, }, }, + [32] = { 16.666667039196, 92, cooldown = 3, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 1, }, }, + [33] = { 16.666667039196, 93, cooldown = 3, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 1, }, }, + [34] = { 16.666667039196, 94, cooldown = 3, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 1, }, }, + [35] = { 16.666667039196, 95, cooldown = 3, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 1, }, }, + [36] = { 16.666667039196, 96, cooldown = 3, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 1, }, }, + [37] = { 16.666667039196, 97, cooldown = 3, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 1, }, }, + [38] = { 16.666667039196, 98, cooldown = 3, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 1, }, }, + [39] = { 16.666667039196, 99, cooldown = 3, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 1, }, }, + [40] = { 16.666667039196, 100, cooldown = 3, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 1, }, }, + }, +} + +skills["DespairMercenary"] = { + name = "Despair", + hidden = true, + mercenary = true, + inheritedFrom = "Despair", + color = 3, + description = "Curses all targets in an area, lowering their chaos resistance.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.Chaos] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "base_chaos_damage_resistance_%", + "base_deal_no_damage", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, -15, levelRequirement = 24, statInterpolation = { 1, 1, 1, }, }, + [2] = { 8200, 1, -16, levelRequirement = 27, statInterpolation = { 1, 1, 1, }, }, + [3] = { 8400, 1, -17, levelRequirement = 30, statInterpolation = { 1, 1, 1, }, }, + [4] = { 8600, 2, -18, levelRequirement = 33, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8800, 2, -18, levelRequirement = 36, statInterpolation = { 1, 1, 1, }, }, + [6] = { 9000, 3, -19, levelRequirement = 39, statInterpolation = { 1, 1, 1, }, }, + [7] = { 9200, 3, -20, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [8] = { 9400, 4, -21, levelRequirement = 45, statInterpolation = { 1, 1, 1, }, }, + [9] = { 9600, 4, -21, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9800, 5, -22, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10000, 5, -23, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 10200, 6, -24, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 10400, 6, -24, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 10600, 7, -25, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 10800, 7, -26, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 11000, 8, -27, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 11200, 8, -27, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 11400, 9, -28, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 11600, 9, -29, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 11800, 10, -30, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 12000, 10, -30, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 12200, 11, -31, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 12400, 11, -32, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 12600, 12, -33, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 12800, 12, -33, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13000, 13, -34, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13200, 13, -35, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 13400, 14, -36, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 13600, 14, -36, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 13800, 15, -37, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 13900, 15, -37, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14000, 15, -38, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14100, 15, -38, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14200, 16, -39, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14300, 16, -39, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14400, 16, -39, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14500, 16, -40, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14600, 17, -40, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14700, 17, -40, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 14800, 17, -41, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["DeterminationMercenary"] = { + name = "Determination", + hidden = true, + mercenary = true, + inheritedFrom = "Determination", + color = 1, + description = "Casts an aura that grants armour to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "determination_aura_armour_+%_final", + "base_physical_damage_reduction_rating", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 40, 90, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 40, 107, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 41, 127, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 41, 150, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 42, 176, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 42, 209, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 43, 246, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 43, 286, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 44, 335, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 44, 373, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 45, 414, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 45, 458, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 46, 510, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 46, 561, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 47, 623, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 47, 689, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 48, 762, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 48, 842, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 49, 930, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 49, 1026, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 50, 1077, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 50, 1131, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 51, 1189, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 51, 1247, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 52, 1310, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 52, 1376, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 53, 1444, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 53, 1518, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 54, 1594, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 54, 1673, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 55, 1716, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 55, 1758, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 55, 1801, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 55, 1845, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 56, 1892, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 56, 1937, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 56, 1985, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 56, 2032, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 57, 2084, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 57, 2133, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["DisciplineMercenary"] = { + name = "Discipline", + hidden = true, + mercenary = true, + inheritedFrom = "Discipline", + color = 3, + description = "Casts an aura that grants additional energy shield and increased energy shield recharge rate to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + constantStats = { + { "energy_shield_recharge_rate_+%", 30 }, + }, + stats = { + "base_maximum_energy_shield", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 60, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 69, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 76, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 85, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 94, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 103, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 114, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 124, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 136, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 143, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 147, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 156, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 165, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 171, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 179, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 185, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 192, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 200, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 205, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 217, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 221, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 231, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 238, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 250, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 262, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 269, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 284, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 294, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 304, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 314, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 314, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 323, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 323, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 332, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 332, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 340, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 340, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 348, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 348, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 356, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["DivineIreMercenary"] = { + name = "Divine Ire", + hidden = true, + mercenary = true, + inheritedFrom = "DivineIre", + color = 3, + baseEffectiveness = 0.49039998650551, + incrementalEffectiveness = 0.04280000180006, + description = "Channelling draws in energy around you to repeatedly build up stages, damaging a number of nearby enemies when you do so. Release to unleash this energy in a burst around you and a beam in front of you. Modifiers to area of effect do not affect the beam. Maximum of 10 Stages.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Channel] = true, [SkillType.Lightning] = true, [SkillType.Totemable] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.22, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "divine_tempest_hit_damage_+%_final_per_stage", 240 }, + { "divine_tempest_base_number_of_nearby_enemies_to_zap", 5 }, + { "divine_tempest_ailment_damage_+%_final_per_stage", 100 }, + { "shock_art_variation", 2 }, + { "spell_maximum_action_distance_+%", -70 }, + { "active_skill_area_of_effect_radius_+%_final", -15 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "divine_tempest_beam_width_+", + "visual_hit_effect_elemental_is_holy", + "skill_can_add_multiple_charges_per_action", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 34, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 37, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 42, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 46, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 54, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 58, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["DivineIreMercenaryEncounter"] = { + name = "Divine Ire", + hidden = true, + mercenary = true, + inheritedFrom = "DivineIre", + color = 3, + baseEffectiveness = 0.49039998650551, + incrementalEffectiveness = 0.035000000149012, + description = "Channelling draws in energy around you to repeatedly build up stages, damaging a number of nearby enemies when you do so. Release to unleash this energy in a burst around you and a beam in front of you. Modifiers to area of effect do not affect the beam. Maximum of 10 Stages.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Channel] = true, [SkillType.Lightning] = true, [SkillType.Totemable] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.22, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "divine_tempest_hit_damage_+%_final_per_stage", 240 }, + { "divine_tempest_base_number_of_nearby_enemies_to_zap", 5 }, + { "divine_tempest_ailment_damage_+%_final_per_stage", 100 }, + { "shock_art_variation", 2 }, + { "spell_maximum_action_distance_+%", -70 }, + { "active_skill_area_of_effect_radius_+%_final", -15 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "divine_tempest_beam_width_+", + "visual_hit_effect_elemental_is_holy", + "skill_can_add_multiple_charges_per_action", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 34, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 37, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 42, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 46, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 54, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 58, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 0.45, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["DivineRetributionMercenary"] = { + name = "Divine Retribution", + hidden = true, + mercenary = true, + inheritedFrom = "DivineRetribution", + color = 3, + baseEffectiveness = 4.0999999046326, + incrementalEffectiveness = 0.043200001120567, + description = "Retaliate against a blocked hit with a surge of divine power, causing multiple waves of lightning bursts to expand outward from a targeted location. This skill cannot be Triggered or used by Totems, Traps, or Mines.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Lightning] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.Cooldown] = true, [SkillType.Retaliation] = true, [SkillType.Cascadable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "retaliation_base_use_window_duration_ms", 2000 }, + { "active_skill_base_area_of_effect_radius", 12 }, + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "divine_retribution_num_waves", 4 }, + { "divine_retribution_blasts_per_wave", 6 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_area_of_effect_radius", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["DoLiterallyNothing"] = { + name = "Do Nothing", + hidden = true, + mercenary = true, + color = 4, + baseEffectiveness = 0, + skillTypes = { }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + }, + stats = { + }, + levels = { + [1] = { levelRequirement = 0, }, + }, +} + +skills["DominatingBlowMercenary"] = { + name = "Dominating Blow", + hidden = true, + mercenary = true, + inheritedFrom = "DominatingBlow", + color = 1, + description = "Attacks enemies with a melee strike, applying a debuff for a short duration. If a non-unique enemy dies while affected by the debuff, the enemy's corpse will be consumed and a Sentinel of Dominance with the same rarity, prefix and suffix modifiers will be summoned for a longer secondary duration.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Minion] = true, [SkillType.Duration] = true, [SkillType.MinionsCanExplode] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.CreatesMinion] = true, [SkillType.CreatesSentinelMinion] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Area] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "minion_attack_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + melee = true, + minion = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "base_max_number_of_dominated_normal_monsters", 9 }, + { "base_max_number_of_dominated_magic_monsters", 3 }, + { "base_max_number_of_dominated_rare_monsters", 1 }, + { "base_secondary_skill_effect_duration", 30000 }, + { "dominating_blow_chance_to_summon_on_hitting_unqiue_%", 25 }, + { "base_max_number_of_vaal_dominated_monsters", 3 }, + }, + stats = { + "is_dominated", + }, + levels = { + [1] = { baseMultiplier = 2.498, damageEffectiveness = 2.498, levelRequirement = 28, }, + [2] = { baseMultiplier = 2.583, damageEffectiveness = 2.583, levelRequirement = 31, }, + [3] = { baseMultiplier = 2.671, damageEffectiveness = 2.671, levelRequirement = 34, }, + [4] = { baseMultiplier = 2.761, damageEffectiveness = 2.761, levelRequirement = 37, }, + [5] = { baseMultiplier = 2.855, damageEffectiveness = 2.855, levelRequirement = 40, }, + [6] = { baseMultiplier = 2.947, damageEffectiveness = 2.947, levelRequirement = 42, }, + [7] = { baseMultiplier = 3.042, damageEffectiveness = 3.042, levelRequirement = 44, }, + [8] = { baseMultiplier = 3.14, damageEffectiveness = 3.14, levelRequirement = 46, }, + [9] = { baseMultiplier = 3.241, damageEffectiveness = 3.241, levelRequirement = 48, }, + [10] = { baseMultiplier = 3.345, damageEffectiveness = 3.345, levelRequirement = 50, }, + [11] = { baseMultiplier = 3.453, damageEffectiveness = 3.453, levelRequirement = 52, }, + [12] = { baseMultiplier = 3.563, damageEffectiveness = 3.563, levelRequirement = 54, }, + [13] = { baseMultiplier = 3.678, damageEffectiveness = 3.678, levelRequirement = 56, }, + [14] = { baseMultiplier = 3.796, damageEffectiveness = 3.796, levelRequirement = 58, }, + [15] = { baseMultiplier = 3.918, damageEffectiveness = 3.918, levelRequirement = 60, }, + [16] = { baseMultiplier = 4.044, damageEffectiveness = 4.044, levelRequirement = 62, }, + [17] = { baseMultiplier = 4.174, damageEffectiveness = 4.174, levelRequirement = 64, }, + [18] = { baseMultiplier = 4.307, damageEffectiveness = 4.307, levelRequirement = 66, }, + [19] = { baseMultiplier = 4.445, damageEffectiveness = 4.445, levelRequirement = 68, }, + [20] = { baseMultiplier = 4.587, damageEffectiveness = 4.587, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.735, damageEffectiveness = 4.735, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.886, damageEffectiveness = 4.886, levelRequirement = 74, }, + [23] = { baseMultiplier = 5.042, damageEffectiveness = 5.042, levelRequirement = 76, }, + [24] = { baseMultiplier = 5.204, damageEffectiveness = 5.204, levelRequirement = 78, }, + [25] = { baseMultiplier = 5.37, damageEffectiveness = 5.37, levelRequirement = 80, }, + [26] = { baseMultiplier = 5.542, damageEffectiveness = 5.542, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.719, damageEffectiveness = 5.719, levelRequirement = 84, }, + [28] = { baseMultiplier = 5.902, damageEffectiveness = 5.902, levelRequirement = 86, }, + [29] = { baseMultiplier = 6.09, damageEffectiveness = 6.09, levelRequirement = 88, }, + [30] = { baseMultiplier = 6.284, damageEffectiveness = 6.284, levelRequirement = 90, }, + [31] = { baseMultiplier = 6.567, damageEffectiveness = 6.567, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.672, damageEffectiveness = 6.672, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.779, damageEffectiveness = 6.779, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.887, damageEffectiveness = 6.887, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.996, damageEffectiveness = 6.996, levelRequirement = 95, }, + [36] = { baseMultiplier = 7.107, damageEffectiveness = 7.107, levelRequirement = 96, }, + [37] = { baseMultiplier = 7.221, damageEffectiveness = 7.221, levelRequirement = 97, }, + [38] = { baseMultiplier = 7.336, damageEffectiveness = 7.336, levelRequirement = 98, }, + [39] = { baseMultiplier = 7.453, damageEffectiveness = 7.453, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.571, damageEffectiveness = 7.571, levelRequirement = 100, }, + }, +} + +skills["DonutBladesMercenary"] = { + name = "Triggerblades", + hidden = true, + mercenary = true, + inheritedFrom = "AfflictionMinionPhysSlamCircleBig", + color = 2, + skillTypes = { [SkillType.Triggerable] = true, [SkillType.Attack] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + }, + stats = { + "active_skill_damage_+%_final", + "is_area_damage", + }, + notMinionStat = { + "active_skill_damage_+%_final", + }, + levels = { + [1] = { 1, baseMultiplier = 0.6, levelRequirement = 1, statInterpolation = { 2, }, }, + [2] = { 120, baseMultiplier = 0.6, levelRequirement = 84, statInterpolation = { 2, }, }, + }, +} + +skills["DonutCircleMercenary"] = { + name = "Seismic Crush", + hidden = true, + mercenary = true, + color = 4, + baseEffectiveness = 4, + incrementalEffectiveness = 0.03999999910593, + skillTypes = { [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "voll_slam_damage_+%_final_at_centre", 50 }, + { "active_skill_area_of_effect_radius_+%_final", 50 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.94999998807907, 1.0499999523163, cooldown = 15, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["DoryanisTouchMercenary"] = { + name = "Touch of God", + hidden = true, + mercenary = true, + inheritedFrom = "DoryanisTouch", + color = 1, + description = "The character uses their fist to slam the ground in front of them, with less attack speed, but more damage. This attack deals Lightning Damage to enemies in a large area, with a chance to Shock them. Cannot be used while wielding a Weapon. Cannot be Evaded.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Lightning] = true, [SkillType.Melee] = true, [SkillType.Multistrikeable] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 100 }, + { "base_chance_to_shock_%", 40 }, + }, + stats = { + "is_area_damage", + "global_always_hit", + }, + levels = { + [1] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 28, storedUses = 1, }, + [2] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 31, storedUses = 1, }, + [3] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 34, storedUses = 1, }, + [4] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 37, storedUses = 1, }, + [5] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 40, storedUses = 1, }, + [6] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 42, storedUses = 1, }, + [7] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 44, storedUses = 1, }, + [8] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 46, storedUses = 1, }, + [9] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 48, storedUses = 1, }, + [10] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 50, storedUses = 1, }, + [11] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 52, storedUses = 1, }, + [12] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 54, storedUses = 1, }, + [13] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 56, storedUses = 1, }, + [14] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 58, storedUses = 1, }, + [15] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 60, storedUses = 1, }, + [16] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 62, storedUses = 1, }, + [17] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 64, storedUses = 1, }, + [18] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 66, storedUses = 1, }, + [19] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 68, storedUses = 1, }, + [20] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 70, storedUses = 1, }, + [21] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 72, storedUses = 1, }, + [22] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 74, storedUses = 1, }, + [23] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 76, storedUses = 1, }, + [24] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 78, storedUses = 1, }, + [25] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 80, storedUses = 1, }, + [26] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 82, storedUses = 1, }, + [27] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 84, storedUses = 1, }, + [28] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 86, storedUses = 1, }, + [29] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 88, storedUses = 1, }, + [30] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 90, storedUses = 1, }, + [31] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 91, storedUses = 1, }, + [32] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 92, storedUses = 1, }, + [33] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 93, storedUses = 1, }, + [34] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 94, storedUses = 1, }, + [35] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 95, storedUses = 1, }, + [36] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 96, storedUses = 1, }, + [37] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 97, storedUses = 1, }, + [38] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 98, storedUses = 1, }, + [39] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 99, storedUses = 1, }, + [40] = { attackSpeedMultiplier = -45, cooldown = 10, damageEffectiveness = 10, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["DropArrowMercenary"] = { + name = "Molten Well", + hidden = true, + mercenary = true, + color = 2, + baseEffectiveness = 4, + incrementalEffectiveness = 0.050000000745058, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Duration] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + }, + constantStats = { + { "base_skill_effect_duration", 2500 }, + { "ground_fire_art_variation", 2 }, + { "active_skill_area_of_effect_radius_+%_final", -35 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "base_is_projectile", + "is_area_damage", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 50.000001117587, cooldown = 8, levelRequirement = 28, storedUses = 3, statInterpolation = { 3, }, }, + [2] = { 50.000001117587, cooldown = 8, levelRequirement = 31, storedUses = 3, statInterpolation = { 3, }, }, + [3] = { 50.000001117587, cooldown = 8, levelRequirement = 34, storedUses = 3, statInterpolation = { 3, }, }, + [4] = { 50.000001117587, cooldown = 8, levelRequirement = 37, storedUses = 3, statInterpolation = { 3, }, }, + [5] = { 50.000001117587, cooldown = 8, levelRequirement = 40, storedUses = 3, statInterpolation = { 3, }, }, + [6] = { 50.000001117587, cooldown = 8, levelRequirement = 42, storedUses = 3, statInterpolation = { 3, }, }, + [7] = { 50.000001117587, cooldown = 8, levelRequirement = 44, storedUses = 3, statInterpolation = { 3, }, }, + [8] = { 50.000001117587, cooldown = 8, levelRequirement = 46, storedUses = 3, statInterpolation = { 3, }, }, + [9] = { 50.000001117587, cooldown = 8, levelRequirement = 48, storedUses = 3, statInterpolation = { 3, }, }, + [10] = { 50.000001117587, cooldown = 8, levelRequirement = 50, storedUses = 3, statInterpolation = { 3, }, }, + [11] = { 50.000001117587, cooldown = 8, levelRequirement = 52, storedUses = 3, statInterpolation = { 3, }, }, + [12] = { 50.000001117587, cooldown = 8, levelRequirement = 54, storedUses = 3, statInterpolation = { 3, }, }, + [13] = { 50.000001117587, cooldown = 8, levelRequirement = 56, storedUses = 3, statInterpolation = { 3, }, }, + [14] = { 50.000001117587, cooldown = 8, levelRequirement = 58, storedUses = 3, statInterpolation = { 3, }, }, + [15] = { 50.000001117587, cooldown = 8, levelRequirement = 60, storedUses = 3, statInterpolation = { 3, }, }, + [16] = { 50.000001117587, cooldown = 8, levelRequirement = 62, storedUses = 3, statInterpolation = { 3, }, }, + [17] = { 50.000001117587, cooldown = 8, levelRequirement = 64, storedUses = 3, statInterpolation = { 3, }, }, + [18] = { 50.000001117587, cooldown = 8, levelRequirement = 66, storedUses = 3, statInterpolation = { 3, }, }, + [19] = { 50.000001117587, cooldown = 8, levelRequirement = 68, storedUses = 3, statInterpolation = { 3, }, }, + [20] = { 50.000001117587, cooldown = 8, levelRequirement = 70, storedUses = 3, statInterpolation = { 3, }, }, + [21] = { 50.000001117587, cooldown = 8, levelRequirement = 72, storedUses = 3, statInterpolation = { 3, }, }, + [22] = { 50.000001117587, cooldown = 8, levelRequirement = 74, storedUses = 3, statInterpolation = { 3, }, }, + [23] = { 50.000001117587, cooldown = 8, levelRequirement = 76, storedUses = 3, statInterpolation = { 3, }, }, + [24] = { 50.000001117587, cooldown = 8, levelRequirement = 78, storedUses = 3, statInterpolation = { 3, }, }, + [25] = { 50.000001117587, cooldown = 8, levelRequirement = 80, storedUses = 3, statInterpolation = { 3, }, }, + [26] = { 50.000001117587, cooldown = 8, levelRequirement = 82, storedUses = 3, statInterpolation = { 3, }, }, + [27] = { 50.000001117587, cooldown = 8, levelRequirement = 84, storedUses = 3, statInterpolation = { 3, }, }, + [28] = { 50.000001117587, cooldown = 8, levelRequirement = 86, storedUses = 3, statInterpolation = { 3, }, }, + [29] = { 50.000001117587, cooldown = 8, levelRequirement = 88, storedUses = 3, statInterpolation = { 3, }, }, + [30] = { 50.000001117587, cooldown = 8, levelRequirement = 90, storedUses = 3, statInterpolation = { 3, }, }, + [31] = { 50.000001117587, cooldown = 8, levelRequirement = 91, storedUses = 3, statInterpolation = { 3, }, }, + [32] = { 50.000001117587, cooldown = 8, levelRequirement = 92, storedUses = 3, statInterpolation = { 3, }, }, + [33] = { 50.000001117587, cooldown = 8, levelRequirement = 93, storedUses = 3, statInterpolation = { 3, }, }, + [34] = { 50.000001117587, cooldown = 8, levelRequirement = 94, storedUses = 3, statInterpolation = { 3, }, }, + [35] = { 50.000001117587, cooldown = 8, levelRequirement = 95, storedUses = 3, statInterpolation = { 3, }, }, + [36] = { 50.000001117587, cooldown = 8, levelRequirement = 96, storedUses = 3, statInterpolation = { 3, }, }, + [37] = { 50.000001117587, cooldown = 8, levelRequirement = 97, storedUses = 3, statInterpolation = { 3, }, }, + [38] = { 50.000001117587, cooldown = 8, levelRequirement = 98, storedUses = 3, statInterpolation = { 3, }, }, + [39] = { 50.000001117587, cooldown = 8, levelRequirement = 99, storedUses = 3, statInterpolation = { 3, }, }, + [40] = { 50.000001117587, cooldown = 8, levelRequirement = 100, storedUses = 3, statInterpolation = { 3, }, }, + }, +} + +skills["DropArrowMercenaryEncounter"] = { + name = "Molten Well", + hidden = true, + mercenary = true, + color = 2, + baseEffectiveness = 3, + incrementalEffectiveness = 0.03999999910593, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Duration] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + }, + constantStats = { + { "base_skill_effect_duration", 2500 }, + { "ground_fire_art_variation", 2 }, + { "active_skill_area_of_effect_radius_+%_final", -35 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "base_is_projectile", + "is_area_damage", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 14.833333426466, cooldown = 8, levelRequirement = 28, storedUses = 3, statInterpolation = { 3, }, }, + [2] = { 14.833333426466, cooldown = 8, levelRequirement = 31, storedUses = 3, statInterpolation = { 3, }, }, + [3] = { 14.833333426466, cooldown = 8, levelRequirement = 34, storedUses = 3, statInterpolation = { 3, }, }, + [4] = { 14.833333426466, cooldown = 8, levelRequirement = 37, storedUses = 3, statInterpolation = { 3, }, }, + [5] = { 14.833333426466, cooldown = 8, levelRequirement = 40, storedUses = 3, statInterpolation = { 3, }, }, + [6] = { 14.833333426466, cooldown = 8, levelRequirement = 42, storedUses = 3, statInterpolation = { 3, }, }, + [7] = { 14.833333426466, cooldown = 8, levelRequirement = 44, storedUses = 3, statInterpolation = { 3, }, }, + [8] = { 14.833333426466, cooldown = 8, levelRequirement = 46, storedUses = 3, statInterpolation = { 3, }, }, + [9] = { 14.833333426466, cooldown = 8, levelRequirement = 48, storedUses = 3, statInterpolation = { 3, }, }, + [10] = { 14.833333426466, cooldown = 8, levelRequirement = 50, storedUses = 3, statInterpolation = { 3, }, }, + [11] = { 14.833333426466, cooldown = 8, levelRequirement = 52, storedUses = 3, statInterpolation = { 3, }, }, + [12] = { 14.833333426466, cooldown = 8, levelRequirement = 54, storedUses = 3, statInterpolation = { 3, }, }, + [13] = { 14.833333426466, cooldown = 8, levelRequirement = 56, storedUses = 3, statInterpolation = { 3, }, }, + [14] = { 14.833333426466, cooldown = 8, levelRequirement = 58, storedUses = 3, statInterpolation = { 3, }, }, + [15] = { 14.833333426466, cooldown = 8, levelRequirement = 60, storedUses = 3, statInterpolation = { 3, }, }, + [16] = { 14.833333426466, cooldown = 8, levelRequirement = 62, storedUses = 3, statInterpolation = { 3, }, }, + [17] = { 14.833333426466, cooldown = 8, levelRequirement = 64, storedUses = 3, statInterpolation = { 3, }, }, + [18] = { 14.833333426466, cooldown = 8, levelRequirement = 66, storedUses = 3, statInterpolation = { 3, }, }, + [19] = { 14.833333426466, cooldown = 8, levelRequirement = 68, storedUses = 3, statInterpolation = { 3, }, }, + [20] = { 14.833333426466, cooldown = 8, levelRequirement = 70, storedUses = 3, statInterpolation = { 3, }, }, + [21] = { 14.833333426466, cooldown = 8, levelRequirement = 72, storedUses = 3, statInterpolation = { 3, }, }, + [22] = { 14.833333426466, cooldown = 8, levelRequirement = 74, storedUses = 3, statInterpolation = { 3, }, }, + [23] = { 14.833333426466, cooldown = 8, levelRequirement = 76, storedUses = 3, statInterpolation = { 3, }, }, + [24] = { 14.833333426466, cooldown = 8, levelRequirement = 78, storedUses = 3, statInterpolation = { 3, }, }, + [25] = { 14.833333426466, cooldown = 8, levelRequirement = 80, storedUses = 3, statInterpolation = { 3, }, }, + [26] = { 14.833333426466, cooldown = 8, levelRequirement = 82, storedUses = 3, statInterpolation = { 3, }, }, + [27] = { 14.833333426466, cooldown = 8, levelRequirement = 84, storedUses = 3, statInterpolation = { 3, }, }, + [28] = { 14.833333426466, cooldown = 8, levelRequirement = 86, storedUses = 3, statInterpolation = { 3, }, }, + [29] = { 14.833333426466, cooldown = 8, levelRequirement = 88, storedUses = 3, statInterpolation = { 3, }, }, + [30] = { 14.833333426466, cooldown = 8, levelRequirement = 90, storedUses = 3, statInterpolation = { 3, }, }, + [31] = { 14.833333426466, cooldown = 8, levelRequirement = 91, storedUses = 3, statInterpolation = { 3, }, }, + [32] = { 14.833333426466, cooldown = 8, levelRequirement = 92, storedUses = 3, statInterpolation = { 3, }, }, + [33] = { 14.833333426466, cooldown = 8, levelRequirement = 93, storedUses = 3, statInterpolation = { 3, }, }, + [34] = { 14.833333426466, cooldown = 8, levelRequirement = 94, storedUses = 3, statInterpolation = { 3, }, }, + [35] = { 14.833333426466, cooldown = 8, levelRequirement = 95, storedUses = 3, statInterpolation = { 3, }, }, + [36] = { 14.833333426466, cooldown = 8, levelRequirement = 96, storedUses = 3, statInterpolation = { 3, }, }, + [37] = { 14.833333426466, cooldown = 8, levelRequirement = 97, storedUses = 3, statInterpolation = { 3, }, }, + [38] = { 14.833333426466, cooldown = 8, levelRequirement = 98, storedUses = 3, statInterpolation = { 3, }, }, + [39] = { 14.833333426466, cooldown = 8, levelRequirement = 99, storedUses = 3, statInterpolation = { 3, }, }, + [40] = { 14.833333426466, cooldown = 8, levelRequirement = 100, storedUses = 3, statInterpolation = { 3, }, }, + }, +} + +skills["DualStrikeMercenary"] = { + name = "Dual Strike", + hidden = true, + mercenary = true, + inheritedFrom = "DualStrike", + color = 2, + baseEffectiveness = 0, + description = "Attacks with both weapons, dealing the damage of both in one strike. Dual wield only. Does not work with wands.", + skillTypes = { [SkillType.Attack] = true, [SkillType.DualWieldOnly] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.ThresholdJewelArea] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + }, + constantStats = { + { "dual_strike_critical_strike_chance_+%_final_against_enemies_on_full_life", 100 }, + { "dual_strike_damage_+%_final_against_enemies_on_full_life", 60 }, + }, + stats = { + "skill_double_hits_when_dual_wielding", + }, + levels = { + [1] = { attackSpeedMultiplier = -30, baseMultiplier = 1.553, damageEffectiveness = 1.553, levelRequirement = 1, }, + [2] = { attackSpeedMultiplier = -30, baseMultiplier = 1.633, damageEffectiveness = 1.633, levelRequirement = 2, }, + [3] = { attackSpeedMultiplier = -30, baseMultiplier = 1.722, damageEffectiveness = 1.722, levelRequirement = 4, }, + [4] = { attackSpeedMultiplier = -30, baseMultiplier = 1.817, damageEffectiveness = 1.817, levelRequirement = 7, }, + [5] = { attackSpeedMultiplier = -30, baseMultiplier = 1.922, damageEffectiveness = 1.922, levelRequirement = 11, }, + [6] = { attackSpeedMultiplier = -30, baseMultiplier = 2.036, damageEffectiveness = 2.036, levelRequirement = 16, }, + [7] = { attackSpeedMultiplier = -30, baseMultiplier = 2.153, damageEffectiveness = 2.153, levelRequirement = 20, }, + [8] = { attackSpeedMultiplier = -30, baseMultiplier = 2.278, damageEffectiveness = 2.278, levelRequirement = 24, }, + [9] = { attackSpeedMultiplier = -30, baseMultiplier = 2.409, damageEffectiveness = 2.409, levelRequirement = 28, }, + [10] = { attackSpeedMultiplier = -30, baseMultiplier = 2.546, damageEffectiveness = 2.546, levelRequirement = 32, }, + [11] = { attackSpeedMultiplier = -30, baseMultiplier = 2.693, damageEffectiveness = 2.693, levelRequirement = 36, }, + [12] = { attackSpeedMultiplier = -30, baseMultiplier = 2.847, damageEffectiveness = 2.847, levelRequirement = 40, }, + [13] = { attackSpeedMultiplier = -30, baseMultiplier = 3.01, damageEffectiveness = 3.01, levelRequirement = 44, }, + [14] = { attackSpeedMultiplier = -30, baseMultiplier = 3.182, damageEffectiveness = 3.182, levelRequirement = 48, }, + [15] = { attackSpeedMultiplier = -30, baseMultiplier = 3.364, damageEffectiveness = 3.364, levelRequirement = 52, }, + [16] = { attackSpeedMultiplier = -30, baseMultiplier = 3.556, damageEffectiveness = 3.556, levelRequirement = 56, }, + [17] = { attackSpeedMultiplier = -30, baseMultiplier = 3.759, damageEffectiveness = 3.759, levelRequirement = 60, }, + [18] = { attackSpeedMultiplier = -30, baseMultiplier = 3.973, damageEffectiveness = 3.973, levelRequirement = 64, }, + [19] = { attackSpeedMultiplier = -30, baseMultiplier = 4.192, damageEffectiveness = 4.192, levelRequirement = 67, }, + [20] = { attackSpeedMultiplier = -30, baseMultiplier = 4.424, damageEffectiveness = 4.424, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = -30, baseMultiplier = 4.66, damageEffectiveness = 4.66, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = -30, baseMultiplier = 4.909, damageEffectiveness = 4.909, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = -30, baseMultiplier = 5.171, damageEffectiveness = 5.171, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = -30, baseMultiplier = 5.448, damageEffectiveness = 5.448, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = -30, baseMultiplier = 5.739, damageEffectiveness = 5.739, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = -30, baseMultiplier = 6.045, damageEffectiveness = 6.045, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = -30, baseMultiplier = 6.368, damageEffectiveness = 6.368, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = -30, baseMultiplier = 6.707, damageEffectiveness = 6.707, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = -30, baseMultiplier = 7.066, damageEffectiveness = 7.066, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = -30, baseMultiplier = 7.442, damageEffectiveness = 7.442, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = -30, baseMultiplier = 8.023, damageEffectiveness = 8.023, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = -30, baseMultiplier = 8.236, damageEffectiveness = 8.236, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = -30, baseMultiplier = 8.456, damageEffectiveness = 8.456, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = -30, baseMultiplier = 8.68, damageEffectiveness = 8.68, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = -30, baseMultiplier = 8.912, damageEffectiveness = 8.912, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = -30, baseMultiplier = 9.149, damageEffectiveness = 9.149, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = -30, baseMultiplier = 9.393, damageEffectiveness = 9.393, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = -30, baseMultiplier = 9.642, damageEffectiveness = 9.642, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = -30, baseMultiplier = 9.899, damageEffectiveness = 9.899, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = -30, baseMultiplier = 10.162, damageEffectiveness = 10.162, levelRequirement = 100, }, + }, +} + +skills["EASRitualDaemonChaosProjectileRuckus"] = { + name = "EASRitualDaemonChaosProjectileRuckus", + hidden = true, + mercenary = true, + inheritedFrom = "EmptyActionSpellWarlordGrandmaster", + color = 4, + skillTypes = { [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 3, + baseFlags = { + spell = true, + }, + stats = { + }, + levels = { + [1] = { cooldown = 6, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["EarthquakeAltMercenary"] = { + name = "Earthquake of Amplification", + hidden = true, + mercenary = true, + inheritedFrom = "EarthquakeAltX", + color = 1, + description = "Smashes the ground, dealing damage in an area and cracking the earth. The crack will erupt in a powerful aftershock after a duration. Cracks created before the first one has erupted will not generate their own aftershocks. Requires an Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Multistrikeable] = true, [SkillType.Duration] = true, [SkillType.Slam] = true, [SkillType.Triggerable] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "base_skill_effect_duration", 1500 }, + { "earthquake_skill_aftershock_hit_damage_+%_final_per_100ms_duration", 15 }, + { "earthquake_skill_aftershock_ailment_damage_+%_final_per_100ms_duration", 5 }, + { "earthquake_skill_aftershock_area_of_effect_+%_final_per_100ms_duration", 2 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 1.437, damageEffectiveness = 1.437, levelRequirement = 28, }, + [2] = { baseMultiplier = 1.476, damageEffectiveness = 1.476, levelRequirement = 31, }, + [3] = { baseMultiplier = 1.515, damageEffectiveness = 1.515, levelRequirement = 34, }, + [4] = { baseMultiplier = 1.555, damageEffectiveness = 1.555, levelRequirement = 37, }, + [5] = { baseMultiplier = 1.595, damageEffectiveness = 1.595, levelRequirement = 40, }, + [6] = { baseMultiplier = 1.634, damageEffectiveness = 1.634, levelRequirement = 42, }, + [7] = { baseMultiplier = 1.674, damageEffectiveness = 1.674, levelRequirement = 44, }, + [8] = { baseMultiplier = 1.716, damageEffectiveness = 1.716, levelRequirement = 46, }, + [9] = { baseMultiplier = 1.758, damageEffectiveness = 1.758, levelRequirement = 48, }, + [10] = { baseMultiplier = 1.801, damageEffectiveness = 1.801, levelRequirement = 50, }, + [11] = { baseMultiplier = 1.845, damageEffectiveness = 1.845, levelRequirement = 52, }, + [12] = { baseMultiplier = 1.89, damageEffectiveness = 1.89, levelRequirement = 54, }, + [13] = { baseMultiplier = 1.936, damageEffectiveness = 1.936, levelRequirement = 56, }, + [14] = { baseMultiplier = 1.983, damageEffectiveness = 1.983, levelRequirement = 58, }, + [15] = { baseMultiplier = 2.032, damageEffectiveness = 2.032, levelRequirement = 60, }, + [16] = { baseMultiplier = 2.081, damageEffectiveness = 2.081, levelRequirement = 62, }, + [17] = { baseMultiplier = 2.133, damageEffectiveness = 2.133, levelRequirement = 64, }, + [18] = { baseMultiplier = 2.184, damageEffectiveness = 2.184, levelRequirement = 66, }, + [19] = { baseMultiplier = 2.238, damageEffectiveness = 2.238, levelRequirement = 68, }, + [20] = { baseMultiplier = 2.293, damageEffectiveness = 2.293, levelRequirement = 70, }, + [21] = { baseMultiplier = 2.348, damageEffectiveness = 2.348, levelRequirement = 72, }, + [22] = { baseMultiplier = 2.405, damageEffectiveness = 2.405, levelRequirement = 74, }, + [23] = { baseMultiplier = 2.463, damageEffectiveness = 2.463, levelRequirement = 76, }, + [24] = { baseMultiplier = 2.524, damageEffectiveness = 2.524, levelRequirement = 78, }, + [25] = { baseMultiplier = 2.585, damageEffectiveness = 2.585, levelRequirement = 80, }, + [26] = { baseMultiplier = 2.648, damageEffectiveness = 2.648, levelRequirement = 82, }, + [27] = { baseMultiplier = 2.712, damageEffectiveness = 2.712, levelRequirement = 84, }, + [28] = { baseMultiplier = 2.777, damageEffectiveness = 2.777, levelRequirement = 86, }, + [29] = { baseMultiplier = 2.845, damageEffectiveness = 2.845, levelRequirement = 88, }, + [30] = { baseMultiplier = 2.914, damageEffectiveness = 2.914, levelRequirement = 90, }, + [31] = { baseMultiplier = 3.011, damageEffectiveness = 3.011, levelRequirement = 91, }, + [32] = { baseMultiplier = 3.048, damageEffectiveness = 3.048, levelRequirement = 92, }, + [33] = { baseMultiplier = 3.085, damageEffectiveness = 3.085, levelRequirement = 93, }, + [34] = { baseMultiplier = 3.122, damageEffectiveness = 3.122, levelRequirement = 94, }, + [35] = { baseMultiplier = 3.16, damageEffectiveness = 3.16, levelRequirement = 95, }, + [36] = { baseMultiplier = 3.198, damageEffectiveness = 3.198, levelRequirement = 96, }, + [37] = { baseMultiplier = 3.236, damageEffectiveness = 3.236, levelRequirement = 97, }, + [38] = { baseMultiplier = 3.275, damageEffectiveness = 3.275, levelRequirement = 98, }, + [39] = { baseMultiplier = 3.315, damageEffectiveness = 3.315, levelRequirement = 99, }, + [40] = { baseMultiplier = 3.355, damageEffectiveness = 3.355, levelRequirement = 100, }, + }, +} + +skills["EarthquakeColdMercenary"] = { + name = "Earthquake of Winter", + hidden = true, + mercenary = true, + inheritedFrom = "Earthquake", + color = 1, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.023299999535084, + description = "Smashes the ground, dealing damage in an area and cracking the earth. The crack will erupt in a powerful aftershock after a duration. Cracks created before the first one has erupted will not generate their own aftershocks. Requires an Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Multistrikeable] = true, [SkillType.Duration] = true, [SkillType.Slam] = true, [SkillType.Triggerable] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "base_skill_effect_duration", 1000 }, + { "quake_slam_fully_charged_explosion_damage_+%_final", 150 }, + { "skill_physical_damage_%_to_convert_to_cold", 100 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 1.437, cooldown = 1.5, damageEffectiveness = 1.437, levelRequirement = 28, storedUses = 1, }, + [2] = { baseMultiplier = 1.476, cooldown = 1.5, damageEffectiveness = 1.476, levelRequirement = 31, storedUses = 1, }, + [3] = { baseMultiplier = 1.515, cooldown = 1.5, damageEffectiveness = 1.515, levelRequirement = 34, storedUses = 1, }, + [4] = { baseMultiplier = 1.555, cooldown = 1.5, damageEffectiveness = 1.555, levelRequirement = 37, storedUses = 1, }, + [5] = { baseMultiplier = 1.595, cooldown = 1.5, damageEffectiveness = 1.595, levelRequirement = 40, storedUses = 1, }, + [6] = { baseMultiplier = 1.634, cooldown = 1.5, damageEffectiveness = 1.634, levelRequirement = 42, storedUses = 1, }, + [7] = { baseMultiplier = 1.674, cooldown = 1.5, damageEffectiveness = 1.674, levelRequirement = 44, storedUses = 1, }, + [8] = { baseMultiplier = 1.716, cooldown = 1.5, damageEffectiveness = 1.716, levelRequirement = 46, storedUses = 1, }, + [9] = { baseMultiplier = 1.758, cooldown = 1.5, damageEffectiveness = 1.758, levelRequirement = 48, storedUses = 1, }, + [10] = { baseMultiplier = 1.801, cooldown = 1.5, damageEffectiveness = 1.801, levelRequirement = 50, storedUses = 1, }, + [11] = { baseMultiplier = 1.845, cooldown = 1.5, damageEffectiveness = 1.845, levelRequirement = 52, storedUses = 1, }, + [12] = { baseMultiplier = 1.89, cooldown = 1.5, damageEffectiveness = 1.89, levelRequirement = 54, storedUses = 1, }, + [13] = { baseMultiplier = 1.936, cooldown = 1.5, damageEffectiveness = 1.936, levelRequirement = 56, storedUses = 1, }, + [14] = { baseMultiplier = 1.983, cooldown = 1.5, damageEffectiveness = 1.983, levelRequirement = 58, storedUses = 1, }, + [15] = { baseMultiplier = 2.032, cooldown = 1.5, damageEffectiveness = 2.032, levelRequirement = 60, storedUses = 1, }, + [16] = { baseMultiplier = 2.081, cooldown = 1.5, damageEffectiveness = 2.081, levelRequirement = 62, storedUses = 1, }, + [17] = { baseMultiplier = 2.133, cooldown = 1.5, damageEffectiveness = 2.133, levelRequirement = 64, storedUses = 1, }, + [18] = { baseMultiplier = 2.184, cooldown = 1.5, damageEffectiveness = 2.184, levelRequirement = 66, storedUses = 1, }, + [19] = { baseMultiplier = 2.238, cooldown = 1.5, damageEffectiveness = 2.238, levelRequirement = 68, storedUses = 1, }, + [20] = { baseMultiplier = 2.293, cooldown = 1.5, damageEffectiveness = 2.293, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 2.348, cooldown = 1.5, damageEffectiveness = 2.348, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 2.405, cooldown = 1.5, damageEffectiveness = 2.405, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 2.463, cooldown = 1.5, damageEffectiveness = 2.463, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 2.524, cooldown = 1.5, damageEffectiveness = 2.524, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 2.585, cooldown = 1.5, damageEffectiveness = 2.585, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 2.648, cooldown = 1.5, damageEffectiveness = 2.648, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 2.712, cooldown = 1.5, damageEffectiveness = 2.712, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 2.777, cooldown = 1.5, damageEffectiveness = 2.777, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 2.845, cooldown = 1.5, damageEffectiveness = 2.845, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 2.914, cooldown = 1.5, damageEffectiveness = 2.914, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 3.011, cooldown = 1.5, damageEffectiveness = 3.011, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 3.048, cooldown = 1.5, damageEffectiveness = 3.048, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 3.085, cooldown = 1.5, damageEffectiveness = 3.085, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 3.122, cooldown = 1.5, damageEffectiveness = 3.122, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 3.16, cooldown = 1.5, damageEffectiveness = 3.16, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 3.198, cooldown = 1.5, damageEffectiveness = 3.198, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 3.236, cooldown = 1.5, damageEffectiveness = 3.236, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 3.275, cooldown = 1.5, damageEffectiveness = 3.275, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 3.315, cooldown = 1.5, damageEffectiveness = 3.315, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 3.355, cooldown = 1.5, damageEffectiveness = 3.355, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["ElementalHitColdOnlyMercenary"] = { + name = "Elemental Hit of Ice", + hidden = true, + mercenary = true, + inheritedFrom = "ElementalHit", + color = 2, + baseEffectiveness = 3.2400000095367, + incrementalEffectiveness = 0.035999998450279, + description = "Each attack with a melee weapon will choose an element at random, and will only be able to deal damage of that element. If the attack hits an enemy, it will deal damage in an area around them, with the radius being larger if that enemy is suffering from an ailment of the chosen element. It will avoid choosing the same element twice in a row.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Fire] = true, [SkillType.Cold] = true, [SkillType.Lightning] = true, [SkillType.Area] = true, [SkillType.RandomElement] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "elemental_hit_damage_+%_final_per_enemy_elemental_ailment", 10 }, + { "active_skill_base_area_of_effect_radius", 14 }, + { "skill_physical_damage_%_to_convert_to_cold", 100 }, + }, + stats = { + "elemental_hit_area_of_effect_+100%_final_vs_enemy_with_associated_ailment", + "elemental_hit_no_physical_chaos_damage", + "elemental_hit_no_damage_of_unchosen_elemental_type", + "quality_display_elemental_hit_is_gem", + "elemental_hit_cannot_roll_fire_damage", + "elemental_hit_cannot_roll_lightning_damage", + }, + levels = { + [1] = { attackSpeedMultiplier = 20, levelRequirement = 12, }, + [2] = { attackSpeedMultiplier = 20, levelRequirement = 15, }, + [3] = { attackSpeedMultiplier = 20, levelRequirement = 19, }, + [4] = { attackSpeedMultiplier = 20, levelRequirement = 23, }, + [5] = { attackSpeedMultiplier = 20, levelRequirement = 27, }, + [6] = { attackSpeedMultiplier = 20, levelRequirement = 31, }, + [7] = { attackSpeedMultiplier = 20, levelRequirement = 35, }, + [8] = { attackSpeedMultiplier = 20, levelRequirement = 38, }, + [9] = { attackSpeedMultiplier = 20, levelRequirement = 41, }, + [10] = { attackSpeedMultiplier = 20, levelRequirement = 44, }, + [11] = { attackSpeedMultiplier = 20, levelRequirement = 47, }, + [12] = { attackSpeedMultiplier = 20, levelRequirement = 50, }, + [13] = { attackSpeedMultiplier = 20, levelRequirement = 53, }, + [14] = { attackSpeedMultiplier = 20, levelRequirement = 56, }, + [15] = { attackSpeedMultiplier = 20, levelRequirement = 59, }, + [16] = { attackSpeedMultiplier = 20, levelRequirement = 62, }, + [17] = { attackSpeedMultiplier = 20, levelRequirement = 64, }, + [18] = { attackSpeedMultiplier = 20, levelRequirement = 66, }, + [19] = { attackSpeedMultiplier = 20, levelRequirement = 68, }, + [20] = { attackSpeedMultiplier = 20, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = 20, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = 20, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = 20, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = 20, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = 20, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = 20, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = 20, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = 20, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = 20, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = 20, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = 20, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = 20, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = 20, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = 20, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = 20, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = 20, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = 20, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = 20, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = 20, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = 20, levelRequirement = 100, }, + }, +} + +skills["ElementalHitColdOnlyMercenaryEncounter"] = { + name = "Elemental Hit of Ice", + hidden = true, + mercenary = true, + inheritedFrom = "ElementalHit", + color = 2, + description = "Each attack with a melee weapon will choose an element at random, and will only be able to deal damage of that element. If the attack hits an enemy, it will deal damage in an area around them, with the radius being larger if that enemy is suffering from an ailment of the chosen element. It will avoid choosing the same element twice in a row.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Fire] = true, [SkillType.Cold] = true, [SkillType.Lightning] = true, [SkillType.Area] = true, [SkillType.RandomElement] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "elemental_hit_damage_+%_final_per_enemy_elemental_ailment", 10 }, + { "active_skill_base_area_of_effect_radius", 14 }, + { "skill_physical_damage_%_to_convert_to_cold", 100 }, + }, + stats = { + "elemental_hit_area_of_effect_+100%_final_vs_enemy_with_associated_ailment", + "elemental_hit_no_physical_chaos_damage", + "elemental_hit_no_damage_of_unchosen_elemental_type", + "quality_display_elemental_hit_is_gem", + "elemental_hit_cannot_roll_fire_damage", + "elemental_hit_cannot_roll_lightning_damage", + }, + levels = { + [1] = { baseMultiplier = 1.7, damageEffectiveness = 1.7, levelRequirement = 0, }, + }, +} + +skills["ElementalWeaknessAuraMapBoss"] = { + name = "Elemental Weakness", + hidden = true, + mercenary = true, + inheritedFrom = "ElementalWeakness", + color = 3, + baseEffectiveness = 0, + description = "Curses all targets in an area, lowering their elemental resistances.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 1.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "base_resist_all_elements_%", -40 }, + { "active_skill_area_of_effect_radius_+%_final", 50 }, + }, + stats = { + "curse_apply_as_aura", + }, + levels = { + [1] = { cooldown = 5, levelRequirement = 1, storedUses = 1, cost = { Mana = 50, }, }, + }, +} + +skills["ElementalWeaknessMercenary"] = { + name = "Elemental Weakness", + hidden = true, + mercenary = true, + inheritedFrom = "ElementalWeakness", + color = 3, + baseEffectiveness = 0, + description = "Curses all targets in an area, lowering their elemental resistances.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "base_resist_all_elements_%", + "base_deal_no_damage", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, -15, levelRequirement = 24, statInterpolation = { 1, 1, 1, }, }, + [2] = { 8200, 1, -16, levelRequirement = 27, statInterpolation = { 1, 1, 1, }, }, + [3] = { 8400, 1, -17, levelRequirement = 30, statInterpolation = { 1, 1, 1, }, }, + [4] = { 8600, 2, -18, levelRequirement = 33, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8800, 2, -18, levelRequirement = 36, statInterpolation = { 1, 1, 1, }, }, + [6] = { 9000, 3, -19, levelRequirement = 39, statInterpolation = { 1, 1, 1, }, }, + [7] = { 9200, 3, -20, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [8] = { 9400, 4, -21, levelRequirement = 45, statInterpolation = { 1, 1, 1, }, }, + [9] = { 9600, 4, -21, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9800, 5, -22, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10000, 5, -23, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 10200, 6, -24, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 10400, 6, -24, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 10600, 7, -25, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 10800, 7, -26, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 11000, 8, -27, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 11200, 8, -27, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 11400, 9, -28, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 11600, 9, -29, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 11800, 10, -30, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 12000, 10, -30, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 12200, 11, -31, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 12400, 11, -32, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 12600, 12, -33, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 12800, 12, -33, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13000, 13, -34, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13200, 13, -35, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 13400, 14, -36, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 13600, 14, -36, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 13800, 15, -37, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 13900, 15, -37, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14000, 15, -38, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14100, 15, -38, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14200, 16, -39, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14300, 16, -39, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14400, 16, -39, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14500, 16, -40, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14600, 17, -40, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14700, 17, -40, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 14800, 17, -41, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["EnduringCryMercenary"] = { + name = "Enduring Cry", + hidden = true, + mercenary = true, + inheritedFrom = "EnduringCry", + color = 1, + baseEffectiveness = 0, + description = "Performs a warcry, taunting all nearby enemies to attack the user and granting a buff to the user and nearby allies. The user and allied players also gain endurance charges.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "enduring_cry_grants_x_additional_endurance_charges", 3 }, + { "base_skill_effect_duration", 1000 }, + { "life_regeneration_rate_per_minute_%", 600 }, + }, + stats = { + "warcry_speed_+%", + "base_deal_no_attack_damage", + "base_deal_no_spell_damage", + "base_deal_no_secondary_damage", + }, + levels = { + [1] = { 0, cooldown = 8, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 2, cooldown = 8, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 4, cooldown = 8, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 6, cooldown = 8, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 8, cooldown = 8, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 10, cooldown = 8, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 12, cooldown = 8, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 14, cooldown = 8, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 16, cooldown = 8, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 18, cooldown = 8, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 20, cooldown = 8, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 22, cooldown = 8, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 24, cooldown = 8, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 26, cooldown = 8, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 28, cooldown = 8, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 30, cooldown = 8, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 32, cooldown = 8, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 34, cooldown = 8, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 36, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 38, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 40, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 41, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 42, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 43, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 44, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 45, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 46, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 47, cooldown = 8, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 48, cooldown = 8, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 49, cooldown = 8, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 49, cooldown = 8, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 50, cooldown = 8, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 50, cooldown = 8, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 51, cooldown = 8, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 51, cooldown = 8, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 52, cooldown = 8, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 52, cooldown = 8, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 53, cooldown = 8, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 53, cooldown = 8, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 54, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["EnfeebleAuraMapBoss"] = { + name = "Enfeeble", + hidden = true, + mercenary = true, + inheritedFrom = "Enfeeble", + color = 3, + baseEffectiveness = 0, + description = "Curses all targets in an area, reducing their accuracy and making them deal less damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 1.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "accuracy_rating_+%", -40 }, + { "enfeeble_damage_+%_final", -40 }, + { "enfeeble_damage_+%_vs_rare_or_unique_final", -15 }, + { "active_skill_area_of_effect_radius_+%_final", 50 }, + }, + stats = { + "curse_apply_as_aura", + }, + levels = { + [1] = { cooldown = 5, levelRequirement = 4, storedUses = 1, cost = { Mana = 50, }, }, + }, +} + +skills["EnfeebleMercenary"] = { + name = "Blasphemy Enfeeble", + hidden = true, + mercenary = true, + inheritedFrom = "Enfeeble", + color = 3, + baseEffectiveness = 0, + description = "Curses all targets in an area, reducing their accuracy and making them deal less damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "accuracy_rating_+%", + "enfeeble_damage_+%_final", + "enfeeble_damage_+%_vs_rare_or_unique_final", + "base_deal_no_damage", + "curse_apply_as_aura", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, -10, -15, -9, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [2] = { 8200, 1, -10, -15, -9, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [3] = { 8400, 1, -11, -16, -10, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [4] = { 8600, 2, -11, -17, -10, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [5] = { 8800, 2, -12, -18, -11, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [6] = { 9000, 3, -12, -18, -11, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [7] = { 9200, 3, -13, -19, -12, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [8] = { 9400, 4, -13, -20, -12, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [9] = { 9600, 4, -14, -21, -13, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [10] = { 9800, 5, -14, -21, -13, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [11] = { 10000, 5, -15, -22, -14, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [12] = { 10200, 6, -15, -23, -14, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [13] = { 10400, 6, -16, -24, -15, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [14] = { 10600, 7, -16, -24, -15, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [15] = { 10800, 7, -17, -25, -16, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [16] = { 11000, 8, -17, -26, -16, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [17] = { 11200, 8, -18, -27, -17, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [18] = { 11400, 9, -18, -27, -17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [19] = { 11600, 9, -19, -28, -18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [20] = { 11800, 10, -19, -29, -18, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [21] = { 12000, 10, -20, -30, -19, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [22] = { 12200, 11, -20, -30, -19, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [23] = { 12400, 11, -21, -30, -20, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [24] = { 12600, 12, -21, -30, -20, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [25] = { 12800, 12, -22, -31, -21, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [26] = { 13000, 13, -22, -31, -21, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [27] = { 13200, 13, -23, -31, -22, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [28] = { 13400, 14, -23, -31, -22, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [29] = { 13600, 14, -24, -32, -23, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [30] = { 13800, 15, -24, -32, -23, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [31] = { 13900, 15, -24, -32, -23, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [32] = { 14000, 15, -25, -32, -24, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [33] = { 14100, 15, -25, -33, -24, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [34] = { 14200, 16, -25, -33, -24, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [35] = { 14300, 16, -25, -33, -24, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [36] = { 14400, 16, -26, -33, -25, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [37] = { 14500, 16, -26, -34, -25, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [38] = { 14600, 17, -26, -34, -25, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [39] = { 14700, 17, -26, -34, -25, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + [40] = { 14800, 17, -27, -34, -26, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, 1, 1, }, }, + }, +} + +skills["EnrageMercenary"] = { + name = "Enrage", + hidden = true, + mercenary = true, + color = 1, + skillTypes = { [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + }, + stats = { + "attack_and_cast_speed_+%", + "base_movement_velocity_+%", + "damage_+%", + }, + levels = { + [1] = { 20, 20, 15, cooldown = 10, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 20, 30, 20, cooldown = 10, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [50] = { 40, 40, 25, cooldown = 10, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [67] = { 40, 50, 30, cooldown = 10, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [80] = { 40, 60, 35, cooldown = 10, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["EnsnaringArrowMercenary"] = { + name = "Ensnaring Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "EnsnaringArrow", + color = 2, + baseEffectiveness = 6.5, + incrementalEffectiveness = 0.052000001072884, + description = "Fires an arrow that remains in the ground behind its final target, tethering that enemy to it. Ensnared enemies have less movement speed while trying to break the snare. The snare will break if they leave the area of effect.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Area] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "tethered_movement_speed_+%_final_per_rope", -40 }, + { "tethered_movement_speed_+%_final_per_rope_vs_rare", -30 }, + { "tethered_movement_speed_+%_final_per_rope_vs_unique", -25 }, + { "tethering_arrow_display_rope_limit", 3 }, + }, + stats = { + "tethered_enemies_take_attack_projectile_damage_taken_+%", + "skill_can_fire_arrows", + "base_is_projectile", + }, + levels = { + [1] = { 15, baseMultiplier = 1.4, cooldown = 5, damageEffectiveness = 1.4, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 15, baseMultiplier = 1.418, cooldown = 5, damageEffectiveness = 1.42, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 16, baseMultiplier = 1.437, cooldown = 5, damageEffectiveness = 1.44, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 16, baseMultiplier = 1.455, cooldown = 5, damageEffectiveness = 1.46, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 16, baseMultiplier = 1.474, cooldown = 5, damageEffectiveness = 1.47, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 16, baseMultiplier = 1.492, cooldown = 5, damageEffectiveness = 1.49, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 17, baseMultiplier = 1.511, cooldown = 5, damageEffectiveness = 1.51, levelRequirement = 37, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 17, baseMultiplier = 1.529, cooldown = 5, damageEffectiveness = 1.53, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 17, baseMultiplier = 1.547, cooldown = 5, damageEffectiveness = 1.55, levelRequirement = 43, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 17, baseMultiplier = 1.566, cooldown = 5, damageEffectiveness = 1.57, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 18, baseMultiplier = 1.584, cooldown = 5, damageEffectiveness = 1.58, levelRequirement = 49, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 18, baseMultiplier = 1.603, cooldown = 5, damageEffectiveness = 1.6, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 18, baseMultiplier = 1.621, cooldown = 5, damageEffectiveness = 1.62, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 18, baseMultiplier = 1.639, cooldown = 5, damageEffectiveness = 1.64, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 19, baseMultiplier = 1.658, cooldown = 5, damageEffectiveness = 1.66, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 19, baseMultiplier = 1.676, cooldown = 5, damageEffectiveness = 1.68, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 19, baseMultiplier = 1.695, cooldown = 5, damageEffectiveness = 1.69, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 19, baseMultiplier = 1.713, cooldown = 5, damageEffectiveness = 1.71, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 20, baseMultiplier = 1.732, cooldown = 5, damageEffectiveness = 1.73, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 20, baseMultiplier = 1.75, cooldown = 5, damageEffectiveness = 1.75, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 20, baseMultiplier = 1.768, cooldown = 5, damageEffectiveness = 1.77, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 21, baseMultiplier = 1.787, cooldown = 5, damageEffectiveness = 1.79, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 21, baseMultiplier = 1.805, cooldown = 5, damageEffectiveness = 1.81, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 21, baseMultiplier = 1.824, cooldown = 5, damageEffectiveness = 1.82, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 21, baseMultiplier = 1.842, cooldown = 5, damageEffectiveness = 1.84, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 22, baseMultiplier = 1.861, cooldown = 5, damageEffectiveness = 1.86, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 22, baseMultiplier = 1.879, cooldown = 5, damageEffectiveness = 1.88, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 22, baseMultiplier = 1.897, cooldown = 5, damageEffectiveness = 1.9, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 22, baseMultiplier = 1.916, cooldown = 5, damageEffectiveness = 1.92, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 23, baseMultiplier = 1.934, cooldown = 5, damageEffectiveness = 1.93, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 23, baseMultiplier = 1.943, cooldown = 5, damageEffectiveness = 1.94, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 23, baseMultiplier = 1.953, cooldown = 5, damageEffectiveness = 1.95, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 23, baseMultiplier = 1.962, cooldown = 5, damageEffectiveness = 1.96, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 23, baseMultiplier = 1.971, cooldown = 5, damageEffectiveness = 1.97, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 23, baseMultiplier = 1.98, cooldown = 5, damageEffectiveness = 1.98, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 23, baseMultiplier = 1.989, cooldown = 5, damageEffectiveness = 1.99, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 24, baseMultiplier = 1.999, cooldown = 5, damageEffectiveness = 2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 24, baseMultiplier = 2.008, cooldown = 5, damageEffectiveness = 2.01, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 24, baseMultiplier = 2.017, cooldown = 5, damageEffectiveness = 2.02, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 24, baseMultiplier = 2.026, cooldown = 5, damageEffectiveness = 2.03, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["EnvyMercenary"] = { + name = "Envy", + hidden = true, + mercenary = true, + inheritedFrom = "Envy", + color = 3, + baseEffectiveness = 2.0999999046326, + incrementalEffectiveness = 0.023000000044703, + description = "Casts an aura that adds chaos damage to the attacks and spells of you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Chaos] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, [SkillType.CanHaveBlessing] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "attack_minimum_added_chaos_damage", + "attack_maximum_added_chaos_damage", + "spell_minimum_added_chaos_damage", + "spell_maximum_added_chaos_damage", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [2] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [3] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [4] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [5] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [6] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [7] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [8] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [9] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [10] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [11] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [12] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [13] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [14] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [15] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [16] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [17] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [18] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [19] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [20] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [21] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [22] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [23] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [24] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [25] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [26] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [27] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [28] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [29] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [30] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [31] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [32] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [33] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [34] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [35] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [36] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [37] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [38] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [39] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + [40] = { 0.5, 0.69999998807907, 0.44999998807907, 0.60000002384186, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, }, }, + }, +} + +skills["EssenceDrainAltMercenary"] = { + name = "Essence Drain of Wickedness", + hidden = true, + mercenary = true, + inheritedFrom = "EssenceDrainAltY", + color = 3, + baseEffectiveness = 4.0479998588562, + incrementalEffectiveness = 0.052700001746416, + description = "Fires a piercing projectile that applies a damage over time debuff when it hits. You are healed for a portion of the debuff damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Multicastable] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1900 }, + { "siphon_life_leech_from_damage_permyriad", 3800 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "always_pierce", + "spell_damage_modifiers_apply_to_skill_dot", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 25.16666707024, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 12, statInterpolation = { 3, 3, 3, }, }, + [2] = { 24.666667535901, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 15, statInterpolation = { 3, 3, 3, }, }, + [3] = { 24.000001490116, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 19, statInterpolation = { 3, 3, 3, }, }, + [4] = { 23.33333345751, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 23, statInterpolation = { 3, 3, 3, }, }, + [5] = { 22.666667411725, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 27, statInterpolation = { 3, 3, 3, }, }, + [6] = { 22.00000136594, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [7] = { 21.49999984478, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 35, statInterpolation = { 3, 3, 3, }, }, + [8] = { 21.000000310441, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 38, statInterpolation = { 3, 3, 3, }, }, + [9] = { 20.666667287548, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 41, statInterpolation = { 3, 3, 3, }, }, + [10] = { 20.16666775321, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [11] = { 19.833334730317, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 47, statInterpolation = { 3, 3, 3, }, }, + [12] = { 19.333333209157, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [13] = { 18.833333674818, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 53, statInterpolation = { 3, 3, 3, }, }, + [14] = { 18.500000651926, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [15] = { 18.166667629033, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 59, statInterpolation = { 3, 3, 3, }, }, + [16] = { 17.833334606141, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 17.499999596427, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 17.333333084981, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 17.000000062088, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 16.833333550642, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 16.666667039196, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 16.333334016303, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 16.166667504857, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 15.833333488554, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 15.833333488554, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 15.500000465661, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 15.333333954215, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 14.999999937912, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 14.833333426466, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 14.666666915019, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 14.500000403573, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 14.333333892127, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 14.333333892127, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 14.333333892127, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 14.166667380681, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 13.999999875824, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 13.833333364377, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 13.833333364377, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 13.833333364377, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 13.666666852931, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["EssenceDrainAltMercenaryEncounter"] = { + name = "Essence Drain of Wickedness", + hidden = true, + mercenary = true, + inheritedFrom = "EssenceDrainAltY", + color = 3, + baseEffectiveness = 3.7999999523163, + incrementalEffectiveness = 0.047499999403954, + description = "Fires a piercing projectile that applies a damage over time debuff when it hits. You are healed for a portion of the debuff damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Multicastable] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1900 }, + { "siphon_life_leech_from_damage_permyriad", 945 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "always_pierce", + "spell_damage_modifiers_apply_to_skill_dot", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 12.58333353512, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 12, statInterpolation = { 3, 3, 3, }, }, + [2] = { 12.333333767951, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 15, statInterpolation = { 3, 3, 3, }, }, + [3] = { 12.000000745058, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 19, statInterpolation = { 3, 3, 3, }, }, + [4] = { 11.666666728755, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 23, statInterpolation = { 3, 3, 3, }, }, + [5] = { 11.333333705862, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 27, statInterpolation = { 3, 3, 3, }, }, + [6] = { 11.00000068297, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [7] = { 10.74999992239, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 35, statInterpolation = { 3, 3, 3, }, }, + [8] = { 10.50000015522, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 38, statInterpolation = { 3, 3, 3, }, }, + [9] = { 10.333333643774, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 41, statInterpolation = { 3, 3, 3, }, }, + [10] = { 10.083333876605, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [11] = { 9.9166673651586, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 47, statInterpolation = { 3, 3, 3, }, }, + [12] = { 9.6666666045785, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [13] = { 9.4166668374091, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 53, statInterpolation = { 3, 3, 3, }, }, + [14] = { 9.2500003259629, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [15] = { 9.0833338145167, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 59, statInterpolation = { 3, 3, 3, }, }, + [16] = { 8.9166673030704, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 8.7499997982134, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 8.6666665424903, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 8.5000000310441, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 8.416666775321, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 8.3333335195979, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 8.1666670081516, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 8.0833337524285, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 7.9166667442769, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 7.9166667442769, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 7.7500002328306, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 7.6666669771075, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 7.4999999689559, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 7.4166667132328, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 7.3333334575097, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 7.2500002017866, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 7.1666669460634, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 7.1666669460634, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 7.1666669460634, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 7.0833336903403, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 6.9999999379118, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 6.9166666821887, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 6.9166666821887, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 6.9166666821887, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 6.8333334264656, 0.34999999403954, 0.52999997138977, critChance = 5, damageEffectiveness = 3.1, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["EtherealKnivesMercenary"] = { + name = "Ethereal Knives", + hidden = true, + mercenary = true, + inheritedFrom = "EtherealKnives", + color = 2, + baseEffectiveness = 3.0380001068115, + incrementalEffectiveness = 0.043600000441074, + description = "Fires an arc of knives outwards in front of the caster which deal physical damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + projectile = true, + spell = true, + }, + constantStats = { + { "active_skill_projectile_speed_+%_variation_final", 50 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_number_of_projectiles", + "base_is_projectile", + "console_skill_dont_chase", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.89999997615814, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 2, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["EtherealKnivesMercenaryEncounter"] = { + name = "Ethereal Knives", + hidden = true, + mercenary = true, + inheritedFrom = "EtherealKnives", + color = 2, + baseEffectiveness = 2.1717000007629, + incrementalEffectiveness = 0.043600000441074, + description = "Fires an arc of knives outwards in front of the caster which deal physical damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + projectile = true, + spell = true, + }, + constantStats = { + { "active_skill_projectile_speed_+%_variation_final", 50 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_number_of_projectiles", + "base_is_projectile", + "console_skill_dont_chase", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.89999997615814, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 1.9, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 10, critChance = 10, damageEffectiveness = 2, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 11, critChance = 10, damageEffectiveness = 2, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 12, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.1, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 13, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 14, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 15, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 16, critChance = 10, damageEffectiveness = 2.2, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["ExplosiveArrowBarrageMercenary"] = { + name = "Explosive Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "ExplosiveArrow", + color = 2, + baseEffectiveness = 1.4859000444412, + incrementalEffectiveness = 0.040300000458956, + description = "Fires an arrow which will stick into an enemy or wall, and then explode, dealing area damage around it, either after a duration or when the maximum number of arrows stuck to that target is reached. If an enemy has multiple Explosive Arrows stuck in them, the first one to explode will consume the others, adding their damage to its explosion.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Fire] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "fuse_arrow_explosion_radius_+_per_fuse_arrow_orb", 2 }, + { "explosive_arrow_explosion_base_damage_+permyriad", -5000 }, + { "explosive_arrow_maximum_bonus_explosion_radius", 12 }, + { "explosive_arrow_hit_damage_+%_final_per_stack", 6 }, + { "explosive_arrow_ailment_damage_+%_final_per_stack", 3 }, + { "explosive_arrow_stack_limit", 20 }, + { "base_skill_effect_duration", 1000 }, + { "number_of_additional_projectiles", 2 }, + { "support_barrage_attack_time_+%_per_projectile_fired", 5 }, + }, + stats = { + "explosive_arrow_explosion_minimum_added_fire_damage", + "explosive_arrow_explosion_maximum_added_fire_damage", + "skill_can_fire_arrows", + "base_is_projectile", + "projectiles_barrage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["ExsanguinateMercenary"] = { + name = "Exsanguinate", + hidden = true, + mercenary = true, + inheritedFrom = "Exsanguinate", + color = 1, + baseEffectiveness = 1.8999999761581, + incrementalEffectiveness = 0.052499998360872, + description = "Releases several tendrils of blood from your character, targeting enemies in a narrow angle in front of you. The beams deal physical damage and inflict a physical damage over time debuff to enemies, which can stack up to 3 times. Effects which allow skills to chain can apply to these tendrils.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Chains] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Physical] = true, [SkillType.CanRapidFire] = true, [SkillType.DamageOverTime] = true, [SkillType.Duration] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "blood_tendrils_beam_count", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 67.163333804583, 7, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 12, statInterpolation = { 3, 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 66.453335181077, 7, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 15, statInterpolation = { 3, 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 65.293333400389, 7, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 19, statInterpolation = { 3, 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 64.146667165856, 7, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 23, statInterpolation = { 3, 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 63.015001433926, 7, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 27, statInterpolation = { 3, 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 61.900001161049, 7, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 31, statInterpolation = { 3, 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 60.796667504236, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 35, statInterpolation = { 3, 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 60.118334842386, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 38, statInterpolation = { 3, 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 59.443336067076, 8, critChance = 6, damageEffectiveness = 2, levelRequirement = 41, statInterpolation = { 3, 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 58.771667204661, 8, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 44, statInterpolation = { 3, 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 58.101667272337, 8, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 47, statInterpolation = { 3, 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 57.435001226552, 8, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 50, statInterpolation = { 3, 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 56.771669067306, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 53, statInterpolation = { 3, 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 56.110001864508, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 56, statInterpolation = { 3, 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 55.453333504697, 9, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 59, statInterpolation = { 3, 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 54.800003005068, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 62, statInterpolation = { 3, 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 54.52166917596, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 64, statInterpolation = { 3, 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 54.243335346853, 9, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 66, statInterpolation = { 3, 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 53.960002674758, 9, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 68, statInterpolation = { 3, 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 53.675001072573, 9, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 70, statInterpolation = { 3, 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 53.38833451394, 9, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 72, statInterpolation = { 3, 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 53.098334068768, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 74, statInterpolation = { 3, 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 52.808333623596, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 76, statInterpolation = { 3, 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 52.514999291884, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 78, statInterpolation = { 3, 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 52.220000003725, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 80, statInterpolation = { 3, 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 51.923335759118, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 82, statInterpolation = { 3, 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 51.626667540868, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 84, statInterpolation = { 3, 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 51.325000479631, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 86, statInterpolation = { 3, 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 51.025002348485, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 88, statInterpolation = { 3, 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 50.723335287248, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 90, statInterpolation = { 3, 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 50.76500290852, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 91, statInterpolation = { 3, 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 50.80666655615, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 92, statInterpolation = { 3, 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 50.845000290883, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 93, statInterpolation = { 3, 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 50.87833518263, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 94, statInterpolation = { 3, 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 50.911666100733, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 95, statInterpolation = { 3, 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 50.940002149493, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 96, statInterpolation = { 3, 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 50.966669268161, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 97, statInterpolation = { 3, 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 50.9883335702, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 98, statInterpolation = { 3, 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 51.010001845881, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 99, statInterpolation = { 3, 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 51.030001191472, 11, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 100, statInterpolation = { 3, 3, 3, 1, }, }, + }, +} + +skills["ExsanguinateMercenaryEncounter"] = { + name = "Exsanguinate", + hidden = true, + mercenary = true, + inheritedFrom = "Exsanguinate", + color = 1, + baseEffectiveness = 1.2000000476837, + incrementalEffectiveness = 0.029999999329448, + description = "Releases several tendrils of blood from your character, targeting enemies in a narrow angle in front of you. The beams deal physical damage and inflict a physical damage over time debuff to enemies, which can stack up to 3 times. Effects which allow skills to chain can apply to these tendrils.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Chains] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Physical] = true, [SkillType.CanRapidFire] = true, [SkillType.DamageOverTime] = true, [SkillType.Duration] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1000 }, + { "skill_surge_type_override", 68 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "blood_tendrils_beam_count", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 12, statInterpolation = { 3, 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 15, statInterpolation = { 3, 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 19, statInterpolation = { 3, 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 23, statInterpolation = { 3, 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 27, statInterpolation = { 3, 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 31, statInterpolation = { 3, 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 35, statInterpolation = { 3, 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 38, statInterpolation = { 3, 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2, levelRequirement = 41, statInterpolation = { 3, 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 44, statInterpolation = { 3, 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 47, statInterpolation = { 3, 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 50, statInterpolation = { 3, 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 53, statInterpolation = { 3, 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 56, statInterpolation = { 3, 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 59, statInterpolation = { 3, 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 62, statInterpolation = { 3, 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 64, statInterpolation = { 3, 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 66, statInterpolation = { 3, 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 68, statInterpolation = { 3, 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 70, statInterpolation = { 3, 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 72, statInterpolation = { 3, 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 74, statInterpolation = { 3, 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 76, statInterpolation = { 3, 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 78, statInterpolation = { 3, 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 80, statInterpolation = { 3, 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 82, statInterpolation = { 3, 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 84, statInterpolation = { 3, 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 86, statInterpolation = { 3, 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 88, statInterpolation = { 3, 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 90, statInterpolation = { 3, 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 91, statInterpolation = { 3, 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 92, statInterpolation = { 3, 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 93, statInterpolation = { 3, 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 94, statInterpolation = { 3, 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 95, statInterpolation = { 3, 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 96, statInterpolation = { 3, 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 97, statInterpolation = { 3, 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 98, statInterpolation = { 3, 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 99, statInterpolation = { 3, 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 25.000000558794, 7, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 100, statInterpolation = { 3, 3, 3, 1, }, }, + }, +} + +skills["EyeOfWinterMercenary"] = { + name = "Eye of Winter", + hidden = true, + mercenary = true, + inheritedFrom = "EyeOfWinter", + color = 3, + baseEffectiveness = 0.30000001192093, + incrementalEffectiveness = 0.050000000745058, + description = "Fires a single eye projectile which constantly releases shard projectiles in a spiral. The shards will damage enemies they impact, dealing cold damage. The eye cannot damage enemies. When the eye dissipates or collides with terrain, it releases a faster spiral of extra shards.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Projectile] = true, [SkillType.ProjectileSpiral] = true, [SkillType.Damage] = true, [SkillType.SingleMainProjectile] = true, [SkillType.Cold] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Trappable] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + projectile = true, + spell = true, + }, + constantStats = { + { "freezing_pulse_damage_+%_final_at_long_range", 100 }, + { "eye_of_winter_base_explosion_shards", 8 }, + { "projectile_firing_forward_distance_override", 100 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_is_projectile", + "single_primary_projectile", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.55, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["FireAegisMercenary"] = { + name = "Flame Aegis", + hidden = true, + mercenary = true, + inheritedFrom = "FireAegis", + color = 4, + description = "Calls forth a protective aegis which takes fire damage from hits for you until depleted. The aegis will be restored to its full value after a short delay if you stop taking fire damage from hits, or if depleted.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Triggerable] = true, [SkillType.Triggered] = true, [SkillType.InbuiltTrigger] = true, [SkillType.Aegis] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "aegis_recharge_delay_ms", 5000 }, + }, + stats = { + "aegis_unique_shield_max_value", + "cast_on_gain_skill", + "spell_uncastable_if_triggerable", + "no_cost", + }, + levels = { + [1] = { 51, levelRequirement = 24, statInterpolation = { 1, }, }, + [2] = { 125, levelRequirement = 27, statInterpolation = { 1, }, }, + [3] = { 224, levelRequirement = 30, statInterpolation = { 1, }, }, + [4] = { 347, levelRequirement = 33, statInterpolation = { 1, }, }, + [5] = { 495, levelRequirement = 36, statInterpolation = { 1, }, }, + [6] = { 667, levelRequirement = 39, statInterpolation = { 1, }, }, + [7] = { 863, levelRequirement = 42, statInterpolation = { 1, }, }, + [8] = { 1083, levelRequirement = 45, statInterpolation = { 1, }, }, + [9] = { 1327, levelRequirement = 48, statInterpolation = { 1, }, }, + [10] = { 1596, levelRequirement = 50, statInterpolation = { 1, }, }, + [11] = { 1889, levelRequirement = 52, statInterpolation = { 1, }, }, + [12] = { 2206, levelRequirement = 54, statInterpolation = { 1, }, }, + [13] = { 2547, levelRequirement = 56, statInterpolation = { 1, }, }, + [14] = { 2913, levelRequirement = 58, statInterpolation = { 1, }, }, + [15] = { 3303, levelRequirement = 60, statInterpolation = { 1, }, }, + [16] = { 3717, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 4155, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 4618, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 5105, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 5616, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 6151, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 6710, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 7294, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 7902, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 8535, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 9191, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 9872, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 10577, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 11306, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 12059, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 12837, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 13639, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 14465, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 15316, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 16190, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 17089, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 18012, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 18960, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 19931, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 20927, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["FireAegisMercenaryEncounter"] = { + name = "Flame Aegis", + hidden = true, + mercenary = true, + inheritedFrom = "FireAegis", + color = 4, + description = "Calls forth a protective aegis which takes fire damage from hits for you until depleted. The aegis will be restored to its full value after a short delay if you stop taking fire damage from hits, or if depleted.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Triggerable] = true, [SkillType.Triggered] = true, [SkillType.InbuiltTrigger] = true, [SkillType.Aegis] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "aegis_recharge_delay_ms", 5000 }, + }, + stats = { + "aegis_unique_shield_max_value", + "cast_on_gain_skill", + "spell_uncastable_if_triggerable", + "no_cost", + }, + levels = { + [1] = { 409, levelRequirement = 24, statInterpolation = { 1, }, }, + [2] = { 571, levelRequirement = 27, statInterpolation = { 1, }, }, + [3] = { 783, levelRequirement = 30, statInterpolation = { 1, }, }, + [4] = { 1058, levelRequirement = 33, statInterpolation = { 1, }, }, + [5] = { 1416, levelRequirement = 36, statInterpolation = { 1, }, }, + [6] = { 1875, levelRequirement = 39, statInterpolation = { 1, }, }, + [7] = { 2464, levelRequirement = 42, statInterpolation = { 1, }, }, + [8] = { 3212, levelRequirement = 45, statInterpolation = { 1, }, }, + [9] = { 4159, levelRequirement = 48, statInterpolation = { 1, }, }, + [10] = { 4925, levelRequirement = 50, statInterpolation = { 1, }, }, + [11] = { 6688, levelRequirement = 52, statInterpolation = { 1, }, }, + [12] = { 7878, levelRequirement = 54, statInterpolation = { 1, }, }, + [13] = { 9271, levelRequirement = 56, statInterpolation = { 1, }, }, + [14] = { 10878, levelRequirement = 58, statInterpolation = { 1, }, }, + [15] = { 12736, levelRequirement = 60, statInterpolation = { 1, }, }, + [16] = { 14905, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 17394, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 20265, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 41026, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 47671, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 55327, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 96180, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 111333, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 171642, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 198250, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 228723, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 303561, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 303561, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 303561, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 303561, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 303561, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 303561, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 303561, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 303561, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 303561, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 303561, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 303561, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 303561, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 303561, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 303561, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["FireEnrageMercenary"] = { + name = "Inflame", + hidden = true, + mercenary = true, + inheritedFrom = "AzmeriDualStrikeDemonFireEnrage", + color = 4, + baseEffectiveness = 1.7889000177383, + incrementalEffectiveness = 0.034000001847744, + skillTypes = { [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 5000 }, + { "base_movement_velocity_+%", 20 }, + { "attack_speed_+%", 50 }, + }, + stats = { + "physical_damage_%_to_add_as_fire", + }, + levels = { + [1] = { 30, cooldown = 10, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["FireballAltMercenary"] = { + name = "Fireball of Impact", + hidden = true, + mercenary = true, + color = 3, + baseEffectiveness = 2.9210000038147, + incrementalEffectiveness = 0.047400001436472, + description = "Unleashes a ball of fire towards a target which explodes, damaging nearby foes.", + skillTypes = { [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "active_skill_has_skill_area_of_effect_+%_final_per_additional_projectile", 50 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "active_skill_base_area_of_effect_radius", + "base_is_projectile", + "projectiles_fire_at_ground", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["FireballAltMercenaryEncounter"] = { + name = "Fireball of Impact", + hidden = true, + mercenary = true, + color = 3, + baseEffectiveness = 2.4000000953674, + incrementalEffectiveness = 0.037999998778105, + description = "Unleashes a ball of fire towards a target which explodes, damaging nearby foes.", + skillTypes = { [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "active_skill_has_skill_area_of_effect_+%_final_per_additional_projectile", 50 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "active_skill_base_area_of_effect_radius", + "base_is_projectile", + "projectiles_fire_at_ground", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 2.9, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.1, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.4, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.4, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.5, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.6, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.6, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["FireballMercenary"] = { + name = "Fireball", + hidden = true, + mercenary = true, + inheritedFrom = "Fireball", + color = 3, + baseEffectiveness = 2.9210000038147, + incrementalEffectiveness = 0.047400001436472, + description = "Unleashes a ball of fire towards a target which explodes, damaging nearby foes.", + skillTypes = { [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_chance_to_ignite_%", 25 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "active_skill_base_area_of_effect_radius", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 2.9, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.1, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.4, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.4, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.5, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.6, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.6, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["FireballMercenaryEncounter"] = { + name = "Fireball", + hidden = true, + mercenary = true, + inheritedFrom = "Fireball", + color = 3, + baseEffectiveness = 2.4000000953674, + incrementalEffectiveness = 0.037999998778105, + description = "Unleashes a ball of fire towards a target which explodes, damaging nearby foes.", + skillTypes = { [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_chance_to_ignite_%", 25 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "active_skill_base_area_of_effect_radius", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 9, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 10, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 11, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 12, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 13, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 14, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 16, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 17, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["FissureSlamMercenary"] = { + name = "Ashen Fissure", + hidden = true, + mercenary = true, + color = 1, + skillTypes = { [SkillType.Attack] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 40 }, + { "cover_in_ash_on_hit_%", 50 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { cooldown = 4.5, levelRequirement = 0, storedUses = 3, }, + }, +} + +skills["FlameDashMercenary"] = { + name = "Flame Dash", + hidden = true, + mercenary = true, + inheritedFrom = "FlameDash", + color = 3, + baseEffectiveness = 0.80000001192093, + incrementalEffectiveness = 0.052499998360872, + description = "Teleport to a location, damaging enemies and leaving a trail of burning ground. Shares a cooldown with other Blink skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Movement] = true, [SkillType.Damage] = true, [SkillType.DamageOverTime] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Travel] = true, [SkillType.Blink] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + duration = true, + movement = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 4000 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "base_fire_damage_to_deal_per_minute", + "base_cooldown_speed_+%", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "base_fire_damage_to_deal_per_minute", + "base_cooldown_speed_+%", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 0, cooldown = 3.5, critChance = 5, damageEffectiveness = 0.8, levelRequirement = 10, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 1, cooldown = 3.5, critChance = 5, damageEffectiveness = 0.8, levelRequirement = 13, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 2, cooldown = 3.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 17, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 3, cooldown = 3.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 21, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 4, cooldown = 3.5, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 25, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 5, cooldown = 3.5, critChance = 5, levelRequirement = 29, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 6, cooldown = 3.5, critChance = 5, levelRequirement = 33, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 7, cooldown = 3.5, critChance = 5, levelRequirement = 36, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 8, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 39, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 9, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 42, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 10, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 45, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 11, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.2, levelRequirement = 48, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 12, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.2, levelRequirement = 51, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 13, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.3, levelRequirement = 54, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 14, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.3, levelRequirement = 57, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.3, levelRequirement = 60, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 16, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 63, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 17, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 66, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 18, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 68, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 19, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 70, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 20, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 72, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 21, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 74, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 22, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 76, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 23, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 78, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 24, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 80, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 25, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 82, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 26, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 84, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 27, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 86, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 28, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 88, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 29, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 90, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 29, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 91, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 30, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 92, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 30, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 93, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 31, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 94, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 31, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 95, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 32, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 96, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 32, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 97, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 33, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 98, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 33, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 99, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 34, cooldown = 3.5, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 100, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + }, +} + +skills["FlameLinkMercenary"] = { + name = "Flame Link", + hidden = true, + mercenary = true, + inheritedFrom = "FlameLink", + color = 1, + baseEffectiveness = 0.52499997615814, + incrementalEffectiveness = 0.039000000804663, + description = "Targets an allied player to apply a buff which links you to them for a duration. While linked, they deal additional fire damage based on your life. If the target dies while linked, you will also die. This skill cannot be triggered, or used by Totems, Traps, or Mines.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Link] = true, [SkillType.Fire] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + link = true, + spell = true, + }, + stats = { + "flame_link_minimum_fire_damage", + "flame_link_maximum_fire_damage", + "base_skill_effect_duration", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 8000, cooldown = 15, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 8100, cooldown = 15, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 8200, cooldown = 15, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 8300, cooldown = 15, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 8400, cooldown = 15, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 8500, cooldown = 15, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 8600, cooldown = 15, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 8700, cooldown = 15, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 8800, cooldown = 15, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 8900, cooldown = 15, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 9000, cooldown = 15, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 9100, cooldown = 15, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 9200, cooldown = 15, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 9300, cooldown = 15, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 9400, cooldown = 15, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 9500, cooldown = 15, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 9600, cooldown = 15, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 9700, cooldown = 15, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 9800, cooldown = 15, levelRequirement = 69, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 9900, cooldown = 15, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 10000, cooldown = 15, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 10100, cooldown = 15, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 10200, cooldown = 15, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 10300, cooldown = 15, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 10400, cooldown = 15, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 10500, cooldown = 15, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 10600, cooldown = 15, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 10700, cooldown = 15, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 10800, cooldown = 15, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 10900, cooldown = 15, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 11000, cooldown = 15, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 11050, cooldown = 15, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 11100, cooldown = 15, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 11150, cooldown = 15, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 11200, cooldown = 15, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 11250, cooldown = 15, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 11300, cooldown = 15, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 11350, cooldown = 15, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 11400, cooldown = 15, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 11450, cooldown = 15, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["FlameSurgeMercenary"] = { + name = "Flame Surge", + hidden = true, + mercenary = true, + inheritedFrom = "FlameSurge", + color = 3, + baseEffectiveness = 2.7952001094818, + incrementalEffectiveness = 0.037799999117851, + description = "Strikes enemies in front of you with a surge of flame. Burning enemies are dealt more damage. If you hit an ignited enemy, will create burning ground under them. Your damage modifiers don't apply to this burning ground.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Area] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Duration] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "flame_surge_ignite_damage_as_burning_ground_damage_%", 25 }, + { "flame_surge_burning_ground_creation_cooldown_ms", 2000 }, + { "base_skill_effect_duration", 4000 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "flame_whip_damage_+%_final_vs_burning_enemies", + "active_skill_base_area_length_+", + "never_ignite", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 50, 0, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 12, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 52, 0, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 15, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 54, 1, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 19, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 56, 1, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 23, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 58, 2, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 27, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 60, 2, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 31, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 62, 3, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 35, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 64, 3, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 38, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 66, 4, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 41, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 68, 4, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 70, 5, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 47, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 72, 5, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 50, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 74, 6, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 53, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 76, 6, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 78, 7, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 59, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 80, 7, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 62, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 82, 8, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 84, 8, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 66, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 86, 9, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 68, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 88, 9, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 90, 10, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 92, 10, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 94, 11, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 96, 11, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 98, 12, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 100, 12, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 102, 13, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 104, 13, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 106, 14, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 108, 14, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 108, 14, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 110, 15, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 110, 15, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 112, 15, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 112, 15, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 114, 16, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 114, 16, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 116, 16, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 116, 16, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 118, 17, critChance = 5, damageEffectiveness = 1.9, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["FlameWallMercenary"] = { + name = "Flame Wall", + hidden = true, + mercenary = true, + inheritedFrom = "FlameWall", + color = 3, + baseEffectiveness = 4.3292999267578, + incrementalEffectiveness = 0.0625, + description = "Create a wall of fire for a duration, which deals burning damage to everything in its area. Each enemy that enters the wall also receives a secondary burning debuff which persists for a short duration after leaving the wall. Any projectiles fired through the wall by you and allies deal added fire damage and apply the wall's secondary debuff on hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.DamageOverTime] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.AreaSpell] = true, [SkillType.Totemable] = true, [SkillType.Fire] = true, [SkillType.DegenOnlySpellDamage] = true, [SkillType.CanRapidFire] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.CausesBurning] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "number_of_allowed_firewalls", 3 }, + { "firewall_attached_projectile_effect_mtx", 1 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "secondary_base_fire_damage_to_deal_per_minute", + "flame_wall_minimum_added_fire_damage", + "flame_wall_maximum_added_fire_damage", + "base_secondary_skill_effect_duration", + "wall_maximum_length", + "base_skill_effect_duration", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + "base_secondary_skill_effect_duration", + "base_skill_effect_duration", + }, + levels = { + [1] = { 5.0000003104409, 16.666667039196, 3, 5, 1000, 40, 3000, cooldown = 4.5, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [2] = { 5.0000003104409, 16.666667039196, 4, 6, 1050, 41, 3100, cooldown = 4.5, levelRequirement = 6, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [3] = { 5.0000003104409, 16.666667039196, 5, 8, 1110, 42, 3200, cooldown = 4.5, levelRequirement = 9, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [4] = { 5.0000003104409, 16.666667039196, 7, 10, 1160, 43, 3300, cooldown = 4.5, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [5] = { 5.0000003104409, 16.666667039196, 9, 13, 1210, 44, 3400, cooldown = 4.5, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [6] = { 5.0000003104409, 16.666667039196, 11, 16, 1260, 45, 3500, cooldown = 4.5, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [7] = { 5.0000003104409, 16.666667039196, 13, 19, 1320, 46, 3600, cooldown = 4.5, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [8] = { 5.0000003104409, 16.666667039196, 16, 24, 1370, 47, 3700, cooldown = 4.5, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [9] = { 5.0000003104409, 16.666667039196, 19, 29, 1420, 48, 3800, cooldown = 4.5, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [10] = { 5.0000003104409, 16.666667039196, 22, 33, 1470, 49, 3900, cooldown = 4.5, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [11] = { 5.0000003104409, 16.666667039196, 27, 40, 1530, 50, 4000, cooldown = 4.5, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [12] = { 5.0000003104409, 16.666667039196, 31, 47, 1580, 51, 4100, cooldown = 4.5, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [13] = { 5.0000003104409, 16.666667039196, 36, 55, 1630, 52, 4200, cooldown = 4.5, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [14] = { 5.0000003104409, 16.666667039196, 42, 63, 1680, 53, 4300, cooldown = 4.5, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [15] = { 5.0000003104409, 16.666667039196, 47, 71, 1740, 54, 4400, cooldown = 4.5, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [16] = { 5.0000003104409, 16.666667039196, 52, 79, 1790, 55, 4500, cooldown = 4.5, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [17] = { 5.0000003104409, 16.666667039196, 58, 87, 1840, 56, 4600, cooldown = 4.5, levelRequirement = 61, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [18] = { 5.0000003104409, 16.666667039196, 64, 96, 1890, 57, 4700, cooldown = 4.5, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [19] = { 5.0000003104409, 16.666667039196, 71, 106, 1950, 58, 4800, cooldown = 4.5, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [20] = { 5.0000003104409, 16.666667039196, 78, 117, 2000, 59, 4900, cooldown = 4.5, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [21] = { 5.0000003104409, 16.666667039196, 83, 125, 2050, 60, 5000, cooldown = 4.5, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [22] = { 5.0000003104409, 16.666667039196, 88, 132, 2110, 61, 5100, cooldown = 4.5, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [23] = { 5.0000003104409, 16.666667039196, 94, 141, 2160, 62, 5200, cooldown = 4.5, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [24] = { 5.0000003104409, 16.666667039196, 100, 150, 2210, 63, 5300, cooldown = 4.5, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [25] = { 5.0000003104409, 16.666667039196, 105, 158, 2260, 64, 5400, cooldown = 4.5, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [26] = { 5.0000003104409, 16.666667039196, 112, 168, 2320, 65, 5500, cooldown = 4.5, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [27] = { 5.0000003104409, 16.666667039196, 118, 177, 2370, 66, 5600, cooldown = 4.5, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [28] = { 5.0000003104409, 16.666667039196, 125, 188, 2420, 67, 5700, cooldown = 4.5, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [29] = { 5.0000003104409, 16.666667039196, 133, 199, 2470, 68, 5800, cooldown = 4.5, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [30] = { 5.0000003104409, 16.666667039196, 140, 210, 2530, 69, 5900, cooldown = 4.5, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [31] = { 5.0000003104409, 16.666667039196, 144, 215, 2550, 69, 5950, cooldown = 4.5, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [32] = { 5.0000003104409, 16.666667039196, 148, 222, 2580, 70, 6000, cooldown = 4.5, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [33] = { 5.0000003104409, 16.666667039196, 153, 229, 2610, 70, 6050, cooldown = 4.5, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [34] = { 5.0000003104409, 16.666667039196, 158, 237, 2630, 71, 6100, cooldown = 4.5, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [35] = { 5.0000003104409, 16.666667039196, 163, 245, 2660, 71, 6150, cooldown = 4.5, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [36] = { 5.0000003104409, 16.666667039196, 169, 253, 2680, 72, 6200, cooldown = 4.5, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [37] = { 5.0000003104409, 16.666667039196, 174, 261, 2710, 72, 6250, cooldown = 4.5, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [38] = { 5.0000003104409, 16.666667039196, 180, 269, 2740, 73, 6300, cooldown = 4.5, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [39] = { 5.0000003104409, 16.666667039196, 186, 278, 2760, 73, 6350, cooldown = 4.5, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [40] = { 5.0000003104409, 16.666667039196, 192, 287, 2790, 74, 6400, cooldown = 4.5, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + }, +} + +skills["FlameWallMercenaryEncounter"] = { + name = "Flame Wall", + hidden = true, + mercenary = true, + inheritedFrom = "FlameWall", + color = 3, + baseEffectiveness = 1.8999999761581, + incrementalEffectiveness = 0.027000000700355, + description = "Create a wall of fire for a duration, which deals burning damage to everything in its area. Each enemy that enters the wall also receives a secondary burning debuff which persists for a short duration after leaving the wall. Any projectiles fired through the wall by you and allies deal added fire damage and apply the wall's secondary debuff on hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.DamageOverTime] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.AreaSpell] = true, [SkillType.Totemable] = true, [SkillType.Fire] = true, [SkillType.DegenOnlySpellDamage] = true, [SkillType.CanRapidFire] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.CausesBurning] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "number_of_allowed_firewalls", 3 }, + { "firewall_attached_projectile_effect_mtx", 1 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "secondary_base_fire_damage_to_deal_per_minute", + "flame_wall_minimum_added_fire_damage", + "flame_wall_maximum_added_fire_damage", + "base_secondary_skill_effect_duration", + "wall_maximum_length", + "base_skill_effect_duration", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + "base_secondary_skill_effect_duration", + "base_skill_effect_duration", + }, + levels = { + [1] = { 5.0000003104409, 16.666667039196, 3, 5, 1000, 40, 3000, cooldown = 4.5, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [2] = { 5.0000003104409, 16.666667039196, 4, 6, 1050, 41, 3100, cooldown = 4.5, levelRequirement = 6, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [3] = { 5.0000003104409, 16.666667039196, 5, 8, 1110, 42, 3200, cooldown = 4.5, levelRequirement = 9, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [4] = { 5.0000003104409, 16.666667039196, 7, 10, 1160, 43, 3300, cooldown = 4.5, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [5] = { 5.0000003104409, 16.666667039196, 9, 13, 1210, 44, 3400, cooldown = 4.5, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [6] = { 5.0000003104409, 16.666667039196, 11, 16, 1260, 45, 3500, cooldown = 4.5, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [7] = { 5.0000003104409, 16.666667039196, 13, 19, 1320, 46, 3600, cooldown = 4.5, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [8] = { 5.0000003104409, 16.666667039196, 16, 24, 1370, 47, 3700, cooldown = 4.5, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [9] = { 5.0000003104409, 16.666667039196, 19, 29, 1420, 48, 3800, cooldown = 4.5, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [10] = { 5.0000003104409, 16.666667039196, 22, 33, 1470, 49, 3900, cooldown = 4.5, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [11] = { 5.0000003104409, 16.666667039196, 27, 40, 1530, 50, 4000, cooldown = 4.5, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [12] = { 5.0000003104409, 16.666667039196, 31, 47, 1580, 51, 4100, cooldown = 4.5, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [13] = { 5.0000003104409, 16.666667039196, 36, 55, 1630, 52, 4200, cooldown = 4.5, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [14] = { 5.0000003104409, 16.666667039196, 42, 63, 1680, 53, 4300, cooldown = 4.5, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [15] = { 5.0000003104409, 16.666667039196, 47, 71, 1740, 54, 4400, cooldown = 4.5, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [16] = { 5.0000003104409, 16.666667039196, 52, 79, 1790, 55, 4500, cooldown = 4.5, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [17] = { 5.0000003104409, 16.666667039196, 58, 87, 1840, 56, 4600, cooldown = 4.5, levelRequirement = 61, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [18] = { 5.0000003104409, 16.666667039196, 64, 96, 1890, 57, 4700, cooldown = 4.5, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [19] = { 5.0000003104409, 16.666667039196, 71, 106, 1950, 58, 4800, cooldown = 4.5, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [20] = { 5.0000003104409, 16.666667039196, 78, 117, 2000, 59, 4900, cooldown = 4.5, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [21] = { 5.0000003104409, 16.666667039196, 83, 125, 2050, 60, 5000, cooldown = 4.5, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [22] = { 5.0000003104409, 16.666667039196, 88, 132, 2110, 61, 5100, cooldown = 4.5, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [23] = { 5.0000003104409, 16.666667039196, 94, 141, 2160, 62, 5200, cooldown = 4.5, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [24] = { 5.0000003104409, 16.666667039196, 100, 150, 2210, 63, 5300, cooldown = 4.5, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [25] = { 5.0000003104409, 16.666667039196, 105, 158, 2260, 64, 5400, cooldown = 4.5, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [26] = { 5.0000003104409, 16.666667039196, 112, 168, 2320, 65, 5500, cooldown = 4.5, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [27] = { 5.0000003104409, 16.666667039196, 118, 177, 2370, 66, 5600, cooldown = 4.5, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [28] = { 5.0000003104409, 16.666667039196, 125, 188, 2420, 67, 5700, cooldown = 4.5, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [29] = { 5.0000003104409, 16.666667039196, 133, 199, 2470, 68, 5800, cooldown = 4.5, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [30] = { 5.0000003104409, 16.666667039196, 140, 210, 2530, 69, 5900, cooldown = 4.5, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [31] = { 5.0000003104409, 16.666667039196, 144, 215, 2550, 69, 5950, cooldown = 4.5, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [32] = { 5.0000003104409, 16.666667039196, 148, 222, 2580, 70, 6000, cooldown = 4.5, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [33] = { 5.0000003104409, 16.666667039196, 153, 229, 2610, 70, 6050, cooldown = 4.5, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [34] = { 5.0000003104409, 16.666667039196, 158, 237, 2630, 71, 6100, cooldown = 4.5, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [35] = { 5.0000003104409, 16.666667039196, 163, 245, 2660, 71, 6150, cooldown = 4.5, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [36] = { 5.0000003104409, 16.666667039196, 169, 253, 2680, 72, 6200, cooldown = 4.5, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [37] = { 5.0000003104409, 16.666667039196, 174, 261, 2710, 72, 6250, cooldown = 4.5, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [38] = { 5.0000003104409, 16.666667039196, 180, 269, 2740, 73, 6300, cooldown = 4.5, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [39] = { 5.0000003104409, 16.666667039196, 186, 278, 2760, 73, 6350, cooldown = 4.5, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + [40] = { 5.0000003104409, 16.666667039196, 192, 287, 2790, 74, 6400, cooldown = 4.5, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, 1, }, }, + }, +} + +skills["FlameblastMercenary"] = { + name = "Flameblast", + hidden = true, + mercenary = true, + inheritedFrom = "Flameblast", + color = 3, + baseEffectiveness = 0.86769998073578, + incrementalEffectiveness = 0.044599998742342, + description = "Channels to build up a large explosion, which is released when you stop using the skill. The longer you channel, the larger the area of effect and damage of the explosion.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Fire] = true, [SkillType.Channel] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.2, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "charged_blast_spell_damage_+%_final_per_stack", 165 }, + { "flameblast_ailment_damage_+%_final_per_stack", 60 }, + { "base_chance_to_ignite_%", 50 }, + { "vaal_flameblast_radius_+_per_stage", 3 }, + { "flameblast_maximum_stages", 10 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["FlameblastMercenaryEncounter"] = { + name = "Flameblast", + hidden = true, + mercenary = true, + inheritedFrom = "Flameblast", + color = 3, + baseEffectiveness = 0.69999998807907, + incrementalEffectiveness = 0.037500001490116, + description = "Channels to build up a large explosion, which is released when you stop using the skill. The longer you channel, the larger the area of effect and damage of the explosion.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Fire] = true, [SkillType.Channel] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.2, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "charged_blast_spell_damage_+%_final_per_stack", 165 }, + { "flameblast_ailment_damage_+%_final_per_stack", 60 }, + { "base_chance_to_ignite_%", 50 }, + { "vaal_flameblast_radius_+_per_stage", 3 }, + { "flameblast_maximum_stages", 10 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 0.9, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["FlammabilityBlasphemyMercenary"] = { + name = "Blasphemy Flammability", + hidden = true, + mercenary = true, + inheritedFrom = "Flammability", + color = 3, + description = "Curses all targets in an area, lowering their fire resistance and giving them a chance to be ignited when hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "chance_to_be_ignited_%", 25 }, + { "support_blasphemy_curse_effect_+%_final", -25 }, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "base_fire_damage_resistance_%", + "base_deal_no_damage", + "curse_apply_as_aura", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, -17, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 8200, 1, -18, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 8400, 1, -19, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 8600, 2, -20, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8800, 2, -21, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 9000, 3, -22, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 9200, 3, -23, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 9400, 4, -24, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 9600, 4, -25, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9800, 5, -26, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10000, 5, -27, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 10200, 6, -28, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 10400, 6, -29, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 10600, 7, -30, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 10800, 7, -31, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 11000, 8, -32, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 11200, 8, -33, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 11400, 9, -34, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 11600, 9, -35, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 11800, 10, -36, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 12000, 10, -37, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 12200, 11, -38, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 12400, 11, -39, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 12600, 12, -40, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 12800, 12, -41, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13000, 13, -42, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13200, 13, -43, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 13400, 14, -44, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 13600, 14, -45, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 13800, 15, -46, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 13900, 15, -46, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14000, 15, -47, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14100, 15, -47, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14200, 16, -48, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14300, 16, -48, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14400, 16, -49, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14500, 16, -49, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14600, 17, -50, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14700, 17, -50, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 14800, 17, -51, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["FlammabilityMercenary"] = { + name = "Flammability", + hidden = true, + mercenary = true, + inheritedFrom = "Flammability", + color = 3, + description = "Curses all targets in an area, lowering their fire resistance and giving them a chance to be ignited when hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "chance_to_be_ignited_%", 25 }, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "base_fire_damage_resistance_%", + "base_deal_no_damage", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, -17, levelRequirement = 24, statInterpolation = { 1, 1, 1, }, }, + [2] = { 8200, 1, -18, levelRequirement = 27, statInterpolation = { 1, 1, 1, }, }, + [3] = { 8400, 1, -19, levelRequirement = 30, statInterpolation = { 1, 1, 1, }, }, + [4] = { 8600, 2, -20, levelRequirement = 33, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8800, 2, -21, levelRequirement = 36, statInterpolation = { 1, 1, 1, }, }, + [6] = { 9000, 3, -22, levelRequirement = 39, statInterpolation = { 1, 1, 1, }, }, + [7] = { 9200, 3, -23, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [8] = { 9400, 4, -24, levelRequirement = 45, statInterpolation = { 1, 1, 1, }, }, + [9] = { 9600, 4, -25, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9800, 5, -26, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10000, 5, -27, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 10200, 6, -28, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 10400, 6, -29, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 10600, 7, -30, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 10800, 7, -31, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 11000, 8, -32, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 11200, 8, -33, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 11400, 9, -34, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 11600, 9, -35, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 11800, 10, -36, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 12000, 10, -37, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 12200, 11, -38, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 12400, 11, -39, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 12600, 12, -40, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 12800, 12, -41, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13000, 13, -42, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13200, 13, -43, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 13400, 14, -44, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 13600, 14, -45, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 13800, 15, -46, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 13900, 15, -46, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14000, 15, -47, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14100, 15, -47, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14200, 16, -48, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14300, 16, -48, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14400, 16, -49, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14500, 16, -49, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14600, 17, -50, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14700, 17, -50, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 14800, 17, -51, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["FleshOfferingMercenary"] = { + name = "Flesh Offering", + hidden = true, + mercenary = true, + inheritedFrom = "FleshOffering", + color = 3, + description = "Consumes a corpse, which temporarily empowers your minions with swiftness. The skill consumes other nearby corpses, increasing the duration for each corpse consumed.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Triggerable] = true, [SkillType.Minion] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Offering] = true, }, + statDescriptionScope = "offering_skill_stat_descriptions", + castTime = 1, + baseFlags = { + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 5000 }, + { "offering_skill_effect_duration_per_corpse", 1000 }, + }, + stats = { + "attack_speed_+%_granted_from_skill", + "base_movement_velocity_+%", + "cast_speed_+%_granted_from_skill", + "base_deal_no_damage", + }, + levels = { + [1] = { 20, 20, 20, cooldown = 10, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 21, 20, 21, cooldown = 10, levelRequirement = 15, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 21, 21, 21, cooldown = 10, levelRequirement = 19, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 22, 21, 22, cooldown = 10, levelRequirement = 23, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 22, 22, 22, cooldown = 10, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 23, 22, 23, cooldown = 10, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 23, 23, 23, cooldown = 10, levelRequirement = 35, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 24, 23, 24, cooldown = 10, levelRequirement = 38, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 24, 24, 24, cooldown = 10, levelRequirement = 41, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 25, 24, 25, cooldown = 10, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 25, 25, 25, cooldown = 10, levelRequirement = 47, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 26, 25, 26, cooldown = 10, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 26, 26, 26, cooldown = 10, levelRequirement = 53, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 27, 26, 27, cooldown = 10, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 27, 27, 27, cooldown = 10, levelRequirement = 59, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 28, 27, 28, cooldown = 10, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 28, 28, 28, cooldown = 10, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 29, 28, 29, cooldown = 10, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 29, 29, 29, cooldown = 10, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 30, 29, 30, cooldown = 10, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 30, 30, 30, cooldown = 10, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 31, 30, 31, cooldown = 10, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 31, 31, 31, cooldown = 10, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 32, 31, 32, cooldown = 10, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 32, 32, 32, cooldown = 10, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 33, 32, 33, cooldown = 10, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 33, 33, 33, cooldown = 10, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 34, 33, 34, cooldown = 10, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 34, 34, 34, cooldown = 10, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 35, 34, 35, cooldown = 10, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 35, 34, 35, cooldown = 10, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 35, 35, 35, cooldown = 10, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 35, 35, 35, cooldown = 10, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 36, 35, 36, cooldown = 10, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 36, 35, 36, cooldown = 10, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 36, 36, 36, cooldown = 10, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 36, 36, 36, cooldown = 10, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 37, 36, 37, cooldown = 10, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 37, 36, 37, cooldown = 10, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 37, 37, 37, cooldown = 10, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["FlickerStrikeMercenary"] = { + name = "Flicker Strike", + hidden = true, + mercenary = true, + inheritedFrom = "FlickerStrike", + color = 2, + description = "Teleports the character to a nearby monster and attacks with a melee weapon. If no specific monster is targeted, one is picked at random. Grants a buff that increases movement speed for a duration. The cooldown can be bypassed by expending a Frenzy Charge.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Movement] = true, [SkillType.Duration] = true, [SkillType.Cooldown] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + melee = true, + movement = true, + }, + constantStats = { + { "base_attack_speed_+%_per_frenzy_charge", 10 }, + { "add_frenzy_charge_on_skill_hit_%", 15 }, + { "flicker_strike_buff_movement_speed_+%", 20 }, + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "ignores_proximity_shield", + "melee_defer_damage_prediction", + }, + levels = { + [1] = { baseMultiplier = 1.773, damageEffectiveness = 1.773, levelRequirement = 10, }, + [2] = { baseMultiplier = 1.853, damageEffectiveness = 1.853, levelRequirement = 13, }, + [3] = { baseMultiplier = 1.94, damageEffectiveness = 1.94, levelRequirement = 17, }, + [4] = { baseMultiplier = 2.03, damageEffectiveness = 2.03, levelRequirement = 21, }, + [5] = { baseMultiplier = 2.125, damageEffectiveness = 2.125, levelRequirement = 25, }, + [6] = { baseMultiplier = 2.224, damageEffectiveness = 2.224, levelRequirement = 29, }, + [7] = { baseMultiplier = 2.327, damageEffectiveness = 2.327, levelRequirement = 33, }, + [8] = { baseMultiplier = 2.432, damageEffectiveness = 2.432, levelRequirement = 36, }, + [9] = { baseMultiplier = 2.54, damageEffectiveness = 2.54, levelRequirement = 39, }, + [10] = { baseMultiplier = 2.654, damageEffectiveness = 2.654, levelRequirement = 42, }, + [11] = { baseMultiplier = 2.773, damageEffectiveness = 2.773, levelRequirement = 45, }, + [12] = { baseMultiplier = 2.896, damageEffectiveness = 2.896, levelRequirement = 48, }, + [13] = { baseMultiplier = 3.025, damageEffectiveness = 3.025, levelRequirement = 51, }, + [14] = { baseMultiplier = 3.16, damageEffectiveness = 3.16, levelRequirement = 54, }, + [15] = { baseMultiplier = 3.301, damageEffectiveness = 3.301, levelRequirement = 57, }, + [16] = { baseMultiplier = 3.447, damageEffectiveness = 3.447, levelRequirement = 60, }, + [17] = { baseMultiplier = 3.6, damageEffectiveness = 3.6, levelRequirement = 63, }, + [18] = { baseMultiplier = 3.761, damageEffectiveness = 3.761, levelRequirement = 66, }, + [19] = { baseMultiplier = 3.921, damageEffectiveness = 3.921, levelRequirement = 68, }, + [20] = { baseMultiplier = 4.089, damageEffectiveness = 4.089, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.263, damageEffectiveness = 4.263, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.445, damageEffectiveness = 4.445, levelRequirement = 74, }, + [23] = { baseMultiplier = 4.635, damageEffectiveness = 4.635, levelRequirement = 76, }, + [24] = { baseMultiplier = 4.833, damageEffectiveness = 4.833, levelRequirement = 78, }, + [25] = { baseMultiplier = 5.038, damageEffectiveness = 5.038, levelRequirement = 80, }, + [26] = { baseMultiplier = 5.253, damageEffectiveness = 5.253, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.477, damageEffectiveness = 5.477, levelRequirement = 84, }, + [28] = { baseMultiplier = 5.71, damageEffectiveness = 5.71, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.953, damageEffectiveness = 5.953, levelRequirement = 88, }, + [30] = { baseMultiplier = 6.206, damageEffectiveness = 6.206, levelRequirement = 90, }, + [31] = { baseMultiplier = 6.587, damageEffectiveness = 6.587, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.727, damageEffectiveness = 6.727, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.87, damageEffectiveness = 6.87, levelRequirement = 93, }, + [34] = { baseMultiplier = 7.017, damageEffectiveness = 7.017, levelRequirement = 94, }, + [35] = { baseMultiplier = 7.165, damageEffectiveness = 7.165, levelRequirement = 95, }, + [36] = { baseMultiplier = 7.318, damageEffectiveness = 7.318, levelRequirement = 96, }, + [37] = { baseMultiplier = 7.473, damageEffectiveness = 7.473, levelRequirement = 97, }, + [38] = { baseMultiplier = 7.632, damageEffectiveness = 7.632, levelRequirement = 98, }, + [39] = { baseMultiplier = 7.794, damageEffectiveness = 7.794, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.96, damageEffectiveness = 7.96, levelRequirement = 100, }, + }, +} + +skills["ForbiddenRiteTotemMercenary"] = { + name = "Forbidden Rite Totem", + hidden = true, + mercenary = true, + inheritedFrom = "ForbiddenRite", + color = 3, + baseEffectiveness = 1.0389000177383, + incrementalEffectiveness = 0.045000001788139, + description = "Lobs an exploding projectile near the targeted location, and extra projectiles toward enemies around you. The projectiles deal chaos damage based on your life and energy shield. Casting this spell damages you.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Chaos] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Chaos] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "soulfeast_take_%_maximum_life_as_chaos_damage", 40 }, + { "skill_base_chaos_damage_%_maximum_life", 12 }, + { "skill_base_chaos_damage_%_maximum_energy_shield", 5 }, + { "soulfeast_take_%_maximum_energy_shield_as_chaos_damage", 25 }, + { "active_skill_projectile_speed_+%_variation_final", 20 }, + { "base_totem_duration", 8000 }, + { "base_totem_range", 70 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "soulfeast_number_of_secondary_projectiles", + "base_is_projectile", + "is_area_damage", + "projectile_behaviour_only_explode", + "is_totem", + "base_skill_is_totemified", + "totem_ignores_cooldown", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 10, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["FrenzyMercenary"] = { + name = "Frenzy", + hidden = true, + mercenary = true, + inheritedFrom = "Frenzy", + color = 2, + baseEffectiveness = 0, + description = "Performs an attack with a ranged weapon that gives the character a frenzy charge if it hits. Frenzy charges increase your attack speed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.WandAttack] = true, }, + weaponTypes = { + ["Bow"] = true, + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "frenzy_skill_attack_damage_+%_final_per_frenzy_charge", 5 }, + { "frenzy_skill_attack_speed_+%_final_per_frenzy_charge", 5 }, + }, + stats = { + "skill_can_fire_arrows", + "skill_can_fire_wand_projectiles", + }, + levels = { + [1] = { baseMultiplier = 1.15, damageEffectiveness = 1.15, levelRequirement = 16, }, + [2] = { baseMultiplier = 1.161, damageEffectiveness = 1.16, levelRequirement = 20, }, + [3] = { baseMultiplier = 1.171, damageEffectiveness = 1.17, levelRequirement = 24, }, + [4] = { baseMultiplier = 1.182, damageEffectiveness = 1.18, levelRequirement = 28, }, + [5] = { baseMultiplier = 1.192, damageEffectiveness = 1.19, levelRequirement = 31, }, + [6] = { baseMultiplier = 1.203, damageEffectiveness = 1.2, levelRequirement = 34, }, + [7] = { baseMultiplier = 1.213, damageEffectiveness = 1.21, levelRequirement = 37, }, + [8] = { baseMultiplier = 1.224, damageEffectiveness = 1.22, levelRequirement = 40, }, + [9] = { baseMultiplier = 1.234, damageEffectiveness = 1.23, levelRequirement = 43, }, + [10] = { baseMultiplier = 1.245, damageEffectiveness = 1.24, levelRequirement = 46, }, + [11] = { baseMultiplier = 1.255, damageEffectiveness = 1.26, levelRequirement = 49, }, + [12] = { baseMultiplier = 1.266, damageEffectiveness = 1.27, levelRequirement = 52, }, + [13] = { baseMultiplier = 1.276, damageEffectiveness = 1.28, levelRequirement = 55, }, + [14] = { baseMultiplier = 1.287, damageEffectiveness = 1.29, levelRequirement = 58, }, + [15] = { baseMultiplier = 1.297, damageEffectiveness = 1.3, levelRequirement = 60, }, + [16] = { baseMultiplier = 1.308, damageEffectiveness = 1.31, levelRequirement = 62, }, + [17] = { baseMultiplier = 1.318, damageEffectiveness = 1.32, levelRequirement = 64, }, + [18] = { baseMultiplier = 1.329, damageEffectiveness = 1.33, levelRequirement = 66, }, + [19] = { baseMultiplier = 1.339, damageEffectiveness = 1.34, levelRequirement = 68, }, + [20] = { baseMultiplier = 1.35, damageEffectiveness = 1.35, levelRequirement = 70, }, + [21] = { baseMultiplier = 1.361, damageEffectiveness = 1.36, levelRequirement = 72, }, + [22] = { baseMultiplier = 1.371, damageEffectiveness = 1.37, levelRequirement = 74, }, + [23] = { baseMultiplier = 1.382, damageEffectiveness = 1.38, levelRequirement = 76, }, + [24] = { baseMultiplier = 1.392, damageEffectiveness = 1.39, levelRequirement = 78, }, + [25] = { baseMultiplier = 1.403, damageEffectiveness = 1.4, levelRequirement = 80, }, + [26] = { baseMultiplier = 1.413, damageEffectiveness = 1.41, levelRequirement = 82, }, + [27] = { baseMultiplier = 1.424, damageEffectiveness = 1.42, levelRequirement = 84, }, + [28] = { baseMultiplier = 1.434, damageEffectiveness = 1.43, levelRequirement = 86, }, + [29] = { baseMultiplier = 1.445, damageEffectiveness = 1.44, levelRequirement = 88, }, + [30] = { baseMultiplier = 1.455, damageEffectiveness = 1.46, levelRequirement = 90, }, + [31] = { baseMultiplier = 1.461, damageEffectiveness = 1.46, levelRequirement = 91, }, + [32] = { baseMultiplier = 1.466, damageEffectiveness = 1.47, levelRequirement = 92, }, + [33] = { baseMultiplier = 1.471, damageEffectiveness = 1.47, levelRequirement = 93, }, + [34] = { baseMultiplier = 1.476, damageEffectiveness = 1.48, levelRequirement = 94, }, + [35] = { baseMultiplier = 1.482, damageEffectiveness = 1.48, levelRequirement = 95, }, + [36] = { baseMultiplier = 1.487, damageEffectiveness = 1.49, levelRequirement = 96, }, + [37] = { baseMultiplier = 1.492, damageEffectiveness = 1.49, levelRequirement = 97, }, + [38] = { baseMultiplier = 1.497, damageEffectiveness = 1.5, levelRequirement = 98, }, + [39] = { baseMultiplier = 1.503, damageEffectiveness = 1.5, levelRequirement = 99, }, + [40] = { baseMultiplier = 1.508, damageEffectiveness = 1.51, levelRequirement = 100, }, + }, +} + +skills["FrostBladesMercenary"] = { + name = "Frost Blades", + hidden = true, + mercenary = true, + inheritedFrom = "FrostBlades", + color = 2, + description = "Attack enemies with increased range, releasing icy blades from the first enemy hit which fly at other enemies. Requires a Melee Weapon.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Cold] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_cold", 60 }, + { "total_projectile_spread_angle_override", 110 }, + { "active_skill_hit_ailment_damage_with_projectile_+%_final", -30 }, + }, + stats = { + "base_number_of_projectiles", + "melee_weapon_range_+", + "show_number_of_projectiles", + }, + levels = { + [1] = { 5, 18, baseMultiplier = 1.438, damageEffectiveness = 1.438, levelRequirement = 1, statInterpolation = { 1, 1, }, }, + [2] = { 5, 18, baseMultiplier = 1.512, damageEffectiveness = 1.512, levelRequirement = 2, statInterpolation = { 1, 1, }, }, + [3] = { 5, 18, baseMultiplier = 1.594, damageEffectiveness = 1.594, levelRequirement = 4, statInterpolation = { 1, 1, }, }, + [4] = { 5, 18, baseMultiplier = 1.682, damageEffectiveness = 1.682, levelRequirement = 7, statInterpolation = { 1, 1, }, }, + [5] = { 5, 18, baseMultiplier = 1.779, damageEffectiveness = 1.779, levelRequirement = 11, statInterpolation = { 1, 1, }, }, + [6] = { 6, 19, baseMultiplier = 1.886, damageEffectiveness = 1.886, levelRequirement = 16, statInterpolation = { 1, 1, }, }, + [7] = { 6, 19, baseMultiplier = 1.994, damageEffectiveness = 1.994, levelRequirement = 20, statInterpolation = { 1, 1, }, }, + [8] = { 6, 19, baseMultiplier = 2.109, damageEffectiveness = 2.109, levelRequirement = 24, statInterpolation = { 1, 1, }, }, + [9] = { 6, 19, baseMultiplier = 2.23, damageEffectiveness = 2.23, levelRequirement = 28, statInterpolation = { 1, 1, }, }, + [10] = { 6, 19, baseMultiplier = 2.358, damageEffectiveness = 2.358, levelRequirement = 32, statInterpolation = { 1, 1, }, }, + [11] = { 7, 20, baseMultiplier = 2.494, damageEffectiveness = 2.494, levelRequirement = 36, statInterpolation = { 1, 1, }, }, + [12] = { 7, 20, baseMultiplier = 2.636, damageEffectiveness = 2.636, levelRequirement = 40, statInterpolation = { 1, 1, }, }, + [13] = { 7, 20, baseMultiplier = 2.787, damageEffectiveness = 2.787, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [14] = { 7, 20, baseMultiplier = 2.947, damageEffectiveness = 2.947, levelRequirement = 48, statInterpolation = { 1, 1, }, }, + [15] = { 7, 20, baseMultiplier = 3.115, damageEffectiveness = 3.115, levelRequirement = 52, statInterpolation = { 1, 1, }, }, + [16] = { 8, 21, baseMultiplier = 3.292, damageEffectiveness = 3.292, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [17] = { 8, 21, baseMultiplier = 3.481, damageEffectiveness = 3.481, levelRequirement = 60, statInterpolation = { 1, 1, }, }, + [18] = { 8, 21, baseMultiplier = 3.679, damageEffectiveness = 3.679, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [19] = { 8, 21, baseMultiplier = 3.882, damageEffectiveness = 3.882, levelRequirement = 67, statInterpolation = { 1, 1, }, }, + [20] = { 8, 21, baseMultiplier = 4.096, damageEffectiveness = 4.096, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 9, 22, baseMultiplier = 4.315, damageEffectiveness = 4.315, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 9, 22, baseMultiplier = 4.546, damageEffectiveness = 4.546, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 9, 22, baseMultiplier = 4.788, damageEffectiveness = 4.788, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 9, 22, baseMultiplier = 5.044, damageEffectiveness = 5.044, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 9, 22, baseMultiplier = 5.314, damageEffectiveness = 5.314, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 10, 23, baseMultiplier = 5.597, damageEffectiveness = 5.597, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 10, 23, baseMultiplier = 5.896, damageEffectiveness = 5.896, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 10, 23, baseMultiplier = 6.211, damageEffectiveness = 6.211, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 10, 23, baseMultiplier = 6.542, damageEffectiveness = 6.542, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 10, 23, baseMultiplier = 6.891, damageEffectiveness = 6.891, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 10, 23, baseMultiplier = 7.428, damageEffectiveness = 7.428, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 11, 24, baseMultiplier = 7.626, damageEffectiveness = 7.626, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 11, 24, baseMultiplier = 7.829, damageEffectiveness = 7.829, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 11, 24, baseMultiplier = 8.038, damageEffectiveness = 8.038, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 11, 24, baseMultiplier = 8.251, damageEffectiveness = 8.251, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 11, 24, baseMultiplier = 8.471, damageEffectiveness = 8.471, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 11, 24, baseMultiplier = 8.697, damageEffectiveness = 8.697, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 11, 24, baseMultiplier = 8.928, damageEffectiveness = 8.928, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 11, 24, baseMultiplier = 9.166, damageEffectiveness = 9.166, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 11, 24, baseMultiplier = 9.41, damageEffectiveness = 9.41, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["FrostBladesMercenaryEncounter"] = { + name = "Frost Blades", + hidden = true, + mercenary = true, + inheritedFrom = "FrostBlades", + color = 2, + description = "Attack enemies with increased range, releasing icy blades from the first enemy hit which fly at other enemies. Requires a Melee Weapon.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Cold] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_cold", 60 }, + { "total_projectile_spread_angle_override", 110 }, + { "active_skill_hit_ailment_damage_with_projectile_+%_final", -30 }, + }, + stats = { + "base_number_of_projectiles", + "melee_weapon_range_+", + "show_number_of_projectiles", + }, + levels = { + [1] = { 6, 19, baseMultiplier = 1.7, damageEffectiveness = 1.7, levelRequirement = 0, statInterpolation = { 1, 1, }, }, + }, +} + +skills["FrostBombMercenary"] = { + name = "Frost Bomb", + hidden = true, + mercenary = true, + inheritedFrom = "FrostBomb", + color = 3, + baseEffectiveness = 2.25, + incrementalEffectiveness = 0.050000000745058, + description = "Creates a crystal that pulses with cold for a duration. Each pulse applies a debuff to nearby enemies for a secondary duration which reduces life regeneration rate, and also inflicts Cold Exposure. When the crystal's duration ends, it explodes, dealing heavy cold damage to enemies around it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Cold] = true, [SkillType.Damage] = true, [SkillType.Multicastable] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Orb] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 24 }, + { "base_skill_effect_duration", 2000 }, + { "base_secondary_skill_effect_duration", 5000 }, + { "base_cold_damage_resistance_%", -15 }, + { "life_regeneration_rate_+%", -75 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "active_skill_base_area_of_effect_radius", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 1.7, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 1.7, levelRequirement = 6, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 1.8, levelRequirement = 9, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 1.8, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 1.9, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 1.9, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 2, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.4, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 4, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.6, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 5, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.7, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.8, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.9, levelRequirement = 61, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.9, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 7, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 8, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 9, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 9, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 10, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 10, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 10, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 11, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 11, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 11, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 11, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 11, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 12, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 12, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 12, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 12, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 12, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 13, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["FrostShieldMercenary"] = { + name = "Frost Shield", + hidden = true, + mercenary = true, + inheritedFrom = "FrostShield", + color = 3, + description = "Place a Frost Shield that drains your energy shield for one second or until you run out, gaining stages while this drain occurs. The Frost Shield takes some damage from hits in place of you and allies while in its area. Enemies in the area are Chilled. You can only have one Frost Shield active at once.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Cold] = true, [SkillType.Totemable] = true, [SkillType.ChillingArea] = true, [SkillType.NonHitChill] = true, [SkillType.ElementalStatus] = true, [SkillType.TotemCastsAlone] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "frost_globe_absorb_damage_%_enemy_in_bubble", 20 }, + { "frost_globe_max_stages", 4 }, + { "frost_globe_absorb_damage_%_enemy_outside_bubble", 60 }, + { "frost_globe_stage_gain_interval_ms", 300 }, + { "base_skill_effect_duration", 10000 }, + }, + stats = { + "frost_globe_health_per_stage", + "energy_shield_lost_per_minute", + "frost_globe_additional_spell_base_critical_strike_chance_per_stage", + }, + levels = { + [1] = { 190, 9000, 10, cooldown = 5, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 200, 9600, 11, cooldown = 5, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 210, 10200, 13, cooldown = 5, levelRequirement = 38, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 230, 11400, 14, cooldown = 5, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 250, 12000, 16, cooldown = 5, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 280, 13200, 17, cooldown = 5, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 300, 14400, 19, cooldown = 5, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 330, 15600, 20, cooldown = 5, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 360, 17400, 22, cooldown = 5, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 390, 18600, 23, cooldown = 5, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 430, 20400, 25, cooldown = 5, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 470, 22800, 26, cooldown = 5, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 520, 24600, 28, cooldown = 5, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 570, 27600, 29, cooldown = 5, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 630, 30000, 31, cooldown = 5, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 690, 33000, 32, cooldown = 5, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 750, 36000, 34, cooldown = 5, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 830, 39600, 35, cooldown = 5, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 870, 41400, 37, cooldown = 5, levelRequirement = 69, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 910, 43800, 38, cooldown = 5, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 1000, 48000, 40, cooldown = 5, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 1090, 52200, 41, cooldown = 5, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 1190, 57000, 43, cooldown = 5, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 1290, 61800, 44, cooldown = 5, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 1400, 67200, 46, cooldown = 5, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 1530, 73200, 47, cooldown = 5, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 1660, 79800, 49, cooldown = 5, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 1800, 86400, 50, cooldown = 5, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 1940, 93000, 52, cooldown = 5, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 2100, 100800, 53, cooldown = 5, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 2180, 104400, 54, cooldown = 5, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 2260, 108600, 55, cooldown = 5, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 2350, 112800, 55, cooldown = 5, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 2440, 117000, 56, cooldown = 5, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 2530, 121200, 57, cooldown = 5, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 2620, 125400, 58, cooldown = 5, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 2720, 130200, 58, cooldown = 5, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 2820, 135000, 59, cooldown = 5, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 2920, 139800, 60, cooldown = 5, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 3020, 144600, 61, cooldown = 5, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["FrostWallMercenary"] = { + name = "Frost Wall", + hidden = true, + mercenary = true, + inheritedFrom = "FrostWall", + color = 3, + baseEffectiveness = 2, + incrementalEffectiveness = 0.033300001174212, + description = "Creates a wall of ice which holds back enemies. Targets under the wall are damaged and pushed back.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.Cascadable] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "wall_expand_delay_ms", 150 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_skill_effect_duration", + "wall_maximum_length", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_skill_effect_duration", + }, + levels = { + [1] = { 0.69999998807907, 1.1000000238419, 3000, 28, cooldown = 4, levelRequirement = 4, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.69999998807907, 1.2000000476837, 3100, 28, cooldown = 4, levelRequirement = 6, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2999999523163, 3200, 28, cooldown = 4, levelRequirement = 9, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 3300, 28, cooldown = 4, levelRequirement = 12, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 3400, 35, cooldown = 4, levelRequirement = 16, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 3500, 35, cooldown = 4, levelRequirement = 20, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 3600, 35, cooldown = 4, levelRequirement = 24, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 3700, 35, cooldown = 4, levelRequirement = 28, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 3800, 42, cooldown = 4, levelRequirement = 32, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 3900, 42, cooldown = 4, levelRequirement = 36, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 4000, 42, cooldown = 4, levelRequirement = 40, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 4100, 42, cooldown = 4, levelRequirement = 44, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 4200, 49, cooldown = 4, levelRequirement = 48, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 4300, 49, cooldown = 4, levelRequirement = 52, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 4400, 49, cooldown = 4, levelRequirement = 55, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 4500, 49, cooldown = 4, levelRequirement = 58, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 4600, 56, cooldown = 4, levelRequirement = 61, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 4700, 56, cooldown = 4, levelRequirement = 64, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 4800, 56, cooldown = 4, levelRequirement = 67, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 4900, 56, cooldown = 4, levelRequirement = 70, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 5000, 63, cooldown = 4, levelRequirement = 72, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 5100, 63, cooldown = 4, levelRequirement = 74, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 5200, 63, cooldown = 4, levelRequirement = 76, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 5300, 63, cooldown = 4, levelRequirement = 78, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 5400, 70, cooldown = 4, levelRequirement = 80, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 5500, 70, cooldown = 4, levelRequirement = 82, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 5600, 70, cooldown = 4, levelRequirement = 84, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 5700, 70, cooldown = 4, levelRequirement = 86, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 5800, 77, cooldown = 4, levelRequirement = 88, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 5900, 77, cooldown = 4, levelRequirement = 90, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 5950, 78, cooldown = 4, levelRequirement = 91, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 6000, 80, cooldown = 4, levelRequirement = 92, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 6050, 81, cooldown = 4, levelRequirement = 93, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 6100, 83, cooldown = 4, levelRequirement = 94, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 6150, 85, cooldown = 4, levelRequirement = 95, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 6200, 87, cooldown = 4, levelRequirement = 96, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 6250, 88, cooldown = 4, levelRequirement = 97, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 6300, 90, cooldown = 4, levelRequirement = 98, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 6350, 92, cooldown = 4, levelRequirement = 99, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 6400, 94, cooldown = 4, levelRequirement = 100, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["FrostbiteMercenary"] = { + name = "Frostbite", + hidden = true, + mercenary = true, + inheritedFrom = "Frostbite", + color = 3, + description = "Curses all targets in an area, lowering their cold resistance and giving them a chance to be frozen when hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "chance_to_be_frozen_%", 25 }, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "base_cold_damage_resistance_%", + "base_deal_no_damage", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, -17, cooldown = 10, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 8200, 1, -18, cooldown = 10, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 8400, 1, -19, cooldown = 10, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 8600, 2, -20, cooldown = 10, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8800, 2, -21, cooldown = 10, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 9000, 3, -22, cooldown = 10, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 9200, 3, -23, cooldown = 10, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 9400, 4, -24, cooldown = 10, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 9600, 4, -25, cooldown = 10, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9800, 5, -26, cooldown = 10, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10000, 5, -27, cooldown = 10, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 10200, 6, -28, cooldown = 10, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 10400, 6, -29, cooldown = 10, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 10600, 7, -30, cooldown = 10, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 10800, 7, -31, cooldown = 10, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 11000, 8, -32, cooldown = 10, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 11200, 8, -33, cooldown = 10, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 11400, 9, -34, cooldown = 10, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 11600, 9, -35, cooldown = 10, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 11800, 10, -36, cooldown = 10, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 12000, 10, -37, cooldown = 10, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 12200, 11, -38, cooldown = 10, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 12400, 11, -39, cooldown = 10, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 12600, 12, -40, cooldown = 10, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 12800, 12, -41, cooldown = 10, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13000, 13, -42, cooldown = 10, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13200, 13, -43, cooldown = 10, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 13400, 14, -44, cooldown = 10, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 13600, 14, -45, cooldown = 10, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 13800, 15, -46, cooldown = 10, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 13900, 15, -46, cooldown = 10, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14000, 15, -47, cooldown = 10, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14100, 15, -47, cooldown = 10, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14200, 16, -48, cooldown = 10, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14300, 16, -48, cooldown = 10, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14400, 16, -49, cooldown = 10, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14500, 16, -49, cooldown = 10, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14600, 17, -50, cooldown = 10, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14700, 17, -50, cooldown = 10, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 14800, 17, -51, cooldown = 10, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["FrostblinkMercenary"] = { + name = "Frostblink", + hidden = true, + mercenary = true, + inheritedFrom = "Frostblink", + color = 3, + baseEffectiveness = 2.0243999958038, + incrementalEffectiveness = 0.047499999403954, + description = "Teleport to a location, damaging enemies and leaving Chilled ground in an area at both ends of the teleport. Shares a cooldown with other Blink skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Movement] = true, [SkillType.Duration] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.ChillingArea] = true, [SkillType.Travel] = true, [SkillType.Blink] = true, [SkillType.Area] = true, [SkillType.Triggerable] = true, [SkillType.Damage] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Instant] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + movement = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "ice_dash_cooldown_recovery_per_nearby_normal_or_magic_enemy", + "ice_dash_cooldown_recovery_per_nearby_rare_or_unique_enemy", + "skill_maximum_travel_distance_+%", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 15, 80, 0, 0, cooldown = 3, critChance = 7.5, damageEffectiveness = 1.8, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 15, 81, 2, 0, cooldown = 3, critChance = 7.5, damageEffectiveness = 1.8, levelRequirement = 6, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 15, 82, 4, 0, cooldown = 2.95, critChance = 7.5, damageEffectiveness = 1.9, levelRequirement = 9, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 15, 83, 6, 0, cooldown = 2.95, critChance = 7.5, damageEffectiveness = 1.9, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 16, 84, 8, 0, cooldown = 2.9, critChance = 7.5, damageEffectiveness = 1.9, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 16, 85, 10, 1, cooldown = 2.9, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 16, 86, 12, 1, cooldown = 2.9, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 16, 87, 14, 1, cooldown = 2.85, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 17, 88, 16, 1, cooldown = 2.85, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 17, 89, 18, 1, cooldown = 2.8, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 17, 90, 20, 2, cooldown = 2.8, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 17, 91, 22, 2, cooldown = 2.8, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 18, 92, 24, 2, cooldown = 2.75, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 18, 93, 26, 2, cooldown = 2.75, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 18, 94, 28, 2, cooldown = 2.7, critChance = 7.5, damageEffectiveness = 2.4, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 18, 95, 30, 3, cooldown = 2.7, critChance = 7.5, damageEffectiveness = 2.4, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 19, 96, 32, 3, cooldown = 2.7, critChance = 7.5, damageEffectiveness = 2.4, levelRequirement = 61, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 19, 97, 34, 3, cooldown = 2.65, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 19, 98, 36, 3, cooldown = 2.65, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 19, 99, 38, 3, cooldown = 2.6, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 20, 100, 40, 4, cooldown = 2.6, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 20, 101, 42, 4, cooldown = 2.6, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 20, 102, 44, 4, cooldown = 2.55, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 20, 103, 46, 4, cooldown = 2.55, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 21, 104, 48, 4, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 21, 105, 50, 5, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 21, 106, 52, 5, cooldown = 2.5, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 21, 107, 54, 5, cooldown = 2.45, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 22, 108, 56, 5, cooldown = 2.45, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 22, 109, 58, 5, cooldown = 2.4, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 22, 109, 59, 5, cooldown = 2.4, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 22, 110, 60, 6, cooldown = 2.4, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 22, 110, 61, 6, cooldown = 2.4, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 22, 111, 62, 6, cooldown = 2.4, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 22, 111, 63, 6, cooldown = 2.35, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 23, 112, 64, 6, cooldown = 2.35, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 23, 112, 65, 6, cooldown = 2.35, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 23, 113, 66, 6, cooldown = 2.35, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 23, 113, 67, 6, cooldown = 2.3, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 23, 114, 68, 6, cooldown = 2.3, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + }, +} + +skills["FrostboltMercenary"] = { + name = "Frostbolt", + hidden = true, + mercenary = true, + inheritedFrom = "FrostBolt", + color = 3, + baseEffectiveness = 2.8582999706268, + incrementalEffectiveness = 0.0472999997437, + description = "Fires a slow-moving projectile that pierces through enemies, dealing cold damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Cold] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + projectile = true, + spell = true, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_is_projectile", + "always_pierce", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 2, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.6, levelRequirement = 4, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.6, levelRequirement = 7, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.7, levelRequirement = 11, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.7, levelRequirement = 16, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.8, levelRequirement = 20, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.8, levelRequirement = 24, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.9, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.9, levelRequirement = 32, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3, levelRequirement = 36, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.2, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.3, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.3, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.4, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.5, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.5, levelRequirement = 67, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["FrostboltMercenaryEncounter"] = { + name = "Frostbolt", + hidden = true, + mercenary = true, + inheritedFrom = "FrostBolt", + color = 3, + baseEffectiveness = 2.8582999706268, + incrementalEffectiveness = 0.041999999433756, + description = "Fires a slow-moving projectile that pierces through enemies, dealing cold damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Cold] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + projectile = true, + spell = true, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_is_projectile", + "always_pierce", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.5, levelRequirement = 2, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.6, levelRequirement = 4, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.6, levelRequirement = 7, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.7, levelRequirement = 11, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.7, levelRequirement = 16, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.8, levelRequirement = 20, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.8, levelRequirement = 24, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.9, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 2.9, levelRequirement = 32, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3, levelRequirement = 36, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.1, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.2, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.3, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.3, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.4, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.5, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.5, levelRequirement = 67, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 7.5, damageEffectiveness = 3.6, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["GSRitualChaosPulse"] = { + name = "GSRitualChaosPulse", + hidden = true, + mercenary = true, + inheritedFrom = "AtlasExileCrusaderMageguardBombExplodeSpectre", + color = 4, + baseEffectiveness = 2.5, + incrementalEffectiveness = 0.03999999910593, + skillTypes = { [SkillType.Spell] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.8, + baseFlags = { + spell = true, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["GalvanicArrowMercenary"] = { + name = "Galvanic Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "GalvanicArrow", + color = 2, + description = "Fire a trio of electrical arrows that quickly dissipate, vanishing shortly after being loosed. The arrows are fired with such force that they create a burst of lightning, damaging enemies in a cone in front of you.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Lightning] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "base_number_of_arrows", 3 }, + }, + stats = { + "active_skill_base_radius_+", + "base_is_projectile", + "skill_can_fire_arrows", + "additive_arrow_speed_modifiers_apply_to_area_of_effect", + "quality_display_base_additional_arrows_is_gem", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, baseMultiplier = 0.92, damageEffectiveness = 0.92, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 0, baseMultiplier = 0.931, damageEffectiveness = 0.931, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 1, baseMultiplier = 0.943, damageEffectiveness = 0.943, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 1, baseMultiplier = 0.954, damageEffectiveness = 0.954, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 1, baseMultiplier = 0.966, damageEffectiveness = 0.966, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 1, baseMultiplier = 0.977, damageEffectiveness = 0.977, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 2, baseMultiplier = 0.989, damageEffectiveness = 0.989, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 2, baseMultiplier = 1.001, damageEffectiveness = 1.001, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 2, baseMultiplier = 1.012, damageEffectiveness = 1.012, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 3, baseMultiplier = 1.024, damageEffectiveness = 1.024, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 3, baseMultiplier = 1.035, damageEffectiveness = 1.035, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 3, baseMultiplier = 1.047, damageEffectiveness = 1.047, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 3, baseMultiplier = 1.058, damageEffectiveness = 1.058, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 4, baseMultiplier = 1.07, damageEffectiveness = 1.07, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 4, baseMultiplier = 1.081, damageEffectiveness = 1.081, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 4, baseMultiplier = 1.093, damageEffectiveness = 1.093, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 5, baseMultiplier = 1.104, damageEffectiveness = 1.104, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 5, baseMultiplier = 1.116, damageEffectiveness = 1.116, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 5, baseMultiplier = 1.127, damageEffectiveness = 1.127, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 5, baseMultiplier = 1.139, damageEffectiveness = 1.139, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 6, baseMultiplier = 1.15, damageEffectiveness = 1.15, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 6, baseMultiplier = 1.162, damageEffectiveness = 1.162, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 6, baseMultiplier = 1.173, damageEffectiveness = 1.173, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 7, baseMultiplier = 1.185, damageEffectiveness = 1.185, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 7, baseMultiplier = 1.196, damageEffectiveness = 1.196, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 7, baseMultiplier = 1.208, damageEffectiveness = 1.208, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 7, baseMultiplier = 1.219, damageEffectiveness = 1.219, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 8, baseMultiplier = 1.231, damageEffectiveness = 1.231, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 8, baseMultiplier = 1.242, damageEffectiveness = 1.242, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 8, baseMultiplier = 1.254, damageEffectiveness = 1.254, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 8, baseMultiplier = 1.259, damageEffectiveness = 1.259, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 9, baseMultiplier = 1.265, damageEffectiveness = 1.265, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 9, baseMultiplier = 1.271, damageEffectiveness = 1.271, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 9, baseMultiplier = 1.277, damageEffectiveness = 1.277, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 9, baseMultiplier = 1.282, damageEffectiveness = 1.282, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 9, baseMultiplier = 1.288, damageEffectiveness = 1.288, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 9, baseMultiplier = 1.294, damageEffectiveness = 1.294, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 9, baseMultiplier = 1.3, damageEffectiveness = 1.3, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 10, baseMultiplier = 1.305, damageEffectiveness = 1.305, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 10, baseMultiplier = 1.311, damageEffectiveness = 1.311, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["GeofriSlam"] = { + name = "GeofriSlam", + hidden = true, + mercenary = true, + inheritedFrom = "AzmeriGeofriSlam", + color = 4, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + }, + constantStats = { + { "active_skill_attack_speed_+%_final", -47 }, + { "active_skill_area_of_effect_radius_+%_final", -50 }, + }, + stats = { + "voll_slam_damage_+%_final_at_centre", + "is_area_damage", + }, + levels = { + [1] = { 100, baseMultiplier = 0.95, cooldown = 5, damageEffectiveness = 0.95, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 80, baseMultiplier = 0.95, cooldown = 5, damageEffectiveness = 0.95, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["GigaFlameDashMercenary"] = { + name = "Greater Flame Dash", + hidden = true, + mercenary = true, + inheritedFrom = "FlameDash", + color = 3, + baseEffectiveness = 0.80000001192093, + incrementalEffectiveness = 0.052499998360872, + description = "Teleport to a location, damaging enemies and leaving a trail of burning ground. Shares a cooldown with other Blink skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Movement] = true, [SkillType.Damage] = true, [SkillType.DamageOverTime] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Travel] = true, [SkillType.Blink] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + duration = true, + movement = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + { "base_spell_repeat_count", 2 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "base_fire_damage_to_deal_per_minute", + "base_cooldown_speed_+%", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + "flame_dash_repeats_target_previous_location", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "base_fire_damage_to_deal_per_minute", + "base_cooldown_speed_+%", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 0, cooldown = 1.5, critChance = 6, damageEffectiveness = 0.8, levelRequirement = 10, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 1, cooldown = 1.5, critChance = 6, damageEffectiveness = 0.8, levelRequirement = 13, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 2, cooldown = 1.5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 17, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 3, cooldown = 1.5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 21, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 4, cooldown = 1.5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 25, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 5, cooldown = 1.5, critChance = 6, levelRequirement = 29, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 6, cooldown = 1.5, critChance = 6, levelRequirement = 33, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 7, cooldown = 1.5, critChance = 6, levelRequirement = 36, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 8, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 39, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 9, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 42, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 10, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.1, levelRequirement = 45, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 11, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 48, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 12, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.2, levelRequirement = 51, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 13, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 54, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 14, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 57, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 60, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 63, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 66, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 68, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 70, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 72, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 74, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 76, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 78, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 80, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 82, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 84, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 86, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 88, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 90, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 91, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 92, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 93, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 94, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 95, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 96, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 97, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 98, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 99, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 33.333334078391, 15, cooldown = 1.5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 100, storedUses = 3, statInterpolation = { 3, 3, 3, 1, }, }, + }, +} + +skills["GigaKineticBlastMercenary"] = { + name = "Greater Kinetic Blast", + hidden = true, + mercenary = true, + inheritedFrom = "KineticBlast", + color = 3, + description = "Fires a projectile from a Wand that causes a series of area explosions in a secondary radius around its point of impact, each damaging enemies.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.WandAttack] = true, }, + weaponTypes = { + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "cluster_burst_spawn_amount", 4 }, + { "active_skill_area_damage_+%_final", -35 }, + { "active_skill_base_area_of_effect_radius", 14 }, + { "active_skill_base_secondary_area_of_effect_radius", 20 }, + { "active_skill_area_of_effect_description_mode", 1 }, + { "active_skill_additive_spell_damage_modifiers_apply_to_attack_damage_at_%_value", 200 }, + }, + stats = { + "cluster_burst_spawn_amount", + "number_of_additional_projectiles", + "base_is_projectile", + "skill_can_fire_wand_projectiles", + }, + levels = { + [1] = { 1, 0, baseMultiplier = 1.4, cooldown = 8, damageEffectiveness = 1.4, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 1, 0, baseMultiplier = 1.408, cooldown = 8, damageEffectiveness = 1.41, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 1, 0, baseMultiplier = 1.416, cooldown = 8, damageEffectiveness = 1.42, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 1, 0, baseMultiplier = 1.424, cooldown = 8, damageEffectiveness = 1.42, levelRequirement = 37, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 1, 0, baseMultiplier = 1.432, cooldown = 8, damageEffectiveness = 1.43, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 1, 0, baseMultiplier = 1.439, cooldown = 8, damageEffectiveness = 1.44, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 1, 0, baseMultiplier = 1.447, cooldown = 8, damageEffectiveness = 1.45, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 1, 0, baseMultiplier = 1.455, cooldown = 8, damageEffectiveness = 1.46, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 1, 0, baseMultiplier = 1.463, cooldown = 8, damageEffectiveness = 1.46, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 2, 2, baseMultiplier = 1.471, cooldown = 8, damageEffectiveness = 1.47, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 2, 2, baseMultiplier = 1.479, cooldown = 8, damageEffectiveness = 1.48, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 2, 2, baseMultiplier = 1.487, cooldown = 8, damageEffectiveness = 1.49, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 2, 2, baseMultiplier = 1.495, cooldown = 8, damageEffectiveness = 1.49, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 2, 2, baseMultiplier = 1.503, cooldown = 8, damageEffectiveness = 1.5, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 3, 2, baseMultiplier = 1.511, cooldown = 8, damageEffectiveness = 1.51, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 3, 2, baseMultiplier = 1.518, cooldown = 8, damageEffectiveness = 1.52, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 3, 2, baseMultiplier = 1.526, cooldown = 8, damageEffectiveness = 1.53, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 3, 2, baseMultiplier = 1.534, cooldown = 8, damageEffectiveness = 1.53, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 3, 2, baseMultiplier = 1.542, cooldown = 8, damageEffectiveness = 1.54, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 4, 2, baseMultiplier = 1.55, cooldown = 8, damageEffectiveness = 1.55, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 4, 3, baseMultiplier = 1.558, cooldown = 8, damageEffectiveness = 1.56, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 4, 3, baseMultiplier = 1.566, cooldown = 8, damageEffectiveness = 1.57, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 4, 3, baseMultiplier = 1.574, cooldown = 8, damageEffectiveness = 1.57, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 4, 3, baseMultiplier = 1.582, cooldown = 8, damageEffectiveness = 1.58, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 5, 3, baseMultiplier = 1.589, cooldown = 8, damageEffectiveness = 1.59, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 5, 3, baseMultiplier = 1.597, cooldown = 8, damageEffectiveness = 1.6, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 5, 3, baseMultiplier = 1.605, cooldown = 8, damageEffectiveness = 1.61, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 5, 3, baseMultiplier = 1.613, cooldown = 8, damageEffectiveness = 1.61, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 5, 3, baseMultiplier = 1.621, cooldown = 8, damageEffectiveness = 1.62, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 6, 3, baseMultiplier = 1.629, cooldown = 8, damageEffectiveness = 1.63, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 6, 3, baseMultiplier = 1.633, cooldown = 8, damageEffectiveness = 1.63, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 6, 3, baseMultiplier = 1.637, cooldown = 8, damageEffectiveness = 1.64, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 6, 3, baseMultiplier = 1.641, cooldown = 8, damageEffectiveness = 1.64, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 6, 3, baseMultiplier = 1.645, cooldown = 8, damageEffectiveness = 1.64, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 7, 3, baseMultiplier = 1.649, cooldown = 8, damageEffectiveness = 1.65, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 7, 3, baseMultiplier = 1.653, cooldown = 8, damageEffectiveness = 1.65, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 7, 3, baseMultiplier = 1.657, cooldown = 8, damageEffectiveness = 1.66, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 7, 3, baseMultiplier = 1.661, cooldown = 8, damageEffectiveness = 1.66, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 7, 3, baseMultiplier = 1.664, cooldown = 8, damageEffectiveness = 1.66, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 8, 3, baseMultiplier = 1.668, cooldown = 8, damageEffectiveness = 1.67, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["GigaLightningArrowMercenary"] = { + name = "Greater Lightning Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "LightningArrow", + color = 2, + description = "Fires a charged arrow which damages enemies by causing them to be struck by a bolt of lightning, which also damages a number of surrounding enemies.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Lightning] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "lightning_arrow_maximum_number_of_extra_targets", 3 }, + { "chance_to_inflict_sapped_%", 50 }, + }, + stats = { + "number_of_additional_projectiles", + "skill_can_fire_arrows", + }, + levels = { + [1] = { 2, baseMultiplier = 1.495, cooldown = 4.5, damageEffectiveness = 1.495, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 2, baseMultiplier = 1.51, cooldown = 4.5, damageEffectiveness = 1.51, levelRequirement = 15, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 2, baseMultiplier = 1.524, cooldown = 4.5, damageEffectiveness = 1.524, levelRequirement = 19, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 2, baseMultiplier = 1.539, cooldown = 4.5, damageEffectiveness = 1.539, levelRequirement = 23, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 3, baseMultiplier = 1.554, cooldown = 4.5, damageEffectiveness = 1.554, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 3, baseMultiplier = 1.567, cooldown = 4.5, damageEffectiveness = 1.567, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 3, baseMultiplier = 1.582, cooldown = 4.5, damageEffectiveness = 1.582, levelRequirement = 35, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 3, baseMultiplier = 1.596, cooldown = 4.5, damageEffectiveness = 1.596, levelRequirement = 38, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 3, baseMultiplier = 1.611, cooldown = 4.5, damageEffectiveness = 1.611, levelRequirement = 41, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 4, baseMultiplier = 1.626, cooldown = 4.5, damageEffectiveness = 1.626, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 4, baseMultiplier = 1.64, cooldown = 4.5, damageEffectiveness = 1.64, levelRequirement = 47, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 4, baseMultiplier = 1.655, cooldown = 4.5, damageEffectiveness = 1.655, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 4, baseMultiplier = 1.67, cooldown = 4.5, damageEffectiveness = 1.67, levelRequirement = 53, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 4, baseMultiplier = 1.684, cooldown = 4.5, damageEffectiveness = 1.684, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 5, baseMultiplier = 1.699, cooldown = 4.5, damageEffectiveness = 1.699, levelRequirement = 59, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 5, baseMultiplier = 1.712, cooldown = 4.5, damageEffectiveness = 1.712, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 5, baseMultiplier = 1.727, cooldown = 4.5, damageEffectiveness = 1.727, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 5, baseMultiplier = 1.742, cooldown = 4.5, damageEffectiveness = 1.742, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 5, baseMultiplier = 1.756, cooldown = 4.5, damageEffectiveness = 1.756, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 6, baseMultiplier = 1.771, cooldown = 4.5, damageEffectiveness = 1.771, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 6, baseMultiplier = 1.786, cooldown = 4.5, damageEffectiveness = 1.786, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 6, baseMultiplier = 1.8, cooldown = 4.5, damageEffectiveness = 1.8, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 6, baseMultiplier = 1.815, cooldown = 4.5, damageEffectiveness = 1.815, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 6, baseMultiplier = 1.83, cooldown = 4.5, damageEffectiveness = 1.83, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 7, baseMultiplier = 1.843, cooldown = 4.5, damageEffectiveness = 1.843, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 7, baseMultiplier = 1.858, cooldown = 4.5, damageEffectiveness = 1.858, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 7, baseMultiplier = 1.872, cooldown = 4.5, damageEffectiveness = 1.872, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 7, baseMultiplier = 1.887, cooldown = 4.5, damageEffectiveness = 1.887, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 7, baseMultiplier = 1.902, cooldown = 4.5, damageEffectiveness = 1.902, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 8, baseMultiplier = 1.916, cooldown = 4.5, damageEffectiveness = 1.916, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 8, baseMultiplier = 1.924, cooldown = 4.5, damageEffectiveness = 1.924, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 8, baseMultiplier = 1.931, cooldown = 4.5, damageEffectiveness = 1.931, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 8, baseMultiplier = 1.938, cooldown = 4.5, damageEffectiveness = 1.938, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 8, baseMultiplier = 1.946, cooldown = 4.5, damageEffectiveness = 1.946, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 9, baseMultiplier = 1.953, cooldown = 4.5, damageEffectiveness = 1.953, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 9, baseMultiplier = 1.96, cooldown = 4.5, damageEffectiveness = 1.96, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 9, baseMultiplier = 1.968, cooldown = 4.5, damageEffectiveness = 1.968, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 9, baseMultiplier = 1.975, cooldown = 4.5, damageEffectiveness = 1.975, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 9, baseMultiplier = 1.981, cooldown = 4.5, damageEffectiveness = 1.981, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 10, baseMultiplier = 1.988, cooldown = 4.5, damageEffectiveness = 1.988, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["GigaRaiseZombieMercenary"] = { + name = "Raise Zombie of Gigantism", + hidden = true, + mercenary = true, + inheritedFrom = "RaiseZombieAltX", + color = 3, + baseEffectiveness = 0, + description = "Raises a zombie minion from a corpse, which will follow you and attack enemies with a melee strike and an area of effect slam.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.85, + baseFlags = { + minion = true, + spell = true, + }, + constantStats = { + { "base_number_of_zombies_allowed", 1 }, + { "minion_actor_scale_+%", 100 }, + }, + stats = { + "active_skill_minion_damage_+%_final", + "active_skill_minion_life_+%_final", + "zombie_slam_cooldown_speed_+%", + "zombie_slam_area_of_effect_+%", + "raise_zombie_does_not_use_corpses", + }, + notMinionStat = { + "active_skill_minion_damage_+%_final", + "active_skill_minion_life_+%_final", + }, + levels = { + [1] = { 0, 0, 0, 0, cooldown = 4, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [2] = { 6, 4, 4, 4, cooldown = 4, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [3] = { 12, 8, 8, 8, cooldown = 4, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [4] = { 18, 12, 12, 12, cooldown = 4, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [5] = { 24, 16, 16, 16, cooldown = 4, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [6] = { 30, 20, 20, 20, cooldown = 4, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [7] = { 36, 24, 24, 24, cooldown = 4, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [8] = { 42, 28, 28, 28, cooldown = 4, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [9] = { 48, 32, 32, 32, cooldown = 4, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [10] = { 54, 36, 36, 36, cooldown = 4, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [11] = { 60, 40, 40, 40, cooldown = 4, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [12] = { 66, 44, 44, 44, cooldown = 4, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [13] = { 72, 48, 48, 48, cooldown = 4, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [14] = { 78, 52, 52, 52, cooldown = 4, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [15] = { 84, 56, 56, 56, cooldown = 4, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [16] = { 90, 60, 60, 60, cooldown = 4, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [17] = { 96, 64, 64, 64, cooldown = 4, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [18] = { 102, 68, 68, 68, cooldown = 4, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [19] = { 108, 72, 72, 72, cooldown = 4, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [20] = { 114, 76, 76, 76, cooldown = 4, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [21] = { 120, 80, 80, 80, cooldown = 4, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [22] = { 126, 84, 84, 84, cooldown = 4, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [23] = { 132, 88, 88, 88, cooldown = 4, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [24] = { 138, 92, 92, 92, cooldown = 4, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [25] = { 144, 96, 96, 96, cooldown = 4, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [26] = { 150, 100, 100, 100, cooldown = 4, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [27] = { 156, 104, 104, 104, cooldown = 4, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [28] = { 162, 108, 108, 108, cooldown = 4, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [29] = { 168, 112, 112, 112, cooldown = 4, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [30] = { 174, 116, 116, 116, cooldown = 4, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [31] = { 177, 118, 118, 118, cooldown = 4, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [32] = { 180, 120, 120, 120, cooldown = 4, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [33] = { 183, 122, 122, 122, cooldown = 4, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [34] = { 186, 124, 124, 124, cooldown = 4, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [35] = { 189, 126, 126, 126, cooldown = 4, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [36] = { 192, 128, 128, 128, cooldown = 4, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [37] = { 195, 130, 130, 130, cooldown = 4, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [38] = { 198, 132, 132, 132, cooldown = 4, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [39] = { 201, 134, 134, 134, cooldown = 4, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [40] = { 204, 136, 136, 136, cooldown = 4, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + }, +} + +skills["GigaRaiseZombieMercenaryEncounter"] = { + name = "Raise Zombie of Gigantism", + hidden = true, + mercenary = true, + inheritedFrom = "RaiseZombieAltX", + color = 3, + baseEffectiveness = 0, + description = "Raises a zombie minion from a corpse, which will follow you and attack enemies with a melee strike and an area of effect slam.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.85, + baseFlags = { + minion = true, + spell = true, + }, + constantStats = { + { "base_number_of_zombies_allowed", 1 }, + { "minion_actor_scale_+%", 100 }, + }, + stats = { + "active_skill_minion_damage_+%_final", + "active_skill_minion_life_+%_final", + "zombie_slam_cooldown_speed_+%", + "zombie_slam_area_of_effect_+%", + "raise_zombie_does_not_use_corpses", + }, + notMinionStat = { + "active_skill_minion_damage_+%_final", + "active_skill_minion_life_+%_final", + }, + levels = { + [1] = { -90, 0, 0, 0, cooldown = 4, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [2] = { -90, 4, 4, 4, cooldown = 4, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [3] = { -90, 8, 8, 8, cooldown = 4, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [4] = { -90, 12, 12, 12, cooldown = 4, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [5] = { -90, 16, 16, 16, cooldown = 4, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [6] = { -90, 20, 20, 20, cooldown = 4, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [7] = { -90, 24, 24, 24, cooldown = 4, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [8] = { -90, 28, 28, 28, cooldown = 4, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [9] = { -90, 32, 32, 32, cooldown = 4, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [10] = { -90, 36, 36, 36, cooldown = 4, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [11] = { -90, 40, 40, 40, cooldown = 4, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [12] = { -90, 44, 44, 44, cooldown = 4, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [13] = { -90, 48, 48, 48, cooldown = 4, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [14] = { -90, 52, 52, 52, cooldown = 4, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [15] = { -90, 56, 56, 56, cooldown = 4, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [16] = { -90, 60, 60, 60, cooldown = 4, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [17] = { -90, 64, 64, 64, cooldown = 4, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [18] = { -90, 68, 68, 68, cooldown = 4, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [19] = { -90, 72, 72, 72, cooldown = 4, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [20] = { -90, 76, 76, 76, cooldown = 4, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [21] = { -90, 80, 80, 80, cooldown = 4, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [22] = { -90, 84, 84, 84, cooldown = 4, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [23] = { -90, 88, 88, 88, cooldown = 4, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [24] = { -90, 92, 92, 92, cooldown = 4, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [25] = { -90, 96, 96, 96, cooldown = 4, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [26] = { -90, 100, 100, 100, cooldown = 4, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [27] = { -90, 104, 104, 104, cooldown = 4, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [28] = { -90, 108, 108, 108, cooldown = 4, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [29] = { -90, 112, 112, 112, cooldown = 4, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [30] = { -90, 116, 116, 116, cooldown = 4, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [31] = { -90, 118, 118, 118, cooldown = 4, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [32] = { -90, 120, 120, 120, cooldown = 4, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [33] = { -90, 122, 122, 122, cooldown = 4, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [34] = { -90, 124, 124, 124, cooldown = 4, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [35] = { -90, 126, 126, 126, cooldown = 4, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [36] = { -90, 128, 128, 128, cooldown = 4, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [37] = { -90, 130, 130, 130, cooldown = 4, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [38] = { -90, 132, 132, 132, cooldown = 4, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [39] = { -90, 134, 134, 134, cooldown = 4, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [40] = { -90, 136, 136, 136, cooldown = 4, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + }, +} + +skills["GigaShockNovaMercenary"] = { + name = "Greater Shock Nova", + hidden = true, + mercenary = true, + inheritedFrom = "ShockNova", + color = 3, + baseEffectiveness = 1.3489999771118, + incrementalEffectiveness = 0.049300000071526, + description = "Casts a ring of Lightning around you, followed by a larger Lightning nova. Each effect hits enemies caught in their area with Lightning Damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.2, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "shock_nova_ring_chance_to_shock_+%", 100 }, + { "shock_maximum_magnitude_+", 10 }, + { "skill_repeat_count", 3 }, + { "support_greater_spell_echo_area_of_effect_+%_per_repeat", 30 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 12, }, }, + [2] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 13, }, }, + [3] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 14, }, }, + [4] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 15, }, }, + [5] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 15, }, }, + [6] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 16, }, }, + [7] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 16, }, }, + [8] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 17, }, }, + [9] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 17, }, }, + [10] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 18, }, }, + [11] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 18, }, }, + [12] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 19, }, }, + [13] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 19, }, }, + [14] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 20, }, }, + [15] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 20, }, }, + [16] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 21, }, }, + [17] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 21, }, }, + [18] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 22, }, }, + [19] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 22, }, }, + [20] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 23, }, }, + [21] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 24, }, }, + [22] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 24, }, }, + [23] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 25, }, }, + [24] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 25, }, }, + [25] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 26, }, }, + [26] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 26, }, }, + [27] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 27, }, }, + [28] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 27, }, }, + [29] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [30] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [31] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [32] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [33] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [34] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [35] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [36] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [37] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [38] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [39] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [40] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 31, }, }, + }, +} + +skills["GigaShockNovaMercenaryEncounter"] = { + name = "Greater Shock Nova", + hidden = true, + mercenary = true, + inheritedFrom = "ShockNova", + color = 3, + baseEffectiveness = 0.30000001192093, + incrementalEffectiveness = 0.049300000071526, + description = "Casts a ring of Lightning around you, followed by a larger Lightning nova. Each effect hits enemies caught in their area with Lightning Damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.4, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "shock_nova_ring_chance_to_shock_+%", 100 }, + { "shock_maximum_magnitude_+", 10 }, + { "skill_repeat_count", 3 }, + { "support_greater_spell_echo_area_of_effect_+%_per_repeat", 30 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 12, }, }, + [2] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 13, }, }, + [3] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 14, }, }, + [4] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 15, }, }, + [5] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 15, }, }, + [6] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 16, }, }, + [7] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 16, }, }, + [8] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 17, }, }, + [9] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 17, }, }, + [10] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 18, }, }, + [11] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 18, }, }, + [12] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 19, }, }, + [13] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 19, }, }, + [14] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 20, }, }, + [15] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 20, }, }, + [16] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 21, }, }, + [17] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 21, }, }, + [18] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 22, }, }, + [19] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 22, }, }, + [20] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 23, }, }, + [21] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 24, }, }, + [22] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 24, }, }, + [23] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 25, }, }, + [24] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 25, }, }, + [25] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 26, }, }, + [26] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 26, }, }, + [27] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 27, }, }, + [28] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 27, }, }, + [29] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [30] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [31] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 28, }, }, + [32] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [33] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [34] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [35] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 29, }, }, + [36] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [37] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [38] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [39] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 30, }, }, + [40] = { 0.5, 1.5, cooldown = 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, }, cost = { Mana = 31, }, }, + }, +} + +skills["GigaSoulrendMercenary"] = { + name = "Greater Soulrend", + hidden = true, + mercenary = true, + inheritedFrom = "Soulrend", + color = 3, + baseEffectiveness = 4.2814998626709, + incrementalEffectiveness = 0.056699998676777, + description = "Fires a projectile that turns towards enemies in front of it, damaging and piercing through those it hits, and leeching some of that damage as energy shield. As the projectile travels, it repeatedly applies a short but powerful chaos damage over time debuff to each enemy in an area around it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Projectile] = true, [SkillType.DamageOverTime] = true, [SkillType.Damage] = true, [SkillType.Chaos] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.ProjectilesFromUser] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_energy_shield_leech_from_spell_damage_permyriad", 400 }, + { "base_skill_effect_duration", 3000 }, + { "active_skill_projectile_speed_+%_final", -60 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_number_of_projectiles", + "spell_damage_modifiers_apply_to_skill_dot", + "base_is_projectile", + "always_pierce", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 42.000000620882, 0.079999998211861, 0.11999999731779, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [2] = { 40.833335040758, 0.079999998211861, 0.12999999523163, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [3] = { 39.833335972081, 0.090000003576279, 0.12999999523163, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [4] = { 38.666666418314, 0.090000003576279, 0.14000000059605, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [5] = { 37.666667349637, 0.10000000149012, 0.15000000596046, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [6] = { 37.000001303852, 0.10000000149012, 0.15000000596046, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [7] = { 36.333335258067, 0.10999999940395, 0.15999999642372, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [8] = { 35.666669212282, 0.10999999940395, 0.15999999642372, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [9] = { 34.999999192854, 0.10999999940395, 0.17000000178814, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [10] = { 34.499999658515, 0.11999999731779, 0.18000000715256, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [11] = { 33.83333361273, 0.11999999731779, 0.18000000715256, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [12] = { 33.166667566945, 0.12999999523163, 0.18999999761581, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [13] = { 32.666668032606, 0.12999999523163, 0.20000000298023, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [14] = { 32, 0.12999999523163, 0.20000000298023, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [15] = { 31.500000465661, 0.14000000059605, 0.20999999344349, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [16] = { 30.833334419876, 0.14000000059605, 0.20999999344349, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [17] = { 30.333334885538, 0.15000000596046, 0.21999999880791, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [18] = { 29.833333364377, 0.15000000596046, 0.23000000417233, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [19] = { 29.333333830039, 0.15999999642372, 0.23000000417233, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [20] = { 28.666667784254, 0.15999999642372, 0.23999999463558, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [21] = { 28.166668249915, 0.15999999642372, 0.25, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [22] = { 27.666666728755, 0.17000000178814, 0.25, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [23] = { 27.166667194416, 0.17000000178814, 0.25999999046326, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [24] = { 26.666667660077, 0.18000000715256, 0.27000001072884, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [25] = { 26.166668125739, 0.18000000715256, 0.27000001072884, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [26] = { 25.833333116025, 0.18999999761581, 0.28000000119209, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [27] = { 25.333333581686, 0.18999999761581, 0.28000000119209, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [28] = { 24.833334047347, 0.18999999761581, 0.28999999165535, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [29] = { 24.333334513009, 0.20000000298023, 0.30000001192093, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [30] = { 24.000001490116, 0.20000000298023, 0.30000001192093, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [31] = { 23.833332991848, 0.20999999344349, 0.31000000238419, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [32] = { 23.499999968956, 0.20999999344349, 0.31999999284744, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [33] = { 23.33333345751, 0.20999999344349, 0.31999999284744, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [34] = { 23.166666946063, 0.21999999880791, 0.33000001311302, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [35] = { 22.833333923171, 0.21999999880791, 0.33000001311302, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [36] = { 22.666667411725, 0.23000000417233, 0.34000000357628, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [37] = { 22.500000900279, 0.23000000417233, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [38] = { 22.333334388832, 0.23999999463558, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [39] = { 22.166667877386, 0.23999999463558, 0.36000001430511, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [40] = { 21.833332867672, 0.23999999463558, 0.37000000476837, 9, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + }, +} + +skills["GigaSoulrendMercenaryEncounter"] = { + name = "Greater Soulrend", + hidden = true, + mercenary = true, + inheritedFrom = "Soulrend", + color = 3, + baseEffectiveness = 2.4000000953674, + incrementalEffectiveness = 0.03999999910593, + description = "Fires a projectile that turns towards enemies in front of it, damaging and piercing through those it hits, and leeching some of that damage as energy shield. As the projectile travels, it repeatedly applies a short but powerful chaos damage over time debuff to each enemy in an area around it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Projectile] = true, [SkillType.DamageOverTime] = true, [SkillType.Damage] = true, [SkillType.Chaos] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.ProjectilesFromUser] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_energy_shield_leech_from_spell_damage_permyriad", 200 }, + { "base_skill_effect_duration", 3000 }, + { "active_skill_projectile_speed_+%_final", -60 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_number_of_projectiles", + "spell_damage_modifiers_apply_to_skill_dot", + "base_is_projectile", + "always_pierce", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [2] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [3] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [4] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [5] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [6] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [7] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [8] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [9] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 5, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [10] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [11] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [12] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [13] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [14] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [15] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [16] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [17] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [18] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [19] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 6, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [20] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [21] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [22] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [23] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [24] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [25] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [26] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [27] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [28] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [29] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 7, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [30] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [31] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [32] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [33] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [34] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [35] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [36] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [37] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [38] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [39] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 8, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + [40] = { 22.500000900279, 0.20000000298023, 0.34999999403954, 9, cooldown = 8, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 3, 1, }, }, + }, +} + +skills["GigaStormCallMercenary"] = { + name = "Greater Stormcall", + hidden = true, + mercenary = true, + inheritedFrom = "StormCall", + color = 3, + baseEffectiveness = 3, + incrementalEffectiveness = 0.050000000745058, + description = "Sets a marker at a location. After a short duration, lightning strikes the marker, dealing damage around it and causing lightning strikes at any other markers you've cast.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Lightning] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1500 }, + { "support_spell_cascade_number_of_cascades_per_side", 2 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.5, 1.5, 0, cooldown = 8, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [2] = { 0.5, 1.5, 0, cooldown = 8, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 15, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [3] = { 0.5, 1.5, 1, cooldown = 8, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 19, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 7, }, }, + [4] = { 0.5, 1.5, 1, cooldown = 8, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 23, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 8, }, }, + [5] = { 0.5, 1.5, 1, cooldown = 8, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [6] = { 0.5, 1.5, 2, cooldown = 8, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [7] = { 0.5, 1.5, 2, cooldown = 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 35, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [8] = { 0.5, 1.5, 2, cooldown = 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [9] = { 0.5, 1.5, 3, cooldown = 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 41, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [10] = { 0.5, 1.5, 3, cooldown = 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [11] = { 0.5, 1.5, 3, cooldown = 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 47, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [12] = { 0.5, 1.5, 4, cooldown = 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [13] = { 0.5, 1.5, 4, cooldown = 8, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 53, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [14] = { 0.5, 1.5, 4, cooldown = 8, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [15] = { 0.5, 1.5, 5, cooldown = 8, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 59, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [16] = { 0.5, 1.5, 5, cooldown = 8, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [17] = { 0.5, 1.5, 5, cooldown = 8, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [18] = { 0.5, 1.5, 6, cooldown = 8, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [19] = { 0.5, 1.5, 6, cooldown = 8, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [20] = { 0.5, 1.5, 6, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [21] = { 0.5, 1.5, 7, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [22] = { 0.5, 1.5, 7, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [23] = { 0.5, 1.5, 7, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [24] = { 0.5, 1.5, 8, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [25] = { 0.5, 1.5, 8, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [26] = { 0.5, 1.5, 8, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [27] = { 0.5, 1.5, 9, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [28] = { 0.5, 1.5, 9, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [29] = { 0.5, 1.5, 9, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [30] = { 0.5, 1.5, 10, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [31] = { 0.5, 1.5, 10, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [32] = { 0.5, 1.5, 10, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [33] = { 0.5, 1.5, 10, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [34] = { 0.5, 1.5, 10, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [35] = { 0.5, 1.5, 10, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [36] = { 0.5, 1.5, 11, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [37] = { 0.5, 1.5, 11, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [38] = { 0.5, 1.5, 11, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [39] = { 0.5, 1.5, 11, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [40] = { 0.5, 1.5, 11, cooldown = 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + }, +} + +skills["GigaStormCallMercenaryEncounter"] = { + name = "Greater Stormcall", + hidden = true, + mercenary = true, + inheritedFrom = "StormCall", + color = 3, + baseEffectiveness = 1.7999999523163, + incrementalEffectiveness = 0.035999998450279, + description = "Sets a marker at a location. After a short duration, lightning strikes the marker, dealing damage around it and causing lightning strikes at any other markers you've cast.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Lightning] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1500 }, + { "support_spell_cascade_number_of_cascades_per_side", 2 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.5, 1.5, 8, cooldown = 8, critChance = 5, levelRequirement = 0, storedUses = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + }, +} + +skills["GigaVortexTrapMercenary"] = { + name = "Greater Vortex Trap", + hidden = true, + mercenary = true, + inheritedFrom = "Vortex", + color = 3, + baseEffectiveness = 1.2086000442505, + incrementalEffectiveness = 0.049499999731779, + description = "An icy blast explodes around the caster, dealing cold damage to enemies, and leaving behind a whirling vortex which deals cold damage over time and chills enemies caught in it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Cold] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.ChillingArea] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, [SkillType.CanRapidFire] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "active_skill_base_area_of_effect_radius", 20 }, + { "active_skill_base_secondary_area_of_effect_radius", 20 }, + { "base_trap_duration", 4000 }, + { "number_of_additional_traps_to_throw", 2 }, + { "throw_traps_in_circle_radius", 20 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_cold_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 114.83333367482, cooldown = 5, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 116.83333975946, cooldown = 5, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 118.50000487392, cooldown = 5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 120.50000301128, cooldown = 5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 122.33333861083, cooldown = 5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 123.33333767951, cooldown = 5, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 124.83333230888, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 126.16667234773, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 127.5000044393, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 128.83333653087, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 130.16666862244, cooldown = 5, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 131.50000071401, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 132.66667026778, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 133.83333187426, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 135.50000493601, cooldown = 5, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 136.66666654249, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 138.16666911915, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 139.66667169581, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 141.33332886298, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 142.66667684913, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 144.16666353121, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 145.66666610787, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 146.99999819944, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 148.33333029101, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 150.16667383785, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 151.50000592942, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 153.33333358169, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 155.16667712852, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 156.16666824992, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 157.99999590218, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 158.83333243305, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 159.66666896393, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 160.5000054948, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 161.33334202568, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 162.16666266198, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 162.99999919285, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 163.83333572373, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 164.6666722546, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 165.50000878548, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 166.16667483126, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["GigaVortexTrapMercenaryEncounter"] = { + name = "Greater Vortex Trap", + hidden = true, + mercenary = true, + inheritedFrom = "Vortex", + color = 3, + baseEffectiveness = 1.2000000476837, + incrementalEffectiveness = 0.045000001788139, + description = "An icy blast explodes around the caster, dealing cold damage to enemies, and leaving behind a whirling vortex which deals cold damage over time and chills enemies caught in it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Cold] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.ChillingArea] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, [SkillType.CanRapidFire] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "active_skill_base_area_of_effect_radius", 20 }, + { "active_skill_base_secondary_area_of_effect_radius", 20 }, + { "base_trap_duration", 4000 }, + { "number_of_additional_traps_to_throw", 2 }, + { "throw_traps_in_circle_radius", 20 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_cold_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 50.000001117587, cooldown = 5, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 0, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["GlacialHammerMercenary"] = { + name = "Glacial Hammer", + hidden = true, + mercenary = true, + inheritedFrom = "GlacialHammer", + color = 1, + description = "Hits enemies, converting some of your physical damage to cold damage. If a non-unique enemy is frozen and is on less than one third life, they will shatter when hit by Glacial Hammer. If striking three times in a row, the third strike will freeze enemies more easily. Requires a Mace, Sceptre or Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Cold] = true, [SkillType.ThresholdJewelArea] = true, }, + weaponTypes = { + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_cold", 100 }, + { "base_chance_to_freeze_%", 25 }, + { "cold_ailment_duration_+%", 35 }, + { "additional_main_hand_hits_per_combo_average", 1 }, + }, + stats = { + "cold_ailment_effect_+%", + "glacial_hammer_third_hit_freeze_as_though_dealt_damage_+%", + }, + levels = { + [1] = { 10, 200, baseMultiplier = 2.185, damageEffectiveness = 2.185, levelRequirement = 1, statInterpolation = { 1, 1, }, }, + [2] = { 11, 210, baseMultiplier = 2.298, damageEffectiveness = 2.298, levelRequirement = 2, statInterpolation = { 1, 1, }, }, + [3] = { 12, 220, baseMultiplier = 2.422, damageEffectiveness = 2.422, levelRequirement = 4, statInterpolation = { 1, 1, }, }, + [4] = { 13, 230, baseMultiplier = 2.557, damageEffectiveness = 2.557, levelRequirement = 7, statInterpolation = { 1, 1, }, }, + [5] = { 14, 240, baseMultiplier = 2.705, damageEffectiveness = 2.705, levelRequirement = 11, statInterpolation = { 1, 1, }, }, + [6] = { 15, 250, baseMultiplier = 2.866, damageEffectiveness = 2.866, levelRequirement = 16, statInterpolation = { 1, 1, }, }, + [7] = { 16, 260, baseMultiplier = 3.031, damageEffectiveness = 3.031, levelRequirement = 20, statInterpolation = { 1, 1, }, }, + [8] = { 17, 270, baseMultiplier = 3.206, damageEffectiveness = 3.206, levelRequirement = 24, statInterpolation = { 1, 1, }, }, + [9] = { 18, 280, baseMultiplier = 3.389, damageEffectiveness = 3.389, levelRequirement = 28, statInterpolation = { 1, 1, }, }, + [10] = { 19, 290, baseMultiplier = 3.584, damageEffectiveness = 3.584, levelRequirement = 32, statInterpolation = { 1, 1, }, }, + [11] = { 20, 300, baseMultiplier = 3.789, damageEffectiveness = 3.789, levelRequirement = 36, statInterpolation = { 1, 1, }, }, + [12] = { 21, 310, baseMultiplier = 4.007, damageEffectiveness = 4.007, levelRequirement = 40, statInterpolation = { 1, 1, }, }, + [13] = { 22, 320, baseMultiplier = 4.236, damageEffectiveness = 4.236, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [14] = { 23, 330, baseMultiplier = 4.478, damageEffectiveness = 4.478, levelRequirement = 48, statInterpolation = { 1, 1, }, }, + [15] = { 24, 340, baseMultiplier = 4.734, damageEffectiveness = 4.734, levelRequirement = 52, statInterpolation = { 1, 1, }, }, + [16] = { 25, 350, baseMultiplier = 5.004, damageEffectiveness = 5.004, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [17] = { 26, 360, baseMultiplier = 5.291, damageEffectiveness = 5.291, levelRequirement = 60, statInterpolation = { 1, 1, }, }, + [18] = { 27, 370, baseMultiplier = 5.592, damageEffectiveness = 5.592, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [19] = { 28, 380, baseMultiplier = 5.9, damageEffectiveness = 5.9, levelRequirement = 67, statInterpolation = { 1, 1, }, }, + [20] = { 29, 390, baseMultiplier = 6.226, damageEffectiveness = 6.226, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 30, 400, baseMultiplier = 6.558, damageEffectiveness = 6.558, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 31, 410, baseMultiplier = 6.909, damageEffectiveness = 6.909, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 32, 420, baseMultiplier = 7.279, damageEffectiveness = 7.279, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 33, 430, baseMultiplier = 7.667, damageEffectiveness = 7.667, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 34, 440, baseMultiplier = 8.077, damageEffectiveness = 8.077, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 35, 450, baseMultiplier = 8.508, damageEffectiveness = 8.508, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 36, 460, baseMultiplier = 8.962, damageEffectiveness = 8.962, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 37, 470, baseMultiplier = 9.441, damageEffectiveness = 9.441, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 38, 480, baseMultiplier = 9.944, damageEffectiveness = 9.944, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 39, 490, baseMultiplier = 10.475, damageEffectiveness = 10.475, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 39, 495, baseMultiplier = 11.292, damageEffectiveness = 11.292, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 40, 500, baseMultiplier = 11.592, damageEffectiveness = 11.592, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 40, 505, baseMultiplier = 11.901, damageEffectiveness = 11.901, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 41, 510, baseMultiplier = 12.217, damageEffectiveness = 12.217, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 41, 515, baseMultiplier = 12.542, damageEffectiveness = 12.542, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 42, 520, baseMultiplier = 12.876, damageEffectiveness = 12.876, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 42, 525, baseMultiplier = 13.219, damageEffectiveness = 13.219, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 43, 530, baseMultiplier = 13.571, damageEffectiveness = 13.571, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 43, 535, baseMultiplier = 13.932, damageEffectiveness = 13.932, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 44, 540, baseMultiplier = 14.302, damageEffectiveness = 14.302, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["GraceMercenary"] = { + name = "Grace", + hidden = true, + mercenary = true, + inheritedFrom = "Grace", + color = 2, + description = "Casts an aura that grants evasion to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "grace_aura_evasion_rating_+%_final", + "base_evasion_rating", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 20, 136, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 20, 163, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 21, 193, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 21, 227, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 22, 266, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 22, 317, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 23, 373, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 23, 433, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 24, 507, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 24, 564, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 25, 626, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 25, 693, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 26, 770, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 26, 848, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 27, 940, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 27, 1039, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 28, 1148, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 28, 1269, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 29, 1401, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 29, 1545, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 30, 1620, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 30, 1701, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 31, 1787, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 31, 1874, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 32, 1967, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 32, 2066, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 33, 2167, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 33, 2277, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 34, 2389, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 34, 2507, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 35, 2570, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 35, 2632, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 35, 2697, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 35, 2762, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 36, 2830, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 36, 2898, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 36, 2969, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 36, 3040, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 37, 3115, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 37, 3188, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["GroundSlamMercenary"] = { + name = "Ground Slam", + hidden = true, + mercenary = true, + inheritedFrom = "GroundSlam", + color = 1, + baseEffectiveness = 0.6700000166893, + incrementalEffectiveness = 0.023299999535084, + description = "Slams the ground in front of you, creating a wave that travels forward and damages enemies with an increased chance to stun. The wave deals more damage to closer enemies. Requires an Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "base_stun_threshold_reduction_+%", 25 }, + }, + stats = { + "active_skill_base_radius_+", + "groundslam_damage_to_close_targets_+%_final", + "is_area_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, 40, baseMultiplier = 1.323, damageEffectiveness = 1.323, levelRequirement = 1, statInterpolation = { 1, 1, }, }, + [2] = { 1, 40, baseMultiplier = 1.388, damageEffectiveness = 1.388, levelRequirement = 2, statInterpolation = { 1, 1, }, }, + [3] = { 1, 41, baseMultiplier = 1.458, damageEffectiveness = 1.458, levelRequirement = 4, statInterpolation = { 1, 1, }, }, + [4] = { 2, 41, baseMultiplier = 1.535, damageEffectiveness = 1.535, levelRequirement = 7, statInterpolation = { 1, 1, }, }, + [5] = { 2, 42, baseMultiplier = 1.618, damageEffectiveness = 1.618, levelRequirement = 11, statInterpolation = { 1, 1, }, }, + [6] = { 3, 42, baseMultiplier = 1.71, damageEffectiveness = 1.71, levelRequirement = 16, statInterpolation = { 1, 1, }, }, + [7] = { 3, 43, baseMultiplier = 1.803, damageEffectiveness = 1.803, levelRequirement = 20, statInterpolation = { 1, 1, }, }, + [8] = { 4, 43, baseMultiplier = 1.902, damageEffectiveness = 1.902, levelRequirement = 24, statInterpolation = { 1, 1, }, }, + [9] = { 4, 44, baseMultiplier = 2.005, damageEffectiveness = 2.005, levelRequirement = 28, statInterpolation = { 1, 1, }, }, + [10] = { 5, 44, baseMultiplier = 2.114, damageEffectiveness = 2.114, levelRequirement = 32, statInterpolation = { 1, 1, }, }, + [11] = { 5, 45, baseMultiplier = 2.229, damageEffectiveness = 2.229, levelRequirement = 36, statInterpolation = { 1, 1, }, }, + [12] = { 6, 45, baseMultiplier = 2.35, damageEffectiveness = 2.35, levelRequirement = 40, statInterpolation = { 1, 1, }, }, + [13] = { 6, 46, baseMultiplier = 2.478, damageEffectiveness = 2.478, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [14] = { 7, 46, baseMultiplier = 2.612, damageEffectiveness = 2.612, levelRequirement = 48, statInterpolation = { 1, 1, }, }, + [15] = { 7, 47, baseMultiplier = 2.753, damageEffectiveness = 2.753, levelRequirement = 52, statInterpolation = { 1, 1, }, }, + [16] = { 8, 47, baseMultiplier = 2.902, damageEffectiveness = 2.902, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [17] = { 8, 48, baseMultiplier = 3.059, damageEffectiveness = 3.059, levelRequirement = 60, statInterpolation = { 1, 1, }, }, + [18] = { 9, 48, baseMultiplier = 3.223, damageEffectiveness = 3.223, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [19] = { 9, 49, baseMultiplier = 3.392, damageEffectiveness = 3.392, levelRequirement = 67, statInterpolation = { 1, 1, }, }, + [20] = { 10, 49, baseMultiplier = 3.569, damageEffectiveness = 3.569, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 10, 50, baseMultiplier = 3.749, damageEffectiveness = 3.749, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 11, 50, baseMultiplier = 3.939, damageEffectiveness = 3.939, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 11, 51, baseMultiplier = 4.137, damageEffectiveness = 4.137, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 12, 51, baseMultiplier = 4.345, damageEffectiveness = 4.345, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 12, 52, baseMultiplier = 4.564, damageEffectiveness = 4.564, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 13, 52, baseMultiplier = 4.794, damageEffectiveness = 4.794, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 13, 53, baseMultiplier = 5.035, damageEffectiveness = 5.035, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 14, 53, baseMultiplier = 5.289, damageEffectiveness = 5.289, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 14, 54, baseMultiplier = 5.555, damageEffectiveness = 5.555, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 15, 54, baseMultiplier = 5.835, damageEffectiveness = 5.835, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 15, 54, baseMultiplier = 6.263, damageEffectiveness = 6.263, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 15, 55, baseMultiplier = 6.42, damageEffectiveness = 6.42, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 16, 55, baseMultiplier = 6.581, damageEffectiveness = 6.581, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 16, 55, baseMultiplier = 6.746, damageEffectiveness = 6.746, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 16, 55, baseMultiplier = 6.917, damageEffectiveness = 6.917, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 17, 55, baseMultiplier = 7.09, damageEffectiveness = 7.09, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 17, 55, baseMultiplier = 7.268, damageEffectiveness = 7.268, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 17, 56, baseMultiplier = 7.451, damageEffectiveness = 7.451, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 18, 56, baseMultiplier = 7.637, damageEffectiveness = 7.637, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 18, 56, baseMultiplier = 7.829, damageEffectiveness = 7.829, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["HasteMercenary"] = { + name = "Haste", + hidden = true, + mercenary = true, + inheritedFrom = "Haste", + color = 2, + description = "Casts an aura that increases the movement speed, attack speed and cast speed of you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "attack_speed_+%_granted_from_skill", + "cast_speed_+%_granted_from_skill", + "base_movement_velocity_+%", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 15, 15, 10, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [2] = { 15, 15, 10, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [3] = { 16, 16, 10, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [4] = { 16, 16, 11, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [5] = { 17, 17, 11, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [6] = { 17, 17, 11, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [7] = { 18, 18, 12, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [8] = { 18, 18, 12, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [9] = { 19, 19, 12, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [10] = { 19, 19, 13, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [11] = { 20, 20, 13, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [12] = { 20, 20, 13, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [13] = { 21, 21, 14, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [14] = { 21, 21, 14, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [15] = { 22, 22, 14, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [16] = { 22, 22, 15, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [17] = { 23, 23, 15, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [18] = { 23, 23, 15, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [19] = { 24, 24, 16, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [20] = { 24, 24, 16, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [21] = { 25, 25, 16, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [22] = { 25, 25, 17, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [23] = { 26, 26, 17, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [24] = { 26, 26, 17, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [25] = { 27, 27, 18, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [26] = { 27, 27, 18, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [27] = { 28, 28, 18, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [28] = { 28, 28, 19, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [29] = { 29, 29, 19, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [30] = { 29, 29, 19, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [31] = { 29, 29, 19, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [32] = { 30, 30, 20, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [33] = { 30, 30, 20, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [34] = { 30, 30, 20, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [35] = { 30, 30, 20, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [36] = { 31, 31, 20, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [37] = { 31, 31, 20, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [38] = { 31, 31, 21, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [39] = { 31, 31, 21, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [40] = { 32, 32, 21, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + }, +} + +skills["HatredMercenary"] = { + name = "Hatred", + hidden = true, + mercenary = true, + inheritedFrom = "Hatred", + color = 2, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.025000000372529, + description = "Casts an aura that grants extra cold damage based on physical damage to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Cold] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "physical_damage_%_to_add_as_cold", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 30, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 30, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 31, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 31, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 32, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 32, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 33, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 33, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 34, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 34, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 35, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 35, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 36, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 36, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 37, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 37, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 38, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 38, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 39, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 39, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 40, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 40, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 41, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 41, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 42, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 42, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 43, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 43, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 44, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 44, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 44, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 45, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 45, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 45, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 45, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 46, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 46, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 46, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 46, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 47, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["HeavyStrikeAltMercenary"] = { + name = "Heavy Strike of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "HeavyStrikeAltY", + color = 1, + baseEffectiveness = 0, + description = "Attacks enemies with a forceful blow. Requires a Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, }, + weaponTypes = { + ["Staff"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + }, + constantStats = { + { "chance_to_deal_double_damage_%_per_10_intelligence", 2 }, + { "active_skill_additive_spell_damage_modifiers_apply_to_attack_damage_at_%_value", 150 }, + }, + stats = { + }, + levels = { + [1] = { attackSpeedMultiplier = -15, baseMultiplier = 2.243, damageEffectiveness = 2.243, levelRequirement = 1, }, + [2] = { attackSpeedMultiplier = -15, baseMultiplier = 2.341, damageEffectiveness = 2.341, levelRequirement = 2, }, + [3] = { attackSpeedMultiplier = -15, baseMultiplier = 2.449, damageEffectiveness = 2.449, levelRequirement = 4, }, + [4] = { attackSpeedMultiplier = -15, baseMultiplier = 2.565, damageEffectiveness = 2.565, levelRequirement = 7, }, + [5] = { attackSpeedMultiplier = -15, baseMultiplier = 2.693, damageEffectiveness = 2.693, levelRequirement = 11, }, + [6] = { attackSpeedMultiplier = -15, baseMultiplier = 2.831, damageEffectiveness = 2.831, levelRequirement = 16, }, + [7] = { attackSpeedMultiplier = -15, baseMultiplier = 2.971, damageEffectiveness = 2.971, levelRequirement = 20, }, + [8] = { attackSpeedMultiplier = -15, baseMultiplier = 3.118, damageEffectiveness = 3.118, levelRequirement = 24, }, + [9] = { attackSpeedMultiplier = -15, baseMultiplier = 3.273, damageEffectiveness = 3.273, levelRequirement = 28, }, + [10] = { attackSpeedMultiplier = -15, baseMultiplier = 3.433, damageEffectiveness = 3.433, levelRequirement = 32, }, + [11] = { attackSpeedMultiplier = -15, baseMultiplier = 3.603, damageEffectiveness = 3.603, levelRequirement = 36, }, + [12] = { attackSpeedMultiplier = -15, baseMultiplier = 3.78, damageEffectiveness = 3.78, levelRequirement = 40, }, + [13] = { attackSpeedMultiplier = -15, baseMultiplier = 3.966, damageEffectiveness = 3.966, levelRequirement = 44, }, + [14] = { attackSpeedMultiplier = -15, baseMultiplier = 4.161, damageEffectiveness = 4.161, levelRequirement = 48, }, + [15] = { attackSpeedMultiplier = -15, baseMultiplier = 4.365, damageEffectiveness = 4.365, levelRequirement = 52, }, + [16] = { attackSpeedMultiplier = -15, baseMultiplier = 4.58, damageEffectiveness = 4.58, levelRequirement = 56, }, + [17] = { attackSpeedMultiplier = -15, baseMultiplier = 4.804, damageEffectiveness = 4.804, levelRequirement = 60, }, + [18] = { attackSpeedMultiplier = -15, baseMultiplier = 5.039, damageEffectiveness = 5.039, levelRequirement = 64, }, + [19] = { attackSpeedMultiplier = -15, baseMultiplier = 5.277, damageEffectiveness = 5.277, levelRequirement = 67, }, + [20] = { attackSpeedMultiplier = -15, baseMultiplier = 5.525, damageEffectiveness = 5.525, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = -15, baseMultiplier = 5.777, damageEffectiveness = 5.777, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = -15, baseMultiplier = 6.04, damageEffectiveness = 6.04, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = -15, baseMultiplier = 6.313, damageEffectiveness = 6.313, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = -15, baseMultiplier = 6.6, damageEffectiveness = 6.6, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = -15, baseMultiplier = 6.899, damageEffectiveness = 6.899, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = -15, baseMultiplier = 7.212, damageEffectiveness = 7.212, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = -15, baseMultiplier = 7.54, damageEffectiveness = 7.54, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = -15, baseMultiplier = 7.881, damageEffectiveness = 7.881, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = -15, baseMultiplier = 8.238, damageEffectiveness = 8.238, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = -15, baseMultiplier = 8.611, damageEffectiveness = 8.611, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = -15, baseMultiplier = 9.177, damageEffectiveness = 9.177, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = -15, baseMultiplier = 9.384, damageEffectiveness = 9.384, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = -15, baseMultiplier = 9.597, damageEffectiveness = 9.597, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = -15, baseMultiplier = 9.814, damageEffectiveness = 9.814, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = -15, baseMultiplier = 10.036, damageEffectiveness = 10.036, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = -15, baseMultiplier = 10.262, damageEffectiveness = 10.262, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = -15, baseMultiplier = 10.494, damageEffectiveness = 10.494, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = -15, baseMultiplier = 10.732, damageEffectiveness = 10.732, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = -15, baseMultiplier = 10.974, damageEffectiveness = 10.974, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = -15, baseMultiplier = 11.222, damageEffectiveness = 11.222, levelRequirement = 100, }, + }, +} + +skills["HeavyStrikeMercenary"] = { + name = "Heavy Strike of Vulnerability", + hidden = true, + mercenary = true, + inheritedFrom = "HeavyStrike", + color = 1, + baseEffectiveness = 0, + description = "Attacks enemies with a forceful blow. Requires a Mace, Sceptre, Axe, Sword or Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + }, + constantStats = { + { "base_stun_threshold_reduction_+%", 25 }, + { "curse_on_hit_%_vulnerability", 50 }, + }, + stats = { + "chance_to_deal_double_damage_%", + }, + levels = { + [1] = { 20, attackSpeedMultiplier = -15, baseMultiplier = 2.243, damageEffectiveness = 2.243, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 21, attackSpeedMultiplier = -15, baseMultiplier = 2.341, damageEffectiveness = 2.341, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 22, attackSpeedMultiplier = -15, baseMultiplier = 2.449, damageEffectiveness = 2.449, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 23, attackSpeedMultiplier = -15, baseMultiplier = 2.565, damageEffectiveness = 2.565, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 24, attackSpeedMultiplier = -15, baseMultiplier = 2.693, damageEffectiveness = 2.693, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 25, attackSpeedMultiplier = -15, baseMultiplier = 2.831, damageEffectiveness = 2.831, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 26, attackSpeedMultiplier = -15, baseMultiplier = 2.971, damageEffectiveness = 2.971, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 27, attackSpeedMultiplier = -15, baseMultiplier = 3.118, damageEffectiveness = 3.118, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 28, attackSpeedMultiplier = -15, baseMultiplier = 3.273, damageEffectiveness = 3.273, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 29, attackSpeedMultiplier = -15, baseMultiplier = 3.433, damageEffectiveness = 3.433, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 30, attackSpeedMultiplier = -15, baseMultiplier = 3.603, damageEffectiveness = 3.603, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 31, attackSpeedMultiplier = -15, baseMultiplier = 3.78, damageEffectiveness = 3.78, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 32, attackSpeedMultiplier = -15, baseMultiplier = 3.966, damageEffectiveness = 3.966, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 33, attackSpeedMultiplier = -15, baseMultiplier = 4.161, damageEffectiveness = 4.161, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 34, attackSpeedMultiplier = -15, baseMultiplier = 4.365, damageEffectiveness = 4.365, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 35, attackSpeedMultiplier = -15, baseMultiplier = 4.58, damageEffectiveness = 4.58, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 36, attackSpeedMultiplier = -15, baseMultiplier = 4.804, damageEffectiveness = 4.804, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 37, attackSpeedMultiplier = -15, baseMultiplier = 5.039, damageEffectiveness = 5.039, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 38, attackSpeedMultiplier = -15, baseMultiplier = 5.277, damageEffectiveness = 5.277, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 39, attackSpeedMultiplier = -15, baseMultiplier = 5.525, damageEffectiveness = 5.525, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 40, attackSpeedMultiplier = -15, baseMultiplier = 5.777, damageEffectiveness = 5.777, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 41, attackSpeedMultiplier = -15, baseMultiplier = 6.04, damageEffectiveness = 6.04, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 42, attackSpeedMultiplier = -15, baseMultiplier = 6.313, damageEffectiveness = 6.313, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 43, attackSpeedMultiplier = -15, baseMultiplier = 6.6, damageEffectiveness = 6.6, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 44, attackSpeedMultiplier = -15, baseMultiplier = 6.899, damageEffectiveness = 6.899, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 45, attackSpeedMultiplier = -15, baseMultiplier = 7.212, damageEffectiveness = 7.212, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 46, attackSpeedMultiplier = -15, baseMultiplier = 7.54, damageEffectiveness = 7.54, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 47, attackSpeedMultiplier = -15, baseMultiplier = 7.881, damageEffectiveness = 7.881, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 48, attackSpeedMultiplier = -15, baseMultiplier = 8.238, damageEffectiveness = 8.238, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 49, attackSpeedMultiplier = -15, baseMultiplier = 8.611, damageEffectiveness = 8.611, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 49, attackSpeedMultiplier = -15, baseMultiplier = 9.177, damageEffectiveness = 9.177, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 50, attackSpeedMultiplier = -15, baseMultiplier = 9.384, damageEffectiveness = 9.384, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 50, attackSpeedMultiplier = -15, baseMultiplier = 9.597, damageEffectiveness = 9.597, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 51, attackSpeedMultiplier = -15, baseMultiplier = 9.814, damageEffectiveness = 9.814, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 51, attackSpeedMultiplier = -15, baseMultiplier = 10.036, damageEffectiveness = 10.036, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 52, attackSpeedMultiplier = -15, baseMultiplier = 10.262, damageEffectiveness = 10.262, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 52, attackSpeedMultiplier = -15, baseMultiplier = 10.494, damageEffectiveness = 10.494, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 53, attackSpeedMultiplier = -15, baseMultiplier = 10.732, damageEffectiveness = 10.732, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 53, attackSpeedMultiplier = -15, baseMultiplier = 10.974, damageEffectiveness = 10.974, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 54, attackSpeedMultiplier = -15, baseMultiplier = 11.222, damageEffectiveness = 11.222, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["HeraldOfAshMercenary"] = { + name = "Herald of Ash", + hidden = true, + mercenary = true, + inheritedFrom = "HeraldOfAsh", + color = 1, + baseEffectiveness = 0.5, + incrementalEffectiveness = 0.032699998468161, + description = "Grants a buff providing fire damage based on your physical damage. While you have this buff, if you kill an enemy, other enemies near them will be burned based on the overkill damage. The burn inflicted by this skill can only be affected by modifiers to damage over time (burning damage is damage over time).", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.CausesBurning] = true, [SkillType.Area] = true, [SkillType.DamageOverTime] = true, [SkillType.Fire] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Herald] = true, [SkillType.Duration] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 4000 }, + { "herald_of_ash_burning_%_overkill_damage_per_minute", 1500 }, + }, + stats = { + "herald_of_ash_burning_damage_+%_final", + "physical_damage_%_to_add_as_fire", + "is_area_damage", + }, + levels = { + [1] = { 0, 15, cooldown = 1.2, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 2, 15, cooldown = 1.2, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 4, 15, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 6, 15, cooldown = 1.2, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 8, 15, cooldown = 1.2, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 10, 16, cooldown = 1.2, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 12, 16, cooldown = 1.2, levelRequirement = 37, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 14, 16, cooldown = 1.2, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 16, 17, cooldown = 1.2, levelRequirement = 43, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 18, 17, cooldown = 1.2, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 20, 17, cooldown = 1.2, levelRequirement = 49, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 22, 18, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 24, 18, cooldown = 1.2, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 26, 18, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 28, 19, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 30, 19, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 32, 19, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 34, 20, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 36, 20, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 38, 20, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 40, 21, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 42, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 44, 21, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 46, 22, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 48, 22, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 50, 22, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 52, 23, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 54, 23, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 56, 23, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 58, 24, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 59, 24, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 60, 24, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 61, 24, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 62, 24, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 63, 24, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 64, 25, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 65, 25, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 66, 25, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 67, 25, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 68, 25, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["HeraldOfIceMercenary"] = { + name = "Herald of Ice", + hidden = true, + mercenary = true, + inheritedFrom = "HeraldOfIce", + color = 2, + baseEffectiveness = 1.3636000156403, + incrementalEffectiveness = 0.023000000044703, + description = "Grants a buff adding cold damage to spells and attacks. If you shatter an enemy, this skill will cause them to explode and deal AoE cold damage to enemies near them. This damage is not affected by modifiers to spell damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Cold] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Herald] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "skill_override_pvp_scaling_time_ms", 1000 }, + { "active_skill_base_area_of_effect_radius", 12 }, + }, + stats = { + "spell_minimum_added_cold_damage", + "spell_maximum_added_cold_damage", + "attack_minimum_added_cold_damage", + "attack_maximum_added_cold_damage", + "secondary_minimum_base_cold_damage", + "secondary_maximum_base_cold_damage", + "is_area_damage", + "base_skill_show_average_damage_instead_of_dps", + "display_skill_deals_secondary_damage", + "damage_cannot_be_reflected", + "skill_can_add_multiple_charges_per_action", + }, + notMinionStat = { + "secondary_minimum_base_cold_damage", + "secondary_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 18, 26, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [2] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 23, 35, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [3] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 30, 45, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [4] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 38, 57, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [5] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 45, 67, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [6] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 53, 80, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [7] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 62, 94, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [8] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 73, 110, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [9] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 85, 128, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [10] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 99, 149, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [11] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 115, 173, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [12] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 134, 200, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [13] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 154, 232, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [14] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 178, 267, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [15] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 195, 293, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [16] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 214, 321, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [17] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 235, 352, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [18] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 257, 386, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [19] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 282, 422, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [20] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 308, 462, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [21] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 337, 505, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [22] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 368, 552, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [23] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 402, 603, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [24] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 438, 658, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [25] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 478, 717, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [26] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 521, 782, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [27] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 568, 852, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [28] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 619, 928, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [29] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 674, 1010, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [30] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 733, 1100, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [31] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 765, 1149, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [32] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 796, 1198, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [33] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 830, 1251, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [34] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 863, 1304, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [35] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 899, 1361, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [36] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 934, 1418, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [37] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 971, 1479, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [38] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 1008, 1540, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [39] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 1047, 1605, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + [40] = { 0.20000000298023, 0.30000001192093, 0.20000000298023, 0.30000001192093, 1085, 1670, cooldown = 1.2, damageEffectiveness = 0.8, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 3, 3, 1, 1, }, }, + }, +} + +skills["HeraldOfPurityMercenary"] = { + name = "Herald of Purity", + hidden = true, + mercenary = true, + inheritedFrom = "HeraldOfPurity", + color = 1, + baseEffectiveness = 0.31700000166893, + incrementalEffectiveness = 0.01799999922514, + description = "Grants a buff which lets you deal more physical damage. When you kill an enemy while you have this buff, this skill will summon a Sentinel of Purity, or refresh the duration and life of an existing one instead if you have the maximum number of them. The Sentinels of Purity have a single-target melee attack and an area melee attack.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.Herald] = true, [SkillType.Minion] = true, [SkillType.Instant] = true, [SkillType.Duration] = true, [SkillType.Physical] = true, [SkillType.CreatesMinion] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, [SkillType.CreatesSentinelMinion] = true, }, + minionSkillTypes = { [SkillType.Damage] = true, [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Area] = true, }, + statDescriptionScope = "minion_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "base_number_of_champions_of_light_allowed", 4 }, + { "herald_of_light_summon_champion_on_unique_or_rare_enemy_hit_%", 50 }, + { "base_skill_effect_duration", 12000 }, + { "display_minion_monster_type", 21 }, + }, + stats = { + "herald_of_purity_physical_damage_+%_final", + "active_skill_minion_physical_damage_+%_final", + "active_skill_minion_life_+%_final", + "base_display_minion_actor_level", + "herald_of_light_summon_champion_on_kill", + }, + notMinionStat = { + "herald_of_purity_physical_damage_+%_final", + "active_skill_minion_physical_damage_+%_final", + "active_skill_minion_life_+%_final", + }, + levels = { + [1] = { 9, 0, 0, 16, cooldown = 1.2, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [2] = { 9, 5, 2, 20, cooldown = 1.2, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [3] = { 9, 10, 4, 24, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [4] = { 9, 15, 6, 28, cooldown = 1.2, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [5] = { 9, 20, 8, 31, cooldown = 1.2, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [6] = { 10, 25, 10, 34, cooldown = 1.2, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [7] = { 10, 30, 12, 37, cooldown = 1.2, levelRequirement = 37, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [8] = { 10, 35, 14, 40, cooldown = 1.2, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [9] = { 10, 40, 16, 43, cooldown = 1.2, levelRequirement = 43, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [10] = { 10, 45, 18, 46, cooldown = 1.2, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [11] = { 11, 50, 20, 49, cooldown = 1.2, levelRequirement = 49, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [12] = { 11, 55, 22, 52, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [13] = { 11, 60, 24, 55, cooldown = 1.2, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [14] = { 11, 65, 26, 58, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [15] = { 11, 70, 28, 60, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [16] = { 12, 75, 30, 62, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [17] = { 12, 80, 32, 64, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [18] = { 12, 85, 34, 66, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [19] = { 12, 90, 36, 68, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [20] = { 12, 95, 38, 70, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [21] = { 13, 100, 40, 72, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [22] = { 13, 105, 42, 74, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [23] = { 13, 110, 44, 76, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [24] = { 13, 115, 46, 78, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [25] = { 13, 120, 48, 80, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [26] = { 14, 125, 50, 82, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [27] = { 14, 130, 52, 84, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [28] = { 14, 135, 54, 86, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [29] = { 14, 140, 56, 88, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [30] = { 14, 145, 58, 90, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [31] = { 14, 147, 60, 91, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [32] = { 15, 150, 62, 92, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [33] = { 15, 152, 64, 93, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [34] = { 15, 155, 66, 94, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [35] = { 15, 157, 68, 95, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [36] = { 15, 160, 70, 96, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [37] = { 15, 162, 72, 97, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [38] = { 15, 165, 74, 98, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [39] = { 15, 167, 76, 99, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [40] = { 15, 170, 78, 100, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + }, +} + +skills["HolyFireMortarMercenary"] = { + name = "Holy Mortar", + hidden = true, + mercenary = true, + color = 3, + baseEffectiveness = 2.5, + incrementalEffectiveness = 0.037999998778105, + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Projectile] = true, [SkillType.Multicastable] = true, [SkillType.Chains] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "fire_mortar_second_hit_damage_+%_final", -60 }, + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + "base_is_projectile", + "always_ignite", + "projectile_uses_contact_position", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 2, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 4, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 7, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 11, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 16, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 20, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 24, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 32, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 36, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 67, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["HolyFlameTotemMercenary"] = { + name = "Holy Flame Totem", + hidden = true, + mercenary = true, + inheritedFrom = "HolyFlameTotem", + color = 1, + baseEffectiveness = 0.74919998645782, + incrementalEffectiveness = 0.032200001180172, + description = "Summons a totem that channels to fire a stream of flame at nearby enemies, and creates an area of consecrated ground around the totem.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.SummonsTotem] = true, [SkillType.Fire] = true, [SkillType.Channel] = true, [SkillType.Physical] = true, [SkillType.Area] = true, }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 17, + castTime = 0.25, + baseFlags = { + area = true, + projectile = true, + spell = true, + totem = true, + }, + constantStats = { + { "base_totem_duration", 8000 }, + { "base_totem_range", 100 }, + { "base_number_of_projectiles", 3 }, + { "skill_physical_damage_%_to_convert_to_fire", 50 }, + { "ignite_art_variation", 7 }, + { "active_skill_projectile_speed_+%_variation_final", 30 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_totem", + "base_skill_is_totemified", + "base_is_projectile", + "always_pierce", + "consecrated_ground_immune_to_curses", + "visual_hit_effect_elemental_is_holy", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.60000002384186, 1.2000000476837, cooldown = 6, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, 3, }, }, + [2] = { 0.60000002384186, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 6, statInterpolation = { 3, 3, }, }, + [3] = { 0.60000002384186, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 9, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 12, statInterpolation = { 3, 3, }, }, + [5] = { 0.69999998807907, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 16, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 20, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 24, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 32, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 36, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 55, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 61, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 67, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 6, damageEffectiveness = 0.35, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["HolyHammersMercenary"] = { + name = "Holy Hammers", + hidden = true, + mercenary = true, + inheritedFrom = "HolyHammers", + color = 1, + description = "Slam the ground, calling down a Holy Hammer from above. On hitting an enemy, another Hammer will cascade forward, repeating if further enemies are hit, up to a cap. A Power Charge can be expended to call down additional Hammers to either side of the initial slam. Requires a Mace, Sceptre or Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Slam] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Lightning] = true, [SkillType.Totemable] = true, [SkillType.Multistrikeable] = true, }, + weaponTypes = { + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "holy_hammers_maximum_number_of_hammerslam_cascades", 2 }, + { "holy_hammers_num_additional_hammerslams_if_consuming_power_charge", 2 }, + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "base_from_skill_shock_art_variation", 2 }, + { "holy_hammers_damage_+%_final_for_initial_hammer_in_cascade", 100 }, + { "active_skill_base_area_of_effect_radius", 18 }, + }, + stats = { + "is_area_damage", + "visual_hit_effect_elemental_is_holy", + "console_skill_dont_chase", + }, + levels = { + [1] = { attackSpeedMultiplier = -15, baseMultiplier = 1.2, damageEffectiveness = 1.2, levelRequirement = 28, }, + [2] = { attackSpeedMultiplier = -15, baseMultiplier = 1.253, damageEffectiveness = 1.253, levelRequirement = 31, }, + [3] = { attackSpeedMultiplier = -15, baseMultiplier = 1.305, damageEffectiveness = 1.305, levelRequirement = 34, }, + [4] = { attackSpeedMultiplier = -15, baseMultiplier = 1.358, damageEffectiveness = 1.358, levelRequirement = 37, }, + [5] = { attackSpeedMultiplier = -15, baseMultiplier = 1.411, damageEffectiveness = 1.411, levelRequirement = 40, }, + [6] = { attackSpeedMultiplier = -15, baseMultiplier = 1.463, damageEffectiveness = 1.463, levelRequirement = 42, }, + [7] = { attackSpeedMultiplier = -15, baseMultiplier = 1.516, damageEffectiveness = 1.516, levelRequirement = 44, }, + [8] = { attackSpeedMultiplier = -15, baseMultiplier = 1.568, damageEffectiveness = 1.568, levelRequirement = 46, }, + [9] = { attackSpeedMultiplier = -15, baseMultiplier = 1.621, damageEffectiveness = 1.621, levelRequirement = 48, }, + [10] = { attackSpeedMultiplier = -15, baseMultiplier = 1.674, damageEffectiveness = 1.674, levelRequirement = 50, }, + [11] = { attackSpeedMultiplier = -15, baseMultiplier = 1.726, damageEffectiveness = 1.726, levelRequirement = 52, }, + [12] = { attackSpeedMultiplier = -15, baseMultiplier = 1.779, damageEffectiveness = 1.779, levelRequirement = 54, }, + [13] = { attackSpeedMultiplier = -15, baseMultiplier = 1.832, damageEffectiveness = 1.832, levelRequirement = 56, }, + [14] = { attackSpeedMultiplier = -15, baseMultiplier = 1.884, damageEffectiveness = 1.884, levelRequirement = 58, }, + [15] = { attackSpeedMultiplier = -15, baseMultiplier = 1.937, damageEffectiveness = 1.937, levelRequirement = 60, }, + [16] = { attackSpeedMultiplier = -15, baseMultiplier = 1.989, damageEffectiveness = 1.989, levelRequirement = 62, }, + [17] = { attackSpeedMultiplier = -15, baseMultiplier = 2.042, damageEffectiveness = 2.042, levelRequirement = 64, }, + [18] = { attackSpeedMultiplier = -15, baseMultiplier = 2.095, damageEffectiveness = 2.095, levelRequirement = 66, }, + [19] = { attackSpeedMultiplier = -15, baseMultiplier = 2.147, damageEffectiveness = 2.147, levelRequirement = 68, }, + [20] = { attackSpeedMultiplier = -15, baseMultiplier = 2.2, damageEffectiveness = 2.2, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = -15, baseMultiplier = 2.253, damageEffectiveness = 2.253, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = -15, baseMultiplier = 2.305, damageEffectiveness = 2.305, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = -15, baseMultiplier = 2.358, damageEffectiveness = 2.358, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = -15, baseMultiplier = 2.411, damageEffectiveness = 2.411, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = -15, baseMultiplier = 2.463, damageEffectiveness = 2.463, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = -15, baseMultiplier = 2.516, damageEffectiveness = 2.516, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = -15, baseMultiplier = 2.568, damageEffectiveness = 2.568, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = -15, baseMultiplier = 2.621, damageEffectiveness = 2.621, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = -15, baseMultiplier = 2.674, damageEffectiveness = 2.674, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = -15, baseMultiplier = 2.726, damageEffectiveness = 2.726, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = -15, baseMultiplier = 2.753, damageEffectiveness = 2.753, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = -15, baseMultiplier = 2.779, damageEffectiveness = 2.779, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = -15, baseMultiplier = 2.805, damageEffectiveness = 2.805, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = -15, baseMultiplier = 2.832, damageEffectiveness = 2.832, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = -15, baseMultiplier = 2.858, damageEffectiveness = 2.858, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = -15, baseMultiplier = 2.884, damageEffectiveness = 2.884, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = -15, baseMultiplier = 2.911, damageEffectiveness = 2.911, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = -15, baseMultiplier = 2.937, damageEffectiveness = 2.937, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = -15, baseMultiplier = 2.963, damageEffectiveness = 2.963, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = -15, baseMultiplier = 2.989, damageEffectiveness = 2.989, levelRequirement = 100, }, + }, +} + +skills["HolyStrikeMercenary"] = { + name = "Holy Strike", + hidden = true, + mercenary = true, + inheritedFrom = "HolyStrike", + color = 1, + description = "Infuse your weapon with holy energy and swing. Successfully hitting an enemy will summon forth a copy of your Main Hand weapon as a Holy Armament. These Holy Armaments are undamageable minions, and will attack the enemies you target with Holy Strike. Requires a Mace, Sceptre or Staff.", + skillTypes = { [SkillType.CreatesMinion] = true, [SkillType.Minion] = true, [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Melee] = true, [SkillType.Multistrikeable] = true, [SkillType.Lightning] = true, [SkillType.Duration] = true, [SkillType.MinionsAreUndamagable] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Lightning] = true, [SkillType.MinionsAreUndamagable] = true, }, + weaponTypes = { + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "minion_attack_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + melee = true, + minion = true, + }, + constantStats = { + { "base_skill_effect_duration", 10000 }, + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "base_from_skill_shock_art_variation", 2 }, + }, + stats = { + "minion_melee_range_+", + "base_holy_strike_maximum_number_of_animated_weapons", + "active_skill_minion_damage_+%_final", + "visual_hit_effect_elemental_is_holy", + "holy_strike_animates_owners_main_hand_weapon", + "console_skill_dont_chase", + }, + notMinionStat = { + "active_skill_minion_damage_+%_final", + }, + levels = { + [1] = { 12, 2, -60, attackSpeedMultiplier = 15, baseMultiplier = 1.553, damageEffectiveness = 1.553, levelRequirement = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 12, 2, -48, attackSpeedMultiplier = 15, baseMultiplier = 1.63, damageEffectiveness = 1.63, levelRequirement = 2, statInterpolation = { 1, 1, 1, }, }, + [3] = { 13, 2, -36, attackSpeedMultiplier = 15, baseMultiplier = 1.712, damageEffectiveness = 1.712, levelRequirement = 4, statInterpolation = { 1, 1, 1, }, }, + [4] = { 13, 2, -24, attackSpeedMultiplier = 15, baseMultiplier = 1.797, damageEffectiveness = 1.797, levelRequirement = 7, statInterpolation = { 1, 1, 1, }, }, + [5] = { 14, 2, -12, attackSpeedMultiplier = 15, baseMultiplier = 1.887, damageEffectiveness = 1.887, levelRequirement = 11, statInterpolation = { 1, 1, 1, }, }, + [6] = { 14, 2, 0, attackSpeedMultiplier = 15, baseMultiplier = 1.981, damageEffectiveness = 1.981, levelRequirement = 16, statInterpolation = { 1, 1, 1, }, }, + [7] = { 15, 2, 12, attackSpeedMultiplier = 15, baseMultiplier = 2.08, damageEffectiveness = 2.08, levelRequirement = 20, statInterpolation = { 1, 1, 1, }, }, + [8] = { 15, 2, 24, attackSpeedMultiplier = 15, baseMultiplier = 2.185, damageEffectiveness = 2.185, levelRequirement = 24, statInterpolation = { 1, 1, 1, }, }, + [9] = { 16, 2, 36, attackSpeedMultiplier = 15, baseMultiplier = 2.294, damageEffectiveness = 2.294, levelRequirement = 28, statInterpolation = { 1, 1, 1, }, }, + [10] = { 16, 2, 48, attackSpeedMultiplier = 15, baseMultiplier = 2.408, damageEffectiveness = 2.408, levelRequirement = 32, statInterpolation = { 1, 1, 1, }, }, + [11] = { 17, 2, 60, attackSpeedMultiplier = 15, baseMultiplier = 2.529, damageEffectiveness = 2.529, levelRequirement = 36, statInterpolation = { 1, 1, 1, }, }, + [12] = { 17, 2, 72, attackSpeedMultiplier = 15, baseMultiplier = 2.655, damageEffectiveness = 2.655, levelRequirement = 40, statInterpolation = { 1, 1, 1, }, }, + [13] = { 17, 2, 84, attackSpeedMultiplier = 15, baseMultiplier = 2.788, damageEffectiveness = 2.788, levelRequirement = 44, statInterpolation = { 1, 1, 1, }, }, + [14] = { 18, 2, 96, attackSpeedMultiplier = 15, baseMultiplier = 2.927, damageEffectiveness = 2.927, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [15] = { 18, 2, 108, attackSpeedMultiplier = 15, baseMultiplier = 3.074, damageEffectiveness = 3.074, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [16] = { 19, 2, 120, attackSpeedMultiplier = 15, baseMultiplier = 3.228, damageEffectiveness = 3.228, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [17] = { 19, 2, 132, attackSpeedMultiplier = 15, baseMultiplier = 3.389, damageEffectiveness = 3.389, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [18] = { 20, 2, 144, attackSpeedMultiplier = 15, baseMultiplier = 3.558, damageEffectiveness = 3.558, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [19] = { 20, 2, 156, attackSpeedMultiplier = 15, baseMultiplier = 3.736, damageEffectiveness = 3.736, levelRequirement = 67, statInterpolation = { 1, 1, 1, }, }, + [20] = { 21, 2, 168, attackSpeedMultiplier = 15, baseMultiplier = 3.923, damageEffectiveness = 3.923, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 21, 2, 180, attackSpeedMultiplier = 15, baseMultiplier = 4.119, damageEffectiveness = 4.119, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 21, 2, 192, attackSpeedMultiplier = 15, baseMultiplier = 4.325, damageEffectiveness = 4.325, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 22, 2, 204, attackSpeedMultiplier = 15, baseMultiplier = 4.541, damageEffectiveness = 4.541, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 22, 2, 216, attackSpeedMultiplier = 15, baseMultiplier = 4.769, damageEffectiveness = 4.769, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 23, 2, 228, attackSpeedMultiplier = 15, baseMultiplier = 5.007, damageEffectiveness = 5.007, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 23, 2, 240, attackSpeedMultiplier = 15, baseMultiplier = 5.257, damageEffectiveness = 5.257, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 24, 2, 252, attackSpeedMultiplier = 15, baseMultiplier = 5.52, damageEffectiveness = 5.52, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 24, 2, 264, attackSpeedMultiplier = 15, baseMultiplier = 5.796, damageEffectiveness = 5.796, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 25, 2, 276, attackSpeedMultiplier = 15, baseMultiplier = 6.086, damageEffectiveness = 6.086, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 25, 2, 288, attackSpeedMultiplier = 15, baseMultiplier = 6.39, damageEffectiveness = 6.39, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 26, 2, 294, attackSpeedMultiplier = 15, baseMultiplier = 6.878, damageEffectiveness = 6.878, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 26, 2, 300, attackSpeedMultiplier = 15, baseMultiplier = 7.049, damageEffectiveness = 7.049, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 26, 2, 306, attackSpeedMultiplier = 15, baseMultiplier = 7.226, damageEffectiveness = 7.226, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 27, 2, 312, attackSpeedMultiplier = 15, baseMultiplier = 7.406, damageEffectiveness = 7.406, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 27, 2, 318, attackSpeedMultiplier = 15, baseMultiplier = 7.592, damageEffectiveness = 7.592, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 28, 2, 324, attackSpeedMultiplier = 15, baseMultiplier = 7.781, damageEffectiveness = 7.781, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 28, 2, 330, attackSpeedMultiplier = 15, baseMultiplier = 7.976, damageEffectiveness = 7.976, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 29, 2, 336, attackSpeedMultiplier = 15, baseMultiplier = 8.175, damageEffectiveness = 8.175, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 29, 2, 342, attackSpeedMultiplier = 15, baseMultiplier = 8.38, damageEffectiveness = 8.38, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 30, 2, 348, attackSpeedMultiplier = 15, baseMultiplier = 8.589, damageEffectiveness = 8.589, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["HydraForkArrowMercenary"] = { + name = "Frigid Forkshot", + hidden = true, + mercenary = true, + inheritedFrom = "AzmeriHydraForkArrow", + color = 2, + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 2, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "active_skill_damage_+%_final", 50 }, + { "skill_physical_damage_%_to_convert_to_cold", 50 }, + }, + stats = { + "base_is_projectile", + }, + levels = { + [1] = { attackSpeedMultiplier = -30, cooldown = 8, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["IceCrashMercenary"] = { + name = "Ice Crash", + hidden = true, + mercenary = true, + inheritedFrom = "IceCrash", + color = 1, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.023299999535084, + description = "Slam the ground, damaging enemies in an area around the impact in three stages of increasing size. Enemies take slightly less damage on the second and third stage, and can only be hit by one stage. Works with Swords, Maces, Sceptres, Axes, Staves and Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Cold] = true, [SkillType.Multistrikeable] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_cold", 100 }, + { "ice_crash_second_hit_damage_+%_final", -15 }, + { "ice_crash_third_hit_damage_+%_final", -30 }, + { "active_skill_base_area_of_effect_radius", 11 }, + { "active_skill_base_secondary_area_of_effect_radius", 21 }, + { "active_skill_base_tertiary_area_of_effect_radius", 31 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 3.329, damageEffectiveness = 3.329, levelRequirement = 28, }, + [2] = { baseMultiplier = 3.443, damageEffectiveness = 3.443, levelRequirement = 31, }, + [3] = { baseMultiplier = 3.561, damageEffectiveness = 3.561, levelRequirement = 34, }, + [4] = { baseMultiplier = 3.682, damageEffectiveness = 3.682, levelRequirement = 37, }, + [5] = { baseMultiplier = 3.807, damageEffectiveness = 3.807, levelRequirement = 40, }, + [6] = { baseMultiplier = 3.93, damageEffectiveness = 3.93, levelRequirement = 42, }, + [7] = { baseMultiplier = 4.056, damageEffectiveness = 4.056, levelRequirement = 44, }, + [8] = { baseMultiplier = 4.187, damageEffectiveness = 4.187, levelRequirement = 46, }, + [9] = { baseMultiplier = 4.322, damageEffectiveness = 4.322, levelRequirement = 48, }, + [10] = { baseMultiplier = 4.46, damageEffectiveness = 4.46, levelRequirement = 50, }, + [11] = { baseMultiplier = 4.604, damageEffectiveness = 4.604, levelRequirement = 52, }, + [12] = { baseMultiplier = 4.751, damageEffectiveness = 4.751, levelRequirement = 54, }, + [13] = { baseMultiplier = 4.904, damageEffectiveness = 4.904, levelRequirement = 56, }, + [14] = { baseMultiplier = 5.062, damageEffectiveness = 5.062, levelRequirement = 58, }, + [15] = { baseMultiplier = 5.224, damageEffectiveness = 5.224, levelRequirement = 60, }, + [16] = { baseMultiplier = 5.392, damageEffectiveness = 5.392, levelRequirement = 62, }, + [17] = { baseMultiplier = 5.565, damageEffectiveness = 5.565, levelRequirement = 64, }, + [18] = { baseMultiplier = 5.742, damageEffectiveness = 5.742, levelRequirement = 66, }, + [19] = { baseMultiplier = 5.927, damageEffectiveness = 5.927, levelRequirement = 68, }, + [20] = { baseMultiplier = 6.116, damageEffectiveness = 6.116, levelRequirement = 70, }, + [21] = { baseMultiplier = 6.313, damageEffectiveness = 6.313, levelRequirement = 72, }, + [22] = { baseMultiplier = 6.515, damageEffectiveness = 6.515, levelRequirement = 74, }, + [23] = { baseMultiplier = 6.723, damageEffectiveness = 6.723, levelRequirement = 76, }, + [24] = { baseMultiplier = 6.938, damageEffectiveness = 6.938, levelRequirement = 78, }, + [25] = { baseMultiplier = 7.16, damageEffectiveness = 7.16, levelRequirement = 80, }, + [26] = { baseMultiplier = 7.389, damageEffectiveness = 7.389, levelRequirement = 82, }, + [27] = { baseMultiplier = 7.625, damageEffectiveness = 7.625, levelRequirement = 84, }, + [28] = { baseMultiplier = 7.869, damageEffectiveness = 7.869, levelRequirement = 86, }, + [29] = { baseMultiplier = 8.12, damageEffectiveness = 8.12, levelRequirement = 88, }, + [30] = { baseMultiplier = 8.38, damageEffectiveness = 8.38, levelRequirement = 90, }, + [31] = { baseMultiplier = 8.757, damageEffectiveness = 8.757, levelRequirement = 91, }, + [32] = { baseMultiplier = 8.896, damageEffectiveness = 8.896, levelRequirement = 92, }, + [33] = { baseMultiplier = 9.039, damageEffectiveness = 9.039, levelRequirement = 93, }, + [34] = { baseMultiplier = 9.182, damageEffectiveness = 9.182, levelRequirement = 94, }, + [35] = { baseMultiplier = 9.328, damageEffectiveness = 9.328, levelRequirement = 95, }, + [36] = { baseMultiplier = 9.477, damageEffectiveness = 9.477, levelRequirement = 96, }, + [37] = { baseMultiplier = 9.628, damageEffectiveness = 9.628, levelRequirement = 97, }, + [38] = { baseMultiplier = 9.781, damageEffectiveness = 9.781, levelRequirement = 98, }, + [39] = { baseMultiplier = 9.937, damageEffectiveness = 9.937, levelRequirement = 99, }, + [40] = { baseMultiplier = 10.095, damageEffectiveness = 10.095, levelRequirement = 100, }, + }, +} + +skills["IceNovaMercenary"] = { + name = "Ice Nova", + hidden = true, + mercenary = true, + inheritedFrom = "IceNova", + color = 3, + baseEffectiveness = 2.2599999904633, + incrementalEffectiveness = 0.043600000441074, + description = "A circle of ice expands from the caster.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 26 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "active_skill_base_area_of_effect_radius", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["IceNovaMercenaryEncounter"] = { + name = "Ice Nova", + hidden = true, + mercenary = true, + inheritedFrom = "IceNova", + color = 3, + baseEffectiveness = 2.2599999904633, + incrementalEffectiveness = 0.037999998778105, + description = "A circle of ice expands from the caster.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 26 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "active_skill_base_area_of_effect_radius", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 1, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 2, critChance = 7.5, damageEffectiveness = 2.1, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 3, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.2, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 4, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 5, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 6, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 7, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 8, critChance = 7.5, damageEffectiveness = 2.3, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["IceNovaProjectedMercenary"] = { + name = "Ice Nova of Projection", + hidden = true, + mercenary = true, + inheritedFrom = "IceNova", + color = 3, + baseEffectiveness = 2.2599999904633, + incrementalEffectiveness = 0.043600000441074, + description = "A circle of ice expands from the caster.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 20 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "active_skill_base_area_of_effect_radius", + "is_area_damage", + "nova_spells_cast_at_target_location", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["IceNovaProjectedMercenaryEncounter"] = { + name = "Ice Nova of Projection", + hidden = true, + mercenary = true, + inheritedFrom = "IceNova", + color = 3, + baseEffectiveness = 2.2599999904633, + incrementalEffectiveness = 0.037999998778105, + description = "A circle of ice expands from the caster.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 20 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "active_skill_base_area_of_effect_radius", + "is_area_damage", + "nova_spells_cast_at_target_location", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 1, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 2, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 6, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 7, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 8, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["IceShotMercenary"] = { + name = "Ice Shot", + hidden = true, + mercenary = true, + inheritedFrom = "IceShot", + color = 2, + description = "Fires an arrow that converts some physical damage to cold on its target and converts all physical damage to cold in a cone behind that target.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Cold] = true, [SkillType.Triggerable] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_cold", 60 }, + { "active_skill_base_area_of_effect_radius", 24 }, + }, + stats = { + "active_skill_chill_as_though_damage_+%_final", + "skill_can_fire_arrows", + }, + levels = { + [1] = { 100, baseMultiplier = 1.495, damageEffectiveness = 1.495, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 105, baseMultiplier = 1.521, damageEffectiveness = 1.521, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 110, baseMultiplier = 1.548, damageEffectiveness = 1.548, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 115, baseMultiplier = 1.574, damageEffectiveness = 1.574, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 120, baseMultiplier = 1.602, damageEffectiveness = 1.602, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 125, baseMultiplier = 1.628, damageEffectiveness = 1.628, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 130, baseMultiplier = 1.655, damageEffectiveness = 1.655, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 135, baseMultiplier = 1.681, damageEffectiveness = 1.681, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 140, baseMultiplier = 1.708, damageEffectiveness = 1.708, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 145, baseMultiplier = 1.734, damageEffectiveness = 1.734, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 150, baseMultiplier = 1.762, damageEffectiveness = 1.762, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 155, baseMultiplier = 1.788, damageEffectiveness = 1.788, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 160, baseMultiplier = 1.815, damageEffectiveness = 1.815, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 165, baseMultiplier = 1.841, damageEffectiveness = 1.841, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 170, baseMultiplier = 1.868, damageEffectiveness = 1.868, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 175, baseMultiplier = 1.894, damageEffectiveness = 1.894, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 180, baseMultiplier = 1.922, damageEffectiveness = 1.922, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 185, baseMultiplier = 1.948, damageEffectiveness = 1.948, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 190, baseMultiplier = 1.975, damageEffectiveness = 1.975, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 195, baseMultiplier = 2.001, damageEffectiveness = 2.001, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 200, baseMultiplier = 2.027, damageEffectiveness = 2.027, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 205, baseMultiplier = 2.054, damageEffectiveness = 2.054, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 210, baseMultiplier = 2.08, damageEffectiveness = 2.08, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 215, baseMultiplier = 2.108, damageEffectiveness = 2.108, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 220, baseMultiplier = 2.134, damageEffectiveness = 2.134, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 225, baseMultiplier = 2.161, damageEffectiveness = 2.161, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 230, baseMultiplier = 2.187, damageEffectiveness = 2.187, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 235, baseMultiplier = 2.214, damageEffectiveness = 2.214, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 240, baseMultiplier = 2.24, damageEffectiveness = 2.24, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 245, baseMultiplier = 2.268, damageEffectiveness = 2.268, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 247, baseMultiplier = 2.28, damageEffectiveness = 2.28, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 250, baseMultiplier = 2.294, damageEffectiveness = 2.294, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 252, baseMultiplier = 2.307, damageEffectiveness = 2.307, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 255, baseMultiplier = 2.321, damageEffectiveness = 2.321, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 257, baseMultiplier = 2.333, damageEffectiveness = 2.333, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 260, baseMultiplier = 2.347, damageEffectiveness = 2.347, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 262, baseMultiplier = 2.361, damageEffectiveness = 2.361, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 265, baseMultiplier = 2.374, damageEffectiveness = 2.374, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 267, baseMultiplier = 2.387, damageEffectiveness = 2.387, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 270, baseMultiplier = 2.4, damageEffectiveness = 2.4, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["IceTrapMercenary"] = { + name = "Ice Trap", + hidden = true, + mercenary = true, + inheritedFrom = "IceTrap", + color = 2, + baseEffectiveness = 2.5, + incrementalEffectiveness = 0.050000000745058, + description = "Throws a trap that creates a series of icy runic explosions when triggered, dealing cold damage to all enemies caught in the blasts.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Mineable] = true, [SkillType.Area] = true, [SkillType.Trapped] = true, [SkillType.Cold] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + spell = true, + trap = true, + }, + constantStats = { + { "base_trap_duration", 4000 }, + { "active_skill_base_area_of_effect_radius", 18 }, + { "active_skill_base_secondary_area_of_effect_radius", 9 }, + { "active_skill_base_tertiary_area_of_effect_radius", 6 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "is_area_damage", + "base_skill_is_trapped", + "base_skill_show_average_damage_instead_of_dps", + "is_trap", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 5, damageEffectiveness = 2.9, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["IcestormMercenary"] = { + name = "Icestorm", + hidden = true, + mercenary = true, + inheritedFrom = "Icestorm", + color = 3, + baseEffectiveness = 0.80000001192093, + incrementalEffectiveness = 0.050000000745058, + description = "Icy bolts rain down over the targeted area. They explode when landing, dealing damage to nearby enemies and chilling them, as well as causing patches of chilled ground. Skill damage is based on Intelligence.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.Cascadable] = true, [SkillType.ChillingArea] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "fire_storm_fireball_delay_ms", 200 }, + { "firestorm_drop_ground_ice_duration_ms", 4000 }, + { "firestorm_max_number_of_storms", 5 }, + { "active_skill_base_area_of_effect_radius", 16 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "support_spell_cascade_number_of_cascades_per_side", + "is_area_damage", + "skill_is_ice_storm", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "support_spell_cascade_number_of_cascades_per_side", + }, + levels = { + [1] = { 0.40000000596046, 0.60000002384186, 0, cooldown = 6.5, critChance = 6, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.40000000596046, 0.60000002384186, 0, cooldown = 6.5, critChance = 6, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.40000000596046, 0.60000002384186, 0, cooldown = 6.5, critChance = 6, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.40000000596046, 0.60000002384186, 0, cooldown = 6.5, critChance = 6, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.40000000596046, 0.60000002384186, 1, cooldown = 6.5, critChance = 6, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.40000000596046, 0.60000002384186, 2, cooldown = 6.5, critChance = 6, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.40000000596046, 0.60000002384186, 3, cooldown = 6.5, critChance = 6, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["InfernalBlowAltMercenary"] = { + name = "Infernal Blow of Immolation", + hidden = true, + mercenary = true, + inheritedFrom = "InfernalBlowAltX", + color = 1, + description = "Attacks with your weapon, applying a charged debuff to you the first time you hit an enemy with this skill. Upon reaching 6 charges, or charges expiring, the charged debuff is removed to damage nearby enemies. Requires a Sword, Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Fire] = true, [SkillType.Duration] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "base_skill_effect_duration", 2200 }, + { "infernal_blow_explosion_damage_%_of_total_per_stack", 80 }, + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + { "active_skill_base_area_of_effect_radius", 24 }, + }, + stats = { + }, + levels = { + [1] = { baseMultiplier = 1.643, damageEffectiveness = 1.643, levelRequirement = 12, }, + [2] = { baseMultiplier = 1.716, damageEffectiveness = 1.716, levelRequirement = 15, }, + [3] = { baseMultiplier = 1.797, damageEffectiveness = 1.797, levelRequirement = 19, }, + [4] = { baseMultiplier = 1.881, damageEffectiveness = 1.881, levelRequirement = 23, }, + [5] = { baseMultiplier = 1.968, damageEffectiveness = 1.968, levelRequirement = 27, }, + [6] = { baseMultiplier = 2.06, damageEffectiveness = 2.06, levelRequirement = 31, }, + [7] = { baseMultiplier = 2.156, damageEffectiveness = 2.156, levelRequirement = 35, }, + [8] = { baseMultiplier = 2.252, damageEffectiveness = 2.252, levelRequirement = 38, }, + [9] = { baseMultiplier = 2.353, damageEffectiveness = 2.353, levelRequirement = 41, }, + [10] = { baseMultiplier = 2.458, damageEffectiveness = 2.458, levelRequirement = 44, }, + [11] = { baseMultiplier = 2.567, damageEffectiveness = 2.567, levelRequirement = 47, }, + [12] = { baseMultiplier = 2.682, damageEffectiveness = 2.682, levelRequirement = 50, }, + [13] = { baseMultiplier = 2.802, damageEffectiveness = 2.802, levelRequirement = 53, }, + [14] = { baseMultiplier = 2.926, damageEffectiveness = 2.926, levelRequirement = 56, }, + [15] = { baseMultiplier = 3.057, damageEffectiveness = 3.057, levelRequirement = 59, }, + [16] = { baseMultiplier = 3.193, damageEffectiveness = 3.193, levelRequirement = 62, }, + [17] = { baseMultiplier = 3.33, damageEffectiveness = 3.33, levelRequirement = 64, }, + [18] = { baseMultiplier = 3.472, damageEffectiveness = 3.472, levelRequirement = 66, }, + [19] = { baseMultiplier = 3.619, damageEffectiveness = 3.619, levelRequirement = 68, }, + [20] = { baseMultiplier = 3.774, damageEffectiveness = 3.774, levelRequirement = 70, }, + [21] = { baseMultiplier = 3.935, damageEffectiveness = 3.935, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.103, damageEffectiveness = 4.103, levelRequirement = 74, }, + [23] = { baseMultiplier = 4.278, damageEffectiveness = 4.278, levelRequirement = 76, }, + [24] = { baseMultiplier = 4.46, damageEffectiveness = 4.46, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.651, damageEffectiveness = 4.651, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.849, damageEffectiveness = 4.849, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.056, damageEffectiveness = 5.056, levelRequirement = 84, }, + [28] = { baseMultiplier = 5.271, damageEffectiveness = 5.271, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.496, damageEffectiveness = 5.496, levelRequirement = 88, }, + [30] = { baseMultiplier = 5.729, damageEffectiveness = 5.729, levelRequirement = 90, }, + [31] = { baseMultiplier = 6.081, damageEffectiveness = 6.081, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.21, damageEffectiveness = 6.21, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.342, damageEffectiveness = 6.342, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.477, damageEffectiveness = 6.477, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.615, damageEffectiveness = 6.615, levelRequirement = 95, }, + [36] = { baseMultiplier = 6.755, damageEffectiveness = 6.755, levelRequirement = 96, }, + [37] = { baseMultiplier = 6.898, damageEffectiveness = 6.898, levelRequirement = 97, }, + [38] = { baseMultiplier = 7.045, damageEffectiveness = 7.045, levelRequirement = 98, }, + [39] = { baseMultiplier = 7.194, damageEffectiveness = 7.194, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.347, damageEffectiveness = 7.347, levelRequirement = 100, }, + }, +} + +skills["InfernalBlowAltMercenaryEncounter"] = { + name = "Infernal Blow of Immolation", + hidden = true, + mercenary = true, + inheritedFrom = "InfernalBlowAltX", + color = 1, + description = "Attacks with your weapon, applying a charged debuff to you the first time you hit an enemy with this skill. Upon reaching 6 charges, or charges expiring, the charged debuff is removed to damage nearby enemies. Requires a Sword, Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Fire] = true, [SkillType.Duration] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "base_skill_effect_duration", 2200 }, + { "infernal_blow_explosion_damage_%_of_total_per_stack", 40 }, + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + { "active_skill_base_area_of_effect_radius", 24 }, + }, + stats = { + }, + levels = { + [1] = { baseMultiplier = 1.643, damageEffectiveness = 1.643, levelRequirement = 12, }, + [2] = { baseMultiplier = 1.716, damageEffectiveness = 1.716, levelRequirement = 15, }, + [3] = { baseMultiplier = 1.797, damageEffectiveness = 1.797, levelRequirement = 19, }, + [4] = { baseMultiplier = 1.881, damageEffectiveness = 1.881, levelRequirement = 23, }, + [5] = { baseMultiplier = 1.968, damageEffectiveness = 1.968, levelRequirement = 27, }, + [6] = { baseMultiplier = 2.06, damageEffectiveness = 2.06, levelRequirement = 31, }, + [7] = { baseMultiplier = 2.156, damageEffectiveness = 2.156, levelRequirement = 35, }, + [8] = { baseMultiplier = 2.252, damageEffectiveness = 2.252, levelRequirement = 38, }, + [9] = { baseMultiplier = 2.353, damageEffectiveness = 2.353, levelRequirement = 41, }, + [10] = { baseMultiplier = 2.458, damageEffectiveness = 2.458, levelRequirement = 44, }, + [11] = { baseMultiplier = 2.567, damageEffectiveness = 2.567, levelRequirement = 47, }, + [12] = { baseMultiplier = 2.682, damageEffectiveness = 2.682, levelRequirement = 50, }, + [13] = { baseMultiplier = 2.802, damageEffectiveness = 2.802, levelRequirement = 53, }, + [14] = { baseMultiplier = 2.926, damageEffectiveness = 2.926, levelRequirement = 56, }, + [15] = { baseMultiplier = 3.057, damageEffectiveness = 3.057, levelRequirement = 59, }, + [16] = { baseMultiplier = 3.193, damageEffectiveness = 3.193, levelRequirement = 62, }, + [17] = { baseMultiplier = 3.33, damageEffectiveness = 3.33, levelRequirement = 64, }, + [18] = { baseMultiplier = 3.472, damageEffectiveness = 3.472, levelRequirement = 66, }, + [19] = { baseMultiplier = 3.619, damageEffectiveness = 3.619, levelRequirement = 68, }, + [20] = { baseMultiplier = 3.774, damageEffectiveness = 3.774, levelRequirement = 70, }, + [21] = { baseMultiplier = 3.935, damageEffectiveness = 3.935, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.103, damageEffectiveness = 4.103, levelRequirement = 74, }, + [23] = { baseMultiplier = 4.278, damageEffectiveness = 4.278, levelRequirement = 76, }, + [24] = { baseMultiplier = 4.46, damageEffectiveness = 4.46, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.651, damageEffectiveness = 4.651, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.849, damageEffectiveness = 4.849, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.056, damageEffectiveness = 5.056, levelRequirement = 84, }, + [28] = { baseMultiplier = 5.271, damageEffectiveness = 5.271, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.496, damageEffectiveness = 5.496, levelRequirement = 88, }, + [30] = { baseMultiplier = 5.729, damageEffectiveness = 5.729, levelRequirement = 90, }, + [31] = { baseMultiplier = 6.081, damageEffectiveness = 6.081, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.21, damageEffectiveness = 6.21, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.342, damageEffectiveness = 6.342, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.477, damageEffectiveness = 6.477, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.615, damageEffectiveness = 6.615, levelRequirement = 95, }, + [36] = { baseMultiplier = 6.755, damageEffectiveness = 6.755, levelRequirement = 96, }, + [37] = { baseMultiplier = 6.898, damageEffectiveness = 6.898, levelRequirement = 97, }, + [38] = { baseMultiplier = 7.045, damageEffectiveness = 7.045, levelRequirement = 98, }, + [39] = { baseMultiplier = 7.194, damageEffectiveness = 7.194, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.347, damageEffectiveness = 7.347, levelRequirement = 100, }, + }, +} + +skills["InfernalCryMercenary"] = { + name = "Infernal Cry", + hidden = true, + mercenary = true, + inheritedFrom = "InfernalCry", + color = 1, + description = "Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. The user and nearby allies gain a buff that grants a portion of their physical damage as extra fire damage. In addition to being taunted, enemies are inflicted with a secondary debuff causing them to explode when they die, dealing fire damage in an area.", + skillTypes = { [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Fire] = true, [SkillType.Damage] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "secondary_debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "infernal_cry_%_max_life_as_fire_on_death", 8 }, + { "infernal_cry_physical_damage_%_to_add_as_fire_per_5_power_up_to_cap", 5 }, + { "skill_empowers_next_x_melee_attacks", 6 }, + }, + stats = { + "warcry_speed_+%", + "base_skill_effect_duration", + "base_secondary_skill_effect_duration", + "base_deal_no_attack_damage", + "base_deal_no_spell_damage", + "damage_cannot_be_reflected", + "base_skill_show_average_damage_instead_of_dps", + "display_skill_deals_secondary_damage", + "cannot_cancel_skill_before_contact_point", + "warcry_count_power_from_enemies", + }, + notMinionStat = { + "base_skill_effect_duration", + "base_secondary_skill_effect_duration", + }, + levels = { + [1] = { 0, 2500, 2500, cooldown = 8, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 2, 2500, 2500, cooldown = 8, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 4, 2600, 2600, cooldown = 8, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 6, 2600, 2600, cooldown = 8, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8, 2700, 2700, cooldown = 8, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 10, 2700, 2700, cooldown = 8, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 12, 2800, 2800, cooldown = 8, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 14, 2800, 2800, cooldown = 8, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 16, 2900, 2900, cooldown = 8, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 18, 2900, 2900, cooldown = 8, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 20, 3000, 3000, cooldown = 8, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 22, 3000, 3000, cooldown = 8, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 24, 3100, 3100, cooldown = 8, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 26, 3100, 3100, cooldown = 8, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 28, 3200, 3200, cooldown = 8, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 30, 3200, 3200, cooldown = 8, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 32, 3300, 3300, cooldown = 8, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 34, 3300, 3300, cooldown = 8, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 36, 3400, 3400, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 38, 3400, 3400, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 40, 3500, 3500, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 41, 3500, 3500, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 42, 3600, 3600, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 43, 3600, 3600, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 44, 3700, 3700, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 45, 3700, 3700, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 46, 3800, 3800, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 47, 3800, 3800, cooldown = 8, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 48, 3900, 3900, cooldown = 8, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 49, 3900, 3900, cooldown = 8, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 49, 3900, 3900, cooldown = 8, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 50, 4000, 4000, cooldown = 8, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 50, 4000, 4000, cooldown = 8, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 51, 4000, 4000, cooldown = 8, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 51, 4000, 4000, cooldown = 8, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 52, 4100, 4100, cooldown = 8, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 52, 4100, 4100, cooldown = 8, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 53, 4100, 4100, cooldown = 8, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 53, 4100, 4100, cooldown = 8, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 54, 4200, 4200, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["InspiringCryMercenary"] = { + name = "Inspiring Cry", + hidden = true, + mercenary = true, + inheritedFrom = "DropBearSummonedRallyingCry", + color = 1, + description = "DNT Unused (replaced)", + skillTypes = { [SkillType.Buff] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.25, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "damage_+%", 25 }, + { "base_skill_effect_duration", 4000 }, + { "base_mana_regeneration_rate_per_minute", 888 }, + { "active_skill_area_of_effect_radius_+%_final", -40 }, + }, + stats = { + "base_deal_no_attack_damage", + "base_deal_no_spell_damage", + "base_deal_no_secondary_damage", + }, + levels = { + [1] = { cooldown = 7, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["IntimidatingCryMercenary"] = { + name = "Intimidating Cry", + hidden = true, + mercenary = true, + inheritedFrom = "IntimidatingCry", + color = 1, + description = "Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. The user and nearby allies gain a buff that grants movement speed.", + skillTypes = { [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "intimidating_cry_movement_speed_+%_per_5_power_up_to_cap", 3 }, + { "skill_empowers_next_x_melee_attacks", 2 }, + }, + stats = { + "warcry_speed_+%", + "base_skill_effect_duration", + "base_deal_no_attack_damage", + "base_deal_no_spell_damage", + "base_deal_no_secondary_damage", + "cannot_cancel_skill_before_contact_point", + "warcry_count_power_from_enemies", + "enemies_taunted_by_your_warcies_are_intimidated", + "use_intimidating_cry_buff_visual_for_intimidate", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 0, 2500, cooldown = 8, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 2, 2500, cooldown = 8, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 4, 2600, cooldown = 8, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 6, 2600, cooldown = 8, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 8, 2700, cooldown = 8, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 10, 2700, cooldown = 8, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 12, 2800, cooldown = 8, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 14, 2800, cooldown = 8, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 16, 2900, cooldown = 8, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 18, 2900, cooldown = 8, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 20, 3000, cooldown = 8, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 22, 3000, cooldown = 8, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 24, 3100, cooldown = 8, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 26, 3100, cooldown = 8, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 28, 3200, cooldown = 8, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 30, 3200, cooldown = 8, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 32, 3300, cooldown = 8, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 34, 3300, cooldown = 8, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 36, 3400, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 38, 3400, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 40, 3500, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 41, 3500, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 42, 3600, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 43, 3600, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 44, 3700, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 45, 3700, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 46, 3800, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 47, 3800, cooldown = 8, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 48, 3900, cooldown = 8, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 49, 3900, cooldown = 8, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 49, 3900, cooldown = 8, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 50, 4000, cooldown = 8, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 50, 4000, cooldown = 8, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 51, 4000, cooldown = 8, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 51, 4000, cooldown = 8, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 52, 4100, cooldown = 8, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 52, 4100, cooldown = 8, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 53, 4100, cooldown = 8, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 53, 4100, cooldown = 8, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 54, 4200, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["IntimidatingCryMercenaryEncounter"] = { + name = "Intimidating Cry", + hidden = true, + mercenary = true, + inheritedFrom = "IntimidatingCry", + color = 1, + description = "Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. The user and nearby allies gain a buff that grants movement speed.", + skillTypes = { [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "intimidating_cry_movement_speed_+%_per_5_power_up_to_cap", 3 }, + { "skill_empowers_next_x_melee_attacks", 0 }, + }, + stats = { + "warcry_speed_+%", + "base_skill_effect_duration", + "base_deal_no_attack_damage", + "base_deal_no_spell_damage", + "base_deal_no_secondary_damage", + "cannot_cancel_skill_before_contact_point", + "warcry_count_power_from_enemies", + "enemies_taunted_by_your_warcies_are_intimidated", + "use_intimidating_cry_buff_visual_for_intimidate", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 0, 2500, cooldown = 8, levelRequirement = 10, storedUses = 1, statInterpolation = { 2, 2, }, }, + [2] = { 54, 4200, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 2, 2, }, }, + }, +} + +skills["KineticBlastAltMercenary"] = { + name = "Kinetic Blast of Clustering", + hidden = true, + mercenary = true, + inheritedFrom = "KineticBlastAltX", + color = 3, + description = "Fires a projectile from a Wand that causes a series of area explosions in a secondary radius around its point of impact, each damaging enemies.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Physical] = true, }, + weaponTypes = { + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "cluster_burst_spawn_amount", 3 }, + { "active_skill_base_area_of_effect_radius", 19 }, + { "active_skill_base_secondary_area_of_effect_radius", 8 }, + { "active_skill_additive_spell_damage_modifiers_apply_to_attack_damage_at_%_value", 200 }, + }, + stats = { + "added_physical_damage_to_attacks_equal_to_%_maximum_mana", + "base_is_projectile", + "skill_can_fire_wand_projectiles", + "kinetic_blast_modifiers_to_number_of_projectiles_instead_apply_to_number_of_clusters", + "projectiles_cannot_split", + }, + levels = { + [1] = { 8, attackSpeedMultiplier = 15, baseMultiplier = 1.4, damageEffectiveness = 1.4, levelRequirement = 28, statInterpolation = { 1, }, }, + [2] = { 8, attackSpeedMultiplier = 15, baseMultiplier = 1.408, damageEffectiveness = 1.41, levelRequirement = 31, statInterpolation = { 1, }, }, + [3] = { 9, attackSpeedMultiplier = 15, baseMultiplier = 1.416, damageEffectiveness = 1.42, levelRequirement = 34, statInterpolation = { 1, }, }, + [4] = { 9, attackSpeedMultiplier = 15, baseMultiplier = 1.424, damageEffectiveness = 1.42, levelRequirement = 37, statInterpolation = { 1, }, }, + [5] = { 10, attackSpeedMultiplier = 15, baseMultiplier = 1.432, damageEffectiveness = 1.43, levelRequirement = 40, statInterpolation = { 1, }, }, + [6] = { 10, attackSpeedMultiplier = 15, baseMultiplier = 1.439, damageEffectiveness = 1.44, levelRequirement = 42, statInterpolation = { 1, }, }, + [7] = { 10, attackSpeedMultiplier = 15, baseMultiplier = 1.447, damageEffectiveness = 1.45, levelRequirement = 44, statInterpolation = { 1, }, }, + [8] = { 11, attackSpeedMultiplier = 15, baseMultiplier = 1.455, damageEffectiveness = 1.46, levelRequirement = 46, statInterpolation = { 1, }, }, + [9] = { 11, attackSpeedMultiplier = 15, baseMultiplier = 1.463, damageEffectiveness = 1.46, levelRequirement = 48, statInterpolation = { 1, }, }, + [10] = { 11, attackSpeedMultiplier = 15, baseMultiplier = 1.471, damageEffectiveness = 1.47, levelRequirement = 50, statInterpolation = { 1, }, }, + [11] = { 12, attackSpeedMultiplier = 15, baseMultiplier = 1.479, damageEffectiveness = 1.48, levelRequirement = 52, statInterpolation = { 1, }, }, + [12] = { 12, attackSpeedMultiplier = 15, baseMultiplier = 1.487, damageEffectiveness = 1.49, levelRequirement = 54, statInterpolation = { 1, }, }, + [13] = { 13, attackSpeedMultiplier = 15, baseMultiplier = 1.495, damageEffectiveness = 1.49, levelRequirement = 56, statInterpolation = { 1, }, }, + [14] = { 13, attackSpeedMultiplier = 15, baseMultiplier = 1.503, damageEffectiveness = 1.5, levelRequirement = 58, statInterpolation = { 1, }, }, + [15] = { 13, attackSpeedMultiplier = 15, baseMultiplier = 1.511, damageEffectiveness = 1.51, levelRequirement = 60, statInterpolation = { 1, }, }, + [16] = { 14, attackSpeedMultiplier = 15, baseMultiplier = 1.518, damageEffectiveness = 1.52, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 14, attackSpeedMultiplier = 15, baseMultiplier = 1.526, damageEffectiveness = 1.53, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 15, attackSpeedMultiplier = 15, baseMultiplier = 1.534, damageEffectiveness = 1.53, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 15, attackSpeedMultiplier = 15, baseMultiplier = 1.542, damageEffectiveness = 1.54, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 15, attackSpeedMultiplier = 15, baseMultiplier = 1.55, damageEffectiveness = 1.55, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 16, attackSpeedMultiplier = 15, baseMultiplier = 1.558, damageEffectiveness = 1.56, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 16, attackSpeedMultiplier = 15, baseMultiplier = 1.566, damageEffectiveness = 1.57, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 16, attackSpeedMultiplier = 15, baseMultiplier = 1.574, damageEffectiveness = 1.57, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 17, attackSpeedMultiplier = 15, baseMultiplier = 1.582, damageEffectiveness = 1.58, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 17, attackSpeedMultiplier = 15, baseMultiplier = 1.589, damageEffectiveness = 1.59, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 18, attackSpeedMultiplier = 15, baseMultiplier = 1.597, damageEffectiveness = 1.6, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 18, attackSpeedMultiplier = 15, baseMultiplier = 1.605, damageEffectiveness = 1.61, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 18, attackSpeedMultiplier = 15, baseMultiplier = 1.613, damageEffectiveness = 1.61, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 19, attackSpeedMultiplier = 15, baseMultiplier = 1.621, damageEffectiveness = 1.62, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 19, attackSpeedMultiplier = 15, baseMultiplier = 1.629, damageEffectiveness = 1.63, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 19, attackSpeedMultiplier = 15, baseMultiplier = 1.633, damageEffectiveness = 1.63, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 20, attackSpeedMultiplier = 15, baseMultiplier = 1.637, damageEffectiveness = 1.64, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 20, attackSpeedMultiplier = 15, baseMultiplier = 1.641, damageEffectiveness = 1.64, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 20, attackSpeedMultiplier = 15, baseMultiplier = 1.645, damageEffectiveness = 1.64, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 20, attackSpeedMultiplier = 15, baseMultiplier = 1.649, damageEffectiveness = 1.65, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 20, attackSpeedMultiplier = 15, baseMultiplier = 1.653, damageEffectiveness = 1.65, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 20, attackSpeedMultiplier = 15, baseMultiplier = 1.657, damageEffectiveness = 1.66, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 21, attackSpeedMultiplier = 15, baseMultiplier = 1.661, damageEffectiveness = 1.66, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 21, attackSpeedMultiplier = 15, baseMultiplier = 1.664, damageEffectiveness = 1.66, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 21, attackSpeedMultiplier = 15, baseMultiplier = 1.668, damageEffectiveness = 1.67, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["KineticBoltMercenary"] = { + name = "Kinetic Bolt", + hidden = true, + mercenary = true, + inheritedFrom = "KineticBolt", + color = 3, + description = "Fire a projectile from your wand that changes direction in a zig-zag pattern at regular intervals or when hitting enemies. Each time it changes direction, a secondary projectile breaks off, flying in the direction it changed away from.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.RangedAttack] = true, [SkillType.Triggerable] = true, [SkillType.WandAttack] = true, }, + weaponTypes = { + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "active_skill_additive_spell_damage_modifiers_apply_to_attack_damage_at_%_value", 200 }, + }, + stats = { + "kinetic_wand_base_number_of_zig_zags", + "base_is_projectile", + "skill_can_fire_wand_projectiles", + "kinetic_bolt_forks_apply_to_zig_zags", + }, + levels = { + [1] = { 5, baseMultiplier = 1.6, damageEffectiveness = 1.6, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 5, baseMultiplier = 1.632, damageEffectiveness = 1.632, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 6, baseMultiplier = 1.663, damageEffectiveness = 1.663, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 6, baseMultiplier = 1.695, damageEffectiveness = 1.695, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 6, baseMultiplier = 1.726, damageEffectiveness = 1.726, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 6, baseMultiplier = 1.758, damageEffectiveness = 1.758, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 6, baseMultiplier = 1.789, damageEffectiveness = 1.789, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 6, baseMultiplier = 1.821, damageEffectiveness = 1.821, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 7, baseMultiplier = 1.853, damageEffectiveness = 1.853, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 7, baseMultiplier = 1.884, damageEffectiveness = 1.884, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 7, baseMultiplier = 1.916, damageEffectiveness = 1.916, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 7, baseMultiplier = 1.947, damageEffectiveness = 1.947, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 7, baseMultiplier = 1.979, damageEffectiveness = 1.979, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 7, baseMultiplier = 2.011, damageEffectiveness = 2.011, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 8, baseMultiplier = 2.042, damageEffectiveness = 2.042, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 8, baseMultiplier = 2.074, damageEffectiveness = 2.074, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 8, baseMultiplier = 2.105, damageEffectiveness = 2.105, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 8, baseMultiplier = 2.137, damageEffectiveness = 2.137, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 8, baseMultiplier = 2.168, damageEffectiveness = 2.168, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 8, baseMultiplier = 2.2, damageEffectiveness = 2.2, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 9, baseMultiplier = 2.232, damageEffectiveness = 2.232, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 9, baseMultiplier = 2.263, damageEffectiveness = 2.263, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 9, baseMultiplier = 2.295, damageEffectiveness = 2.295, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 9, baseMultiplier = 2.326, damageEffectiveness = 2.326, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 9, baseMultiplier = 2.358, damageEffectiveness = 2.358, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 9, baseMultiplier = 2.389, damageEffectiveness = 2.389, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 10, baseMultiplier = 2.421, damageEffectiveness = 2.421, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 10, baseMultiplier = 2.453, damageEffectiveness = 2.453, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 10, baseMultiplier = 2.484, damageEffectiveness = 2.484, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 10, baseMultiplier = 2.516, damageEffectiveness = 2.516, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 10, baseMultiplier = 2.532, damageEffectiveness = 2.532, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 10, baseMultiplier = 2.547, damageEffectiveness = 2.547, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 10, baseMultiplier = 2.563, damageEffectiveness = 2.563, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 10, baseMultiplier = 2.579, damageEffectiveness = 2.579, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 10, baseMultiplier = 2.595, damageEffectiveness = 2.595, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 11, baseMultiplier = 2.611, damageEffectiveness = 2.611, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 11, baseMultiplier = 2.626, damageEffectiveness = 2.626, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 11, baseMultiplier = 2.642, damageEffectiveness = 2.642, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 11, baseMultiplier = 2.658, damageEffectiveness = 2.658, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 11, baseMultiplier = 2.674, damageEffectiveness = 2.674, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["KineticRainAltXMercenary"] = { + name = "Kinetic Rain of Impact", + hidden = true, + mercenary = true, + inheritedFrom = "KineticRainAltX", + color = 3, + description = "Swing your wand to cause a number of projectiles to rain down within a large area in front of you, directly targeting the locations of enemies in the area. The locations where each projectile will land are shown with markers before they fall. Each projectile explodes when hitting the ground, dealing area damage.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Projectile] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Totemable] = true, [SkillType.WandAttack] = true, [SkillType.RangedAttack] = true, [SkillType.Rain] = true, }, + weaponTypes = { + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 19, + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 90 }, + { "active_skill_area_of_effect_description_mode", 8 }, + { "active_skill_base_secondary_area_of_effect_radius", 45 }, + { "active_skill_secondary_area_of_effect_description_mode", 8 }, + { "active_skill_base_tertiary_area_of_effect_radius", 12 }, + { "active_skill_tertiary_area_of_effect_description_mode", 1 }, + { "active_skill_additive_spell_damage_modifiers_apply_to_attack_damage_at_%_value", 200 }, + }, + stats = { + "base_number_of_projectiles", + "is_area_damage", + "base_is_projectile", + "quality_display_base_number_of_projectiles_is_gem", + "skill_can_fire_wand_projectiles", + "quality_display_spell_damage_to_attack_damage_is_gem", + }, + levels = { + [1] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.2, damageEffectiveness = 1.2, levelRequirement = 28, statInterpolation = { 1, }, }, + [2] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.208, damageEffectiveness = 1.208, levelRequirement = 31, statInterpolation = { 1, }, }, + [3] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.216, damageEffectiveness = 1.216, levelRequirement = 34, statInterpolation = { 1, }, }, + [4] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.224, damageEffectiveness = 1.224, levelRequirement = 37, statInterpolation = { 1, }, }, + [5] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.232, damageEffectiveness = 1.232, levelRequirement = 40, statInterpolation = { 1, }, }, + [6] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.239, damageEffectiveness = 1.239, levelRequirement = 42, statInterpolation = { 1, }, }, + [7] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.247, damageEffectiveness = 1.247, levelRequirement = 44, statInterpolation = { 1, }, }, + [8] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.255, damageEffectiveness = 1.255, levelRequirement = 46, statInterpolation = { 1, }, }, + [9] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.263, damageEffectiveness = 1.263, levelRequirement = 48, statInterpolation = { 1, }, }, + [10] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.271, damageEffectiveness = 1.271, levelRequirement = 50, statInterpolation = { 1, }, }, + [11] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.279, damageEffectiveness = 1.279, levelRequirement = 52, statInterpolation = { 1, }, }, + [12] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.287, damageEffectiveness = 1.287, levelRequirement = 54, statInterpolation = { 1, }, }, + [13] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.295, damageEffectiveness = 1.295, levelRequirement = 56, statInterpolation = { 1, }, }, + [14] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.303, damageEffectiveness = 1.303, levelRequirement = 58, statInterpolation = { 1, }, }, + [15] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.311, damageEffectiveness = 1.311, levelRequirement = 60, statInterpolation = { 1, }, }, + [16] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.318, damageEffectiveness = 1.318, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.326, damageEffectiveness = 1.326, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.334, damageEffectiveness = 1.334, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.342, damageEffectiveness = 1.342, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.35, damageEffectiveness = 1.35, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.358, damageEffectiveness = 1.358, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.366, damageEffectiveness = 1.366, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.374, damageEffectiveness = 1.374, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.382, damageEffectiveness = 1.382, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.389, damageEffectiveness = 1.389, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.397, damageEffectiveness = 1.397, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.405, damageEffectiveness = 1.405, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.413, damageEffectiveness = 1.413, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.421, damageEffectiveness = 1.421, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.429, damageEffectiveness = 1.429, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.433, damageEffectiveness = 1.433, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.437, damageEffectiveness = 1.437, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.441, damageEffectiveness = 1.441, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.445, damageEffectiveness = 1.445, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.449, damageEffectiveness = 1.449, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.453, damageEffectiveness = 1.453, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.457, damageEffectiveness = 1.457, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.461, damageEffectiveness = 1.461, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.464, damageEffectiveness = 1.464, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 10, attackSpeedMultiplier = 20, baseMultiplier = 1.468, damageEffectiveness = 1.468, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["LacerateMercenary"] = { + name = "Lacerate", + hidden = true, + mercenary = true, + inheritedFrom = "Lacerate", + color = 2, + description = "Slashes twice, releasing waves of force that damage enemies they hit. Enemies in the middle of the slashes can be hit by both. The slashes will have a chance to inflict bleeding in Blood Stance, or have a wider angle in Sand Stance. Can be used with Axes and Swords. You are in Blood Stance by default.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Physical] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "chance_to_bleed_on_hit_%_chance_in_blood_stance", 25 }, + { "skill_angle_+%_in_sand_stance", 50 }, + }, + stats = { + "active_skill_base_radius_+", + "active_skill_bleeding_damage_+%_final_in_blood_stance", + "is_area_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, 50, baseMultiplier = 1.711, damageEffectiveness = 1.711, levelRequirement = 12, statInterpolation = { 1, 1, }, }, + [2] = { 0, 52, baseMultiplier = 1.788, damageEffectiveness = 1.788, levelRequirement = 15, statInterpolation = { 1, 1, }, }, + [3] = { 1, 54, baseMultiplier = 1.871, damageEffectiveness = 1.871, levelRequirement = 19, statInterpolation = { 1, 1, }, }, + [4] = { 1, 56, baseMultiplier = 1.959, damageEffectiveness = 1.959, levelRequirement = 23, statInterpolation = { 1, 1, }, }, + [5] = { 2, 58, baseMultiplier = 2.05, damageEffectiveness = 2.05, levelRequirement = 27, statInterpolation = { 1, 1, }, }, + [6] = { 2, 60, baseMultiplier = 2.146, damageEffectiveness = 2.146, levelRequirement = 31, statInterpolation = { 1, 1, }, }, + [7] = { 3, 62, baseMultiplier = 2.246, damageEffectiveness = 2.246, levelRequirement = 35, statInterpolation = { 1, 1, }, }, + [8] = { 3, 64, baseMultiplier = 2.346, damageEffectiveness = 2.346, levelRequirement = 38, statInterpolation = { 1, 1, }, }, + [9] = { 4, 66, baseMultiplier = 2.451, damageEffectiveness = 2.451, levelRequirement = 41, statInterpolation = { 1, 1, }, }, + [10] = { 4, 68, baseMultiplier = 2.561, damageEffectiveness = 2.561, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [11] = { 5, 70, baseMultiplier = 2.675, damageEffectiveness = 2.675, levelRequirement = 47, statInterpolation = { 1, 1, }, }, + [12] = { 5, 72, baseMultiplier = 2.794, damageEffectiveness = 2.794, levelRequirement = 50, statInterpolation = { 1, 1, }, }, + [13] = { 6, 74, baseMultiplier = 2.918, damageEffectiveness = 2.918, levelRequirement = 53, statInterpolation = { 1, 1, }, }, + [14] = { 6, 76, baseMultiplier = 3.049, damageEffectiveness = 3.049, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [15] = { 7, 78, baseMultiplier = 3.185, damageEffectiveness = 3.185, levelRequirement = 59, statInterpolation = { 1, 1, }, }, + [16] = { 7, 80, baseMultiplier = 3.325, damageEffectiveness = 3.325, levelRequirement = 62, statInterpolation = { 1, 1, }, }, + [17] = { 8, 82, baseMultiplier = 3.468, damageEffectiveness = 3.468, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [18] = { 8, 84, baseMultiplier = 3.616, damageEffectiveness = 3.616, levelRequirement = 66, statInterpolation = { 1, 1, }, }, + [19] = { 9, 86, baseMultiplier = 3.771, damageEffectiveness = 3.771, levelRequirement = 68, statInterpolation = { 1, 1, }, }, + [20] = { 9, 88, baseMultiplier = 3.931, damageEffectiveness = 3.931, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 10, 90, baseMultiplier = 4.099, damageEffectiveness = 4.099, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 10, 92, baseMultiplier = 4.273, damageEffectiveness = 4.273, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 11, 94, baseMultiplier = 4.456, damageEffectiveness = 4.456, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 11, 96, baseMultiplier = 4.646, damageEffectiveness = 4.646, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 12, 98, baseMultiplier = 4.845, damageEffectiveness = 4.845, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 12, 100, baseMultiplier = 5.051, damageEffectiveness = 5.051, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 13, 102, baseMultiplier = 5.266, damageEffectiveness = 5.266, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 13, 104, baseMultiplier = 5.49, damageEffectiveness = 5.49, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 14, 106, baseMultiplier = 5.725, damageEffectiveness = 5.725, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 14, 108, baseMultiplier = 5.968, damageEffectiveness = 5.968, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 14, 109, baseMultiplier = 6.334, damageEffectiveness = 6.334, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 15, 110, baseMultiplier = 6.469, damageEffectiveness = 6.469, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 15, 111, baseMultiplier = 6.607, damageEffectiveness = 6.607, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 15, 112, baseMultiplier = 6.746, damageEffectiveness = 6.746, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 15, 113, baseMultiplier = 6.89, damageEffectiveness = 6.89, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 16, 114, baseMultiplier = 7.037, damageEffectiveness = 7.037, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 16, 115, baseMultiplier = 7.186, damageEffectiveness = 7.186, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 16, 116, baseMultiplier = 7.339, damageEffectiveness = 7.339, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 16, 117, baseMultiplier = 7.494, damageEffectiveness = 7.494, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 17, 118, baseMultiplier = 7.654, damageEffectiveness = 7.654, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["LancingSteelMercenary"] = { + name = "Lancing Steel", + hidden = true, + mercenary = true, + inheritedFrom = "LancingSteel", + color = 2, + description = "Thrust an Axe or Sword forward, consuming your Steel Shards to form a cluster of shards in front of you. The cluster will fire a number of projectiles in sequence, aiming at enemies in front of or close to it. Steel Shards are gained with the Call of Steel Skill.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Damage] = true, [SkillType.ProjectileSpeed] = true, [SkillType.RangedAttack] = true, [SkillType.Physical] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.Steel] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "base_number_of_projectiles", 4 }, + { "attacks_impale_on_hit_%_chance", 20 }, + { "steel_ammo_consumed_per_use", 4 }, + { "number_of_projectiles_to_fire_+%_final_per_steel_ammo_consumed", 50 }, + { "lancing_steel_damage_+%_final_after_first_hit_on_target", -60 }, + }, + stats = { + "base_is_projectile", + }, + levels = { + [1] = { attackSpeedMultiplier = -20, baseMultiplier = 1.1, damageEffectiveness = 1.1, levelRequirement = 28, }, + [2] = { attackSpeedMultiplier = -20, baseMultiplier = 1.134, damageEffectiveness = 1.134, levelRequirement = 31, }, + [3] = { attackSpeedMultiplier = -20, baseMultiplier = 1.168, damageEffectiveness = 1.168, levelRequirement = 34, }, + [4] = { attackSpeedMultiplier = -20, baseMultiplier = 1.203, damageEffectiveness = 1.203, levelRequirement = 37, }, + [5] = { attackSpeedMultiplier = -20, baseMultiplier = 1.237, damageEffectiveness = 1.237, levelRequirement = 40, }, + [6] = { attackSpeedMultiplier = -20, baseMultiplier = 1.271, damageEffectiveness = 1.271, levelRequirement = 42, }, + [7] = { attackSpeedMultiplier = -20, baseMultiplier = 1.305, damageEffectiveness = 1.305, levelRequirement = 44, }, + [8] = { attackSpeedMultiplier = -20, baseMultiplier = 1.339, damageEffectiveness = 1.339, levelRequirement = 46, }, + [9] = { attackSpeedMultiplier = -20, baseMultiplier = 1.374, damageEffectiveness = 1.374, levelRequirement = 48, }, + [10] = { attackSpeedMultiplier = -20, baseMultiplier = 1.408, damageEffectiveness = 1.408, levelRequirement = 50, }, + [11] = { attackSpeedMultiplier = -20, baseMultiplier = 1.442, damageEffectiveness = 1.442, levelRequirement = 52, }, + [12] = { attackSpeedMultiplier = -20, baseMultiplier = 1.476, damageEffectiveness = 1.476, levelRequirement = 54, }, + [13] = { attackSpeedMultiplier = -20, baseMultiplier = 1.511, damageEffectiveness = 1.511, levelRequirement = 56, }, + [14] = { attackSpeedMultiplier = -20, baseMultiplier = 1.545, damageEffectiveness = 1.545, levelRequirement = 58, }, + [15] = { attackSpeedMultiplier = -20, baseMultiplier = 1.579, damageEffectiveness = 1.579, levelRequirement = 60, }, + [16] = { attackSpeedMultiplier = -20, baseMultiplier = 1.613, damageEffectiveness = 1.613, levelRequirement = 62, }, + [17] = { attackSpeedMultiplier = -20, baseMultiplier = 1.647, damageEffectiveness = 1.647, levelRequirement = 64, }, + [18] = { attackSpeedMultiplier = -20, baseMultiplier = 1.682, damageEffectiveness = 1.682, levelRequirement = 66, }, + [19] = { attackSpeedMultiplier = -20, baseMultiplier = 1.716, damageEffectiveness = 1.716, levelRequirement = 68, }, + [20] = { attackSpeedMultiplier = -20, baseMultiplier = 1.75, damageEffectiveness = 1.75, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = -20, baseMultiplier = 1.784, damageEffectiveness = 1.784, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = -20, baseMultiplier = 1.818, damageEffectiveness = 1.818, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = -20, baseMultiplier = 1.853, damageEffectiveness = 1.853, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = -20, baseMultiplier = 1.887, damageEffectiveness = 1.887, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = -20, baseMultiplier = 1.921, damageEffectiveness = 1.921, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = -20, baseMultiplier = 1.955, damageEffectiveness = 1.955, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = -20, baseMultiplier = 1.989, damageEffectiveness = 1.989, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = -20, baseMultiplier = 2.024, damageEffectiveness = 2.024, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = -20, baseMultiplier = 2.058, damageEffectiveness = 2.058, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = -20, baseMultiplier = 2.092, damageEffectiveness = 2.092, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = -20, baseMultiplier = 2.109, damageEffectiveness = 2.109, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = -20, baseMultiplier = 2.126, damageEffectiveness = 2.126, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = -20, baseMultiplier = 2.143, damageEffectiveness = 2.143, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = -20, baseMultiplier = 2.161, damageEffectiveness = 2.161, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = -20, baseMultiplier = 2.178, damageEffectiveness = 2.178, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = -20, baseMultiplier = 2.195, damageEffectiveness = 2.195, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = -20, baseMultiplier = 2.212, damageEffectiveness = 2.212, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = -20, baseMultiplier = 2.229, damageEffectiveness = 2.229, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = -20, baseMultiplier = 2.246, damageEffectiveness = 2.246, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = -20, baseMultiplier = 2.263, damageEffectiveness = 2.263, levelRequirement = 100, }, + }, +} + +skills["LeapSlamMercenary"] = { + name = "Leap Slam", + hidden = true, + mercenary = true, + inheritedFrom = "LeapSlam", + color = 1, + description = "Jump through the air, damaging and knocking back enemies with your weapon where you land. Enemies you would land on are pushed out of the way. Requires an Axe, Mace, Sceptre, Sword or Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Movement] = true, [SkillType.Travel] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.4, + baseFlags = { + area = true, + attack = true, + melee = true, + movement = true, + }, + constantStats = { + { "additional_weapon_base_attack_time_ms", 550 }, + { "active_skill_base_area_of_effect_radius", 15 }, + }, + stats = { + "stun_duration_+%_vs_enemies_that_are_on_full_life", + "is_area_damage", + "always_stun_enemies_that_are_on_full_life", + "leap_slam_always_knockback_within_range", + }, + levels = { + [1] = { 20, baseMultiplier = 1.364, damageEffectiveness = 1.364, levelRequirement = 10, statInterpolation = { 1, }, }, + [2] = { 21, baseMultiplier = 1.425, damageEffectiveness = 1.425, levelRequirement = 13, statInterpolation = { 1, }, }, + [3] = { 22, baseMultiplier = 1.492, damageEffectiveness = 1.492, levelRequirement = 17, statInterpolation = { 1, }, }, + [4] = { 23, baseMultiplier = 1.562, damageEffectiveness = 1.562, levelRequirement = 21, statInterpolation = { 1, }, }, + [5] = { 24, baseMultiplier = 1.634, damageEffectiveness = 1.634, levelRequirement = 25, statInterpolation = { 1, }, }, + [6] = { 25, baseMultiplier = 1.71, damageEffectiveness = 1.71, levelRequirement = 29, statInterpolation = { 1, }, }, + [7] = { 26, baseMultiplier = 1.79, damageEffectiveness = 1.79, levelRequirement = 33, statInterpolation = { 1, }, }, + [8] = { 27, baseMultiplier = 1.871, damageEffectiveness = 1.871, levelRequirement = 36, statInterpolation = { 1, }, }, + [9] = { 28, baseMultiplier = 1.954, damageEffectiveness = 1.954, levelRequirement = 39, statInterpolation = { 1, }, }, + [10] = { 29, baseMultiplier = 2.041, damageEffectiveness = 2.041, levelRequirement = 42, statInterpolation = { 1, }, }, + [11] = { 30, baseMultiplier = 2.133, damageEffectiveness = 2.133, levelRequirement = 45, statInterpolation = { 1, }, }, + [12] = { 31, baseMultiplier = 2.227, damageEffectiveness = 2.227, levelRequirement = 48, statInterpolation = { 1, }, }, + [13] = { 32, baseMultiplier = 2.327, damageEffectiveness = 2.327, levelRequirement = 51, statInterpolation = { 1, }, }, + [14] = { 33, baseMultiplier = 2.431, damageEffectiveness = 2.431, levelRequirement = 54, statInterpolation = { 1, }, }, + [15] = { 34, baseMultiplier = 2.538, damageEffectiveness = 2.538, levelRequirement = 57, statInterpolation = { 1, }, }, + [16] = { 35, baseMultiplier = 2.652, damageEffectiveness = 2.652, levelRequirement = 60, statInterpolation = { 1, }, }, + [17] = { 36, baseMultiplier = 2.77, damageEffectiveness = 2.77, levelRequirement = 63, statInterpolation = { 1, }, }, + [18] = { 37, baseMultiplier = 2.892, damageEffectiveness = 2.892, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 38, baseMultiplier = 3.017, damageEffectiveness = 3.017, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 39, baseMultiplier = 3.145, damageEffectiveness = 3.145, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 40, baseMultiplier = 3.28, damageEffectiveness = 3.28, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 41, baseMultiplier = 3.419, damageEffectiveness = 3.419, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 42, baseMultiplier = 3.565, damageEffectiveness = 3.565, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 43, baseMultiplier = 3.718, damageEffectiveness = 3.718, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 44, baseMultiplier = 3.875, damageEffectiveness = 3.875, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 45, baseMultiplier = 4.041, damageEffectiveness = 4.041, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 46, baseMultiplier = 4.213, damageEffectiveness = 4.213, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 47, baseMultiplier = 4.393, damageEffectiveness = 4.393, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 48, baseMultiplier = 4.58, damageEffectiveness = 4.58, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 49, baseMultiplier = 4.775, damageEffectiveness = 4.775, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 50, baseMultiplier = 5.067, damageEffectiveness = 5.067, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 50, baseMultiplier = 5.175, damageEffectiveness = 5.175, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 51, baseMultiplier = 5.285, damageEffectiveness = 5.285, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 51, baseMultiplier = 5.397, damageEffectiveness = 5.397, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 52, baseMultiplier = 5.513, damageEffectiveness = 5.513, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 52, baseMultiplier = 5.629, damageEffectiveness = 5.629, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 53, baseMultiplier = 5.749, damageEffectiveness = 5.749, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 53, baseMultiplier = 5.871, damageEffectiveness = 5.871, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 54, baseMultiplier = 5.995, damageEffectiveness = 5.995, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 54, baseMultiplier = 6.123, damageEffectiveness = 6.123, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["LeapSlamMercenaryAlt"] = { + name = "Leap Slam of Groundbreaking", + hidden = true, + mercenary = true, + inheritedFrom = "LeapSlamAltX", + color = 1, + description = "Jump a short distance through the air, damaging and knocking back enemies with your weapon where you land. Enemies you would land on are pushed out of the way. Requires an Axe, Mace, Sceptre, Sword or Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Movement] = true, [SkillType.Travel] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.4, + baseFlags = { + area = true, + attack = true, + melee = true, + movement = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 20 }, + }, + stats = { + "stun_duration_+%_vs_enemies_that_are_on_full_life", + "is_area_damage", + "always_stun_enemies_that_are_on_full_life", + "leap_slam_always_knockback_within_range", + }, + levels = { + [1] = { 20, attackSpeedMultiplier = -30, baseMultiplier = 2.864, damageEffectiveness = 2.864, levelRequirement = 10, statInterpolation = { 1, }, }, + [2] = { 21, attackSpeedMultiplier = -30, baseMultiplier = 2.993, damageEffectiveness = 2.993, levelRequirement = 13, statInterpolation = { 1, }, }, + [3] = { 22, attackSpeedMultiplier = -30, baseMultiplier = 3.133, damageEffectiveness = 3.133, levelRequirement = 17, statInterpolation = { 1, }, }, + [4] = { 23, attackSpeedMultiplier = -30, baseMultiplier = 3.279, damageEffectiveness = 3.279, levelRequirement = 21, statInterpolation = { 1, }, }, + [5] = { 24, attackSpeedMultiplier = -30, baseMultiplier = 3.433, damageEffectiveness = 3.433, levelRequirement = 25, statInterpolation = { 1, }, }, + [6] = { 25, attackSpeedMultiplier = -30, baseMultiplier = 3.593, damageEffectiveness = 3.593, levelRequirement = 29, statInterpolation = { 1, }, }, + [7] = { 26, attackSpeedMultiplier = -30, baseMultiplier = 3.76, damageEffectiveness = 3.76, levelRequirement = 33, statInterpolation = { 1, }, }, + [8] = { 27, attackSpeedMultiplier = -30, baseMultiplier = 3.928, damageEffectiveness = 3.928, levelRequirement = 36, statInterpolation = { 1, }, }, + [9] = { 28, attackSpeedMultiplier = -30, baseMultiplier = 4.104, damageEffectiveness = 4.104, levelRequirement = 39, statInterpolation = { 1, }, }, + [10] = { 29, attackSpeedMultiplier = -30, baseMultiplier = 4.287, damageEffectiveness = 4.287, levelRequirement = 42, statInterpolation = { 1, }, }, + [11] = { 30, attackSpeedMultiplier = -30, baseMultiplier = 4.478, damageEffectiveness = 4.478, levelRequirement = 45, statInterpolation = { 1, }, }, + [12] = { 31, attackSpeedMultiplier = -30, baseMultiplier = 4.678, damageEffectiveness = 4.678, levelRequirement = 48, statInterpolation = { 1, }, }, + [13] = { 32, attackSpeedMultiplier = -30, baseMultiplier = 4.887, damageEffectiveness = 4.887, levelRequirement = 51, statInterpolation = { 1, }, }, + [14] = { 33, attackSpeedMultiplier = -30, baseMultiplier = 5.104, damageEffectiveness = 5.104, levelRequirement = 54, statInterpolation = { 1, }, }, + [15] = { 34, attackSpeedMultiplier = -30, baseMultiplier = 5.331, damageEffectiveness = 5.331, levelRequirement = 57, statInterpolation = { 1, }, }, + [16] = { 35, attackSpeedMultiplier = -30, baseMultiplier = 5.569, damageEffectiveness = 5.569, levelRequirement = 60, statInterpolation = { 1, }, }, + [17] = { 36, attackSpeedMultiplier = -30, baseMultiplier = 5.817, damageEffectiveness = 5.817, levelRequirement = 63, statInterpolation = { 1, }, }, + [18] = { 37, attackSpeedMultiplier = -30, baseMultiplier = 6.075, damageEffectiveness = 6.075, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 38, attackSpeedMultiplier = -30, baseMultiplier = 6.335, damageEffectiveness = 6.335, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 39, attackSpeedMultiplier = -30, baseMultiplier = 6.605, damageEffectiveness = 6.605, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 40, attackSpeedMultiplier = -30, baseMultiplier = 6.887, damageEffectiveness = 6.887, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 41, attackSpeedMultiplier = -30, baseMultiplier = 7.18, damageEffectiveness = 7.18, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 42, attackSpeedMultiplier = -30, baseMultiplier = 7.486, damageEffectiveness = 7.486, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 43, attackSpeedMultiplier = -30, baseMultiplier = 7.806, damageEffectiveness = 7.806, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 44, attackSpeedMultiplier = -30, baseMultiplier = 8.139, damageEffectiveness = 8.139, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 45, attackSpeedMultiplier = -30, baseMultiplier = 8.486, damageEffectiveness = 8.486, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 46, attackSpeedMultiplier = -30, baseMultiplier = 8.848, damageEffectiveness = 8.848, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 47, attackSpeedMultiplier = -30, baseMultiplier = 9.224, damageEffectiveness = 9.224, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 48, attackSpeedMultiplier = -30, baseMultiplier = 9.617, damageEffectiveness = 9.617, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 49, attackSpeedMultiplier = -30, baseMultiplier = 10.026, damageEffectiveness = 10.026, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 50, attackSpeedMultiplier = -30, baseMultiplier = 10.642, damageEffectiveness = 10.642, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 50, attackSpeedMultiplier = -30, baseMultiplier = 10.868, damageEffectiveness = 10.868, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 51, attackSpeedMultiplier = -30, baseMultiplier = 11.099, damageEffectiveness = 11.099, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 51, attackSpeedMultiplier = -30, baseMultiplier = 11.335, damageEffectiveness = 11.335, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 52, attackSpeedMultiplier = -30, baseMultiplier = 11.576, damageEffectiveness = 11.576, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 52, attackSpeedMultiplier = -30, baseMultiplier = 11.821, damageEffectiveness = 11.821, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 53, attackSpeedMultiplier = -30, baseMultiplier = 12.073, damageEffectiveness = 12.073, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 53, attackSpeedMultiplier = -30, baseMultiplier = 12.329, damageEffectiveness = 12.329, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 54, attackSpeedMultiplier = -30, baseMultiplier = 12.59, damageEffectiveness = 12.59, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 54, attackSpeedMultiplier = -30, baseMultiplier = 12.858, damageEffectiveness = 12.858, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["LightningArrowMercenary"] = { + name = "Lightning Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "LightningArrow", + color = 2, + description = "Fires a charged arrow which damages enemies by causing them to be struck by a bolt of lightning, which also damages a number of surrounding enemies.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Lightning] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "lightning_arrow_maximum_number_of_extra_targets", 3 }, + }, + stats = { + "active_skill_shock_as_though_damage_+%_final", + "skill_can_fire_arrows", + }, + levels = { + [1] = { 100, baseMultiplier = 1.495, damageEffectiveness = 1.495, levelRequirement = 12, statInterpolation = { 1, }, }, + [2] = { 110, baseMultiplier = 1.51, damageEffectiveness = 1.51, levelRequirement = 15, statInterpolation = { 1, }, }, + [3] = { 120, baseMultiplier = 1.524, damageEffectiveness = 1.524, levelRequirement = 19, statInterpolation = { 1, }, }, + [4] = { 130, baseMultiplier = 1.539, damageEffectiveness = 1.539, levelRequirement = 23, statInterpolation = { 1, }, }, + [5] = { 140, baseMultiplier = 1.554, damageEffectiveness = 1.554, levelRequirement = 27, statInterpolation = { 1, }, }, + [6] = { 150, baseMultiplier = 1.567, damageEffectiveness = 1.567, levelRequirement = 31, statInterpolation = { 1, }, }, + [7] = { 160, baseMultiplier = 1.582, damageEffectiveness = 1.582, levelRequirement = 35, statInterpolation = { 1, }, }, + [8] = { 170, baseMultiplier = 1.596, damageEffectiveness = 1.596, levelRequirement = 38, statInterpolation = { 1, }, }, + [9] = { 180, baseMultiplier = 1.611, damageEffectiveness = 1.611, levelRequirement = 41, statInterpolation = { 1, }, }, + [10] = { 190, baseMultiplier = 1.626, damageEffectiveness = 1.626, levelRequirement = 44, statInterpolation = { 1, }, }, + [11] = { 200, baseMultiplier = 1.64, damageEffectiveness = 1.64, levelRequirement = 47, statInterpolation = { 1, }, }, + [12] = { 210, baseMultiplier = 1.655, damageEffectiveness = 1.655, levelRequirement = 50, statInterpolation = { 1, }, }, + [13] = { 220, baseMultiplier = 1.67, damageEffectiveness = 1.67, levelRequirement = 53, statInterpolation = { 1, }, }, + [14] = { 230, baseMultiplier = 1.684, damageEffectiveness = 1.684, levelRequirement = 56, statInterpolation = { 1, }, }, + [15] = { 240, baseMultiplier = 1.699, damageEffectiveness = 1.699, levelRequirement = 59, statInterpolation = { 1, }, }, + [16] = { 250, baseMultiplier = 1.712, damageEffectiveness = 1.712, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 260, baseMultiplier = 1.727, damageEffectiveness = 1.727, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 270, baseMultiplier = 1.742, damageEffectiveness = 1.742, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 280, baseMultiplier = 1.756, damageEffectiveness = 1.756, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 290, baseMultiplier = 1.771, damageEffectiveness = 1.771, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 300, baseMultiplier = 1.786, damageEffectiveness = 1.786, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 310, baseMultiplier = 1.8, damageEffectiveness = 1.8, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 320, baseMultiplier = 1.815, damageEffectiveness = 1.815, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 330, baseMultiplier = 1.83, damageEffectiveness = 1.83, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 340, baseMultiplier = 1.843, damageEffectiveness = 1.843, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 350, baseMultiplier = 1.858, damageEffectiveness = 1.858, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 360, baseMultiplier = 1.872, damageEffectiveness = 1.872, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 370, baseMultiplier = 1.887, damageEffectiveness = 1.887, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 380, baseMultiplier = 1.902, damageEffectiveness = 1.902, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 390, baseMultiplier = 1.916, damageEffectiveness = 1.916, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 400, baseMultiplier = 1.924, damageEffectiveness = 1.924, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 410, baseMultiplier = 1.931, damageEffectiveness = 1.931, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 420, baseMultiplier = 1.938, damageEffectiveness = 1.938, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 430, baseMultiplier = 1.946, damageEffectiveness = 1.946, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 440, baseMultiplier = 1.953, damageEffectiveness = 1.953, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 450, baseMultiplier = 1.96, damageEffectiveness = 1.96, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 460, baseMultiplier = 1.968, damageEffectiveness = 1.968, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 470, baseMultiplier = 1.975, damageEffectiveness = 1.975, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 480, baseMultiplier = 1.981, damageEffectiveness = 1.981, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 490, baseMultiplier = 1.988, damageEffectiveness = 1.988, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["LightningSpireTrapMercenary"] = { + name = "Lightning Spire Trap", + hidden = true, + mercenary = true, + inheritedFrom = "LightningSpireTrap", + color = 3, + baseEffectiveness = 0.61379998922348, + incrementalEffectiveness = 0.048900000751019, + description = "Throws a trap which, once triggered, will repeatedly strike multiple areas around it for a duration, dealing lightning damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Duration] = true, [SkillType.Damage] = true, [SkillType.Mineable] = true, [SkillType.Area] = true, [SkillType.Trapped] = true, [SkillType.Lightning] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + spell = true, + trap = true, + }, + constantStats = { + { "base_trap_duration", 4000 }, + { "base_skill_effect_duration", 3500 }, + { "lightning_tower_trap_number_of_beams", 3 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "critical_strike_chance_+%_vs_shocked_enemies", + "lightning_tower_trap_base_interval_duration_ms", + "is_area_damage", + "base_skill_is_trapped", + "modifiers_to_trap_throw_speed_apply_to_lightning_spire_trap_frequency", + "is_trap", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, 100, 550, cooldown = 8, critChance = 6, damageEffectiveness = 0.65, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.5, 1.5, 102, 540, cooldown = 8, critChance = 6, damageEffectiveness = 0.65, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.5, 1.5, 104, 530, cooldown = 8, critChance = 6, damageEffectiveness = 0.65, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.5, 1.5, 106, 520, cooldown = 8, critChance = 6, damageEffectiveness = 0.7, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.5, 1.5, 108, 510, cooldown = 8, critChance = 6, damageEffectiveness = 0.7, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.5, 1.5, 110, 500, cooldown = 8, critChance = 6, damageEffectiveness = 0.7, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.5, 1.5, 112, 490, cooldown = 8, critChance = 6, damageEffectiveness = 0.7, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.5, 1.5, 114, 480, cooldown = 8, critChance = 6, damageEffectiveness = 0.75, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.5, 1.5, 116, 470, cooldown = 8, critChance = 6, damageEffectiveness = 0.75, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.5, 1.5, 118, 460, cooldown = 8, critChance = 6, damageEffectiveness = 0.75, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.5, 1.5, 120, 450, cooldown = 8, critChance = 6, damageEffectiveness = 0.75, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.5, 1.5, 122, 440, cooldown = 8, critChance = 6, damageEffectiveness = 0.75, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.5, 1.5, 124, 430, cooldown = 8, critChance = 6, damageEffectiveness = 0.8, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.5, 1.5, 126, 420, cooldown = 8, critChance = 6, damageEffectiveness = 0.8, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.5, 1.5, 128, 410, cooldown = 8, critChance = 6, damageEffectiveness = 0.8, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.5, 1.5, 130, 400, cooldown = 8, critChance = 6, damageEffectiveness = 0.8, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.5, 1.5, 132, 390, cooldown = 8, critChance = 6, damageEffectiveness = 0.8, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.5, 1.5, 134, 380, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.5, 1.5, 136, 370, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.5, 1.5, 138, 360, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.5, 1.5, 140, 350, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.5, 1.5, 142, 345, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.5, 1.5, 144, 340, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.5, 1.5, 146, 335, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.5, 1.5, 148, 330, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.5, 1.5, 150, 325, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.5, 1.5, 152, 320, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.5, 1.5, 154, 315, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.5, 1.5, 156, 310, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.5, 1.5, 158, 305, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.5, 1.5, 159, 303, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.5, 1.5, 160, 300, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.5, 1.5, 161, 298, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.5, 1.5, 162, 295, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.5, 1.5, 163, 293, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.5, 1.5, 164, 290, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.5, 1.5, 165, 288, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.5, 1.5, 166, 285, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.5, 1.5, 167, 283, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.5, 1.5, 168, 280, cooldown = 8, critChance = 6, damageEffectiveness = 0.85, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["LightningStrikeFireMercenary"] = { + name = "Flamebolt Strike", + hidden = true, + mercenary = true, + inheritedFrom = "LightningStrike", + color = 2, + description = "Infuses your melee weapon with electrical energies as you swing. In addition to converting some of your physical damage to lightning damage, the stored energy is released from the weapon as projectiles as you strike, flying out to hit farther-away enemies. The projectiles cannot miss if the melee attack hit a target.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Lightning] = true, [SkillType.ProjectilesNotFromUser] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 50 }, + { "total_projectile_spread_angle_override", 70 }, + { "active_skill_projectile_speed_+%_variation_final", 30 }, + { "active_skill_hit_ailment_damage_with_projectile_+%_final", -50 }, + }, + stats = { + "base_number_of_projectiles", + "show_number_of_projectiles", + }, + levels = { + [1] = { 3, baseMultiplier = 1.985, damageEffectiveness = 1.985, levelRequirement = 12, statInterpolation = { 1, }, }, + [2] = { 3, baseMultiplier = 2.074, damageEffectiveness = 2.074, levelRequirement = 15, statInterpolation = { 1, }, }, + [3] = { 3, baseMultiplier = 2.171, damageEffectiveness = 2.171, levelRequirement = 19, statInterpolation = { 1, }, }, + [4] = { 3, baseMultiplier = 2.273, damageEffectiveness = 2.273, levelRequirement = 23, statInterpolation = { 1, }, }, + [5] = { 3, baseMultiplier = 2.378, damageEffectiveness = 2.378, levelRequirement = 27, statInterpolation = { 1, }, }, + [6] = { 3, baseMultiplier = 2.489, damageEffectiveness = 2.489, levelRequirement = 31, statInterpolation = { 1, }, }, + [7] = { 3, baseMultiplier = 2.605, damageEffectiveness = 2.605, levelRequirement = 35, statInterpolation = { 1, }, }, + [8] = { 3, baseMultiplier = 2.721, damageEffectiveness = 2.721, levelRequirement = 38, statInterpolation = { 1, }, }, + [9] = { 3, baseMultiplier = 2.843, damageEffectiveness = 2.843, levelRequirement = 41, statInterpolation = { 1, }, }, + [10] = { 3, baseMultiplier = 2.97, damageEffectiveness = 2.97, levelRequirement = 44, statInterpolation = { 1, }, }, + [11] = { 3, baseMultiplier = 3.102, damageEffectiveness = 3.102, levelRequirement = 47, statInterpolation = { 1, }, }, + [12] = { 3, baseMultiplier = 3.241, damageEffectiveness = 3.241, levelRequirement = 50, statInterpolation = { 1, }, }, + [13] = { 3, baseMultiplier = 3.385, damageEffectiveness = 3.385, levelRequirement = 53, statInterpolation = { 1, }, }, + [14] = { 3, baseMultiplier = 3.537, damageEffectiveness = 3.537, levelRequirement = 56, statInterpolation = { 1, }, }, + [15] = { 3, baseMultiplier = 3.694, damageEffectiveness = 3.694, levelRequirement = 59, statInterpolation = { 1, }, }, + [16] = { 3, baseMultiplier = 3.858, damageEffectiveness = 3.858, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 3, baseMultiplier = 4.023, damageEffectiveness = 4.023, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 3, baseMultiplier = 4.194, damageEffectiveness = 4.194, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 3, baseMultiplier = 4.373, damageEffectiveness = 4.373, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 3, baseMultiplier = 4.56, damageEffectiveness = 4.56, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 3, baseMultiplier = 4.755, damageEffectiveness = 4.755, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 3, baseMultiplier = 4.958, damageEffectiveness = 4.958, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 3, baseMultiplier = 5.169, damageEffectiveness = 5.169, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 3, baseMultiplier = 5.39, damageEffectiveness = 5.39, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 3, baseMultiplier = 5.62, damageEffectiveness = 5.62, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 3, baseMultiplier = 5.86, damageEffectiveness = 5.86, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 3, baseMultiplier = 6.109, damageEffectiveness = 6.109, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 3, baseMultiplier = 6.37, damageEffectiveness = 6.37, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 3, baseMultiplier = 6.641, damageEffectiveness = 6.641, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 3, baseMultiplier = 6.923, damageEffectiveness = 6.923, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 3, baseMultiplier = 7.348, damageEffectiveness = 7.348, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 3, baseMultiplier = 7.504, damageEffectiveness = 7.504, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 3, baseMultiplier = 7.664, damageEffectiveness = 7.664, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 3, baseMultiplier = 7.826, damageEffectiveness = 7.826, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 3, baseMultiplier = 7.993, damageEffectiveness = 7.993, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 3, baseMultiplier = 8.162, damageEffectiveness = 8.162, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 3, baseMultiplier = 8.336, damageEffectiveness = 8.336, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 3, baseMultiplier = 8.513, damageEffectiveness = 8.513, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 3, baseMultiplier = 8.693, damageEffectiveness = 8.693, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 3, baseMultiplier = 8.878, damageEffectiveness = 8.878, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["LightningTrapMercenary"] = { + name = "Lightning Trap", + hidden = true, + mercenary = true, + inheritedFrom = "LightningTrap", + color = 3, + baseEffectiveness = 2.4788999557495, + incrementalEffectiveness = 0.043200001120567, + description = "Throws a trap that launches a ring of projectiles through the enemy that set it off, dealing lightning damage to them and subsequent targets.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Trapped] = true, [SkillType.Mineable] = true, [SkillType.Lightning] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + projectile = true, + spell = true, + trap = true, + }, + constantStats = { + { "base_trap_duration", 4000 }, + { "base_number_of_projectiles", 9 }, + { "base_chance_to_shock_%", 20 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "shock_effect_+%", + "critical_strike_chance_+%_vs_shocked_enemies", + "projectiles_nova", + "is_trap", + "base_skill_is_trapped", + "base_is_projectile", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, 0, 80, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 12, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.5, 1.5, 1, 82, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 15, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.5, 1.5, 2, 84, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 19, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.5, 1.5, 3, 86, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 23, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.5, 1.5, 4, 88, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 27, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.5, 1.5, 5, 90, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 31, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.5, 1.5, 6, 92, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 35, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.5, 1.5, 7, 94, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 38, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.5, 1.5, 8, 96, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 41, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.5, 1.5, 9, 98, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.5, 1.5, 10, 100, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 47, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.5, 1.5, 11, 102, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 50, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.5, 1.5, 12, 104, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 53, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.5, 1.5, 13, 106, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.5, 1.5, 14, 108, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 59, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.5, 1.5, 15, 110, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 62, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.5, 1.5, 16, 112, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.5, 1.5, 17, 114, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 66, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.5, 1.5, 18, 116, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 68, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.5, 1.5, 19, 118, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.5, 1.5, 20, 120, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.5, 1.5, 21, 122, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.5, 1.5, 22, 124, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.5, 1.5, 23, 126, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.5, 1.5, 24, 128, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.5, 1.5, 25, 130, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.5, 1.5, 26, 132, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.5, 1.5, 27, 134, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.5, 1.5, 28, 136, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.5, 1.5, 29, 138, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.5, 1.5, 29, 139, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.5, 1.5, 30, 140, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.5, 1.5, 30, 141, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.5, 1.5, 31, 142, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.5, 1.5, 31, 143, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.5, 1.5, 32, 144, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.5, 1.5, 32, 145, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.5, 1.5, 33, 146, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.5, 1.5, 33, 147, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.5, 1.5, 34, 148, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["LightningWarpMercenary"] = { + name = "Lightning Warp", + hidden = true, + mercenary = true, + inheritedFrom = "LightningWarp", + color = 3, + baseEffectiveness = 1.2000000476837, + incrementalEffectiveness = 0.045000001788139, + description = "Waits for a duration before teleporting to a targeted destination, with the duration based on the distance and your movement speed. When the teleport occurs, lightning damage is dealt to the area around both where the player was and where they teleported to. Casting again will queue up multiple teleportations to occur in sequence.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Movement] = true, [SkillType.Lightning] = true, [SkillType.AreaSpell] = true, [SkillType.Travel] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "variable_duration_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + movement = true, + spell = true, + }, + constantStats = { + { "max_number_of_lightning_warp_markers", 50 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "skill_effect_duration_+%", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.5, 1.5, -30, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 10, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.5, 1.5, -31, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 13, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.5, 1.5, -32, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 17, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.5, 1.5, -33, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 21, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.5, 1.5, -34, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 25, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.5, 1.5, -35, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 29, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.5, 1.5, -36, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 33, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.5, 1.5, -37, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 36, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.5, 1.5, -38, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 39, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.5, 1.5, -39, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 42, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.5, 1.5, -40, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 45, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.5, 1.5, -41, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 48, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.5, 1.5, -42, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 51, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.5, 1.5, -43, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 54, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.5, 1.5, -44, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 57, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.5, 1.5, -45, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 60, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.5, 1.5, -46, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 63, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.5, 1.5, -47, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 66, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.5, 1.5, -48, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 68, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.5, 1.5, -49, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 70, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.5, 1.5, -50, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 72, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.5, 1.5, -51, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 74, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.5, 1.5, -52, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 76, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.5, 1.5, -53, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 78, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.5, 1.5, -54, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 80, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.5, 1.5, -55, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 82, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.5, 1.5, -56, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 84, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.5, 1.5, -57, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 86, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.5, 1.5, -58, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 88, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.5, 1.5, -59, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 90, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.5, 1.5, -60, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 91, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.5, 1.5, -60, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 92, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.5, 1.5, -61, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 93, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.5, 1.5, -61, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 94, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.5, 1.5, -62, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 95, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.5, 1.5, -62, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 96, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.5, 1.5, -63, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 97, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.5, 1.5, -63, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 98, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.5, 1.5, -64, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 99, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.5, 1.5, -64, 0, cooldown = 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 100, storedUses = 2, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["LightningWarpPhysMercenary"] = { + name = "Bloody Warp", + hidden = true, + mercenary = true, + inheritedFrom = "LightningWarp", + color = 3, + baseEffectiveness = 1.9125000238419, + incrementalEffectiveness = 0.04280000180006, + description = "Waits for a duration before teleporting to a targeted destination, with the duration based on the distance and your movement speed. When the teleport occurs, lightning damage is dealt to the area around both where the player was and where they teleported to. Casting again will queue up multiple teleportations to occur in sequence.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Movement] = true, [SkillType.Lightning] = true, [SkillType.AreaSpell] = true, [SkillType.Travel] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "variable_duration_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + movement = true, + spell = true, + }, + constantStats = { + { "skill_override_pvp_scaling_time_ms", 1000 }, + { "max_number_of_lightning_warp_markers", 50 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "skill_effect_duration_+%", + "active_skill_base_radius_+", + "base_skill_show_average_damage_instead_of_dps", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, -30, 0, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 10, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.10000000149012, 1.8999999761581, -31, 0, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 13, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.10000000149012, 1.8999999761581, -32, 0, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 17, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.10000000149012, 1.8999999761581, -33, 1, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 21, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.10000000149012, 1.8999999761581, -34, 1, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 25, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.10000000149012, 1.8999999761581, -35, 1, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 29, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.10000000149012, 1.8999999761581, -36, 1, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 33, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.10000000149012, 1.8999999761581, -37, 2, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.10000000149012, 1.8999999761581, -38, 2, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 39, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.10000000149012, 1.8999999761581, -39, 2, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.10000000149012, 1.8999999761581, -40, 2, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 45, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.10000000149012, 1.8999999761581, -41, 2, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.10000000149012, 1.8999999761581, -42, 3, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 51, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.10000000149012, 1.8999999761581, -43, 3, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.10000000149012, 1.8999999761581, -44, 3, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 57, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.10000000149012, 1.8999999761581, -45, 3, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.10000000149012, 1.8999999761581, -46, 4, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 63, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.10000000149012, 1.8999999761581, -47, 4, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.10000000149012, 1.8999999761581, -48, 4, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.10000000149012, 1.8999999761581, -49, 4, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.10000000149012, 1.8999999761581, -50, 5, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.10000000149012, 1.8999999761581, -51, 5, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.10000000149012, 1.8999999761581, -52, 5, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.10000000149012, 1.8999999761581, -53, 5, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.10000000149012, 1.8999999761581, -54, 5, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.10000000149012, 1.8999999761581, -55, 6, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.10000000149012, 1.8999999761581, -56, 6, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.10000000149012, 1.8999999761581, -57, 6, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.10000000149012, 1.8999999761581, -58, 6, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.10000000149012, 1.8999999761581, -59, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.10000000149012, 1.8999999761581, -60, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.10000000149012, 1.8999999761581, -60, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.10000000149012, 1.8999999761581, -61, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.10000000149012, 1.8999999761581, -61, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.10000000149012, 1.8999999761581, -62, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.10000000149012, 1.8999999761581, -62, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.10000000149012, 1.8999999761581, -63, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.10000000149012, 1.8999999761581, -63, 7, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.10000000149012, 1.8999999761581, -64, 8, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.10000000149012, 1.8999999761581, -64, 8, cooldown = 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["LightningWarpTrapsMercenary"] = { + name = "Lightning Warp Trap", + hidden = true, + mercenary = true, + inheritedFrom = "LightningWarp", + color = 3, + baseEffectiveness = 1.9125000238419, + incrementalEffectiveness = 0.04280000180006, + description = "Waits for a duration before teleporting to a targeted destination, with the duration based on the distance and your movement speed. When the teleport occurs, lightning damage is dealt to the area around both where the player was and where they teleported to. Casting again will queue up multiple teleportations to occur in sequence.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Movement] = true, [SkillType.Lightning] = true, [SkillType.AreaSpell] = true, [SkillType.Travel] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "variable_duration_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + movement = true, + spell = true, + }, + constantStats = { + { "max_number_of_lightning_warp_markers", 50 }, + { "base_trap_duration", 4000 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "skill_effect_duration_+%", + "active_skill_base_radius_+", + "is_area_damage", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, -30, 0, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 10, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.10000000149012, 1.8999999761581, -31, 0, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 13, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.10000000149012, 1.8999999761581, -32, 0, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 17, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.10000000149012, 1.8999999761581, -33, 1, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 21, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.10000000149012, 1.8999999761581, -34, 1, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 25, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.10000000149012, 1.8999999761581, -35, 1, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 29, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.10000000149012, 1.8999999761581, -36, 1, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 33, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.10000000149012, 1.8999999761581, -37, 2, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.10000000149012, 1.8999999761581, -38, 2, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 39, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.10000000149012, 1.8999999761581, -39, 2, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 42, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.10000000149012, 1.8999999761581, -40, 2, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 45, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.10000000149012, 1.8999999761581, -41, 2, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.10000000149012, 1.8999999761581, -42, 3, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 51, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.10000000149012, 1.8999999761581, -43, 3, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 54, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.10000000149012, 1.8999999761581, -44, 3, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 57, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.10000000149012, 1.8999999761581, -45, 3, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.10000000149012, 1.8999999761581, -46, 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 63, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.10000000149012, 1.8999999761581, -47, 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 66, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.10000000149012, 1.8999999761581, -48, 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 68, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.10000000149012, 1.8999999761581, -49, 4, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.10000000149012, 1.8999999761581, -50, 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.10000000149012, 1.8999999761581, -51, 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.10000000149012, 1.8999999761581, -52, 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.10000000149012, 1.8999999761581, -53, 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.10000000149012, 1.8999999761581, -54, 5, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.10000000149012, 1.8999999761581, -55, 6, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.10000000149012, 1.8999999761581, -56, 6, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.10000000149012, 1.8999999761581, -57, 6, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.10000000149012, 1.8999999761581, -58, 6, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.10000000149012, 1.8999999761581, -59, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.10000000149012, 1.8999999761581, -60, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.10000000149012, 1.8999999761581, -60, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.10000000149012, 1.8999999761581, -61, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.10000000149012, 1.8999999761581, -61, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.10000000149012, 1.8999999761581, -62, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.10000000149012, 1.8999999761581, -62, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.10000000149012, 1.8999999761581, -63, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.10000000149012, 1.8999999761581, -63, 7, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.10000000149012, 1.8999999761581, -64, 8, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.10000000149012, 1.8999999761581, -64, 8, critChance = 6, damageEffectiveness = 0.9, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["LunarisSpellBarrageTrapMercenary"] = { + name = "[DNT] UNUSED", + hidden = true, + mercenary = true, + color = 4, + baseEffectiveness = 1.8181999921799, + incrementalEffectiveness = 0.050000000745058, + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cold] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 100 }, + { "fire_storm_fireball_delay_ms", 300 }, + { "cast_on_trigger_cascade_event_%", 100 }, + { "base_trap_duration", 4000 }, + { "number_of_additional_traps_to_throw", 2 }, + { "throw_traps_in_circle_radius", 20 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "is_area_damage", + "cannot_stun", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 0, statInterpolation = { 3, 3, }, }, + }, +} + +skills["MalevolenceMercenary"] = { + name = "Malevolence", + hidden = true, + mercenary = true, + inheritedFrom = "Malevolence", + color = 3, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.025000000372529, + description = "Casts an aura that multiplies damage over time and increases skill effect duration of you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "delirium_aura_damage_over_time_+%_final", + "active_skill_base_radius_+", + "delirium_skill_effect_duration_+%", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 14, 0, 10, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 14, 1, 10, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 14, 2, 11, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 15, 3, 11, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 15, 4, 12, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 15, 5, 12, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 16, 6, 13, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 16, 7, 13, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 16, 8, 14, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 17, 9, 14, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 17, 10, 15, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 17, 11, 15, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 18, 12, 16, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 18, 13, 16, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 18, 14, 17, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 19, 15, 17, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 19, 16, 18, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 19, 17, 18, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 20, 18, 19, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 20, 19, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 20, 20, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 21, 21, 20, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 21, 22, 21, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 21, 23, 21, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 22, 24, 22, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 22, 25, 22, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 22, 26, 23, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 23, 27, 23, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 23, 28, 24, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 23, 29, 24, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 23, 29, 24, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 24, 30, 25, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 24, 30, 25, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 24, 31, 25, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 24, 31, 25, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 24, 32, 26, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 24, 32, 26, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 25, 33, 26, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 25, 33, 26, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 25, 34, 27, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["MassEnduranceMercenary"] = { + name = "Endure", + hidden = true, + mercenary = true, + color = 4, + baseEffectiveness = 1.8700000047684, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "number_of_endurance_charges_to_gain", 3 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 8, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["MassFrenzyMercenary"] = { + name = "Incite", + hidden = true, + mercenary = true, + inheritedFrom = "MassFrenzy", + color = 4, + baseEffectiveness = 1.8700000047684, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "number_of_frenzy_charges_to_gain", 3 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 8, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["MercenaryLightningDelayedBlast"] = { + name = "Unnerving Blast", + hidden = true, + mercenary = true, + inheritedFrom = "DelayedBlastSpectre", + color = 3, + baseEffectiveness = 4.6251997947693, + incrementalEffectiveness = 0.034400001168251, + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Triggerable] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 40 }, + { "chance_to_unnerve_on_hit_%", 100 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, cooldown = 3.5, critChance = 5, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 5, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["MeteorUpheavalMercenary"] = { + name = "Meteor", + hidden = true, + mercenary = true, + inheritedFrom = "IncursionMeteorUpheaval", + color = 4, + baseEffectiveness = 4.166699886322, + incrementalEffectiveness = 0.03999999910593, + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Fire] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.2, + baseFlags = { + spell = true, + }, + constantStats = { + { "upheaval_number_of_spikes", 4 }, + { "skill_physical_damage_%_to_convert_to_fire", 80 }, + { "active_skill_area_of_effect_+%_final", -30 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, cooldown = 6, critChance = 5, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["MeteorUpheavalMercenaryEncounter"] = { + name = "Meteor", + hidden = true, + mercenary = true, + inheritedFrom = "IncursionMeteorUpheaval", + color = 4, + baseEffectiveness = 3.2999999523163, + incrementalEffectiveness = 0.035999998450279, + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Fire] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.2, + baseFlags = { + spell = true, + }, + constantStats = { + { "upheaval_number_of_spikes", 4 }, + { "skill_physical_damage_%_to_convert_to_fire", 80 }, + { "active_skill_area_of_effect_+%_final", -30 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, cooldown = 6, critChance = 5, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["MirrorArrowMercenary"] = { + name = "Mirror Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "MirrorArrow", + color = 2, + description = "Fires an arrow at the target destination. When the arrow lands, a clone is summoned. The clone is a minion that uses your bow and quiver.", + skillTypes = { [SkillType.ProjectileSpeed] = true, [SkillType.Attack] = true, [SkillType.Minion] = true, [SkillType.RangedAttack] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Movement] = true, [SkillType.Triggerable] = true, [SkillType.CreatesMinion] = true, [SkillType.Travel] = true, [SkillType.Cooldown] = true, [SkillType.Rain] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesFromUser] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "minion_attack_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + minion = true, + movement = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "number_of_monsters_to_summon", 1 }, + { "display_minion_monster_type", 25 }, + }, + stats = { + "base_display_minion_actor_level", + "base_cooldown_speed_+%", + "active_skill_minion_damage_+%_final", + "base_is_projectile", + }, + notMinionStat = { + "base_cooldown_speed_+%", + "active_skill_minion_damage_+%_final", + }, + levels = { + [1] = { 10, 0, 0, cooldown = 6, levelRequirement = 10, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [2] = { 13, 2, 3, cooldown = 6, levelRequirement = 13, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [3] = { 17, 5, 6, cooldown = 6, levelRequirement = 17, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [4] = { 21, 7, 9, cooldown = 6, levelRequirement = 21, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [5] = { 25, 10, 12, cooldown = 6, levelRequirement = 25, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [6] = { 29, 12, 15, cooldown = 6, levelRequirement = 29, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [7] = { 33, 15, 18, cooldown = 6, levelRequirement = 33, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [8] = { 36, 17, 21, cooldown = 6, levelRequirement = 36, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [9] = { 39, 20, 24, cooldown = 6, levelRequirement = 39, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [10] = { 42, 22, 27, cooldown = 6, levelRequirement = 42, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [11] = { 45, 25, 30, cooldown = 6, levelRequirement = 45, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [12] = { 48, 27, 33, cooldown = 6, levelRequirement = 48, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [13] = { 51, 30, 36, cooldown = 6, levelRequirement = 51, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [14] = { 54, 32, 39, cooldown = 6, levelRequirement = 54, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [15] = { 57, 35, 42, cooldown = 6, levelRequirement = 57, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [16] = { 60, 37, 45, cooldown = 6, levelRequirement = 60, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [17] = { 63, 40, 48, cooldown = 6, levelRequirement = 63, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [18] = { 66, 42, 51, cooldown = 6, levelRequirement = 66, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [19] = { 68, 45, 54, cooldown = 6, levelRequirement = 68, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [20] = { 70, 47, 57, cooldown = 6, levelRequirement = 70, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [21] = { 72, 50, 60, cooldown = 6, levelRequirement = 72, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [22] = { 74, 52, 63, cooldown = 6, levelRequirement = 74, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [23] = { 76, 55, 66, cooldown = 6, levelRequirement = 76, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [24] = { 78, 57, 69, cooldown = 6, levelRequirement = 78, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [25] = { 80, 60, 72, cooldown = 6, levelRequirement = 80, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [26] = { 82, 62, 75, cooldown = 6, levelRequirement = 82, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [27] = { 84, 65, 78, cooldown = 6, levelRequirement = 84, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [28] = { 86, 67, 81, cooldown = 6, levelRequirement = 86, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [29] = { 88, 70, 84, cooldown = 6, levelRequirement = 88, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [30] = { 90, 72, 87, cooldown = 6, levelRequirement = 90, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [31] = { 91, 73, 88, cooldown = 6, levelRequirement = 91, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [32] = { 92, 75, 90, cooldown = 6, levelRequirement = 92, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [33] = { 93, 76, 91, cooldown = 6, levelRequirement = 93, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [34] = { 94, 77, 93, cooldown = 6, levelRequirement = 94, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [35] = { 95, 78, 94, cooldown = 6, levelRequirement = 95, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [36] = { 96, 80, 96, cooldown = 6, levelRequirement = 96, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [37] = { 97, 81, 97, cooldown = 6, levelRequirement = 97, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [38] = { 98, 82, 99, cooldown = 6, levelRequirement = 98, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [39] = { 99, 83, 100, cooldown = 6, levelRequirement = 99, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + [40] = { 100, 85, 102, cooldown = 6, levelRequirement = 100, storedUses = 2, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["MoltenShellMercenary"] = { + name = "Molten Shell", + hidden = true, + mercenary = true, + inheritedFrom = "MoltenShell", + color = 1, + baseEffectiveness = 9.6499996185303, + incrementalEffectiveness = 0.016499999910593, + description = "Applies a buff that adds to your armour, and can take some of the damage from hits for you before being depleted. When the buff expires or is depleted, the skill deals reflected damage to enemies around you based on the total damage that was taken from the buff. Shares a cooldown with other Guard skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.TotemCastsWhenNotDetached] = true, [SkillType.Fire] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.Triggerable] = true, [SkillType.Guard] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.4, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "skill_override_pvp_scaling_time_ms", 200 }, + { "molten_shell_damage_absorbed_%", 75 }, + { "molten_shell_damage_absorb_limit_%_of_armour", 10 }, + { "molten_shell_max_damage_absorbed", 5000 }, + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "base_physical_damage_reduction_rating", + "is_area_damage", + "damage_originates_from_initiator_location", + }, + levels = { + [1] = { 1, cooldown = 8, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, }, }, + [2] = { 1, cooldown = 8, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, }, }, + [3] = { 1, cooldown = 8, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, }, }, + [4] = { 1, cooldown = 8, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, }, }, + [5] = { 1, cooldown = 8, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, }, }, + [6] = { 1, cooldown = 8, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, }, }, + [7] = { 1, cooldown = 8, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, }, }, + [8] = { 1, cooldown = 8, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, }, }, + [9] = { 1, cooldown = 8, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, }, }, + [10] = { 1, cooldown = 8, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, }, }, + [11] = { 1, cooldown = 8, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, }, }, + [12] = { 1, cooldown = 8, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, }, }, + [13] = { 1, cooldown = 8, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, }, }, + [14] = { 1, cooldown = 8, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, }, }, + [15] = { 1, cooldown = 8, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, }, }, + [16] = { 1, cooldown = 8, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, }, }, + [17] = { 1, cooldown = 8, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, }, }, + [18] = { 1, cooldown = 8, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, }, }, + [19] = { 1, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, }, }, + [20] = { 1, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, }, }, + [21] = { 1, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, }, }, + [22] = { 1, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, }, }, + [23] = { 1, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, }, }, + [24] = { 1, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, }, }, + [25] = { 1, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, }, }, + [26] = { 1, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, }, }, + [27] = { 1, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, }, }, + [28] = { 1, cooldown = 8, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, }, }, + [29] = { 1, cooldown = 8, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, }, }, + [30] = { 1, cooldown = 8, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, }, }, + [31] = { 1, cooldown = 8, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, }, }, + [32] = { 1, cooldown = 8, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, }, }, + [33] = { 1, cooldown = 8, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, }, }, + [34] = { 1, cooldown = 8, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, }, }, + [35] = { 1, cooldown = 8, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, }, }, + [36] = { 1, cooldown = 8, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, }, }, + [37] = { 1, cooldown = 8, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, }, }, + [38] = { 1, cooldown = 8, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, }, }, + [39] = { 1, cooldown = 8, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, }, }, + [40] = { 1, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["MoltenStrikeHolyMercenary"] = { + name = "Sanctified Strike", + hidden = true, + mercenary = true, + inheritedFrom = "MoltenStrike", + color = 1, + description = "Infuses your melee weapon with molten energies to attack with physical and fire damage. This attack causes balls of molten magma to launch forth from the enemies you hit, divided amongst all enemies hit by the strike. These will deal area attack damage to enemies where they land.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Fire] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.ThresholdJewelChaining] = true, [SkillType.Multistrikeable] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 60 }, + { "base_number_of_projectiles", 4 }, + { "active_skill_hit_ailment_damage_with_projectile_+%_final", -60 }, + }, + stats = { + "show_number_of_projectiles", + }, + levels = { + [1] = { baseMultiplier = 1.265, damageEffectiveness = 1.265, levelRequirement = 1, }, + [2] = { baseMultiplier = 1.324, damageEffectiveness = 1.324, levelRequirement = 2, }, + [3] = { baseMultiplier = 1.389, damageEffectiveness = 1.389, levelRequirement = 4, }, + [4] = { baseMultiplier = 1.46, damageEffectiveness = 1.46, levelRequirement = 7, }, + [5] = { baseMultiplier = 1.537, damageEffectiveness = 1.537, levelRequirement = 11, }, + [6] = { baseMultiplier = 1.62, damageEffectiveness = 1.62, levelRequirement = 16, }, + [7] = { baseMultiplier = 1.705, damageEffectiveness = 1.705, levelRequirement = 20, }, + [8] = { baseMultiplier = 1.794, damageEffectiveness = 1.794, levelRequirement = 24, }, + [9] = { baseMultiplier = 1.889, damageEffectiveness = 1.889, levelRequirement = 28, }, + [10] = { baseMultiplier = 1.988, damageEffectiveness = 1.988, levelRequirement = 32, }, + [11] = { baseMultiplier = 2.092, damageEffectiveness = 2.092, levelRequirement = 36, }, + [12] = { baseMultiplier = 2.201, damageEffectiveness = 2.201, levelRequirement = 40, }, + [13] = { baseMultiplier = 2.316, damageEffectiveness = 2.316, levelRequirement = 44, }, + [14] = { baseMultiplier = 2.437, damageEffectiveness = 2.437, levelRequirement = 48, }, + [15] = { baseMultiplier = 2.564, damageEffectiveness = 2.564, levelRequirement = 52, }, + [16] = { baseMultiplier = 2.697, damageEffectiveness = 2.697, levelRequirement = 56, }, + [17] = { baseMultiplier = 2.837, damageEffectiveness = 2.837, levelRequirement = 60, }, + [18] = { baseMultiplier = 2.985, damageEffectiveness = 2.985, levelRequirement = 64, }, + [19] = { baseMultiplier = 3.135, damageEffectiveness = 3.135, levelRequirement = 67, }, + [20] = { baseMultiplier = 3.292, damageEffectiveness = 3.292, levelRequirement = 70, }, + [21] = { baseMultiplier = 3.452, damageEffectiveness = 3.452, levelRequirement = 72, }, + [22] = { baseMultiplier = 3.619, damageEffectiveness = 3.619, levelRequirement = 74, }, + [23] = { baseMultiplier = 3.794, damageEffectiveness = 3.794, levelRequirement = 76, }, + [24] = { baseMultiplier = 3.977, damageEffectiveness = 3.977, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.17, damageEffectiveness = 4.17, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.372, damageEffectiveness = 4.372, levelRequirement = 82, }, + [27] = { baseMultiplier = 4.583, damageEffectiveness = 4.583, levelRequirement = 84, }, + [28] = { baseMultiplier = 4.805, damageEffectiveness = 4.805, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.037, damageEffectiveness = 5.037, levelRequirement = 88, }, + [30] = { baseMultiplier = 5.281, damageEffectiveness = 5.281, levelRequirement = 90, }, + [31] = { baseMultiplier = 5.651, damageEffectiveness = 5.651, levelRequirement = 91, }, + [32] = { baseMultiplier = 5.787, damageEffectiveness = 5.787, levelRequirement = 92, }, + [33] = { baseMultiplier = 5.927, damageEffectiveness = 5.927, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.07, damageEffectiveness = 6.07, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.216, damageEffectiveness = 6.216, levelRequirement = 95, }, + [36] = { baseMultiplier = 6.367, damageEffectiveness = 6.367, levelRequirement = 96, }, + [37] = { baseMultiplier = 6.519, damageEffectiveness = 6.519, levelRequirement = 97, }, + [38] = { baseMultiplier = 6.677, damageEffectiveness = 6.677, levelRequirement = 98, }, + [39] = { baseMultiplier = 6.837, damageEffectiveness = 6.837, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.003, damageEffectiveness = 7.003, levelRequirement = 100, }, + }, +} + +skills["MoltenStrikeMercenary"] = { + name = "Molten Strike", + hidden = true, + mercenary = true, + inheritedFrom = "MoltenStrike", + color = 1, + description = "Infuses your melee weapon with molten energies to attack with physical and fire damage. This attack causes balls of molten magma to launch forth from the enemies you hit, divided amongst all enemies hit by the strike. These will deal area attack damage to enemies where they land.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Fire] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.ThresholdJewelChaining] = true, [SkillType.Multistrikeable] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + { "base_number_of_projectiles", 4 }, + { "active_skill_hit_ailment_damage_with_projectile_+%_final", -60 }, + }, + stats = { + "show_number_of_projectiles", + }, + levels = { + [1] = { baseMultiplier = 1.265, damageEffectiveness = 1.265, levelRequirement = 1, }, + [2] = { baseMultiplier = 1.324, damageEffectiveness = 1.324, levelRequirement = 2, }, + [3] = { baseMultiplier = 1.389, damageEffectiveness = 1.389, levelRequirement = 4, }, + [4] = { baseMultiplier = 1.46, damageEffectiveness = 1.46, levelRequirement = 7, }, + [5] = { baseMultiplier = 1.537, damageEffectiveness = 1.537, levelRequirement = 11, }, + [6] = { baseMultiplier = 1.62, damageEffectiveness = 1.62, levelRequirement = 16, }, + [7] = { baseMultiplier = 1.705, damageEffectiveness = 1.705, levelRequirement = 20, }, + [8] = { baseMultiplier = 1.794, damageEffectiveness = 1.794, levelRequirement = 24, }, + [9] = { baseMultiplier = 1.889, damageEffectiveness = 1.889, levelRequirement = 28, }, + [10] = { baseMultiplier = 1.988, damageEffectiveness = 1.988, levelRequirement = 32, }, + [11] = { baseMultiplier = 2.092, damageEffectiveness = 2.092, levelRequirement = 36, }, + [12] = { baseMultiplier = 2.201, damageEffectiveness = 2.201, levelRequirement = 40, }, + [13] = { baseMultiplier = 2.316, damageEffectiveness = 2.316, levelRequirement = 44, }, + [14] = { baseMultiplier = 2.437, damageEffectiveness = 2.437, levelRequirement = 48, }, + [15] = { baseMultiplier = 2.564, damageEffectiveness = 2.564, levelRequirement = 52, }, + [16] = { baseMultiplier = 2.697, damageEffectiveness = 2.697, levelRequirement = 56, }, + [17] = { baseMultiplier = 2.837, damageEffectiveness = 2.837, levelRequirement = 60, }, + [18] = { baseMultiplier = 2.985, damageEffectiveness = 2.985, levelRequirement = 64, }, + [19] = { baseMultiplier = 3.135, damageEffectiveness = 3.135, levelRequirement = 67, }, + [20] = { baseMultiplier = 3.292, damageEffectiveness = 3.292, levelRequirement = 70, }, + [21] = { baseMultiplier = 3.452, damageEffectiveness = 3.452, levelRequirement = 72, }, + [22] = { baseMultiplier = 3.619, damageEffectiveness = 3.619, levelRequirement = 74, }, + [23] = { baseMultiplier = 3.794, damageEffectiveness = 3.794, levelRequirement = 76, }, + [24] = { baseMultiplier = 3.977, damageEffectiveness = 3.977, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.17, damageEffectiveness = 4.17, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.372, damageEffectiveness = 4.372, levelRequirement = 82, }, + [27] = { baseMultiplier = 4.583, damageEffectiveness = 4.583, levelRequirement = 84, }, + [28] = { baseMultiplier = 4.805, damageEffectiveness = 4.805, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.037, damageEffectiveness = 5.037, levelRequirement = 88, }, + [30] = { baseMultiplier = 5.281, damageEffectiveness = 5.281, levelRequirement = 90, }, + [31] = { baseMultiplier = 5.651, damageEffectiveness = 5.651, levelRequirement = 91, }, + [32] = { baseMultiplier = 5.787, damageEffectiveness = 5.787, levelRequirement = 92, }, + [33] = { baseMultiplier = 5.927, damageEffectiveness = 5.927, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.07, damageEffectiveness = 6.07, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.216, damageEffectiveness = 6.216, levelRequirement = 95, }, + [36] = { baseMultiplier = 6.367, damageEffectiveness = 6.367, levelRequirement = 96, }, + [37] = { baseMultiplier = 6.519, damageEffectiveness = 6.519, levelRequirement = 97, }, + [38] = { baseMultiplier = 6.677, damageEffectiveness = 6.677, levelRequirement = 98, }, + [39] = { baseMultiplier = 6.837, damageEffectiveness = 6.837, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.003, damageEffectiveness = 7.003, levelRequirement = 100, }, + }, +} + +skills["MoltenStrikePoisonMercenary"] = { + name = "Profane Strike", + hidden = true, + mercenary = true, + inheritedFrom = "MoltenStrike", + color = 2, + description = "Infuses your melee weapon with molten energies to attack with physical and fire damage. This attack causes balls of molten magma to launch forth from the enemies you hit, divided amongst all enemies hit by the strike. These will deal area attack damage to enemies where they land.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Fire] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.ThresholdJewelChaining] = true, [SkillType.Multistrikeable] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_chaos", 40 }, + { "base_number_of_projectiles", 4 }, + { "active_skill_hit_ailment_damage_with_projectile_+%_final", -60 }, + { "base_chance_to_poison_on_hit_%", 30 }, + }, + stats = { + "show_number_of_projectiles", + }, + levels = { + [1] = { baseMultiplier = 1.265, damageEffectiveness = 1.265, levelRequirement = 1, }, + [2] = { baseMultiplier = 1.324, damageEffectiveness = 1.324, levelRequirement = 2, }, + [3] = { baseMultiplier = 1.389, damageEffectiveness = 1.389, levelRequirement = 4, }, + [4] = { baseMultiplier = 1.46, damageEffectiveness = 1.46, levelRequirement = 7, }, + [5] = { baseMultiplier = 1.537, damageEffectiveness = 1.537, levelRequirement = 11, }, + [6] = { baseMultiplier = 1.62, damageEffectiveness = 1.62, levelRequirement = 16, }, + [7] = { baseMultiplier = 1.705, damageEffectiveness = 1.705, levelRequirement = 20, }, + [8] = { baseMultiplier = 1.794, damageEffectiveness = 1.794, levelRequirement = 24, }, + [9] = { baseMultiplier = 1.889, damageEffectiveness = 1.889, levelRequirement = 28, }, + [10] = { baseMultiplier = 1.988, damageEffectiveness = 1.988, levelRequirement = 32, }, + [11] = { baseMultiplier = 2.092, damageEffectiveness = 2.092, levelRequirement = 36, }, + [12] = { baseMultiplier = 2.201, damageEffectiveness = 2.201, levelRequirement = 40, }, + [13] = { baseMultiplier = 2.316, damageEffectiveness = 2.316, levelRequirement = 44, }, + [14] = { baseMultiplier = 2.437, damageEffectiveness = 2.437, levelRequirement = 48, }, + [15] = { baseMultiplier = 2.564, damageEffectiveness = 2.564, levelRequirement = 52, }, + [16] = { baseMultiplier = 2.697, damageEffectiveness = 2.697, levelRequirement = 56, }, + [17] = { baseMultiplier = 2.837, damageEffectiveness = 2.837, levelRequirement = 60, }, + [18] = { baseMultiplier = 2.985, damageEffectiveness = 2.985, levelRequirement = 64, }, + [19] = { baseMultiplier = 3.135, damageEffectiveness = 3.135, levelRequirement = 67, }, + [20] = { baseMultiplier = 3.292, damageEffectiveness = 3.292, levelRequirement = 70, }, + [21] = { baseMultiplier = 3.452, damageEffectiveness = 3.452, levelRequirement = 72, }, + [22] = { baseMultiplier = 3.619, damageEffectiveness = 3.619, levelRequirement = 74, }, + [23] = { baseMultiplier = 3.794, damageEffectiveness = 3.794, levelRequirement = 76, }, + [24] = { baseMultiplier = 3.977, damageEffectiveness = 3.977, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.17, damageEffectiveness = 4.17, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.372, damageEffectiveness = 4.372, levelRequirement = 82, }, + [27] = { baseMultiplier = 4.583, damageEffectiveness = 4.583, levelRequirement = 84, }, + [28] = { baseMultiplier = 4.805, damageEffectiveness = 4.805, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.037, damageEffectiveness = 5.037, levelRequirement = 88, }, + [30] = { baseMultiplier = 5.281, damageEffectiveness = 5.281, levelRequirement = 90, }, + [31] = { baseMultiplier = 5.651, damageEffectiveness = 5.651, levelRequirement = 91, }, + [32] = { baseMultiplier = 5.787, damageEffectiveness = 5.787, levelRequirement = 92, }, + [33] = { baseMultiplier = 5.927, damageEffectiveness = 5.927, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.07, damageEffectiveness = 6.07, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.216, damageEffectiveness = 6.216, levelRequirement = 95, }, + [36] = { baseMultiplier = 6.367, damageEffectiveness = 6.367, levelRequirement = 96, }, + [37] = { baseMultiplier = 6.519, damageEffectiveness = 6.519, levelRequirement = 97, }, + [38] = { baseMultiplier = 6.677, damageEffectiveness = 6.677, levelRequirement = 98, }, + [39] = { baseMultiplier = 6.837, damageEffectiveness = 6.837, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.003, damageEffectiveness = 7.003, levelRequirement = 100, }, + }, +} + +skills["OfferingOfJudgementChaosMercenary"] = { + name = "Altar of Chaos", + hidden = true, + mercenary = true, + inheritedFrom = "AzmeriGoddessOfferingOfJudgement", + color = 4, + baseEffectiveness = 2.666699886322, + incrementalEffectiveness = 0.050000000745058, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Damage] = true, [SkillType.AreaSpell] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "is_area_damage", + "base_is_projectile", + }, + levels = { + [1] = { 16.666667039196, cooldown = 10, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["OrbOfStormsMercenary"] = { + name = "Orb of Storms", + hidden = true, + mercenary = true, + inheritedFrom = "OrbOfStorms", + color = 3, + baseEffectiveness = 0.80000001192093, + incrementalEffectiveness = 0.04619999974966, + description = "Creates a stationary electrical orb that strikes enemies in its area of effect with beams of lightning that can then split to hit more enemies. Modifiers to cast speed will increase how frequently it does this. Casting this skill again will replace the previous orb.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Lightning] = true, [SkillType.Area] = true, [SkillType.Chains] = true, [SkillType.Triggerable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Orb] = true, [SkillType.Multicastable] = true, }, + statDescriptionScope = "beam_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "projectile_number_to_split", 3 }, + { "orb_of_storms_base_channelling_bolt_frequency_ms", 500 }, + { "active_skill_base_area_of_effect_radius", 28 }, + { "active_skill_base_secondary_area_of_effect_radius", 35 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "orb_of_storms_maximum_number_of_hits", + "orb_of_storms_base_bolt_frequency_ms", + "storm_cloud_destroy_when_caster_dies", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, 10, 3500, cooldown = 0.5, damageEffectiveness = 0.8, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.5, 1.5, 11, 3450, cooldown = 0.5, damageEffectiveness = 0.8, levelRequirement = 6, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 4, }, }, + [3] = { 0.5, 1.5, 12, 3400, cooldown = 0.5, damageEffectiveness = 0.9, levelRequirement = 9, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 5, }, }, + [4] = { 0.5, 1.5, 13, 3350, cooldown = 0.5, damageEffectiveness = 0.9, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 5, }, }, + [5] = { 0.5, 1.5, 14, 3300, cooldown = 0.5, damageEffectiveness = 0.9, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 6, }, }, + [6] = { 0.5, 1.5, 15, 3250, cooldown = 0.5, damageEffectiveness = 0.9, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 7, }, }, + [7] = { 0.5, 1.5, 16, 3200, cooldown = 0.5, damageEffectiveness = 0.9, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 7, }, }, + [8] = { 0.5, 1.5, 17, 3150, cooldown = 0.5, damageEffectiveness = 0.9, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 8, }, }, + [9] = { 0.5, 1.5, 18, 3100, cooldown = 0.5, damageEffectiveness = 0.9, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 9, }, }, + [10] = { 0.5, 1.5, 19, 3050, cooldown = 0.5, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 10, }, }, + [11] = { 0.5, 1.5, 20, 3000, cooldown = 0.5, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 10, }, }, + [12] = { 0.5, 1.5, 21, 2950, cooldown = 0.5, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 11, }, }, + [13] = { 0.5, 1.5, 22, 2900, cooldown = 0.5, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 12, }, }, + [14] = { 0.5, 1.5, 23, 2850, cooldown = 0.5, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 12, }, }, + [15] = { 0.5, 1.5, 24, 2800, cooldown = 0.5, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 13, }, }, + [16] = { 0.5, 1.5, 25, 2750, cooldown = 0.5, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 14, }, }, + [17] = { 0.5, 1.5, 26, 2700, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 61, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 14, }, }, + [18] = { 0.5, 1.5, 27, 2650, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 15, }, }, + [19] = { 0.5, 1.5, 28, 2600, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 15, }, }, + [20] = { 0.5, 1.5, 29, 2550, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 16, }, }, + [21] = { 0.5, 1.5, 30, 2500, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 16, }, }, + [22] = { 0.5, 1.5, 31, 2450, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 17, }, }, + [23] = { 0.5, 1.5, 32, 2400, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 17, }, }, + [24] = { 0.5, 1.5, 33, 2350, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 18, }, }, + [25] = { 0.5, 1.5, 34, 2300, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 18, }, }, + [26] = { 0.5, 1.5, 35, 2250, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 18, }, }, + [27] = { 0.5, 1.5, 36, 2200, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 19, }, }, + [28] = { 0.5, 1.5, 37, 2150, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 19, }, }, + [29] = { 0.5, 1.5, 38, 2100, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 19, }, }, + [30] = { 0.5, 1.5, 39, 2050, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 20, }, }, + [31] = { 0.5, 1.5, 39, 2000, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 20, }, }, + [32] = { 0.5, 1.5, 40, 1950, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 20, }, }, + [33] = { 0.5, 1.5, 40, 1900, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 20, }, }, + [34] = { 0.5, 1.5, 41, 1850, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 21, }, }, + [35] = { 0.5, 1.5, 41, 1800, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 21, }, }, + [36] = { 0.5, 1.5, 42, 1750, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 21, }, }, + [37] = { 0.5, 1.5, 42, 1700, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 21, }, }, + [38] = { 0.5, 1.5, 43, 1650, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 21, }, }, + [39] = { 0.5, 1.5, 43, 1600, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 22, }, }, + [40] = { 0.5, 1.5, 44, 1550, cooldown = 0.5, damageEffectiveness = 1.1, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, cost = { Mana = 22, }, }, + }, +} + +skills["PerforateMercenary"] = { + name = "Perforate", + hidden = true, + mercenary = true, + inheritedFrom = "Perforate", + color = 1, + description = "Smash the ground to bring forth multiple spears to damage enemies. When in Blood Stance, multiple spikes burst from the ground in sequence, able to hit enemies multiple times. In Sand Stance, the spikes are thrust outwards. Requires a Sword or Axe. You are in Blood Stance by default.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Melee] = true, [SkillType.Multistrikeable] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "blood_spears_base_number_of_spears", 7 }, + { "blood_spears_damage_+%_final_in_blood_stance", -75 }, + { "blood_spears_aoe_modifiers_apply_to_blood_spear_placement_range_at_%_value", 50 }, + }, + stats = { + "skill_area_of_effect_+%_final_in_sand_stance", + "is_area_damage", + }, + levels = { + [1] = { 0, baseMultiplier = 2.185, damageEffectiveness = 2.185, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 4, baseMultiplier = 2.298, damageEffectiveness = 2.298, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 8, baseMultiplier = 2.422, damageEffectiveness = 2.422, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 12, baseMultiplier = 2.557, damageEffectiveness = 2.557, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 16, baseMultiplier = 2.705, damageEffectiveness = 2.705, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 20, baseMultiplier = 2.866, damageEffectiveness = 2.866, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 24, baseMultiplier = 3.031, damageEffectiveness = 3.031, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 28, baseMultiplier = 3.206, damageEffectiveness = 3.206, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 32, baseMultiplier = 3.389, damageEffectiveness = 3.389, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 36, baseMultiplier = 3.584, damageEffectiveness = 3.584, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 40, baseMultiplier = 3.789, damageEffectiveness = 3.789, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 44, baseMultiplier = 4.007, damageEffectiveness = 4.007, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 48, baseMultiplier = 4.236, damageEffectiveness = 4.236, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 52, baseMultiplier = 4.478, damageEffectiveness = 4.478, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 56, baseMultiplier = 4.734, damageEffectiveness = 4.734, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 60, baseMultiplier = 5.004, damageEffectiveness = 5.004, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 64, baseMultiplier = 5.291, damageEffectiveness = 5.291, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 68, baseMultiplier = 5.592, damageEffectiveness = 5.592, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 72, baseMultiplier = 5.9, damageEffectiveness = 5.9, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 76, baseMultiplier = 6.226, damageEffectiveness = 6.226, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 80, baseMultiplier = 6.558, damageEffectiveness = 6.558, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 84, baseMultiplier = 6.909, damageEffectiveness = 6.909, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 88, baseMultiplier = 7.279, damageEffectiveness = 7.279, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 92, baseMultiplier = 7.667, damageEffectiveness = 7.667, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 96, baseMultiplier = 8.077, damageEffectiveness = 8.077, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 100, baseMultiplier = 8.508, damageEffectiveness = 8.508, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 104, baseMultiplier = 8.962, damageEffectiveness = 8.962, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 108, baseMultiplier = 9.441, damageEffectiveness = 9.441, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 112, baseMultiplier = 9.944, damageEffectiveness = 9.944, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 116, baseMultiplier = 10.475, damageEffectiveness = 10.475, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 118, baseMultiplier = 11.292, damageEffectiveness = 11.292, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 120, baseMultiplier = 11.592, damageEffectiveness = 11.592, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 122, baseMultiplier = 11.901, damageEffectiveness = 11.901, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 124, baseMultiplier = 12.217, damageEffectiveness = 12.217, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 126, baseMultiplier = 12.542, damageEffectiveness = 12.542, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 128, baseMultiplier = 12.876, damageEffectiveness = 12.876, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 130, baseMultiplier = 13.219, damageEffectiveness = 13.219, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 132, baseMultiplier = 13.571, damageEffectiveness = 13.571, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 134, baseMultiplier = 13.932, damageEffectiveness = 13.932, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 136, baseMultiplier = 14.302, damageEffectiveness = 14.302, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["PestilentStrikeMercenary"] = { + name = "Pestilent Strike", + hidden = true, + mercenary = true, + inheritedFrom = "PestilentStrike", + color = 2, + description = "Attacks with your weapon, inflicting a debuff on enemies hit by the strike. If a debuffed enemy dies while poisoned, Pestilent Strike inflicts a secondary chaos damage over time debuff on enemies around them, based on the poisons on the slain enemy. This damage is not affected by your damage modifiers. Requires a Claw or Dagger.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Chaos] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "mamba_strike_deal_%_of_all_poison_total_damage_per_minute", 3000 }, + { "base_secondary_skill_effect_duration", 1000 }, + { "base_chance_to_poison_on_hit_%", 60 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "active_skill_poison_duration_+%_final", 30 }, + { "base_skill_effect_duration", 1000 }, + }, + stats = { + "visual_hit_effect_chaos_is_green", + }, + levels = { + [1] = { baseMultiplier = 2.573, damageEffectiveness = 2.573, levelRequirement = 28, }, + [2] = { baseMultiplier = 2.661, damageEffectiveness = 2.661, levelRequirement = 31, }, + [3] = { baseMultiplier = 2.751, damageEffectiveness = 2.751, levelRequirement = 34, }, + [4] = { baseMultiplier = 2.845, damageEffectiveness = 2.845, levelRequirement = 37, }, + [5] = { baseMultiplier = 2.942, damageEffectiveness = 2.942, levelRequirement = 40, }, + [6] = { baseMultiplier = 3.036, damageEffectiveness = 3.036, levelRequirement = 42, }, + [7] = { baseMultiplier = 3.134, damageEffectiveness = 3.134, levelRequirement = 44, }, + [8] = { baseMultiplier = 3.235, damageEffectiveness = 3.235, levelRequirement = 46, }, + [9] = { baseMultiplier = 3.339, damageEffectiveness = 3.339, levelRequirement = 48, }, + [10] = { baseMultiplier = 3.446, damageEffectiveness = 3.446, levelRequirement = 50, }, + [11] = { baseMultiplier = 3.558, damageEffectiveness = 3.558, levelRequirement = 52, }, + [12] = { baseMultiplier = 3.672, damageEffectiveness = 3.672, levelRequirement = 54, }, + [13] = { baseMultiplier = 3.79, damageEffectiveness = 3.79, levelRequirement = 56, }, + [14] = { baseMultiplier = 3.911, damageEffectiveness = 3.911, levelRequirement = 58, }, + [15] = { baseMultiplier = 4.036, damageEffectiveness = 4.036, levelRequirement = 60, }, + [16] = { baseMultiplier = 4.167, damageEffectiveness = 4.167, levelRequirement = 62, }, + [17] = { baseMultiplier = 4.3, damageEffectiveness = 4.3, levelRequirement = 64, }, + [18] = { baseMultiplier = 4.437, damageEffectiveness = 4.437, levelRequirement = 66, }, + [19] = { baseMultiplier = 4.58, damageEffectiveness = 4.58, levelRequirement = 68, }, + [20] = { baseMultiplier = 4.726, damageEffectiveness = 4.726, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.878, damageEffectiveness = 4.878, levelRequirement = 72, }, + [22] = { baseMultiplier = 5.034, damageEffectiveness = 5.034, levelRequirement = 74, }, + [23] = { baseMultiplier = 5.195, damageEffectiveness = 5.195, levelRequirement = 76, }, + [24] = { baseMultiplier = 5.362, damageEffectiveness = 5.362, levelRequirement = 78, }, + [25] = { baseMultiplier = 5.532, damageEffectiveness = 5.532, levelRequirement = 80, }, + [26] = { baseMultiplier = 5.71, damageEffectiveness = 5.71, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.892, damageEffectiveness = 5.892, levelRequirement = 84, }, + [28] = { baseMultiplier = 6.08, damageEffectiveness = 6.08, levelRequirement = 86, }, + [29] = { baseMultiplier = 6.275, damageEffectiveness = 6.275, levelRequirement = 88, }, + [30] = { baseMultiplier = 6.475, damageEffectiveness = 6.475, levelRequirement = 90, }, + [31] = { baseMultiplier = 6.767, damageEffectiveness = 6.767, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.875, damageEffectiveness = 6.875, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.984, damageEffectiveness = 6.984, levelRequirement = 93, }, + [34] = { baseMultiplier = 7.096, damageEffectiveness = 7.096, levelRequirement = 94, }, + [35] = { baseMultiplier = 7.208, damageEffectiveness = 7.208, levelRequirement = 95, }, + [36] = { baseMultiplier = 7.323, damageEffectiveness = 7.323, levelRequirement = 96, }, + [37] = { baseMultiplier = 7.44, damageEffectiveness = 7.44, levelRequirement = 97, }, + [38] = { baseMultiplier = 7.558, damageEffectiveness = 7.558, levelRequirement = 98, }, + [39] = { baseMultiplier = 7.678, damageEffectiveness = 7.678, levelRequirement = 99, }, + [40] = { baseMultiplier = 7.801, damageEffectiveness = 7.801, levelRequirement = 100, }, + }, +} + +skills["PhysStormCallMercenary"] = { + name = "[DNT] Unused", + hidden = true, + mercenary = true, + inheritedFrom = "StormCall", + color = 3, + baseEffectiveness = 4.5, + incrementalEffectiveness = 0.026000000536442, + description = "Sets a marker at a location. After a short duration, lightning strikes the marker, dealing damage around it and causing lightning strikes at any other markers you've cast.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Lightning] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "active_skill_area_of_effect_radius_+%_final", -13 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, cooldown = 4, critChance = 5, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["PhysicalAegisMercenary"] = { + name = "Physical Aegis", + hidden = true, + mercenary = true, + inheritedFrom = "PhysicalAegis", + color = 4, + description = "Calls forth a protective aegis which takes physical damage from hits for you until depleted. The aegis will be restored to its full value after a short delay if you stop taking physical damage from hits, or if depleted.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Triggerable] = true, [SkillType.Triggered] = true, [SkillType.InbuiltTrigger] = true, [SkillType.Aegis] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "active_skill_display_aegis_variation", 4 }, + { "aegis_recharge_delay_ms", 5000 }, + }, + stats = { + "aegis_unique_shield_max_value", + "cast_on_gain_skill", + "spell_uncastable_if_triggerable", + "no_cost", + }, + levels = { + [1] = { 51, levelRequirement = 24, statInterpolation = { 1, }, }, + [2] = { 125, levelRequirement = 27, statInterpolation = { 1, }, }, + [3] = { 224, levelRequirement = 30, statInterpolation = { 1, }, }, + [4] = { 347, levelRequirement = 33, statInterpolation = { 1, }, }, + [5] = { 495, levelRequirement = 36, statInterpolation = { 1, }, }, + [6] = { 667, levelRequirement = 39, statInterpolation = { 1, }, }, + [7] = { 863, levelRequirement = 42, statInterpolation = { 1, }, }, + [8] = { 1083, levelRequirement = 45, statInterpolation = { 1, }, }, + [9] = { 1327, levelRequirement = 48, statInterpolation = { 1, }, }, + [10] = { 1596, levelRequirement = 50, statInterpolation = { 1, }, }, + [11] = { 1889, levelRequirement = 52, statInterpolation = { 1, }, }, + [12] = { 2206, levelRequirement = 54, statInterpolation = { 1, }, }, + [13] = { 2547, levelRequirement = 56, statInterpolation = { 1, }, }, + [14] = { 2913, levelRequirement = 58, statInterpolation = { 1, }, }, + [15] = { 3303, levelRequirement = 60, statInterpolation = { 1, }, }, + [16] = { 3717, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 4155, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 4618, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 5105, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 5616, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 6151, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 6710, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 7294, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 7902, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 8535, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 9191, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 9872, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 10577, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 11306, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 12059, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 12837, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 13639, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 14465, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 15316, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 16190, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 17089, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 18012, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 18960, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 19931, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 20927, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["PhysicalAegisMercenaryEncounter"] = { + name = "Physical Aegis", + hidden = true, + mercenary = true, + inheritedFrom = "PhysicalAegis", + color = 4, + description = "Calls forth a protective aegis which takes physical damage from hits for you until depleted. The aegis will be restored to its full value after a short delay if you stop taking physical damage from hits, or if depleted.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Triggerable] = true, [SkillType.Triggered] = true, [SkillType.InbuiltTrigger] = true, [SkillType.Aegis] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "active_skill_display_aegis_variation", 4 }, + { "aegis_recharge_delay_ms", 5000 }, + }, + stats = { + "aegis_unique_shield_max_value", + "cast_on_gain_skill", + "spell_uncastable_if_triggerable", + "no_cost", + }, + levels = { + [1] = { 409, levelRequirement = 24, statInterpolation = { 1, }, }, + [2] = { 571, levelRequirement = 27, statInterpolation = { 1, }, }, + [3] = { 783, levelRequirement = 30, statInterpolation = { 1, }, }, + [4] = { 1058, levelRequirement = 33, statInterpolation = { 1, }, }, + [5] = { 1416, levelRequirement = 36, statInterpolation = { 1, }, }, + [6] = { 1875, levelRequirement = 39, statInterpolation = { 1, }, }, + [7] = { 2464, levelRequirement = 42, statInterpolation = { 1, }, }, + [8] = { 3212, levelRequirement = 45, statInterpolation = { 1, }, }, + [9] = { 4159, levelRequirement = 48, statInterpolation = { 1, }, }, + [10] = { 4925, levelRequirement = 50, statInterpolation = { 1, }, }, + [11] = { 6688, levelRequirement = 52, statInterpolation = { 1, }, }, + [12] = { 7878, levelRequirement = 54, statInterpolation = { 1, }, }, + [13] = { 9271, levelRequirement = 56, statInterpolation = { 1, }, }, + [14] = { 10878, levelRequirement = 58, statInterpolation = { 1, }, }, + [15] = { 12736, levelRequirement = 60, statInterpolation = { 1, }, }, + [16] = { 14905, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 17394, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 20265, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 41026, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 47671, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 55327, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 96180, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 111333, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 171642, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 198250, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 228723, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 303561, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 303561, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 303561, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 303561, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 303561, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 303561, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 303561, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 303561, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 303561, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 303561, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 303561, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 303561, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 303561, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 303561, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["PhysicalBeaconMercenary"] = { + name = "Beacons of Faith", + hidden = true, + mercenary = true, + color = 1, + baseEffectiveness = 3.5, + incrementalEffectiveness = 0.031500000506639, + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.2, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "life_regeneration_rate_per_minute_%", 180 }, + { "number_of_beacons", 30 }, + { "beacon_placement_radius", 100 }, + { "active_skill_area_of_effect_radius_+%_final", -45 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_skill_effect_duration", + "is_area_damage", + "firestorm_avoid_unwalkable_terrain", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_skill_effect_duration", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 3300, cooldown = 8, levelRequirement = 3, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 3250, cooldown = 8, levelRequirement = 5, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 3200, cooldown = 8, levelRequirement = 8, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 3150, cooldown = 8, levelRequirement = 11, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 3100, cooldown = 8, levelRequirement = 15, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 3050, cooldown = 8, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 3000, cooldown = 8, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 2950, cooldown = 8, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2900, cooldown = 8, levelRequirement = 29, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2850, cooldown = 8, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2800, cooldown = 8, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 2750, cooldown = 8, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 2700, cooldown = 8, levelRequirement = 45, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 2650, cooldown = 8, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 2600, cooldown = 8, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 2550, cooldown = 8, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 2500, cooldown = 8, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 2450, cooldown = 8, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 2400, cooldown = 8, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 2350, cooldown = 8, levelRequirement = 65, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 2300, cooldown = 8, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 2250, cooldown = 8, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 2200, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 2150, cooldown = 8, levelRequirement = 69, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 2100, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 2000, cooldown = 8, levelRequirement = 71, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 1950, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 1850, cooldown = 8, levelRequirement = 73, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 1800, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 1750, cooldown = 8, levelRequirement = 75, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 1650, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 1600, cooldown = 8, levelRequirement = 77, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 1500, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 1450, cooldown = 8, levelRequirement = 79, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 1350, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 1250, cooldown = 8, levelRequirement = 81, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 1100, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["PoachersMarkMercenary"] = { + name = "Poacher's Mark", + hidden = true, + mercenary = true, + inheritedFrom = "PoachersMark", + color = 2, + baseEffectiveness = 0.25170001387596, + incrementalEffectiveness = 0.024100000038743, + description = "Curses a single enemy, lowering their physical damage reduction, and adding physical damage to all hits against them. Attacking the cursed enemy will grant life and mana, and killing them will grant a frenzy charge. You can only have one Mark at a time.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Mark] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + spell = true, + }, + constantStats = { + { "base_additional_physical_damage_reduction_%", -20 }, + { "chance_to_grant_frenzy_charge_on_death_%", 100 }, + }, + stats = { + "minimum_added_physical_damage_taken", + "maximum_added_physical_damage_taken", + "life_granted_when_hit_by_attacks", + "mana_granted_when_hit_by_attacks", + "base_deal_no_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 15, 8, cooldown = 6, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 17, 9, cooldown = 6, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 19, 10, cooldown = 6, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 21, 11, cooldown = 6, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 24, 12, cooldown = 6, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 26, 13, cooldown = 6, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 28, 14, cooldown = 6, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 30, 15, cooldown = 6, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 33, 16, cooldown = 6, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 34, 17, cooldown = 6, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 36, 18, cooldown = 6, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 37, 19, cooldown = 6, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 39, 19, cooldown = 6, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 40, 20, cooldown = 6, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 42, 21, cooldown = 6, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 43, 22, cooldown = 6, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 45, 22, cooldown = 6, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 46, 23, cooldown = 6, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 48, 24, cooldown = 6, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 50, 25, cooldown = 6, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 51, 25, cooldown = 6, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 53, 26, cooldown = 6, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 54, 27, cooldown = 6, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 56, 27, cooldown = 6, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 57, 28, cooldown = 6, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 59, 29, cooldown = 6, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 60, 30, cooldown = 6, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 62, 30, cooldown = 6, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 63, 31, cooldown = 6, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 65, 32, cooldown = 6, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 65, 32, cooldown = 6, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 66, 33, cooldown = 6, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 67, 33, cooldown = 6, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 68, 33, cooldown = 6, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 69, 34, cooldown = 6, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 69, 34, cooldown = 6, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 70, 34, cooldown = 6, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 71, 35, cooldown = 6, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 72, 35, cooldown = 6, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 72, 36, cooldown = 6, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["PowerSiphonMercenary"] = { + name = "Power Siphon", + hidden = true, + mercenary = true, + inheritedFrom = "PowerSiphon", + color = 3, + description = "Fires your wand to fire a single projectile each at a number of nearby enemies, granting you a power charge if an enemy is killed by, or soon after, the hit.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.WandAttack] = true, }, + weaponTypes = { + ["Wand"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "chance_to_gain_power_charge_on_rare_or_unique_enemy_hit_%", 20 }, + { "critical_strike_multiplier_+_per_power_charge", 20 }, + { "critical_strike_chance_+%_final_per_power_charge_from_power_siphon", 10 }, + { "number_of_projectiles_override", 1 }, + { "active_skill_additive_spell_damage_modifiers_apply_to_attack_damage_at_%_value", 150 }, + }, + stats = { + "power_siphon_base_fire_at_x_targets", + "kill_enemy_on_hit_if_under_10%_life", + "skill_can_fire_wand_projectiles", + "projectiles_are_not_fired", + "skill_can_add_multiple_charges_per_action", + }, + levels = { + [1] = { 4, baseMultiplier = 0.9, damageEffectiveness = 0.9, levelRequirement = 12, statInterpolation = { 1, }, }, + [2] = { 4, baseMultiplier = 0.908, damageEffectiveness = 0.908, levelRequirement = 15, statInterpolation = { 1, }, }, + [3] = { 4, baseMultiplier = 0.916, damageEffectiveness = 0.916, levelRequirement = 19, statInterpolation = { 1, }, }, + [4] = { 4, baseMultiplier = 0.924, damageEffectiveness = 0.924, levelRequirement = 23, statInterpolation = { 1, }, }, + [5] = { 4, baseMultiplier = 0.932, damageEffectiveness = 0.932, levelRequirement = 27, statInterpolation = { 1, }, }, + [6] = { 5, baseMultiplier = 0.939, damageEffectiveness = 0.939, levelRequirement = 31, statInterpolation = { 1, }, }, + [7] = { 5, baseMultiplier = 0.947, damageEffectiveness = 0.947, levelRequirement = 35, statInterpolation = { 1, }, }, + [8] = { 5, baseMultiplier = 0.955, damageEffectiveness = 0.955, levelRequirement = 38, statInterpolation = { 1, }, }, + [9] = { 5, baseMultiplier = 0.963, damageEffectiveness = 0.963, levelRequirement = 41, statInterpolation = { 1, }, }, + [10] = { 5, baseMultiplier = 0.971, damageEffectiveness = 0.971, levelRequirement = 44, statInterpolation = { 1, }, }, + [11] = { 6, baseMultiplier = 0.979, damageEffectiveness = 0.979, levelRequirement = 47, statInterpolation = { 1, }, }, + [12] = { 6, baseMultiplier = 0.987, damageEffectiveness = 0.987, levelRequirement = 50, statInterpolation = { 1, }, }, + [13] = { 6, baseMultiplier = 0.995, damageEffectiveness = 0.995, levelRequirement = 53, statInterpolation = { 1, }, }, + [14] = { 6, baseMultiplier = 1.003, damageEffectiveness = 1.003, levelRequirement = 56, statInterpolation = { 1, }, }, + [15] = { 6, baseMultiplier = 1.011, damageEffectiveness = 1.011, levelRequirement = 59, statInterpolation = { 1, }, }, + [16] = { 7, baseMultiplier = 1.018, damageEffectiveness = 1.018, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 7, baseMultiplier = 1.026, damageEffectiveness = 1.026, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 7, baseMultiplier = 1.034, damageEffectiveness = 1.034, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 7, baseMultiplier = 1.042, damageEffectiveness = 1.042, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 7, baseMultiplier = 1.05, damageEffectiveness = 1.05, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 8, baseMultiplier = 1.058, damageEffectiveness = 1.058, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 8, baseMultiplier = 1.066, damageEffectiveness = 1.066, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 8, baseMultiplier = 1.074, damageEffectiveness = 1.074, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 8, baseMultiplier = 1.082, damageEffectiveness = 1.082, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 8, baseMultiplier = 1.089, damageEffectiveness = 1.089, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 9, baseMultiplier = 1.097, damageEffectiveness = 1.097, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 9, baseMultiplier = 1.105, damageEffectiveness = 1.105, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 9, baseMultiplier = 1.113, damageEffectiveness = 1.113, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 9, baseMultiplier = 1.121, damageEffectiveness = 1.121, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 9, baseMultiplier = 1.129, damageEffectiveness = 1.129, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 10, baseMultiplier = 1.133, damageEffectiveness = 1.133, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 10, baseMultiplier = 1.137, damageEffectiveness = 1.137, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 10, baseMultiplier = 1.141, damageEffectiveness = 1.141, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 10, baseMultiplier = 1.145, damageEffectiveness = 1.145, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 10, baseMultiplier = 1.149, damageEffectiveness = 1.149, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 11, baseMultiplier = 1.153, damageEffectiveness = 1.153, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 11, baseMultiplier = 1.157, damageEffectiveness = 1.157, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 11, baseMultiplier = 1.161, damageEffectiveness = 1.161, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 11, baseMultiplier = 1.164, damageEffectiveness = 1.164, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 11, baseMultiplier = 1.168, damageEffectiveness = 1.168, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["PrecisionMercenary"] = { + name = "Precision", + hidden = true, + mercenary = true, + inheritedFrom = "Precision", + color = 2, + description = "Casts an aura that grants accuracy and critical strike chance to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "accuracy_rating", + "skill_buff_grants_critical_strike_chance_+%", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 93, 20, 0, cooldown = 1.2, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 128, 22, 1, cooldown = 1.2, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 162, 24, 2, cooldown = 1.2, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 193, 26, 3, cooldown = 1.2, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 223, 28, 4, cooldown = 1.2, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 276, 30, 5, cooldown = 1.2, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 305, 32, 6, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 332, 34, 7, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 359, 36, 8, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 385, 38, 9, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 444, 40, 10, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 469, 42, 11, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 493, 44, 12, cooldown = 1.2, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 516, 46, 13, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 539, 48, 14, cooldown = 1.2, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 606, 50, 15, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 630, 52, 16, cooldown = 1.2, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 653, 54, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 677, 56, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 701, 58, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 778, 60, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 804, 62, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 831, 64, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 857, 66, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 883, 68, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 972, 70, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 1000, 72, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 1029, 74, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 1058, 76, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 1087, 78, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 1172, 79, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 1187, 80, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 1203, 81, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 1218, 82, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 1233, 83, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 1324, 84, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 1340, 85, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 1357, 86, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 1374, 87, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 1390, 88, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["PrideMercenary"] = { + name = "Pride", + hidden = true, + mercenary = true, + inheritedFrom = "Pride", + color = 1, + description = "Casts an aura that causes nearby enemies to take more physical damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.AuraAffectsEnemies] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "physical_damage_aura_nearby_enemies_physical_damage_taken_+%", + "physical_damage_aura_nearby_enemies_physical_damage_taken_+%_max", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 15, 30, 0, levelRequirement = 24, statInterpolation = { 1, 1, 1, }, }, + [2] = { 15, 30, 1, levelRequirement = 27, statInterpolation = { 1, 1, 1, }, }, + [3] = { 15, 31, 1, levelRequirement = 30, statInterpolation = { 1, 1, 1, }, }, + [4] = { 15, 31, 2, levelRequirement = 33, statInterpolation = { 1, 1, 1, }, }, + [5] = { 16, 32, 2, levelRequirement = 36, statInterpolation = { 1, 1, 1, }, }, + [6] = { 16, 32, 3, levelRequirement = 39, statInterpolation = { 1, 1, 1, }, }, + [7] = { 16, 33, 3, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [8] = { 16, 33, 4, levelRequirement = 45, statInterpolation = { 1, 1, 1, }, }, + [9] = { 17, 34, 4, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 17, 34, 5, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 17, 35, 5, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 17, 35, 6, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 18, 36, 6, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 18, 36, 7, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 18, 37, 7, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 18, 37, 8, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 19, 38, 8, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 19, 38, 9, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 19, 39, 9, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 19, 39, 10, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 20, 40, 10, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 20, 40, 11, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 20, 41, 11, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 20, 41, 12, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 21, 42, 12, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 21, 42, 13, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 21, 43, 13, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 21, 43, 14, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 22, 44, 14, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 22, 44, 15, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 22, 45, 15, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 22, 45, 15, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 22, 46, 15, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 22, 46, 16, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 22, 47, 16, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 23, 47, 16, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 23, 48, 16, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 23, 48, 17, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 23, 49, 17, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 23, 49, 17, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["ProximityShieldMercenary"] = { + name = "Proximity Shield", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Triggerable] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.1, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 4000 }, + { "active_skill_area_of_effect_radius_+%_final", 15 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 14, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["PunctureMercenary"] = { + name = "Puncture", + hidden = true, + mercenary = true, + inheritedFrom = "Puncture", + color = 2, + description = "Punctures enemies with your Bow, causing a bleeding debuff, which will be affected by modifiers to skill duration.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Physical] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + }, + stats = { + "active_skill_bleeding_damage_+%_final", + "skill_can_fire_arrows", + "global_bleed_on_hit", + "bleed_duration_is_skill_duration", + }, + notMinionStat = { + "active_skill_bleeding_damage_+%_final", + }, + levels = { + [1] = { 30, baseMultiplier = 1.684, damageEffectiveness = 1.684, levelRequirement = 4, statInterpolation = { 1, }, }, + [2] = { 31, baseMultiplier = 1.704, damageEffectiveness = 1.704, levelRequirement = 6, statInterpolation = { 1, }, }, + [3] = { 32, baseMultiplier = 1.723, damageEffectiveness = 1.723, levelRequirement = 9, statInterpolation = { 1, }, }, + [4] = { 33, baseMultiplier = 1.743, damageEffectiveness = 1.743, levelRequirement = 12, statInterpolation = { 1, }, }, + [5] = { 34, baseMultiplier = 1.762, damageEffectiveness = 1.762, levelRequirement = 16, statInterpolation = { 1, }, }, + [6] = { 35, baseMultiplier = 1.782, damageEffectiveness = 1.782, levelRequirement = 20, statInterpolation = { 1, }, }, + [7] = { 36, baseMultiplier = 1.802, damageEffectiveness = 1.802, levelRequirement = 24, statInterpolation = { 1, }, }, + [8] = { 37, baseMultiplier = 1.821, damageEffectiveness = 1.821, levelRequirement = 28, statInterpolation = { 1, }, }, + [9] = { 38, baseMultiplier = 1.841, damageEffectiveness = 1.841, levelRequirement = 32, statInterpolation = { 1, }, }, + [10] = { 39, baseMultiplier = 1.861, damageEffectiveness = 1.861, levelRequirement = 36, statInterpolation = { 1, }, }, + [11] = { 40, baseMultiplier = 1.88, damageEffectiveness = 1.88, levelRequirement = 40, statInterpolation = { 1, }, }, + [12] = { 41, baseMultiplier = 1.9, damageEffectiveness = 1.9, levelRequirement = 44, statInterpolation = { 1, }, }, + [13] = { 42, baseMultiplier = 1.92, damageEffectiveness = 1.92, levelRequirement = 48, statInterpolation = { 1, }, }, + [14] = { 43, baseMultiplier = 1.939, damageEffectiveness = 1.939, levelRequirement = 52, statInterpolation = { 1, }, }, + [15] = { 44, baseMultiplier = 1.959, damageEffectiveness = 1.959, levelRequirement = 55, statInterpolation = { 1, }, }, + [16] = { 45, baseMultiplier = 1.979, damageEffectiveness = 1.979, levelRequirement = 58, statInterpolation = { 1, }, }, + [17] = { 46, baseMultiplier = 1.998, damageEffectiveness = 1.998, levelRequirement = 61, statInterpolation = { 1, }, }, + [18] = { 47, baseMultiplier = 2.017, damageEffectiveness = 2.017, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 48, baseMultiplier = 2.038, damageEffectiveness = 2.038, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 49, baseMultiplier = 2.057, damageEffectiveness = 2.057, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 50, baseMultiplier = 2.076, damageEffectiveness = 2.076, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 51, baseMultiplier = 2.097, damageEffectiveness = 2.097, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 52, baseMultiplier = 2.116, damageEffectiveness = 2.116, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 53, baseMultiplier = 2.135, damageEffectiveness = 2.135, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 54, baseMultiplier = 2.156, damageEffectiveness = 2.156, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 55, baseMultiplier = 2.175, damageEffectiveness = 2.175, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 56, baseMultiplier = 2.194, damageEffectiveness = 2.194, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 57, baseMultiplier = 2.215, damageEffectiveness = 2.215, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 58, baseMultiplier = 2.234, damageEffectiveness = 2.234, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 59, baseMultiplier = 2.253, damageEffectiveness = 2.253, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 60, baseMultiplier = 2.264, damageEffectiveness = 2.264, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 61, baseMultiplier = 2.274, damageEffectiveness = 2.274, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 62, baseMultiplier = 2.283, damageEffectiveness = 2.283, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 63, baseMultiplier = 2.293, damageEffectiveness = 2.293, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 64, baseMultiplier = 2.302, damageEffectiveness = 2.302, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 65, baseMultiplier = 2.312, damageEffectiveness = 2.312, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 66, baseMultiplier = 2.323, damageEffectiveness = 2.323, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 67, baseMultiplier = 2.332, damageEffectiveness = 2.332, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 68, baseMultiplier = 2.342, damageEffectiveness = 2.342, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 69, baseMultiplier = 2.352, damageEffectiveness = 2.352, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["PunctureMercenaryEncounter"] = { + name = "Puncture", + hidden = true, + mercenary = true, + inheritedFrom = "Puncture", + color = 2, + description = "Punctures enemies with your Bow, causing a bleeding debuff, which will be affected by modifiers to skill duration.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Physical] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "base_skill_effect_duration", 4000 }, + }, + stats = { + "active_skill_bleeding_damage_+%_final", + "skill_can_fire_arrows", + "global_bleed_on_hit", + "bleed_duration_is_skill_duration", + }, + notMinionStat = { + "active_skill_bleeding_damage_+%_final", + }, + levels = { + [1] = { 30, attackSpeedMultiplier = -40, baseMultiplier = 1.5472, damageEffectiveness = 1.5472, levelRequirement = 4, statInterpolation = { 1, }, }, + [2] = { 31, attackSpeedMultiplier = -40, baseMultiplier = 1.5632, damageEffectiveness = 1.5632, levelRequirement = 6, statInterpolation = { 1, }, }, + [3] = { 32, attackSpeedMultiplier = -40, baseMultiplier = 1.5784, damageEffectiveness = 1.5784, levelRequirement = 9, statInterpolation = { 1, }, }, + [4] = { 33, attackSpeedMultiplier = -40, baseMultiplier = 1.5944, damageEffectiveness = 1.5944, levelRequirement = 12, statInterpolation = { 1, }, }, + [5] = { 34, attackSpeedMultiplier = -40, baseMultiplier = 1.6096, damageEffectiveness = 1.6096, levelRequirement = 16, statInterpolation = { 1, }, }, + [6] = { 35, attackSpeedMultiplier = -40, baseMultiplier = 1.6256, damageEffectiveness = 1.6256, levelRequirement = 20, statInterpolation = { 1, }, }, + [7] = { 36, attackSpeedMultiplier = -40, baseMultiplier = 1.6416, damageEffectiveness = 1.6416, levelRequirement = 24, statInterpolation = { 1, }, }, + [8] = { 37, attackSpeedMultiplier = -40, baseMultiplier = 1.6568, damageEffectiveness = 1.6568, levelRequirement = 28, statInterpolation = { 1, }, }, + [9] = { 38, attackSpeedMultiplier = -40, baseMultiplier = 1.6728, damageEffectiveness = 1.6728, levelRequirement = 32, statInterpolation = { 1, }, }, + [10] = { 39, attackSpeedMultiplier = -40, baseMultiplier = 1.6888, damageEffectiveness = 1.6888, levelRequirement = 36, statInterpolation = { 1, }, }, + [11] = { 40, attackSpeedMultiplier = -40, baseMultiplier = 1.704, damageEffectiveness = 1.704, levelRequirement = 40, statInterpolation = { 1, }, }, + [12] = { 41, attackSpeedMultiplier = -40, baseMultiplier = 1.72, damageEffectiveness = 1.72, levelRequirement = 44, statInterpolation = { 1, }, }, + [13] = { 42, attackSpeedMultiplier = -40, baseMultiplier = 1.736, damageEffectiveness = 1.736, levelRequirement = 48, statInterpolation = { 1, }, }, + [14] = { 43, attackSpeedMultiplier = -40, baseMultiplier = 1.7512, damageEffectiveness = 1.7512, levelRequirement = 52, statInterpolation = { 1, }, }, + [15] = { 44, attackSpeedMultiplier = -40, baseMultiplier = 1.7672, damageEffectiveness = 1.7672, levelRequirement = 55, statInterpolation = { 1, }, }, + [16] = { 45, attackSpeedMultiplier = -40, baseMultiplier = 1.7832, damageEffectiveness = 1.7832, levelRequirement = 58, statInterpolation = { 1, }, }, + [17] = { 46, attackSpeedMultiplier = -40, baseMultiplier = 1.7984, damageEffectiveness = 1.7984, levelRequirement = 61, statInterpolation = { 1, }, }, + [18] = { 47, attackSpeedMultiplier = -40, baseMultiplier = 1.8136, damageEffectiveness = 1.8136, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 48, attackSpeedMultiplier = -40, baseMultiplier = 1.8304, damageEffectiveness = 1.8304, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 49, attackSpeedMultiplier = -40, baseMultiplier = 1.8456, damageEffectiveness = 1.8456, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 50, attackSpeedMultiplier = -40, baseMultiplier = 1.8608, damageEffectiveness = 1.8608, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 51, attackSpeedMultiplier = -40, baseMultiplier = 1.8776, damageEffectiveness = 1.8776, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 52, attackSpeedMultiplier = -40, baseMultiplier = 1.8928, damageEffectiveness = 1.8928, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 53, attackSpeedMultiplier = -40, baseMultiplier = 1.908, damageEffectiveness = 1.908, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 54, attackSpeedMultiplier = -40, baseMultiplier = 1.9248, damageEffectiveness = 1.9248, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 55, attackSpeedMultiplier = -40, baseMultiplier = 1.94, damageEffectiveness = 1.94, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 56, attackSpeedMultiplier = -40, baseMultiplier = 1.9552, damageEffectiveness = 1.9552, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 57, attackSpeedMultiplier = -40, baseMultiplier = 1.972, damageEffectiveness = 1.972, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 58, attackSpeedMultiplier = -40, baseMultiplier = 1.9872, damageEffectiveness = 1.9872, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 59, attackSpeedMultiplier = -40, baseMultiplier = 2.0024, damageEffectiveness = 2.0024, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 60, attackSpeedMultiplier = -40, baseMultiplier = 2.0112, damageEffectiveness = 2.0112, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 61, attackSpeedMultiplier = -40, baseMultiplier = 2.0192, damageEffectiveness = 2.0192, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 62, attackSpeedMultiplier = -40, baseMultiplier = 2.0264, damageEffectiveness = 2.0264, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 63, attackSpeedMultiplier = -40, baseMultiplier = 2.0344, damageEffectiveness = 2.0344, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 64, attackSpeedMultiplier = -40, baseMultiplier = 2.0416, damageEffectiveness = 2.0416, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 65, attackSpeedMultiplier = -40, baseMultiplier = 2.0496, damageEffectiveness = 2.0496, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 66, attackSpeedMultiplier = -40, baseMultiplier = 2.0584, damageEffectiveness = 2.0584, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 67, attackSpeedMultiplier = -40, baseMultiplier = 2.0656, damageEffectiveness = 2.0656, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 68, attackSpeedMultiplier = -40, baseMultiplier = 2.0736, damageEffectiveness = 2.0736, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 69, attackSpeedMultiplier = -40, baseMultiplier = 2.0816, damageEffectiveness = 2.0816, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["PunishmentMercenary"] = { + name = "Punishment", + hidden = true, + mercenary = true, + inheritedFrom = "Punishment", + color = 1, + description = "Curses all targets in an area, causing them to be debilitated when they hit enemies and increasing damage they take while on low life.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "debilitate_self_for_x_milliseconds_on_hit", 2000 }, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "damage_taken_+%_on_low_life", + "base_deal_no_damage", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 8000, 0, 30, levelRequirement = 24, statInterpolation = { 1, 1, 1, }, }, + [2] = { 8200, 1, 31, levelRequirement = 27, statInterpolation = { 1, 1, 1, }, }, + [3] = { 8400, 1, 33, levelRequirement = 30, statInterpolation = { 1, 1, 1, }, }, + [4] = { 8600, 2, 34, levelRequirement = 33, statInterpolation = { 1, 1, 1, }, }, + [5] = { 8800, 2, 36, levelRequirement = 36, statInterpolation = { 1, 1, 1, }, }, + [6] = { 9000, 3, 37, levelRequirement = 39, statInterpolation = { 1, 1, 1, }, }, + [7] = { 9200, 3, 39, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [8] = { 9400, 4, 40, levelRequirement = 45, statInterpolation = { 1, 1, 1, }, }, + [9] = { 9600, 4, 42, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9800, 5, 43, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10000, 5, 45, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 10200, 6, 46, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 10400, 6, 48, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 10600, 7, 49, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 10800, 7, 51, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 11000, 8, 52, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 11200, 8, 54, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 11400, 9, 55, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 11600, 9, 57, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 11800, 10, 58, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 12000, 10, 60, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 12200, 11, 61, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 12400, 11, 63, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 12600, 12, 64, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 12800, 12, 66, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 13000, 13, 67, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 13200, 13, 69, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 13400, 14, 70, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 13600, 14, 72, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 13800, 15, 73, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 13900, 15, 74, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 14000, 15, 75, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 14100, 15, 75, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 14200, 16, 76, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 14300, 16, 77, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 14400, 16, 78, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 14500, 16, 78, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 14600, 17, 79, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 14700, 17, 80, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 14800, 17, 81, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["PurifyingFlameMercenary"] = { + name = "Purifying Flame", + hidden = true, + mercenary = true, + inheritedFrom = "PurifyingFlame", + color = 3, + baseEffectiveness = 2.4525001049042, + incrementalEffectiveness = 0.046799998730421, + description = "A wave of divine fire deals damage in a line, then creates Consecrated Ground and deals damage in an area around the targeted location. A larger shockwave then expands outwards, damaging enemies standing on Consecrated Ground that were not already hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 50 }, + { "ignite_art_variation", 7 }, + { "sanctify_wave_damage_+%_final", -25 }, + { "base_skill_effect_duration", 4000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + "active_skill_ground_consecration_radius_+", + "is_area_damage", + "visual_hit_effect_elemental_is_holy", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, 0, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, 0, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 2, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 4, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 0, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 7, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 0, 1, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 11, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 0, 2, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 16, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, 2, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 20, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 1, 2, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 24, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 1, 3, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 28, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 1, 3, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 32, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 1, 3, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 1, 4, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 40, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 1, 4, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 2, 4, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 2, 5, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 52, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 2, 5, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 2, 5, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 2, 6, critChance = 6, damageEffectiveness = 2.9, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 2, 6, critChance = 6, damageEffectiveness = 2.9, levelRequirement = 67, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 2, 6, critChance = 6, damageEffectiveness = 3, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 3, 7, critChance = 6, damageEffectiveness = 3, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 3, 7, critChance = 6, damageEffectiveness = 3, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 3, 7, critChance = 6, damageEffectiveness = 3, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 3, 8, critChance = 6, damageEffectiveness = 3, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 3, 8, critChance = 6, damageEffectiveness = 3, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 3, 8, critChance = 6, damageEffectiveness = 3, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 3, 9, critChance = 6, damageEffectiveness = 3, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 4, 9, critChance = 6, damageEffectiveness = 3, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 4, 9, critChance = 6, damageEffectiveness = 3, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 4, 10, critChance = 6, damageEffectiveness = 3, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 4, 10, critChance = 6, damageEffectiveness = 3, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 4, 10, critChance = 6, damageEffectiveness = 3, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 4, 10, critChance = 6, damageEffectiveness = 3, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 4, 10, critChance = 6, damageEffectiveness = 3, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 4, 10, critChance = 6, damageEffectiveness = 3, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 4, 11, critChance = 6, damageEffectiveness = 3, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 4, 11, critChance = 6, damageEffectiveness = 3, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 4, 11, critChance = 6, damageEffectiveness = 3, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 4, 11, critChance = 6, damageEffectiveness = 3, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 5, 11, critChance = 6, damageEffectiveness = 3, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["PurifyingFlameMercenaryEncounter"] = { + name = "Purifying Flame", + hidden = true, + mercenary = true, + inheritedFrom = "PurifyingFlame", + color = 3, + baseEffectiveness = 2, + incrementalEffectiveness = 0.042500000447035, + description = "A wave of divine fire deals damage in a line, then creates Consecrated Ground and deals damage in an area around the targeted location. A larger shockwave then expands outwards, damaging enemies standing on Consecrated Ground that were not already hit.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 50 }, + { "ignite_art_variation", 7 }, + { "sanctify_wave_damage_+%_final", -25 }, + { "base_skill_effect_duration", 4000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + "active_skill_ground_consecration_radius_+", + "is_area_damage", + "visual_hit_effect_elemental_is_holy", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 4, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 0, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["PurityOfFireMercenary"] = { + name = "Purity of Fire", + hidden = true, + mercenary = true, + inheritedFrom = "PurityOfFire", + color = 1, + description = "Casts an aura that grants fire resistance to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Fire] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "base_fire_damage_resistance_%", + "base_maximum_fire_damage_resistance_%", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 22, 0, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 23, 0, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 24, 0, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 25, 0, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 26, 1, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 27, 1, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 28, 1, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 29, 1, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 30, 1, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 31, 1, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 32, 2, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 33, 2, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 34, 2, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 35, 2, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 36, 2, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 37, 2, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 38, 3, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 39, 3, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 40, 3, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 41, 4, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 42, 4, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 43, 4, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 44, 5, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 45, 5, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 46, 5, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 47, 5, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 48, 5, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 49, 5, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 50, 5, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 51, 5, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 51, 5, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 52, 5, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 52, 5, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 53, 5, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 53, 5, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 54, 5, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 54, 5, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 55, 5, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 55, 5, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 56, 5, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["PurityOfIceMercenary"] = { + name = "Purity of Ice", + hidden = true, + mercenary = true, + inheritedFrom = "PurityOfIce", + color = 2, + description = "Casts an aura that grants cold resistance to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Cold] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "base_cold_damage_resistance_%", + "base_maximum_cold_damage_resistance_%", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 22, 0, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 23, 0, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 24, 0, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 25, 0, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 26, 1, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 27, 1, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 28, 1, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 29, 1, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 30, 1, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 31, 1, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 32, 2, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 33, 2, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 34, 2, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 35, 2, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 36, 2, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 37, 2, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 38, 3, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 39, 3, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 40, 3, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 41, 4, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 42, 4, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 43, 4, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 44, 5, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 45, 5, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 46, 5, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 47, 5, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 48, 5, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 49, 5, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 50, 5, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 51, 5, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 51, 5, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 52, 5, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 52, 5, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 53, 5, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 53, 5, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 54, 5, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 54, 5, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 55, 5, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 55, 5, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 56, 5, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["PurityOfLightningMercenary"] = { + name = "Purity of Lightning", + hidden = true, + mercenary = true, + inheritedFrom = "PurityOfLightning", + color = 3, + description = "Casts an aura that grants lightning resistance to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Lightning] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "base_lightning_damage_resistance_%", + "base_maximum_lightning_damage_resistance_%", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 22, 0, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 23, 0, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 24, 0, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 25, 0, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 26, 1, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 27, 1, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 28, 1, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 29, 1, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 30, 1, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 31, 1, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 32, 2, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 33, 2, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 34, 2, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 35, 2, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 36, 2, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 37, 2, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 38, 3, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 39, 3, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 40, 3, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 41, 4, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 42, 4, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 43, 4, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 44, 5, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 45, 5, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 46, 5, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 47, 5, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 48, 5, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 49, 5, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 50, 5, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 51, 5, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 51, 5, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 52, 5, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 52, 5, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 53, 5, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 53, 5, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 54, 5, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 54, 5, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 55, 5, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 55, 5, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 56, 5, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["QuickGuardAllyMercenary"] = { + name = "Steelskin Ally", + hidden = true, + mercenary = true, + inheritedFrom = "QuickGuard", + color = 1, + baseEffectiveness = 10, + incrementalEffectiveness = 0.029999999329448, + description = "Applies a buff which can take some of the damage from hits for you before being depleted. Shares a cooldown with other Guard skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Instant] = true, [SkillType.Duration] = true, [SkillType.Triggerable] = true, [SkillType.Guard] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "quick_guard_damage_absorbed_%", 75 }, + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "quick_guard_damage_absorb_limit", + "base_deal_no_damage", + }, + levels = { + [1] = { 1, cooldown = 4, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, }, }, + [2] = { 1, cooldown = 4, levelRequirement = 6, storedUses = 1, statInterpolation = { 3, }, }, + [3] = { 1, cooldown = 4, levelRequirement = 9, storedUses = 1, statInterpolation = { 3, }, }, + [4] = { 1, cooldown = 4, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, }, }, + [5] = { 1, cooldown = 4, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, }, }, + [6] = { 1, cooldown = 4, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, }, }, + [7] = { 1, cooldown = 4, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, }, }, + [8] = { 1, cooldown = 4, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, }, }, + [9] = { 1, cooldown = 4, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, }, }, + [10] = { 1, cooldown = 4, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, }, }, + [11] = { 1, cooldown = 4, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, }, }, + [12] = { 1, cooldown = 4, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, }, }, + [13] = { 1, cooldown = 4, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, }, }, + [14] = { 1, cooldown = 4, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, }, }, + [15] = { 1, cooldown = 4, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, }, }, + [16] = { 1, cooldown = 4, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, }, }, + [17] = { 1, cooldown = 4, levelRequirement = 61, storedUses = 1, statInterpolation = { 3, }, }, + [18] = { 1, cooldown = 4, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, }, }, + [19] = { 1, cooldown = 4, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, }, }, + [20] = { 1, cooldown = 4, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, }, }, + [21] = { 1, cooldown = 4, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, }, }, + [22] = { 1, cooldown = 4, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, }, }, + [23] = { 1, cooldown = 4, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, }, }, + [24] = { 1, cooldown = 4, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, }, }, + [25] = { 1, cooldown = 4, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, }, }, + [26] = { 1, cooldown = 4, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, }, }, + [27] = { 1, cooldown = 4, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, }, }, + [28] = { 1, cooldown = 4, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, }, }, + [29] = { 1, cooldown = 4, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, }, }, + [30] = { 1, cooldown = 4, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, }, }, + [31] = { 1, cooldown = 4, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, }, }, + [32] = { 1, cooldown = 4, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, }, }, + [33] = { 1, cooldown = 4, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, }, }, + [34] = { 1, cooldown = 4, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, }, }, + [35] = { 1, cooldown = 4, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, }, }, + [36] = { 1, cooldown = 4, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, }, }, + [37] = { 1, cooldown = 4, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, }, }, + [38] = { 1, cooldown = 4, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, }, }, + [39] = { 1, cooldown = 4, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, }, }, + [40] = { 1, cooldown = 4, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["RainOfArrowsAltMercenary"] = { + name = "Rain of Arrows of Saturation", + hidden = true, + mercenary = true, + inheritedFrom = "RainOfArrowsAltY", + color = 2, + description = "Fires multiple arrows into the air, to slowly land in sequence after a delay, starting at the targeted location and spreading outwards in all directions. Each arrow deals damage in an area around it. Half of the arrows will land directly on targets if there are targets in their range.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.ProjectileNumber] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + }, + stats = { + "base_number_of_arrows", + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + "cannot_pierce", + }, + levels = { + [1] = { 27, baseMultiplier = 0.25, cooldown = 2, damageEffectiveness = 0.25, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 27, baseMultiplier = 0.255, cooldown = 2, damageEffectiveness = 0.255, levelRequirement = 15, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 27, baseMultiplier = 0.261, cooldown = 2, damageEffectiveness = 0.261, levelRequirement = 19, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 27, baseMultiplier = 0.266, cooldown = 2, damageEffectiveness = 0.266, levelRequirement = 23, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 29, baseMultiplier = 0.271, cooldown = 2, damageEffectiveness = 0.271, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 29, baseMultiplier = 0.276, cooldown = 2, damageEffectiveness = 0.276, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 29, baseMultiplier = 0.282, cooldown = 2, damageEffectiveness = 0.282, levelRequirement = 35, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 29, baseMultiplier = 0.287, cooldown = 2, damageEffectiveness = 0.287, levelRequirement = 38, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 30, baseMultiplier = 0.292, cooldown = 2, damageEffectiveness = 0.292, levelRequirement = 41, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 30, baseMultiplier = 0.297, cooldown = 2, damageEffectiveness = 0.297, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 30, baseMultiplier = 0.303, cooldown = 2, damageEffectiveness = 0.303, levelRequirement = 47, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 30, baseMultiplier = 0.308, cooldown = 2, damageEffectiveness = 0.308, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 32, baseMultiplier = 0.313, cooldown = 2, damageEffectiveness = 0.313, levelRequirement = 53, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 32, baseMultiplier = 0.318, cooldown = 2, damageEffectiveness = 0.318, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 32, baseMultiplier = 0.324, cooldown = 2, damageEffectiveness = 0.324, levelRequirement = 59, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 32, baseMultiplier = 0.329, cooldown = 2, damageEffectiveness = 0.329, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 33, baseMultiplier = 0.334, cooldown = 2, damageEffectiveness = 0.334, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 33, baseMultiplier = 0.339, cooldown = 2, damageEffectiveness = 0.339, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 33, baseMultiplier = 0.345, cooldown = 2, damageEffectiveness = 0.345, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 33, baseMultiplier = 0.35, cooldown = 2, damageEffectiveness = 0.35, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 35, baseMultiplier = 0.355, cooldown = 2, damageEffectiveness = 0.355, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 35, baseMultiplier = 0.361, cooldown = 2, damageEffectiveness = 0.361, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 35, baseMultiplier = 0.366, cooldown = 2, damageEffectiveness = 0.366, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 35, baseMultiplier = 0.371, cooldown = 2, damageEffectiveness = 0.371, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 36, baseMultiplier = 0.376, cooldown = 2, damageEffectiveness = 0.376, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 36, baseMultiplier = 0.382, cooldown = 2, damageEffectiveness = 0.382, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 36, baseMultiplier = 0.387, cooldown = 2, damageEffectiveness = 0.387, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 36, baseMultiplier = 0.392, cooldown = 2, damageEffectiveness = 0.392, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 38, baseMultiplier = 0.397, cooldown = 2, damageEffectiveness = 0.397, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 38, baseMultiplier = 0.403, cooldown = 2, damageEffectiveness = 0.403, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 38, baseMultiplier = 0.405, cooldown = 2, damageEffectiveness = 0.405, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 38, baseMultiplier = 0.408, cooldown = 2, damageEffectiveness = 0.408, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 38, baseMultiplier = 0.411, cooldown = 2, damageEffectiveness = 0.411, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 38, baseMultiplier = 0.413, cooldown = 2, damageEffectiveness = 0.413, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 38, baseMultiplier = 0.416, cooldown = 2, damageEffectiveness = 0.416, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 39, baseMultiplier = 0.418, cooldown = 2, damageEffectiveness = 0.418, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 39, baseMultiplier = 0.421, cooldown = 2, damageEffectiveness = 0.421, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 39, baseMultiplier = 0.424, cooldown = 2, damageEffectiveness = 0.424, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 39, baseMultiplier = 0.426, cooldown = 2, damageEffectiveness = 0.426, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 39, baseMultiplier = 0.429, cooldown = 2, damageEffectiveness = 0.429, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["RaiseSpectreAltMercenary"] = { + name = "Raise Spectre of Transience", + hidden = true, + mercenary = true, + inheritedFrom = "RaiseSpectreAltX", + color = 3, + baseEffectiveness = 0, + description = "Raises a spectral version of a defeated foe as a temporary minion to fight for you in battle for a duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, [SkillType.Duration] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Projectile] = true, [SkillType.Chains] = true, [SkillType.Duration] = true, [SkillType.SummonsTotem] = true, [SkillType.Trapped] = true, [SkillType.RemoteMined] = true, [SkillType.DamageOverTime] = true, [SkillType.Channel] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Warcry] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.65, + baseFlags = { + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "minion_critical_strike_chance_+%", 1000 }, + { "spectres_have_base_duration_ms", 30000 }, + { "active_skill_minion_movement_velocity_+%_final", 55 }, + { "movement_velocity_cap", -53 }, + { "minion_elemental_resistance_%", 30 }, + }, + stats = { + "base_number_of_spectres_allowed", + "raised_spectre_level", + "accuracy_rating", + "cannot_use_spectre_corpses", + }, + levels = { + [1] = { 4, 28, 0, levelRequirement = 28, statInterpolation = { 1, 1, 1, }, }, + [2] = { 4, 31, 0, levelRequirement = 31, statInterpolation = { 1, 1, 1, }, }, + [3] = { 4, 34, 0, levelRequirement = 34, statInterpolation = { 1, 1, 1, }, }, + [4] = { 4, 37, 0, levelRequirement = 37, statInterpolation = { 1, 1, 1, }, }, + [5] = { 4, 40, 0, levelRequirement = 40, statInterpolation = { 1, 1, 1, }, }, + [6] = { 4, 42, 0, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [7] = { 4, 44, 0, levelRequirement = 44, statInterpolation = { 1, 1, 1, }, }, + [8] = { 4, 46, 0, levelRequirement = 46, statInterpolation = { 1, 1, 1, }, }, + [9] = { 4, 48, 0, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 4, 50, 0, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 5, 52, 0, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 5, 54, 0, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 5, 56, 0, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 5, 58, 0, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 5, 60, 0, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 5, 62, 0, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 5, 64, 0, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 5, 66, 0, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 5, 68, 0, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 6, 70, 0, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 6, 72, 0, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 6, 73, 0, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 6, 74, 0, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 6, 75, 0, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 6, 76, 0, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 6, 77, 0, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 6, 78, 0, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 6, 79, 0, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 7, 80, 0, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 7, 81, 0, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 7, 82, 0, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 7, 83, 0, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 7, 84, 0, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 7, 85, 0, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 7, 86, 0, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 7, 87, 0, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 7, 88, 0, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 7, 89, 0, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 7, 90, 0, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 7, 91, 0, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["RaiseSpectreAltMercenaryEncounter"] = { + name = "Raise Spectre of Transience", + hidden = true, + mercenary = true, + inheritedFrom = "RaiseSpectreAltX", + color = 3, + baseEffectiveness = 0, + description = "Raises a spectral version of a defeated foe as a temporary minion to fight for you in battle for a duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, [SkillType.Duration] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Projectile] = true, [SkillType.Chains] = true, [SkillType.Duration] = true, [SkillType.SummonsTotem] = true, [SkillType.Trapped] = true, [SkillType.RemoteMined] = true, [SkillType.DamageOverTime] = true, [SkillType.Channel] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Warcry] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.65, + baseFlags = { + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "minion_critical_strike_chance_+%", 1000 }, + { "spectres_have_base_duration_ms", 30000 }, + { "active_skill_minion_movement_velocity_+%_final", 55 }, + { "movement_velocity_cap", -53 }, + { "minion_elemental_resistance_%", 30 }, + { "active_skill_minion_damage_+%_final", -50 }, + }, + stats = { + "base_number_of_spectres_allowed", + "raised_spectre_level", + "accuracy_rating", + "cannot_use_spectre_corpses", + }, + levels = { + [1] = { 4, 28, 0, levelRequirement = 28, statInterpolation = { 1, 1, 1, }, }, + [2] = { 4, 31, 0, levelRequirement = 31, statInterpolation = { 1, 1, 1, }, }, + [3] = { 4, 34, 0, levelRequirement = 34, statInterpolation = { 1, 1, 1, }, }, + [4] = { 4, 37, 0, levelRequirement = 37, statInterpolation = { 1, 1, 1, }, }, + [5] = { 4, 40, 0, levelRequirement = 40, statInterpolation = { 1, 1, 1, }, }, + [6] = { 4, 42, 0, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [7] = { 4, 44, 0, levelRequirement = 44, statInterpolation = { 1, 1, 1, }, }, + [8] = { 4, 46, 0, levelRequirement = 46, statInterpolation = { 1, 1, 1, }, }, + [9] = { 4, 48, 0, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [10] = { 4, 50, 0, levelRequirement = 50, statInterpolation = { 1, 1, 1, }, }, + [11] = { 5, 52, 0, levelRequirement = 52, statInterpolation = { 1, 1, 1, }, }, + [12] = { 5, 54, 0, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [13] = { 5, 56, 0, levelRequirement = 56, statInterpolation = { 1, 1, 1, }, }, + [14] = { 5, 58, 0, levelRequirement = 58, statInterpolation = { 1, 1, 1, }, }, + [15] = { 5, 60, 0, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [16] = { 5, 62, 0, levelRequirement = 62, statInterpolation = { 1, 1, 1, }, }, + [17] = { 5, 64, 0, levelRequirement = 64, statInterpolation = { 1, 1, 1, }, }, + [18] = { 5, 66, 0, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 5, 68, 0, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 6, 70, 0, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 6, 72, 0, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 6, 73, 0, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 6, 74, 0, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 6, 75, 0, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 6, 76, 0, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 6, 77, 0, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 6, 78, 0, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 6, 79, 0, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 7, 80, 0, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 7, 81, 0, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 7, 82, 0, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 7, 83, 0, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 7, 84, 0, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 7, 85, 0, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 7, 86, 0, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 7, 87, 0, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 7, 88, 0, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 7, 89, 0, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 7, 90, 0, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 7, 91, 0, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["RaiseZombieAltMercenary"] = { + name = "Raise Zombie of Falling", + hidden = true, + mercenary = true, + inheritedFrom = "RaiseZombieAltY", + color = 3, + description = "Raises necromantic energies into the sky above a targeted location, where they coalesce into a zombie minion. The minion then attacks by falling to the ground, causing an impact that deals damage in an area. The zombie cannot survive the impact.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + minion = true, + spell = true, + }, + constantStats = { + { "active_skill_minion_from_alternate_gem_index", 2 }, + { "base_number_of_zombies_allowed", 200 }, + }, + stats = { + "raise_zombie_does_not_use_corpses", + }, + levels = { + [1] = { levelRequirement = 1, }, + [2] = { levelRequirement = 2, }, + [3] = { levelRequirement = 4, }, + [4] = { levelRequirement = 7, }, + [5] = { levelRequirement = 11, }, + [6] = { levelRequirement = 16, }, + [7] = { levelRequirement = 20, }, + [8] = { levelRequirement = 24, }, + [9] = { levelRequirement = 28, }, + [10] = { levelRequirement = 32, }, + [11] = { levelRequirement = 36, }, + [12] = { levelRequirement = 40, }, + [13] = { levelRequirement = 44, }, + [14] = { levelRequirement = 48, }, + [15] = { levelRequirement = 52, }, + [16] = { levelRequirement = 56, }, + [17] = { levelRequirement = 60, }, + [18] = { levelRequirement = 64, }, + [19] = { levelRequirement = 67, }, + [20] = { levelRequirement = 70, }, + [21] = { levelRequirement = 72, }, + [22] = { levelRequirement = 74, }, + [23] = { levelRequirement = 76, }, + [24] = { levelRequirement = 78, }, + [25] = { levelRequirement = 80, }, + [26] = { levelRequirement = 82, }, + [27] = { levelRequirement = 84, }, + [28] = { levelRequirement = 86, }, + [29] = { levelRequirement = 88, }, + [30] = { levelRequirement = 90, }, + [31] = { levelRequirement = 91, }, + [32] = { levelRequirement = 92, }, + [33] = { levelRequirement = 93, }, + [34] = { levelRequirement = 94, }, + [35] = { levelRequirement = 95, }, + [36] = { levelRequirement = 96, }, + [37] = { levelRequirement = 97, }, + [38] = { levelRequirement = 98, }, + [39] = { levelRequirement = 99, }, + [40] = { levelRequirement = 100, }, + }, +} + +skills["RaiseZombieAltMercenaryEncounter"] = { + name = "Raise Zombie of Falling", + hidden = true, + mercenary = true, + inheritedFrom = "RaiseZombieAltY", + color = 3, + description = "Raises necromantic energies into the sky above a targeted location, where they coalesce into a zombie minion. The minion then attacks by falling to the ground, causing an impact that deals damage in an area. The zombie cannot survive the impact.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + minion = true, + spell = true, + }, + constantStats = { + { "active_skill_minion_from_alternate_gem_index", 2 }, + { "base_number_of_zombies_allowed", 200 }, + }, + stats = { + "raise_zombie_does_not_use_corpses", + }, + levels = { + [1] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 1, }, + [2] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 2, }, + [3] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 4, }, + [4] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 7, }, + [5] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 11, }, + [6] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 16, }, + [7] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 20, }, + [8] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 24, }, + [9] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 28, }, + [10] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 32, }, + [11] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 36, }, + [12] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 40, }, + [13] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 44, }, + [14] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 48, }, + [15] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 52, }, + [16] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 56, }, + [17] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 60, }, + [18] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 64, }, + [19] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 67, }, + [20] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 70, }, + [21] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 72, }, + [22] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 74, }, + [23] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 76, }, + [24] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 78, }, + [25] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 80, }, + [26] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 82, }, + [27] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 84, }, + [28] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 86, }, + [29] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 88, }, + [30] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 90, }, + [31] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 91, }, + [32] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 92, }, + [33] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 93, }, + [34] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 94, }, + [35] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 95, }, + [36] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 96, }, + [37] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 97, }, + [38] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 98, }, + [39] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 99, }, + [40] = { baseMultiplier = 0.4, damageEffectiveness = 0.4, levelRequirement = 100, }, + }, +} + +skills["RallyingCryMercenary"] = { + name = "Rallying Cry", + hidden = true, + mercenary = true, + inheritedFrom = "RallyingCry", + color = 1, + description = "Performs a warcry, taunting nearby enemies to attack the user and exerting subsequent attacks. Nearby allies gain a buff based on the damage of your weapon.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Warcry] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + warcry = true, + }, + constantStats = { + { "rallying_cry_damage_+%_final_from_osm_per_nearby_ally", 5 }, + { "skill_empowers_next_x_melee_attacks", 5 }, + { "rallying_cry_weapon_damage_%_for_allies_per_5_monster_power", 4 }, + { "rallying_cry_buff_effect_on_minions_+%_final", 100 }, + }, + stats = { + "warcry_speed_+%", + "base_skill_effect_duration", + "base_deal_no_attack_damage", + "base_deal_no_spell_damage", + "base_deal_no_secondary_damage", + "cannot_cancel_skill_before_contact_point", + "warcry_gain_mp_from_allies", + "warcry_count_power_from_enemies", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 0, 2500, cooldown = 8, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 2, 2500, cooldown = 8, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 4, 2600, cooldown = 8, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 6, 2600, cooldown = 8, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 8, 2700, cooldown = 8, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 10, 2700, cooldown = 8, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 12, 2800, cooldown = 8, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 14, 2800, cooldown = 8, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 16, 2900, cooldown = 8, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 18, 2900, cooldown = 8, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 20, 3000, cooldown = 8, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 22, 3000, cooldown = 8, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 24, 3100, cooldown = 8, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 26, 3100, cooldown = 8, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 28, 3200, cooldown = 8, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 30, 3200, cooldown = 8, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 32, 3300, cooldown = 8, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 34, 3300, cooldown = 8, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 36, 3400, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 38, 3400, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 40, 3500, cooldown = 8, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 41, 3500, cooldown = 8, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 42, 3600, cooldown = 8, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 43, 3600, cooldown = 8, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 44, 3700, cooldown = 8, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 45, 3700, cooldown = 8, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 46, 3800, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 47, 3800, cooldown = 8, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 48, 3900, cooldown = 8, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 49, 3900, cooldown = 8, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 49, 3900, cooldown = 8, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 50, 4000, cooldown = 8, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 50, 4000, cooldown = 8, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 51, 4000, cooldown = 8, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 51, 4000, cooldown = 8, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 52, 4100, cooldown = 8, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 52, 4100, cooldown = 8, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 53, 4100, cooldown = 8, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 53, 4100, cooldown = 8, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 54, 4200, cooldown = 8, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["ReapMercenary"] = { + name = "Reap", + hidden = true, + mercenary = true, + inheritedFrom = "Reap", + color = 1, + baseEffectiveness = 1.405699968338, + incrementalEffectiveness = 0.05009999871254, + description = "A bloody scythe swipes across a selected area, applying a physical damage over time debuff and hitting enemies with physical damage. If any survive, you gain a blood charge which raises the damage and cost of the skill. Players can have 5 maximum blood charges.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Physical] = true, [SkillType.DamageOverTime] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, [SkillType.Cascadable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "blood_scythe_damage_+%_final_per_charge", 15 }, + { "blood_scythe_cost_+%_final_per_charge", 20 }, + { "base_skill_effect_duration", 1000 }, + { "active_skill_base_area_of_effect_radius", 25 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 100.66666828096, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 28, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 99.485002198232, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 98.429999962126, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 34, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 97.163337654049, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 37, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 96.02666910549, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 40, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 95.549998829638, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 42, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 95.04666540876, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 94.516668842857, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 46, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 94.139999268601, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 48, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 93.558337395452, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 93.133332426846, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 52, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 92.685002173396, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 54, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 92.213338687817, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 91.718334022822, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 58, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 91.200004072984, critChance = 6, damageEffectiveness = 2, levelRequirement = 60, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 90.65833294373, critChance = 6, damageEffectiveness = 2, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 89.900002899518, critChance = 6, damageEffectiveness = 2, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 89.115001762994, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 89.089999600773, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 88.655004893479, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 88.199998919666, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 87.523335187907, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 87.026669540107, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 86.510000573074, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 85.973336234093, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 85.416668575878, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 84.840005545716, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 84.454999268291, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 83.839998529752, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 83.205002419266, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 83.200003576279, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 83.403334892367, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 83.380001660238, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 83.346670742134, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 83.526668826093, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 83.475003518847, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 83.413332578341, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 83.570005377457, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 83.490000047808, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 83.400004979471, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["ReapMercenaryEncounter"] = { + name = "Reap", + hidden = true, + mercenary = true, + inheritedFrom = "Reap", + color = 1, + baseEffectiveness = 1.25, + incrementalEffectiveness = 0.037500001490116, + description = "A bloody scythe swipes across a selected area, applying a physical damage over time debuff and hitting enemies with physical damage. If any survive, you gain a blood charge which raises the damage and cost of the skill. Players can have 5 maximum blood charges.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Physical] = true, [SkillType.DamageOverTime] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, [SkillType.Cascadable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "blood_scythe_damage_+%_final_per_charge", 10 }, + { "blood_scythe_cost_+%_final_per_charge", 20 }, + { "base_skill_effect_duration", 1000 }, + { "active_skill_base_area_of_effect_radius", 25 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 28, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 34, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 37, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 40, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 42, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 46, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 48, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.8, levelRequirement = 52, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 54, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 58, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2, levelRequirement = 60, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 14.999999937912, critChance = 6, damageEffectiveness = 2.1, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["RemoteSlamMercenary"] = { + name = "Tunnelslam", + hidden = true, + mercenary = true, + color = 1, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Damage] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + }, + constantStats = { + { "chance_to_intimidate_on_hit_%", 50 }, + }, + stats = { + "active_skill_damage_+%_final", + "is_area_damage", + }, + notMinionStat = { + "active_skill_damage_+%_final", + }, + levels = { + [1] = { 1, cooldown = 8, levelRequirement = 1, storedUses = 1, statInterpolation = { 2, }, }, + [2] = { 80, cooldown = 8, levelRequirement = 84, storedUses = 1, statInterpolation = { 2, }, }, + }, +} + +skills["RitualDaemonChaosProjectile1"] = { + name = "RitualDaemonChaosProjectile1", + hidden = true, + mercenary = true, + inheritedFrom = "BetrayalSecretPoliceCurveDagger1", + color = 4, + baseEffectiveness = 1.0499999523163, + incrementalEffectiveness = 0.045000001788139, + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "lunaris_glaive_angle", -25 }, + { "lunaris_glaive_acceleration_x", 500 }, + { "lunaris_glaive_acceleration_y", 500 }, + { "monster_reverse_point_blank_damage_-%_at_minimum_range", 40 }, + { "skill_visual_scale_+%", -30 }, + { "number_of_additional_projectiles", 4 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["RitualDaemonChaosProjectile2"] = { + name = "RitualDaemonChaosProjectile2", + hidden = true, + mercenary = true, + inheritedFrom = "BetrayalSecretPoliceCurveDagger1", + color = 4, + baseEffectiveness = 1.0499999523163, + incrementalEffectiveness = 0.045000001788139, + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "lunaris_glaive_angle", -20 }, + { "lunaris_glaive_acceleration_x", 500 }, + { "lunaris_glaive_acceleration_y", 375 }, + { "monster_reverse_point_blank_damage_-%_at_minimum_range", 40 }, + { "skill_visual_scale_+%", -30 }, + { "number_of_additional_projectiles", 4 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["RitualDaemonChaosProjectile3"] = { + name = "RitualDaemonChaosProjectile3", + hidden = true, + mercenary = true, + inheritedFrom = "BetrayalSecretPoliceCurveDagger1", + color = 4, + baseEffectiveness = 1.0499999523163, + incrementalEffectiveness = 0.045000001788139, + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "lunaris_glaive_angle", -15 }, + { "lunaris_glaive_acceleration_x", 375 }, + { "lunaris_glaive_acceleration_y", 375 }, + { "monster_reverse_point_blank_damage_-%_at_minimum_range", 40 }, + { "skill_visual_scale_+%", -30 }, + { "number_of_additional_projectiles", 4 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["RitualDaemonChaosProjectile4"] = { + name = "RitualDaemonChaosProjectile4", + hidden = true, + mercenary = true, + inheritedFrom = "BetrayalSecretPoliceCurveDagger1", + color = 4, + baseEffectiveness = 1.0499999523163, + incrementalEffectiveness = 0.045000001788139, + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "lunaris_glaive_angle", -10 }, + { "lunaris_glaive_acceleration_x", 375 }, + { "lunaris_glaive_acceleration_y", 500 }, + { "monster_reverse_point_blank_damage_-%_at_minimum_range", 40 }, + { "skill_visual_scale_+%", -30 }, + { "number_of_additional_projectiles", 4 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["RitualDaemonChaosProjectile5"] = { + name = "RitualDaemonChaosProjectile5", + hidden = true, + mercenary = true, + inheritedFrom = "BetrayalSecretPoliceCurveDagger1", + color = 4, + baseEffectiveness = 1.0499999523163, + incrementalEffectiveness = 0.045000001788139, + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "lunaris_glaive_angle", -5 }, + { "lunaris_glaive_acceleration_x", 250 }, + { "lunaris_glaive_acceleration_y", 250 }, + { "monster_reverse_point_blank_damage_-%_at_minimum_range", 40 }, + { "skill_visual_scale_+%", -30 }, + { "number_of_additional_projectiles", 4 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["RitualDaemonChaosProjectile6"] = { + name = "RitualDaemonChaosProjectile6", + hidden = true, + mercenary = true, + inheritedFrom = "BetrayalSecretPoliceCurveDagger1", + color = 4, + baseEffectiveness = 1.0499999523163, + incrementalEffectiveness = 0.045000001788139, + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "lunaris_glaive_acceleration_x", 150 }, + { "lunaris_glaive_acceleration_y", 150 }, + { "monster_reverse_point_blank_damage_-%_at_minimum_range", 40 }, + { "skill_visual_scale_+%", -30 }, + { "number_of_additional_projectiles", 4 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + "projectiles_nova", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, levelRequirement = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["RollingMagmaMercenary"] = { + name = "Rolling Magma", + hidden = true, + mercenary = true, + inheritedFrom = "RollingMagma", + color = 3, + baseEffectiveness = 2.5980000495911, + incrementalEffectiveness = 0.045000001788139, + description = "Lob a fiery orb that deals area damage as it hits the ground. The skill chains, bouncing forward to deal damage multiple times.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Multicastable] = true, [SkillType.Chains] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "monster_projectile_variation", 1 }, + { "display_projectiles_chain_when_impacting_ground", 1 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "number_of_chains", + "active_skill_base_radius_+", + "base_number_of_projectiles", + "is_area_damage", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.89999997615814, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [2] = { 0.89999997615814, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 2, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 4, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 7, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 11, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 16, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 20, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 24, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 28, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 32, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 40, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 52, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 67, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 3, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, 1, }, }, + }, +} + +skills["RollingMagmaMercenaryEncounter"] = { + name = "Rolling Magma", + hidden = true, + mercenary = true, + inheritedFrom = "RollingMagma", + color = 3, + baseEffectiveness = 2, + incrementalEffectiveness = 0.037500001490116, + description = "Lob a fiery orb that deals area damage as it hits the ground. The skill chains, bouncing forward to deal damage multiple times.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Multicastable] = true, [SkillType.Chains] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + projectile = true, + spell = true, + }, + constantStats = { + { "monster_projectile_variation", 1 }, + { "display_projectiles_chain_when_impacting_ground", 1 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "number_of_chains", + "active_skill_base_radius_+", + "base_number_of_projectiles", + "is_area_damage", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.89999997615814, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [2] = { 0.89999997615814, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 2, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 4, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 2, 0, 0, critChance = 5, damageEffectiveness = 2.3, levelRequirement = 7, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 11, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 16, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 20, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.4, levelRequirement = 24, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, 1, 0, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 28, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 32, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.5, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 40, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, 2, 1, critChance = 5, damageEffectiveness = 2.6, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 52, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.7, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 3, 3, 2, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 67, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 3, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 4, 4, 3, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 4, 5, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 4, 6, 4, critChance = 5, damageEffectiveness = 2.8, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, 1, }, }, + }, +} + +skills["SSMHolySpectresMercenary"] = { + name = "Raise Spectre: Holy Flame Elementals", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "number_of_monsters_to_summon", 4 }, + { "alternate_minion", 670 }, + { "summon_specific_monsters_in_front_offset", 30 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + "action_attack_or_cast_time_uses_animation_length", + }, + levels = { + [1] = { cooldown = 4, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SSMMercenaryRelic"] = { + name = "Relic of Binding", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "alternate_minion", 668 }, + { "number_of_monsters_to_summon", 3 }, + { "summon_specific_monsters_radius_+%", 15 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + }, + levels = { + [1] = { cooldown = 15, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SSMMercenarySoulrendOrb"] = { + name = "Summon Seeking Void", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "alternate_minion", 669 }, + { "number_of_monsters_to_summon", 1 }, + { "summon_specific_monsters_radius_+%", -50 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + }, + levels = { + [1] = { cooldown = 18, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["SSMPaganBishopMercenary"] = { + name = "Reinforce: Fallen Bishop", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "number_of_monsters_to_summon", 1 }, + { "alternate_minion", 671 }, + { "summon_specific_monsters_in_front_offset", 30 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + "action_attack_or_cast_time_uses_animation_length", + }, + levels = { + [1] = { cooldown = 7, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SSMPaganBishopMercenaryEncounter"] = { + name = "Reinforce: Fallen Bishop", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "number_of_monsters_to_summon", 1 }, + { "alternate_minion", 671 }, + { "summon_specific_monsters_in_front_offset", 30 }, + { "active_skill_minion_damage_+%_final", -80 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + "action_attack_or_cast_time_uses_animation_length", + }, + levels = { + [1] = { cooldown = 7, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SSMSkeletalBossMercenary"] = { + name = "Reinforce: Fallen Osseotitan", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "number_of_monsters_to_summon", 1 }, + { "alternate_minion", 673 }, + { "summon_specific_monsters_in_front_offset", 30 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + "action_attack_or_cast_time_uses_animation_length", + }, + levels = { + [1] = { cooldown = 7, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SSMSkeletalBossMercenaryEncounter"] = { + name = "Reinforce: Fallen Osseotitan", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "number_of_monsters_to_summon", 1 }, + { "alternate_minion", 673 }, + { "summon_specific_monsters_in_front_offset", 30 }, + { "active_skill_minion_damage_+%_final", -80 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + "action_attack_or_cast_time_uses_animation_length", + }, + levels = { + [1] = { cooldown = 7, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SSMVollMercenary"] = { + name = "Reinforce: Fallen Emperor", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "number_of_monsters_to_summon", 1 }, + { "alternate_minion", 672 }, + { "summon_specific_monsters_in_front_offset", 30 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + "action_attack_or_cast_time_uses_animation_length", + }, + levels = { + [1] = { cooldown = 7, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SSMVollMercenaryEncounter"] = { + name = "Reinforce: Fallen Emperor", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + spell = true, + }, + constantStats = { + { "number_of_monsters_to_summon", 1 }, + { "alternate_minion", 672 }, + { "summon_specific_monsters_in_front_offset", 30 }, + { "active_skill_minion_damage_+%_final", -80 }, + }, + stats = { + "summoned_monsters_are_minions", + "summoned_monsters_no_drops_or_experience", + "minion_dies_when_parent_dies", + "action_attack_or_cast_time_uses_animation_length", + }, + levels = { + [1] = { cooldown = 7, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["SandstormChaosMercenary"] = { + name = "Scourstorm", + hidden = true, + mercenary = true, + inheritedFrom = "SandstormChaosElementalSummoned", + color = 4, + baseEffectiveness = 16.840000152588, + incrementalEffectiveness = 0.016499999910593, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 10000 }, + { "active_skill_area_of_effect_radius_+%_final", 80 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "is_area_damage", + }, + levels = { + [1] = { 16.666667039196, cooldown = 18, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, }, }, + [2] = { 16.666667039196, cooldown = 18, levelRequirement = 2, storedUses = 1, statInterpolation = { 3, }, }, + [3] = { 16.666667039196, cooldown = 18, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, }, }, + [4] = { 16.666667039196, cooldown = 18, levelRequirement = 7, storedUses = 1, statInterpolation = { 3, }, }, + [5] = { 16.666667039196, cooldown = 18, levelRequirement = 11, storedUses = 1, statInterpolation = { 3, }, }, + [6] = { 16.666667039196, cooldown = 18, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, }, }, + [7] = { 16.666667039196, cooldown = 18, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, }, }, + [8] = { 16.666667039196, cooldown = 18, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, }, }, + [9] = { 16.666667039196, cooldown = 18, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, }, }, + [10] = { 16.666667039196, cooldown = 18, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, }, }, + [11] = { 16.666667039196, cooldown = 18, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, }, }, + [12] = { 16.666667039196, cooldown = 18, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, }, }, + [13] = { 16.666667039196, cooldown = 18, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, }, }, + [14] = { 16.666667039196, cooldown = 18, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, }, }, + [15] = { 16.666667039196, cooldown = 18, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, }, }, + [16] = { 16.666667039196, cooldown = 18, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, }, }, + [17] = { 16.666667039196, cooldown = 18, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, }, }, + [18] = { 16.666667039196, cooldown = 18, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, }, }, + [19] = { 16.666667039196, cooldown = 18, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, }, }, + [20] = { 16.666667039196, cooldown = 18, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, }, }, + [21] = { 16.666667039196, cooldown = 18, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, }, }, + [22] = { 16.666667039196, cooldown = 18, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, }, }, + [23] = { 16.666667039196, cooldown = 18, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, }, }, + [24] = { 16.666667039196, cooldown = 18, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, }, }, + [25] = { 16.666667039196, cooldown = 18, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, }, }, + [26] = { 16.666667039196, cooldown = 18, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, }, }, + [27] = { 16.666667039196, cooldown = 18, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, }, }, + [28] = { 16.666667039196, cooldown = 18, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, }, }, + [29] = { 16.666667039196, cooldown = 18, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, }, }, + [30] = { 16.666667039196, cooldown = 18, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["ScorchingRayTotemMercenary"] = { + name = "Scorching Ray Totem", + hidden = true, + mercenary = true, + inheritedFrom = "ScorchingRay", + color = 3, + baseEffectiveness = 3.6275000572205, + incrementalEffectiveness = 0.048900000751019, + description = "Unleash a beam of fire that burns enemies it touches. Remaining in the beam raises the burning, adding a portion of the beam's damage in stages. Inflicts Fire Exposure at maximum stages. Enemies who leave the beam continue to burn for a duration. Increasing cast speed also increases the rate at which the beam turns.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Totemable] = true, [SkillType.DamageOverTime] = true, [SkillType.Fire] = true, [SkillType.CausesBurning] = true, [SkillType.Duration] = true, [SkillType.Channel] = true, [SkillType.DegenOnlySpellDamage] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.25, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1500 }, + { "fire_beam_additional_stack_damage_+%_final", -40 }, + { "display_max_fire_beam_stacks", 8 }, + { "base_fire_damage_resistance_%", -25 }, + { "base_totem_duration", 6000 }, + { "base_totem_range", 50 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "spell_damage_modifiers_apply_to_skill_dot", + "is_totem", + "base_skill_is_totemified", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 16.666667039196, cooldown = 6, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, }, }, + [2] = { 16.666667039196, cooldown = 6, levelRequirement = 15, storedUses = 1, statInterpolation = { 3, }, }, + [3] = { 16.666667039196, cooldown = 6, levelRequirement = 19, storedUses = 1, statInterpolation = { 3, }, }, + [4] = { 16.666667039196, cooldown = 6, levelRequirement = 23, storedUses = 1, statInterpolation = { 3, }, }, + [5] = { 16.666667039196, cooldown = 6, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, }, }, + [6] = { 16.666667039196, cooldown = 6, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, }, }, + [7] = { 16.666667039196, cooldown = 6, levelRequirement = 35, storedUses = 1, statInterpolation = { 3, }, }, + [8] = { 16.666667039196, cooldown = 6, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, }, }, + [9] = { 16.666667039196, cooldown = 6, levelRequirement = 41, storedUses = 1, statInterpolation = { 3, }, }, + [10] = { 16.666667039196, cooldown = 6, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, }, }, + [11] = { 16.666667039196, cooldown = 6, levelRequirement = 47, storedUses = 1, statInterpolation = { 3, }, }, + [12] = { 16.666667039196, cooldown = 6, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, }, }, + [13] = { 16.666667039196, cooldown = 6, levelRequirement = 53, storedUses = 1, statInterpolation = { 3, }, }, + [14] = { 16.666667039196, cooldown = 6, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, }, }, + [15] = { 16.666667039196, cooldown = 6, levelRequirement = 59, storedUses = 1, statInterpolation = { 3, }, }, + [16] = { 16.666667039196, cooldown = 6, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, }, }, + [17] = { 16.666667039196, cooldown = 6, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, }, }, + [18] = { 16.666667039196, cooldown = 6, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, }, }, + [19] = { 16.666667039196, cooldown = 6, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, }, }, + [20] = { 16.666667039196, cooldown = 6, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, }, }, + [21] = { 16.666667039196, cooldown = 6, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, }, }, + [22] = { 16.666667039196, cooldown = 6, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, }, }, + [23] = { 16.666667039196, cooldown = 6, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, }, }, + [24] = { 16.666667039196, cooldown = 6, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, }, }, + [25] = { 16.666667039196, cooldown = 6, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, }, }, + [26] = { 16.666667039196, cooldown = 6, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, }, }, + [27] = { 16.666667039196, cooldown = 6, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, }, }, + [28] = { 16.666667039196, cooldown = 6, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, }, }, + [29] = { 16.666667039196, cooldown = 6, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, }, }, + [30] = { 16.666667039196, cooldown = 6, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, }, }, + [31] = { 16.666667039196, cooldown = 6, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, }, }, + [32] = { 16.666667039196, cooldown = 6, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, }, }, + [33] = { 16.666667039196, cooldown = 6, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, }, }, + [34] = { 16.666667039196, cooldown = 6, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, }, }, + [35] = { 16.666667039196, cooldown = 6, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, }, }, + [36] = { 16.666667039196, cooldown = 6, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, }, }, + [37] = { 16.666667039196, cooldown = 6, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, }, }, + [38] = { 16.666667039196, cooldown = 6, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, }, }, + [39] = { 16.666667039196, cooldown = 6, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, }, }, + [40] = { 16.666667039196, cooldown = 6, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["ScorchingRayTotemMercenaryEncounter"] = { + name = "Scorching Ray Totem", + hidden = true, + mercenary = true, + inheritedFrom = "ScorchingRay", + color = 3, + baseEffectiveness = 3.6275000572205, + incrementalEffectiveness = 0.048900000751019, + description = "Unleash a beam of fire that burns enemies it touches. Remaining in the beam raises the burning, adding a portion of the beam's damage in stages. Inflicts Fire Exposure at maximum stages. Enemies who leave the beam continue to burn for a duration. Increasing cast speed also increases the rate at which the beam turns.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Totemable] = true, [SkillType.DamageOverTime] = true, [SkillType.Fire] = true, [SkillType.CausesBurning] = true, [SkillType.Duration] = true, [SkillType.Channel] = true, [SkillType.DegenOnlySpellDamage] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.25, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1500 }, + { "fire_beam_additional_stack_damage_+%_final", -40 }, + { "display_max_fire_beam_stacks", 8 }, + { "base_fire_damage_resistance_%", -25 }, + { "base_totem_duration", 6000 }, + { "base_totem_range", 50 }, + }, + stats = { + "base_fire_damage_to_deal_per_minute", + "spell_damage_modifiers_apply_to_skill_dot", + "is_totem", + "base_skill_is_totemified", + }, + notMinionStat = { + "base_fire_damage_to_deal_per_minute", + }, + levels = { + [1] = { 4.1666667597989, cooldown = 6, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, }, }, + [2] = { 4.1666667597989, cooldown = 6, levelRequirement = 15, storedUses = 1, statInterpolation = { 3, }, }, + [3] = { 4.1666667597989, cooldown = 6, levelRequirement = 19, storedUses = 1, statInterpolation = { 3, }, }, + [4] = { 4.1666667597989, cooldown = 6, levelRequirement = 23, storedUses = 1, statInterpolation = { 3, }, }, + [5] = { 4.1666667597989, cooldown = 6, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, }, }, + [6] = { 4.1666667597989, cooldown = 6, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, }, }, + [7] = { 4.1666667597989, cooldown = 6, levelRequirement = 35, storedUses = 1, statInterpolation = { 3, }, }, + [8] = { 4.1666667597989, cooldown = 6, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, }, }, + [9] = { 4.1666667597989, cooldown = 6, levelRequirement = 41, storedUses = 1, statInterpolation = { 3, }, }, + [10] = { 4.1666667597989, cooldown = 6, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, }, }, + [11] = { 4.1666667597989, cooldown = 6, levelRequirement = 47, storedUses = 1, statInterpolation = { 3, }, }, + [12] = { 4.1666667597989, cooldown = 6, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, }, }, + [13] = { 4.1666667597989, cooldown = 6, levelRequirement = 53, storedUses = 1, statInterpolation = { 3, }, }, + [14] = { 4.1666667597989, cooldown = 6, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, }, }, + [15] = { 4.1666667597989, cooldown = 6, levelRequirement = 59, storedUses = 1, statInterpolation = { 3, }, }, + [16] = { 4.1666667597989, cooldown = 6, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, }, }, + [17] = { 4.1666667597989, cooldown = 6, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, }, }, + [18] = { 4.1666667597989, cooldown = 6, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, }, }, + [19] = { 4.1666667597989, cooldown = 6, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, }, }, + [20] = { 4.1666667597989, cooldown = 6, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, }, }, + [21] = { 4.1666667597989, cooldown = 6, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, }, }, + [22] = { 4.1666667597989, cooldown = 6, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, }, }, + [23] = { 4.1666667597989, cooldown = 6, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, }, }, + [24] = { 4.1666667597989, cooldown = 6, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, }, }, + [25] = { 4.1666667597989, cooldown = 6, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, }, }, + [26] = { 4.1666667597989, cooldown = 6, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, }, }, + [27] = { 4.1666667597989, cooldown = 6, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, }, }, + [28] = { 4.1666667597989, cooldown = 6, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, }, }, + [29] = { 4.1666667597989, cooldown = 6, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, }, }, + [30] = { 4.1666667597989, cooldown = 6, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, }, }, + [31] = { 4.1666667597989, cooldown = 6, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, }, }, + [32] = { 4.1666667597989, cooldown = 6, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, }, }, + [33] = { 4.1666667597989, cooldown = 6, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, }, }, + [34] = { 4.1666667597989, cooldown = 6, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, }, }, + [35] = { 4.1666667597989, cooldown = 6, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, }, }, + [36] = { 4.1666667597989, cooldown = 6, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, }, }, + [37] = { 4.1666667597989, cooldown = 6, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, }, }, + [38] = { 4.1666667597989, cooldown = 6, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, }, }, + [39] = { 4.1666667597989, cooldown = 6, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, }, }, + [40] = { 4.1666667597989, cooldown = 6, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["ScourgeArrowAltMercenary"] = { + name = "Scourge Arrow of Menace", + hidden = true, + mercenary = true, + inheritedFrom = "ScourgeArrowAltX", + color = 2, + description = "Fire an arrow that leaves a spore pod in its wake. The spore pod blooms, firing thorn arrows, which travel for a short time before dissipating. Modifiers that cause additional projectiles to be fired will only apply to the initial arrows, each of which leaves its own spore pod.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Damage] = true, [SkillType.Chaos] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "virulent_arrow_number_of_pod_projectiles", 4 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "virulent_arrow_pod_projectile_damage_+%_final", -33 }, + { "override_turn_duration_ms", 100 }, + { "scourge_arrow_X_pods_per_projectile", 1 }, + }, + stats = { + "skill_can_fire_arrows", + "base_arrows_always_pierce", + "visual_hit_effect_chaos_is_green", + }, + levels = { + [1] = { baseMultiplier = 0.695, damageEffectiveness = 0.695, levelRequirement = 28, }, + [2] = { baseMultiplier = 0.698, damageEffectiveness = 0.698, levelRequirement = 31, }, + [3] = { baseMultiplier = 0.702, damageEffectiveness = 0.702, levelRequirement = 34, }, + [4] = { baseMultiplier = 0.7055, damageEffectiveness = 0.7055, levelRequirement = 37, }, + [5] = { baseMultiplier = 0.7085, damageEffectiveness = 0.7085, levelRequirement = 40, }, + [6] = { baseMultiplier = 0.712, damageEffectiveness = 0.712, levelRequirement = 42, }, + [7] = { baseMultiplier = 0.716, damageEffectiveness = 0.716, levelRequirement = 44, }, + [8] = { baseMultiplier = 0.719, damageEffectiveness = 0.719, levelRequirement = 46, }, + [9] = { baseMultiplier = 0.7225, damageEffectiveness = 0.7225, levelRequirement = 48, }, + [10] = { baseMultiplier = 0.7255, damageEffectiveness = 0.7255, levelRequirement = 50, }, + [11] = { baseMultiplier = 0.7295, damageEffectiveness = 0.7295, levelRequirement = 52, }, + [12] = { baseMultiplier = 0.7325, damageEffectiveness = 0.7325, levelRequirement = 54, }, + [13] = { baseMultiplier = 0.736, damageEffectiveness = 0.736, levelRequirement = 56, }, + [14] = { baseMultiplier = 0.739, damageEffectiveness = 0.739, levelRequirement = 58, }, + [15] = { baseMultiplier = 0.743, damageEffectiveness = 0.743, levelRequirement = 60, }, + [16] = { baseMultiplier = 0.7465, damageEffectiveness = 0.7465, levelRequirement = 62, }, + [17] = { baseMultiplier = 0.7495, damageEffectiveness = 0.7495, levelRequirement = 64, }, + [18] = { baseMultiplier = 0.753, damageEffectiveness = 0.753, levelRequirement = 66, }, + [19] = { baseMultiplier = 0.7565, damageEffectiveness = 0.7565, levelRequirement = 68, }, + [20] = { baseMultiplier = 0.76, damageEffectiveness = 0.76, levelRequirement = 70, }, + [21] = { baseMultiplier = 0.763, damageEffectiveness = 0.763, levelRequirement = 72, }, + [22] = { baseMultiplier = 0.767, damageEffectiveness = 0.767, levelRequirement = 74, }, + [23] = { baseMultiplier = 0.7705, damageEffectiveness = 0.7705, levelRequirement = 76, }, + [24] = { baseMultiplier = 0.7735, damageEffectiveness = 0.7735, levelRequirement = 78, }, + [25] = { baseMultiplier = 0.777, damageEffectiveness = 0.777, levelRequirement = 80, }, + [26] = { baseMultiplier = 0.781, damageEffectiveness = 0.781, levelRequirement = 82, }, + [27] = { baseMultiplier = 0.784, damageEffectiveness = 0.784, levelRequirement = 84, }, + [28] = { baseMultiplier = 0.7875, damageEffectiveness = 0.7875, levelRequirement = 86, }, + [29] = { baseMultiplier = 0.7905, damageEffectiveness = 0.7905, levelRequirement = 88, }, + [30] = { baseMultiplier = 0.7945, damageEffectiveness = 0.7945, levelRequirement = 90, }, + [31] = { baseMultiplier = 0.7955, damageEffectiveness = 0.7955, levelRequirement = 91, }, + [32] = { baseMultiplier = 0.7975, damageEffectiveness = 0.7975, levelRequirement = 92, }, + [33] = { baseMultiplier = 0.7995, damageEffectiveness = 0.7995, levelRequirement = 93, }, + [34] = { baseMultiplier = 0.801, damageEffectiveness = 0.801, levelRequirement = 94, }, + [35] = { baseMultiplier = 0.803, damageEffectiveness = 0.803, levelRequirement = 95, }, + [36] = { baseMultiplier = 0.804, damageEffectiveness = 0.804, levelRequirement = 96, }, + [37] = { baseMultiplier = 0.806, damageEffectiveness = 0.806, levelRequirement = 97, }, + [38] = { baseMultiplier = 0.808, damageEffectiveness = 0.808, levelRequirement = 98, }, + [39] = { baseMultiplier = 0.8095, damageEffectiveness = 0.8095, levelRequirement = 99, }, + [40] = { baseMultiplier = 0.8115, damageEffectiveness = 0.8115, levelRequirement = 100, }, + }, +} + +skills["ShatteringSteelMercenary"] = { + name = "Shattering Steel", + hidden = true, + mercenary = true, + inheritedFrom = "ShatteringSteel", + color = 2, + description = "Swing an Axe or Sword, firing projectiles which shatter on impact or soon after being launched, dealing area damage in front of where they shatter.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Damage] = true, [SkillType.ProjectileSpeed] = true, [SkillType.RangedAttack] = true, [SkillType.Area] = true, [SkillType.Physical] = true, [SkillType.ProjectilesFromUser] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "attacks_impale_on_hit_%_chance", 40 }, + { "base_number_of_projectiles", 3 }, + { "active_skill_projectile_speed_+%_variation_final", 100 }, + { "active_skill_additional_projectiles_fire_parallel_x_dist", 90 }, + }, + stats = { + "base_is_projectile", + }, + levels = { + [1] = { attackSpeedMultiplier = -15, baseMultiplier = 1.7, damageEffectiveness = 1.7, levelRequirement = 12, }, + [2] = { attackSpeedMultiplier = -15, baseMultiplier = 1.75, damageEffectiveness = 1.75, levelRequirement = 15, }, + [3] = { attackSpeedMultiplier = -15, baseMultiplier = 1.8, damageEffectiveness = 1.8, levelRequirement = 19, }, + [4] = { attackSpeedMultiplier = -15, baseMultiplier = 1.85, damageEffectiveness = 1.85, levelRequirement = 23, }, + [5] = { attackSpeedMultiplier = -15, baseMultiplier = 1.9, damageEffectiveness = 1.9, levelRequirement = 27, }, + [6] = { attackSpeedMultiplier = -15, baseMultiplier = 1.95, damageEffectiveness = 1.95, levelRequirement = 31, }, + [7] = { attackSpeedMultiplier = -15, baseMultiplier = 2, damageEffectiveness = 2, levelRequirement = 35, }, + [8] = { attackSpeedMultiplier = -15, baseMultiplier = 2.05, damageEffectiveness = 2.05, levelRequirement = 38, }, + [9] = { attackSpeedMultiplier = -15, baseMultiplier = 2.1, damageEffectiveness = 2.1, levelRequirement = 41, }, + [10] = { attackSpeedMultiplier = -15, baseMultiplier = 2.15, damageEffectiveness = 2.15, levelRequirement = 44, }, + [11] = { attackSpeedMultiplier = -15, baseMultiplier = 2.2, damageEffectiveness = 2.2, levelRequirement = 47, }, + [12] = { attackSpeedMultiplier = -15, baseMultiplier = 2.25, damageEffectiveness = 2.25, levelRequirement = 50, }, + [13] = { attackSpeedMultiplier = -15, baseMultiplier = 2.3, damageEffectiveness = 2.3, levelRequirement = 53, }, + [14] = { attackSpeedMultiplier = -15, baseMultiplier = 2.35, damageEffectiveness = 2.35, levelRequirement = 56, }, + [15] = { attackSpeedMultiplier = -15, baseMultiplier = 2.4, damageEffectiveness = 2.4, levelRequirement = 59, }, + [16] = { attackSpeedMultiplier = -15, baseMultiplier = 2.45, damageEffectiveness = 2.45, levelRequirement = 62, }, + [17] = { attackSpeedMultiplier = -15, baseMultiplier = 2.5, damageEffectiveness = 2.5, levelRequirement = 64, }, + [18] = { attackSpeedMultiplier = -15, baseMultiplier = 2.55, damageEffectiveness = 2.55, levelRequirement = 66, }, + [19] = { attackSpeedMultiplier = -15, baseMultiplier = 2.6, damageEffectiveness = 2.6, levelRequirement = 68, }, + [20] = { attackSpeedMultiplier = -15, baseMultiplier = 2.65, damageEffectiveness = 2.65, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = -15, baseMultiplier = 2.7, damageEffectiveness = 2.7, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = -15, baseMultiplier = 2.75, damageEffectiveness = 2.75, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = -15, baseMultiplier = 2.8, damageEffectiveness = 2.8, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = -15, baseMultiplier = 2.85, damageEffectiveness = 2.85, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = -15, baseMultiplier = 2.9, damageEffectiveness = 2.9, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = -15, baseMultiplier = 2.95, damageEffectiveness = 2.95, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = -15, baseMultiplier = 3, damageEffectiveness = 3, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = -15, baseMultiplier = 3.05, damageEffectiveness = 3.05, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = -15, baseMultiplier = 3.1, damageEffectiveness = 3.1, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = -15, baseMultiplier = 3.15, damageEffectiveness = 3.15, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = -15, baseMultiplier = 3.175, damageEffectiveness = 3.175, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = -15, baseMultiplier = 3.2, damageEffectiveness = 3.2, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = -15, baseMultiplier = 3.225, damageEffectiveness = 3.225, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = -15, baseMultiplier = 3.25, damageEffectiveness = 3.25, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = -15, baseMultiplier = 3.275, damageEffectiveness = 3.275, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = -15, baseMultiplier = 3.3, damageEffectiveness = 3.3, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = -15, baseMultiplier = 3.325, damageEffectiveness = 3.325, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = -15, baseMultiplier = 3.35, damageEffectiveness = 3.35, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = -15, baseMultiplier = 3.375, damageEffectiveness = 3.375, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = -15, baseMultiplier = 3.4, damageEffectiveness = 3.4, levelRequirement = 100, }, + }, +} + +skills["ShieldChargeMercenary"] = { + name = "Shield Charge", + hidden = true, + mercenary = true, + inheritedFrom = "ShieldCharge", + color = 1, + baseEffectiveness = 2.0499999523163, + incrementalEffectiveness = 0.024599999189377, + description = "Charges at a targeted location or enemy, pushing away enemies in your path and repeatedly dealing off-hand damage in a small area in front of you. You deal damage in a larger area when you reach the target. The further you travel, the more damage you deal, and the greater your chance of stunning enemies.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RequiresShield] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Movement] = true, [SkillType.Travel] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + movement = true, + }, + constantStats = { + { "shield_charge_scaling_stun_threshold_reduction_+%_at_maximum_range", 75 }, + { "shield_charge_damage_+%_maximum", 100 }, + }, + stats = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + "base_movement_velocity_+%", + "off_hand_minimum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "off_hand_maximum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "ignores_proximity_shield", + "is_area_damage", + "shield_charge_attack_time_+30%_if_no_charge", + "attack_is_melee_override", + }, + notMinionStat = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 90, 3, 5, attackTime = 500, critChance = 5, levelRequirement = 4, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 91, 3, 5, attackTime = 500, critChance = 5, levelRequirement = 6, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 92, 4, 6, attackTime = 500, critChance = 5, levelRequirement = 9, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 93, 4, 7, attackTime = 500, critChance = 5, levelRequirement = 12, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 94, 5, 7, attackTime = 500, critChance = 5, levelRequirement = 16, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 95, 5, 7, attackTime = 500, critChance = 5, levelRequirement = 20, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 96, 5, 7, attackTime = 500, critChance = 5, levelRequirement = 24, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 97, 5, 7, attackTime = 500, critChance = 5, levelRequirement = 28, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 98, 5, 7, attackTime = 500, critChance = 5, levelRequirement = 32, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 99, 5, 8, attackTime = 500, critChance = 5, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 100, 5, 8, attackTime = 500, critChance = 5, levelRequirement = 40, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 101, 6, 9, attackTime = 500, critChance = 5, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 102, 6, 9, attackTime = 500, critChance = 5, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 103, 6, 9, attackTime = 500, critChance = 5, levelRequirement = 52, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 104, 6, 10, attackTime = 500, critChance = 5, levelRequirement = 55, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 105, 6, 10, attackTime = 500, critChance = 5, levelRequirement = 58, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 106, 7, 11, attackTime = 500, critChance = 5, levelRequirement = 61, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 107, 7, 12, attackTime = 500, critChance = 5, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 108, 8, 12, attackTime = 500, critChance = 5, levelRequirement = 67, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 109, 8, 12, attackTime = 500, critChance = 5, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 110, 8, 13, attackTime = 500, critChance = 5, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 111, 9, 14, attackTime = 500, critChance = 5, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 112, 9, 14, attackTime = 500, critChance = 5, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 113, 10, 15, attackTime = 500, critChance = 5, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 114, 10, 15, attackTime = 500, critChance = 5, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 115, 10, 15, attackTime = 500, critChance = 5, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 116, 10, 16, attackTime = 500, critChance = 5, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 117, 10, 16, attackTime = 500, critChance = 5, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 118, 11, 16, attackTime = 500, critChance = 5, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 119, 11, 16, attackTime = 500, critChance = 5, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 119, 11, 16, attackTime = 500, critChance = 5, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 120, 12, 16, attackTime = 500, critChance = 5, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 120, 12, 16, attackTime = 500, critChance = 5, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 121, 12, 16, attackTime = 500, critChance = 5, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 121, 13, 17, attackTime = 500, critChance = 5, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 122, 13, 17, attackTime = 500, critChance = 5, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 122, 13, 17, attackTime = 500, critChance = 5, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 123, 13, 17, attackTime = 500, critChance = 5, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 123, 13, 17, attackTime = 500, critChance = 5, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 124, 14, 18, attackTime = 500, critChance = 5, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, 1, }, }, + }, +} + +skills["ShieldChargeMercenaryEncounter"] = { + name = "Shield Charge", + hidden = true, + mercenary = true, + inheritedFrom = "ShieldCharge", + color = 1, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.017500000074506, + description = "Charges at a targeted location or enemy, pushing away enemies in your path and repeatedly dealing off-hand damage in a small area in front of you. You deal damage in a larger area when you reach the target. The further you travel, the more damage you deal, and the greater your chance of stunning enemies.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RequiresShield] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Movement] = true, [SkillType.Travel] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + movement = true, + }, + constantStats = { + { "shield_charge_scaling_stun_threshold_reduction_+%_at_maximum_range", 40 }, + { "shield_charge_damage_+%_maximum", 20 }, + }, + stats = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + "base_movement_velocity_+%", + "off_hand_minimum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "off_hand_maximum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "ignores_proximity_shield", + "is_area_damage", + "shield_charge_attack_time_+30%_if_no_charge", + "attack_is_melee_override", + }, + notMinionStat = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 90, 2, 3, attackTime = 500, critChance = 5, levelRequirement = 4, statInterpolation = { 3, 3, 2, 2, 2, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 124, 4, 7, attackTime = 500, critChance = 5, levelRequirement = 100, statInterpolation = { 3, 3, 2, 2, 2, }, }, + }, +} + +skills["ShieldCrushMercenary"] = { + name = "Shield Crush", + hidden = true, + mercenary = true, + inheritedFrom = "ShieldCrush", + color = 1, + baseEffectiveness = 1.3899999856949, + incrementalEffectiveness = 0.032999999821186, + description = "Swipe your shield, dealing area damage in three waves in front of you. Enemies can be hit by two of the waves where they overlap.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RequiresShield] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + stats = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + "off_hand_minimum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "off_hand_maximum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "active_skill_base_radius_+", + "is_area_damage", + "attack_is_melee_override", + }, + notMinionStat = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 3, 5, 0, attackTime = 800, critChance = 5, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 3, 5, 0, attackTime = 800, critChance = 5, levelRequirement = 2, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 3, 5, 1, attackTime = 800, critChance = 5, levelRequirement = 4, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 5, 7, 1, attackTime = 800, critChance = 5, levelRequirement = 7, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 5, 7, 1, attackTime = 800, critChance = 5, levelRequirement = 11, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 5, 7, 2, attackTime = 800, critChance = 5, levelRequirement = 16, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 5, 7, 2, attackTime = 800, critChance = 5, levelRequirement = 20, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 5, 7, 2, attackTime = 800, critChance = 5, levelRequirement = 24, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 5, 7, 3, attackTime = 800, critChance = 5, levelRequirement = 28, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 5, 8, 3, attackTime = 800, critChance = 5, levelRequirement = 32, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 5, 8, 3, attackTime = 800, critChance = 5, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 6, 9, 4, attackTime = 800, critChance = 5, levelRequirement = 40, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 6, 9, 4, attackTime = 800, critChance = 5, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 6, 9, 4, attackTime = 800, critChance = 5, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 6, 9, 5, attackTime = 800, critChance = 5, levelRequirement = 52, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 6, 9, 5, attackTime = 800, critChance = 5, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 6, 9, 5, attackTime = 800, critChance = 5, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 8, 12, 6, attackTime = 800, critChance = 5, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 8, 12, 6, attackTime = 800, critChance = 5, levelRequirement = 67, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 8, 12, 6, attackTime = 800, critChance = 5, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 8, 12, 7, attackTime = 800, critChance = 5, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 8, 12, 7, attackTime = 800, critChance = 5, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 8, 12, 7, attackTime = 800, critChance = 5, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 10, 15, 8, attackTime = 800, critChance = 5, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 10, 15, 8, attackTime = 800, critChance = 5, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 10, 15, 8, attackTime = 800, critChance = 5, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 10, 15, 9, attackTime = 800, critChance = 5, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 10, 16, 9, attackTime = 800, critChance = 5, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 11, 16, 9, attackTime = 800, critChance = 5, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 11, 16, 10, attackTime = 800, critChance = 5, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 11, 16, 10, attackTime = 800, critChance = 5, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 11, 16, 10, attackTime = 800, critChance = 5, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 11, 17, 10, attackTime = 800, critChance = 5, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 13, 19, 10, attackTime = 800, critChance = 5, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 13, 19, 10, attackTime = 800, critChance = 5, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 13, 20, 11, attackTime = 800, critChance = 5, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 13, 20, 11, attackTime = 800, critChance = 5, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 13, 20, 11, attackTime = 800, critChance = 5, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 14, 20, 11, attackTime = 800, critChance = 5, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 14, 21, 11, attackTime = 800, critChance = 5, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, 1, }, }, + }, +} + +skills["ShieldCrushMercenaryEncounter"] = { + name = "Shield Crush", + hidden = true, + mercenary = true, + inheritedFrom = "ShieldCrush", + color = 1, + incrementalEffectiveness = 0.029999999329448, + description = "Swipe your shield, dealing area damage in three waves in front of you. Enemies can be hit by two of the waves where they overlap.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RequiresShield] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + stats = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + "off_hand_minimum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "off_hand_maximum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "active_skill_base_radius_+", + "is_area_damage", + "attack_is_melee_override", + }, + notMinionStat = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 2, 3, 0, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 2, 3, 0, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 2, 3, 1, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 1, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 1, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 2, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 2, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 2, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 2, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 2, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 4, 2, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 5, 3, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 5, 3, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 5, 3, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 5, 4, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 5, 4, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 3, 5, 4, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 4, 6, 5, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 4, 6, 5, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 4, 6, 5, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 4, 6, 5, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 4, 6, 5, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 4, 6, 5, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 5, 8, 6, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 5, 8, 6, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 5, 8, 6, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 5, 8, 7, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 5, 8, 7, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 6, 8, 7, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 6, 8, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 6, 8, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 6, 8, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 6, 9, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 7, 10, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 7, 10, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 7, 10, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 7, 10, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 7, 10, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 7, 10, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [1] = { 0.80000001192093, 1.2000000476837, 7, 11, 8, attackTime = 800, baseMultiplier = 0.4, critChance = 5, damageEffectiveness = 0.4, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, }, }, + }, +} + +skills["ShockwaveTotemMercenary"] = { + name = "Shockwave Totem of Shocking", + hidden = true, + mercenary = true, + inheritedFrom = "ShockwaveTotem", + color = 1, + baseEffectiveness = 1.0778000354767, + incrementalEffectiveness = 0.043600000441074, + description = "Summons a totem that shakes the earth around it, knocking back and damaging nearby enemies", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.SummonsTotem] = true, [SkillType.Multicastable] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 5, + castTime = 0.6, + baseFlags = { + area = true, + spell = true, + totem = true, + }, + constantStats = { + { "base_totem_duration", 8000 }, + { "base_totem_range", 80 }, + { "base_global_chance_to_knockback_%", 25 }, + { "active_skill_base_area_of_effect_radius", 24 }, + { "skill_physical_damage_%_to_convert_to_lightning", 60 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "is_totem", + "is_area_damage", + "base_skill_is_totemified", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.69999998807907, 1.3999999761581, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.69999998807907, 1.2999999523163, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["ShrapnelBallistaMercenary"] = { + name = "Shrapnel Ballista", + hidden = true, + mercenary = true, + inheritedFrom = "ShrapnelBallista", + color = 2, + description = "Summons a ballista totem that fires multiple arrows with extreme force, breaking them apart into shrapnel. Enemies can be hit by multiple arrows from the same attack. Requires a Bow.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.RangedAttack] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.SummonsTotem] = true, [SkillType.AttackInPlaceIsDefault] = true, [SkillType.TotemsAreBallistae] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 18, + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + totem = true, + }, + constantStats = { + { "base_totem_range", 40 }, + { "base_totem_duration", 8000 }, + { "base_number_of_arrows", 3 }, + }, + stats = { + "attack_skills_additional_ballista_totems_allowed", + "active_skill_damage_+%_final", + "base_is_projectile", + "base_skill_is_totemified", + "is_totem", + "skill_can_fire_arrows", + "projectiles_can_shotgun", + "is_ranged_attack_totem", + "quality_display_base_additional_arrows_is_gem", + }, + notMinionStat = { + "active_skill_damage_+%_final", + }, + levels = { + [1] = { 2, -33, baseMultiplier = 0.456, damageEffectiveness = 0.456, levelRequirement = 4, statInterpolation = { 1, 2, }, }, + [2] = { 2, -20, baseMultiplier = 0.46, damageEffectiveness = 0.46, levelRequirement = 6, statInterpolation = { 1, 2, }, }, + [3] = { 2, 0, baseMultiplier = 0.463, damageEffectiveness = 0.463, levelRequirement = 9, statInterpolation = { 1, 2, }, }, + [4] = { 2, 0, baseMultiplier = 0.467, damageEffectiveness = 0.467, levelRequirement = 12, statInterpolation = { 1, 2, }, }, + [5] = { 2, 0, baseMultiplier = 0.472, damageEffectiveness = 0.472, levelRequirement = 16, statInterpolation = { 1, 2, }, }, + [6] = { 2, 0, baseMultiplier = 0.475, damageEffectiveness = 0.475, levelRequirement = 20, statInterpolation = { 1, 2, }, }, + [7] = { 2, 0, baseMultiplier = 0.479, damageEffectiveness = 0.479, levelRequirement = 24, statInterpolation = { 1, 2, }, }, + [8] = { 2, 0, baseMultiplier = 0.482, damageEffectiveness = 0.482, levelRequirement = 28, statInterpolation = { 1, 2, }, }, + [9] = { 2, 0, baseMultiplier = 0.486, damageEffectiveness = 0.486, levelRequirement = 32, statInterpolation = { 1, 2, }, }, + [10] = { 2, 0, baseMultiplier = 0.49, damageEffectiveness = 0.49, levelRequirement = 36, statInterpolation = { 1, 2, }, }, + [11] = { 3, 0, baseMultiplier = 0.494, damageEffectiveness = 0.494, levelRequirement = 40, statInterpolation = { 1, 2, }, }, + [12] = { 3, 0, baseMultiplier = 0.498, damageEffectiveness = 0.498, levelRequirement = 44, statInterpolation = { 1, 2, }, }, + [13] = { 3, 0, baseMultiplier = 0.502, damageEffectiveness = 0.502, levelRequirement = 48, statInterpolation = { 1, 2, }, }, + [14] = { 3, 0, baseMultiplier = 0.505, damageEffectiveness = 0.505, levelRequirement = 52, statInterpolation = { 1, 2, }, }, + [15] = { 3, 0, baseMultiplier = 0.509, damageEffectiveness = 0.509, levelRequirement = 55, statInterpolation = { 1, 2, }, }, + [16] = { 3, 0, baseMultiplier = 0.512, damageEffectiveness = 0.512, levelRequirement = 58, statInterpolation = { 1, 2, }, }, + [17] = { 3, 0, baseMultiplier = 0.517, damageEffectiveness = 0.517, levelRequirement = 61, statInterpolation = { 1, 2, }, }, + [18] = { 3, 0, baseMultiplier = 0.521, damageEffectiveness = 0.521, levelRequirement = 64, statInterpolation = { 1, 2, }, }, + [19] = { 3, 0, baseMultiplier = 0.524, damageEffectiveness = 0.524, levelRequirement = 67, statInterpolation = { 1, 2, }, }, + [20] = { 3, 0, baseMultiplier = 0.528, damageEffectiveness = 0.528, levelRequirement = 70, statInterpolation = { 1, 2, }, }, + [21] = { 3, 0, baseMultiplier = 0.532, damageEffectiveness = 0.532, levelRequirement = 72, statInterpolation = { 1, 2, }, }, + [22] = { 4, 0, baseMultiplier = 0.535, damageEffectiveness = 0.535, levelRequirement = 74, statInterpolation = { 1, 2, }, }, + [23] = { 4, 0, baseMultiplier = 0.539, damageEffectiveness = 0.539, levelRequirement = 76, statInterpolation = { 1, 2, }, }, + [24] = { 4, 0, baseMultiplier = 0.544, damageEffectiveness = 0.544, levelRequirement = 78, statInterpolation = { 1, 2, }, }, + [25] = { 4, 0, baseMultiplier = 0.547, damageEffectiveness = 0.547, levelRequirement = 80, statInterpolation = { 1, 2, }, }, + [26] = { 4, 0, baseMultiplier = 0.551, damageEffectiveness = 0.551, levelRequirement = 82, statInterpolation = { 1, 2, }, }, + [27] = { 4, 0, baseMultiplier = 0.554, damageEffectiveness = 0.554, levelRequirement = 84, statInterpolation = { 1, 2, }, }, + [28] = { 4, 0, baseMultiplier = 0.558, damageEffectiveness = 0.558, levelRequirement = 86, statInterpolation = { 1, 2, }, }, + [29] = { 4, 0, baseMultiplier = 0.562, damageEffectiveness = 0.562, levelRequirement = 88, statInterpolation = { 1, 2, }, }, + [30] = { 4, 0, baseMultiplier = 0.566, damageEffectiveness = 0.566, levelRequirement = 90, statInterpolation = { 1, 2, }, }, + [31] = { 4, 0, baseMultiplier = 0.568, damageEffectiveness = 0.568, levelRequirement = 91, statInterpolation = { 1, 2, }, }, + [32] = { 4, 0, baseMultiplier = 0.57, damageEffectiveness = 0.57, levelRequirement = 92, statInterpolation = { 1, 2, }, }, + [33] = { 4, 0, baseMultiplier = 0.571, damageEffectiveness = 0.571, levelRequirement = 93, statInterpolation = { 1, 2, }, }, + [34] = { 4, 0, baseMultiplier = 0.574, damageEffectiveness = 0.574, levelRequirement = 94, statInterpolation = { 1, 2, }, }, + [35] = { 4, 0, baseMultiplier = 0.575, damageEffectiveness = 0.575, levelRequirement = 95, statInterpolation = { 1, 2, }, }, + [36] = { 4, 0, baseMultiplier = 0.577, damageEffectiveness = 0.577, levelRequirement = 96, statInterpolation = { 1, 2, }, }, + [37] = { 4, 0, baseMultiplier = 0.58, damageEffectiveness = 0.58, levelRequirement = 97, statInterpolation = { 1, 2, }, }, + [38] = { 4, 0, baseMultiplier = 0.581, damageEffectiveness = 0.581, levelRequirement = 98, statInterpolation = { 1, 2, }, }, + [39] = { 4, 0, baseMultiplier = 0.583, damageEffectiveness = 0.583, levelRequirement = 99, statInterpolation = { 1, 2, }, }, + [40] = { 4, 0, baseMultiplier = 0.584, damageEffectiveness = 0.584, levelRequirement = 100, statInterpolation = { 1, 2, }, }, + }, +} + +skills["SiegeBallistaAltMercenary"] = { + name = "Siege Ballista of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "SiegeBallistaAltY", + color = 2, + description = "Summons a ring of ballista totems around a targeted location. These ballistae fire once at the targeted location and then expire. Requires a Bow.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.RangedAttack] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.SummonsTotem] = true, [SkillType.AttackInPlaceIsDefault] = true, [SkillType.TotemsAreBallistae] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 12, + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + totem = true, + }, + constantStats = { + { "base_totem_range", 80 }, + { "base_totem_duration", 4000 }, + { "totem_formation_radius_override", 3 }, + { "totem_placement_range_+%", 300 }, + { "active_skill_summon_X_totems_in_ring_override", 4 }, + }, + stats = { + "active_skill_summon_X_totems_in_ring_override", + "base_number_of_totems_allowed", + "totem_fire_in_formation", + "base_is_projectile", + "base_skill_is_totemified", + "is_totem", + "skill_can_fire_arrows", + "is_ranged_attack_totem", + "ignores_trap_and_mine_cooldown_limit", + }, + levels = { + [1] = { 0, 3, baseMultiplier = 0.8, cooldown = 8, damageEffectiveness = 0.8, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 0, 3, baseMultiplier = 0.811, cooldown = 8, damageEffectiveness = 0.811, levelRequirement = 15, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 0, 3, baseMultiplier = 0.821, cooldown = 8, damageEffectiveness = 0.821, levelRequirement = 19, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 0, 3, baseMultiplier = 0.832, cooldown = 8, damageEffectiveness = 0.832, levelRequirement = 23, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 0, 4, baseMultiplier = 0.842, cooldown = 8, damageEffectiveness = 0.842, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 0, 4, baseMultiplier = 0.853, cooldown = 8, damageEffectiveness = 0.853, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 0, 4, baseMultiplier = 0.863, cooldown = 8, damageEffectiveness = 0.863, levelRequirement = 35, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 0, 4, baseMultiplier = 0.874, cooldown = 8, damageEffectiveness = 0.874, levelRequirement = 38, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 0, 4, baseMultiplier = 0.884, cooldown = 8, damageEffectiveness = 0.884, levelRequirement = 41, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 0, 5, baseMultiplier = 0.895, cooldown = 8, damageEffectiveness = 0.895, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 0, 5, baseMultiplier = 0.905, cooldown = 8, damageEffectiveness = 0.905, levelRequirement = 47, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 0, 5, baseMultiplier = 0.916, cooldown = 8, damageEffectiveness = 0.916, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 0, 5, baseMultiplier = 0.926, cooldown = 8, damageEffectiveness = 0.926, levelRequirement = 53, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 0, 5, baseMultiplier = 0.937, cooldown = 8, damageEffectiveness = 0.937, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 0, 6, baseMultiplier = 0.947, cooldown = 8, damageEffectiveness = 0.947, levelRequirement = 59, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 0, 6, baseMultiplier = 0.958, cooldown = 8, damageEffectiveness = 0.958, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 0, 6, baseMultiplier = 0.968, cooldown = 8, damageEffectiveness = 0.968, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 0, 6, baseMultiplier = 0.979, cooldown = 8, damageEffectiveness = 0.979, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 0, 6, baseMultiplier = 0.989, cooldown = 8, damageEffectiveness = 0.989, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 0, 7, cooldown = 8, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 0, 7, baseMultiplier = 1.011, cooldown = 8, damageEffectiveness = 1.011, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 0, 7, baseMultiplier = 1.021, cooldown = 8, damageEffectiveness = 1.021, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 0, 7, baseMultiplier = 1.032, cooldown = 8, damageEffectiveness = 1.032, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 0, 7, baseMultiplier = 1.042, cooldown = 8, damageEffectiveness = 1.042, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 0, 8, baseMultiplier = 1.053, cooldown = 8, damageEffectiveness = 1.053, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 0, 8, baseMultiplier = 1.063, cooldown = 8, damageEffectiveness = 1.063, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 0, 8, baseMultiplier = 1.074, cooldown = 8, damageEffectiveness = 1.074, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 0, 8, baseMultiplier = 1.084, cooldown = 8, damageEffectiveness = 1.084, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 0, 8, baseMultiplier = 1.095, cooldown = 8, damageEffectiveness = 1.095, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 0, 9, baseMultiplier = 1.105, cooldown = 8, damageEffectiveness = 1.105, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 0, 9, baseMultiplier = 1.111, cooldown = 8, damageEffectiveness = 1.111, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 0, 9, baseMultiplier = 1.116, cooldown = 8, damageEffectiveness = 1.116, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 0, 9, baseMultiplier = 1.121, cooldown = 8, damageEffectiveness = 1.121, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 0, 9, baseMultiplier = 1.126, cooldown = 8, damageEffectiveness = 1.126, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 0, 10, baseMultiplier = 1.132, cooldown = 8, damageEffectiveness = 1.132, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 0, 10, baseMultiplier = 1.137, cooldown = 8, damageEffectiveness = 1.137, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 0, 10, baseMultiplier = 1.142, cooldown = 8, damageEffectiveness = 1.142, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 0, 10, baseMultiplier = 1.147, cooldown = 8, damageEffectiveness = 1.147, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 0, 10, baseMultiplier = 1.153, cooldown = 8, damageEffectiveness = 1.153, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 0, 11, baseMultiplier = 1.158, cooldown = 8, damageEffectiveness = 1.158, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["SigilOfPowerMercenary"] = { + name = "Sigil of Power", + hidden = true, + mercenary = true, + inheritedFrom = "SigilOfPower", + color = 3, + baseEffectiveness = 0.38400000333786, + incrementalEffectiveness = 0.028000000864267, + description = "Places a Sigil on the ground, which grants a buff to you and allies in the area around it for a duration. The Sigil gains stages as you spend mana in its area, making the buff more powerful. You can only have one Sigil of Power at a time.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Totemable] = true, [SkillType.Lightning] = true, [SkillType.Arcane] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "circle_of_power_max_stages", 4 }, + { "base_skill_effect_duration", 12000 }, + }, + stats = { + "circle_of_power_min_added_lightning_per_stage", + "circle_of_power_max_added_lightning_per_stage", + "base_circle_of_power_mana_spend_per_upgrade", + "circle_of_power_enemy_damage_+%_final_at_max_stages", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, 72, -10, cooldown = 16, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.10000000149012, 1.8999999761581, 80, -10, cooldown = 16, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.10000000149012, 1.8999999761581, 90, -11, cooldown = 16, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.10000000149012, 1.8999999761581, 99, -11, cooldown = 16, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.10000000149012, 1.8999999761581, 110, -12, cooldown = 16, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.10000000149012, 1.8999999761581, 121, -12, cooldown = 16, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.10000000149012, 1.8999999761581, 135, -13, cooldown = 16, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.10000000149012, 1.8999999761581, 148, -13, cooldown = 16, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.10000000149012, 1.8999999761581, 163, -14, cooldown = 16, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.10000000149012, 1.8999999761581, 178, -14, cooldown = 16, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.10000000149012, 1.8999999761581, 196, -15, cooldown = 16, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.10000000149012, 1.8999999761581, 213, -15, cooldown = 16, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.10000000149012, 1.8999999761581, 233, -16, cooldown = 16, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.10000000149012, 1.8999999761581, 252, -16, cooldown = 16, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.10000000149012, 1.8999999761581, 274, -17, cooldown = 16, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.10000000149012, 1.8999999761581, 296, -17, cooldown = 16, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.10000000149012, 1.8999999761581, 337, -18, cooldown = 16, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.10000000149012, 1.8999999761581, 379, -18, cooldown = 16, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.10000000149012, 1.8999999761581, 389, -19, cooldown = 16, levelRequirement = 69, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.10000000149012, 1.8999999761581, 400, -19, cooldown = 16, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.10000000149012, 1.8999999761581, 461, -20, cooldown = 16, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.10000000149012, 1.8999999761581, 527, -20, cooldown = 16, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.10000000149012, 1.8999999761581, 600, -20, cooldown = 16, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.10000000149012, 1.8999999761581, 680, -21, cooldown = 16, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.10000000149012, 1.8999999761581, 766, -21, cooldown = 16, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.10000000149012, 1.8999999761581, 860, -21, cooldown = 16, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.10000000149012, 1.8999999761581, 961, -22, cooldown = 16, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.10000000149012, 1.8999999761581, 1070, -22, cooldown = 16, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.10000000149012, 1.8999999761581, 1187, -22, cooldown = 16, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.10000000149012, 1.8999999761581, 1312, -23, cooldown = 16, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.10000000149012, 1.8999999761581, 1379, -23, cooldown = 16, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.10000000149012, 1.8999999761581, 1446, -23, cooldown = 16, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.10000000149012, 1.8999999761581, 1518, -23, cooldown = 16, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.10000000149012, 1.8999999761581, 1667, -23, cooldown = 16, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.10000000149012, 1.8999999761581, 1743, -24, cooldown = 16, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.10000000149012, 1.8999999761581, 1825, -24, cooldown = 16, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.10000000149012, 1.8999999761581, 1906, -24, cooldown = 16, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.10000000149012, 1.8999999761581, 1992, -24, cooldown = 16, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.10000000149012, 1.8999999761581, 2078, -24, cooldown = 16, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.10000000149012, 1.8999999761581, 72, -10, cooldown = 16, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["SigilOfPowerMercenaryEncounter"] = { + name = "Sigil of Power", + hidden = true, + mercenary = true, + inheritedFrom = "SigilOfPower", + color = 3, + baseEffectiveness = 0.38400000333786, + incrementalEffectiveness = 0.028000000864267, + description = "Places a Sigil on the ground, which grants a buff to you and allies in the area around it for a duration. The Sigil gains stages as you spend mana in its area, making the buff more powerful. You can only have one Sigil of Power at a time.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Totemable] = true, [SkillType.Lightning] = true, [SkillType.Arcane] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "circle_of_power_max_stages", 4 }, + { "base_skill_effect_duration", 8000 }, + }, + stats = { + "circle_of_power_min_added_lightning_per_stage", + "circle_of_power_max_added_lightning_per_stage", + "base_circle_of_power_mana_spend_per_upgrade", + "circle_of_power_enemy_damage_+%_final_at_max_stages", + }, + levels = { + [1] = { 0.019999999552965, 0.37999999523163, 10, -10, cooldown = 16, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, 3, 2, 2, }, }, + [2] = { 0.019999999552965, 0.37999999523163, 500, -24, cooldown = 16, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 2, 2, }, }, + }, +} + +skills["SkeletonLargeMapBoneProjectile"] = { + name = "SkeletonLargeMapBoneProjectile", + hidden = true, + mercenary = true, + inheritedFrom = "Snipe", + color = 4, + baseEffectiveness = 1.8700000047684, + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.5, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "monster_projectile_variation", 118 }, + { "spell_maximum_action_distance_+%", -30 }, + { "active_skill_cast_speed_+%_final", -20 }, + { "number_of_additional_projectiles", 3 }, + { "active_skill_damage_+%_final", 20 }, + }, + stats = { + "base_is_projectile", + }, + levels = { + [1] = { baseMultiplier = 1.2, damageEffectiveness = 1.2, levelRequirement = 1, }, + }, +} + +skills["SmiteMercenary"] = { + name = "Smite", + hidden = true, + mercenary = true, + inheritedFrom = "Smite", + color = 1, + baseEffectiveness = 0.60000002384186, + incrementalEffectiveness = 0.028000000864267, + description = "Performs a melee attack, and causes lightning to strike a nearby enemy, dealing damage in an area. Each target can only be hit once by this skill. Hitting an enemy grants an aura for a duration. Requires a Sword, Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Melee] = true, [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Multistrikeable] = true, [SkillType.Damage] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Aura] = true, [SkillType.Buff] = true, [SkillType.Lightning] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + aura = true, + duration = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "base_skill_effect_duration", 4000 }, + { "base_smite_number_of_targets", 1 }, + { "smite_lightning_target_range", 50 }, + { "active_skill_base_area_of_effect_radius", 15 }, + { "active_skill_base_secondary_area_of_effect_radius", 36 }, + { "active_skill_secondary_area_of_effect_description_mode", 4 }, + }, + stats = { + "minimum_added_lightning_damage_from_skill", + "maximum_added_lightning_damage_from_skill", + "base_chance_to_shock_%_from_skill", + "active_skill_base_area_of_effect_radius", + "active_skill_base_secondary_area_of_effect_radius", + "active_skill_area_damage_+%_final", + "visual_hit_effect_elemental_is_holy", + }, + notMinionStat = { + "active_skill_area_damage_+%_final", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, 10, 0, 0, -30, baseMultiplier = 2.254, damageEffectiveness = 2.254, levelRequirement = 1, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [2] = { 0.10000000149012, 1.8999999761581, 10, 0, 0, -29, baseMultiplier = 2.337, damageEffectiveness = 2.337, levelRequirement = 2, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [3] = { 0.10000000149012, 1.8999999761581, 11, 1, 1, -29, baseMultiplier = 2.428, damageEffectiveness = 2.428, levelRequirement = 4, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [4] = { 0.10000000149012, 1.8999999761581, 11, 1, 1, -28, baseMultiplier = 2.527, damageEffectiveness = 2.527, levelRequirement = 7, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [5] = { 0.10000000149012, 1.8999999761581, 12, 1, 1, -28, baseMultiplier = 2.635, damageEffectiveness = 2.635, levelRequirement = 11, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [6] = { 0.10000000149012, 1.8999999761581, 12, 2, 2, -27, baseMultiplier = 2.751, damageEffectiveness = 2.751, levelRequirement = 16, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [7] = { 0.10000000149012, 1.8999999761581, 13, 2, 2, -27, baseMultiplier = 2.868, damageEffectiveness = 2.868, levelRequirement = 20, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [8] = { 0.10000000149012, 1.8999999761581, 13, 2, 2, -26, baseMultiplier = 2.99, damageEffectiveness = 2.99, levelRequirement = 24, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [9] = { 0.10000000149012, 1.8999999761581, 14, 3, 3, -26, baseMultiplier = 3.116, damageEffectiveness = 3.116, levelRequirement = 28, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [10] = { 0.10000000149012, 1.8999999761581, 14, 3, 3, -25, baseMultiplier = 3.248, damageEffectiveness = 3.248, levelRequirement = 32, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [11] = { 0.10000000149012, 1.8999999761581, 15, 3, 3, -25, baseMultiplier = 3.385, damageEffectiveness = 3.385, levelRequirement = 36, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [12] = { 0.10000000149012, 1.8999999761581, 15, 4, 4, -24, baseMultiplier = 3.528, damageEffectiveness = 3.528, levelRequirement = 40, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [13] = { 0.10000000149012, 1.8999999761581, 16, 4, 4, -24, baseMultiplier = 3.677, damageEffectiveness = 3.677, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [14] = { 0.10000000149012, 1.8999999761581, 16, 4, 4, -23, baseMultiplier = 3.831, damageEffectiveness = 3.831, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [15] = { 0.10000000149012, 1.8999999761581, 17, 5, 5, -23, baseMultiplier = 3.993, damageEffectiveness = 3.993, levelRequirement = 52, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [16] = { 0.10000000149012, 1.8999999761581, 17, 5, 5, -22, baseMultiplier = 4.16, damageEffectiveness = 4.16, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [17] = { 0.10000000149012, 1.8999999761581, 18, 5, 5, -22, baseMultiplier = 4.335, damageEffectiveness = 4.335, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [18] = { 0.10000000149012, 1.8999999761581, 18, 6, 6, -21, baseMultiplier = 4.516, damageEffectiveness = 4.516, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [19] = { 0.10000000149012, 1.8999999761581, 19, 6, 6, -21, baseMultiplier = 4.698, damageEffectiveness = 4.698, levelRequirement = 67, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [20] = { 0.10000000149012, 1.8999999761581, 19, 6, 6, -20, baseMultiplier = 4.886, damageEffectiveness = 4.886, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [21] = { 0.10000000149012, 1.8999999761581, 20, 7, 7, -20, baseMultiplier = 5.074, damageEffectiveness = 5.074, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [22] = { 0.10000000149012, 1.8999999761581, 20, 7, 7, -19, baseMultiplier = 5.269, damageEffectiveness = 5.269, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [23] = { 0.10000000149012, 1.8999999761581, 21, 7, 7, -19, baseMultiplier = 5.471, damageEffectiveness = 5.471, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [24] = { 0.10000000149012, 1.8999999761581, 21, 8, 8, -18, baseMultiplier = 5.681, damageEffectiveness = 5.681, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [25] = { 0.10000000149012, 1.8999999761581, 22, 8, 8, -18, baseMultiplier = 5.899, damageEffectiveness = 5.899, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [26] = { 0.10000000149012, 1.8999999761581, 22, 8, 8, -17, baseMultiplier = 6.125, damageEffectiveness = 6.125, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [27] = { 0.10000000149012, 1.8999999761581, 23, 8, 8, -17, baseMultiplier = 6.36, damageEffectiveness = 6.36, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [28] = { 0.10000000149012, 1.8999999761581, 23, 9, 9, -16, baseMultiplier = 6.603, damageEffectiveness = 6.603, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [29] = { 0.10000000149012, 1.8999999761581, 24, 9, 9, -16, baseMultiplier = 6.857, damageEffectiveness = 6.857, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [30] = { 0.10000000149012, 1.8999999761581, 24, 9, 9, -15, baseMultiplier = 7.12, damageEffectiveness = 7.12, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [31] = { 0.10000000149012, 1.8999999761581, 24, 10, 10, -15, baseMultiplier = 7.509, damageEffectiveness = 7.509, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [32] = { 0.10000000149012, 1.8999999761581, 25, 10, 10, -15, baseMultiplier = 7.653, damageEffectiveness = 7.653, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [33] = { 0.10000000149012, 1.8999999761581, 25, 10, 10, -15, baseMultiplier = 7.799, damageEffectiveness = 7.799, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [34] = { 0.10000000149012, 1.8999999761581, 25, 10, 10, -14, baseMultiplier = 7.948, damageEffectiveness = 7.948, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [35] = { 0.10000000149012, 1.8999999761581, 25, 10, 10, -14, baseMultiplier = 8.1, damageEffectiveness = 8.1, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [36] = { 0.10000000149012, 1.8999999761581, 26, 10, 10, -14, baseMultiplier = 8.255, damageEffectiveness = 8.255, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [37] = { 0.10000000149012, 1.8999999761581, 26, 11, 11, -14, baseMultiplier = 8.412, damageEffectiveness = 8.412, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [38] = { 0.10000000149012, 1.8999999761581, 26, 11, 11, -13, baseMultiplier = 8.572, damageEffectiveness = 8.572, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [39] = { 0.10000000149012, 1.8999999761581, 26, 11, 11, -13, baseMultiplier = 8.737, damageEffectiveness = 8.737, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + [40] = { 0.10000000149012, 1.8999999761581, 27, 11, 11, -13, baseMultiplier = 8.903, damageEffectiveness = 8.903, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, 1, 1, }, }, + }, +} + +skills["SmokeMineMercenary"] = { + name = "Smoke Mine", + hidden = true, + mercenary = true, + inheritedFrom = "SmokeMine", + color = 2, + description = "Throws a mine that will teleport you to it when detonated. It covers both your escape and arrival with a cloud of smoke that blinds enemies, and gives you a temporary buff to movement speed. Shares a cooldown with other Blink skills.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Movement] = true, [SkillType.RemoteMined] = true, [SkillType.AreaSpell] = true, [SkillType.Travel] = true, [SkillType.HasReservation] = true, [SkillType.Blink] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + mine = true, + movement = true, + spell = true, + }, + constantStats = { + { "base_mine_duration", 8000 }, + { "base_secondary_skill_effect_duration", 1000 }, + { "ground_smoke_art_variation", 5 }, + }, + stats = { + "base_skill_effect_duration", + "base_movement_velocity_+%", + "is_remote_mine", + "base_skill_is_mined", + "base_deal_no_damage", + "disable_mine_detonation_cascade", + "mine_detonates_instantly", + "additive_mine_duration_modifiers_apply_to_buff_effect_duration", + "mine_cannot_rearm", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 4000, 20, cooldown = 5, levelRequirement = 10, storedUses = 3, statInterpolation = { 1, 1, }, }, + [2] = { 4100, 20, cooldown = 5, levelRequirement = 13, storedUses = 3, statInterpolation = { 1, 1, }, }, + [3] = { 4100, 21, cooldown = 5, levelRequirement = 17, storedUses = 3, statInterpolation = { 1, 1, }, }, + [4] = { 4200, 21, cooldown = 5, levelRequirement = 21, storedUses = 3, statInterpolation = { 1, 1, }, }, + [5] = { 4200, 22, cooldown = 5, levelRequirement = 25, storedUses = 3, statInterpolation = { 1, 1, }, }, + [6] = { 4300, 22, cooldown = 5, levelRequirement = 29, storedUses = 3, statInterpolation = { 1, 1, }, }, + [7] = { 4300, 23, cooldown = 5, levelRequirement = 33, storedUses = 3, statInterpolation = { 1, 1, }, }, + [8] = { 4400, 23, cooldown = 5, levelRequirement = 36, storedUses = 3, statInterpolation = { 1, 1, }, }, + [9] = { 4400, 24, cooldown = 5, levelRequirement = 39, storedUses = 3, statInterpolation = { 1, 1, }, }, + [10] = { 4500, 24, cooldown = 5, levelRequirement = 42, storedUses = 3, statInterpolation = { 1, 1, }, }, + [11] = { 4500, 25, cooldown = 5, levelRequirement = 45, storedUses = 3, statInterpolation = { 1, 1, }, }, + [12] = { 4600, 25, cooldown = 5, levelRequirement = 48, storedUses = 3, statInterpolation = { 1, 1, }, }, + [13] = { 4600, 26, cooldown = 5, levelRequirement = 51, storedUses = 3, statInterpolation = { 1, 1, }, }, + [14] = { 4700, 26, cooldown = 5, levelRequirement = 54, storedUses = 3, statInterpolation = { 1, 1, }, }, + [15] = { 4700, 27, cooldown = 5, levelRequirement = 57, storedUses = 3, statInterpolation = { 1, 1, }, }, + [16] = { 4800, 27, cooldown = 5, levelRequirement = 60, storedUses = 3, statInterpolation = { 1, 1, }, }, + [17] = { 4800, 28, cooldown = 5, levelRequirement = 63, storedUses = 3, statInterpolation = { 1, 1, }, }, + [18] = { 4900, 28, cooldown = 5, levelRequirement = 66, storedUses = 3, statInterpolation = { 1, 1, }, }, + [19] = { 4900, 29, cooldown = 5, levelRequirement = 68, storedUses = 3, statInterpolation = { 1, 1, }, }, + [20] = { 5000, 29, cooldown = 5, levelRequirement = 70, storedUses = 3, statInterpolation = { 1, 1, }, }, + [21] = { 5000, 30, cooldown = 5, levelRequirement = 72, storedUses = 3, statInterpolation = { 1, 1, }, }, + [22] = { 5100, 30, cooldown = 5, levelRequirement = 74, storedUses = 3, statInterpolation = { 1, 1, }, }, + [23] = { 5100, 31, cooldown = 5, levelRequirement = 76, storedUses = 3, statInterpolation = { 1, 1, }, }, + [24] = { 5200, 31, cooldown = 5, levelRequirement = 78, storedUses = 3, statInterpolation = { 1, 1, }, }, + [25] = { 5200, 32, cooldown = 5, levelRequirement = 80, storedUses = 3, statInterpolation = { 1, 1, }, }, + [26] = { 5300, 32, cooldown = 5, levelRequirement = 82, storedUses = 3, statInterpolation = { 1, 1, }, }, + [27] = { 5300, 33, cooldown = 5, levelRequirement = 84, storedUses = 3, statInterpolation = { 1, 1, }, }, + [28] = { 5400, 33, cooldown = 5, levelRequirement = 86, storedUses = 3, statInterpolation = { 1, 1, }, }, + [29] = { 5400, 34, cooldown = 5, levelRequirement = 88, storedUses = 3, statInterpolation = { 1, 1, }, }, + [30] = { 5500, 34, cooldown = 5, levelRequirement = 90, storedUses = 3, statInterpolation = { 1, 1, }, }, + [31] = { 5500, 34, cooldown = 5, levelRequirement = 91, storedUses = 3, statInterpolation = { 1, 1, }, }, + [32] = { 5600, 35, cooldown = 5, levelRequirement = 92, storedUses = 3, statInterpolation = { 1, 1, }, }, + [33] = { 5600, 35, cooldown = 5, levelRequirement = 93, storedUses = 3, statInterpolation = { 1, 1, }, }, + [34] = { 5700, 35, cooldown = 5, levelRequirement = 94, storedUses = 3, statInterpolation = { 1, 1, }, }, + [35] = { 5700, 35, cooldown = 5, levelRequirement = 95, storedUses = 3, statInterpolation = { 1, 1, }, }, + [36] = { 5800, 36, cooldown = 5, levelRequirement = 96, storedUses = 3, statInterpolation = { 1, 1, }, }, + [37] = { 5800, 36, cooldown = 5, levelRequirement = 97, storedUses = 3, statInterpolation = { 1, 1, }, }, + [38] = { 5900, 36, cooldown = 5, levelRequirement = 98, storedUses = 3, statInterpolation = { 1, 1, }, }, + [39] = { 5900, 36, cooldown = 5, levelRequirement = 99, storedUses = 3, statInterpolation = { 1, 1, }, }, + [40] = { 6000, 37, cooldown = 5, levelRequirement = 100, storedUses = 3, statInterpolation = { 1, 1, }, }, + }, +} + +skills["SoulrendAltMercenary"] = { + name = "Soulrend of Reaping", + hidden = true, + mercenary = true, + inheritedFrom = "SoulrendAltX", + color = 3, + baseEffectiveness = 8.6300001144409, + incrementalEffectiveness = 0.056699998676777, + description = "Fires a projectile that deals chaos damage to enemies it hits and leeches some of that damage as energy shield.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.Damage] = true, [SkillType.Chaos] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.CanRapidFire] = true, [SkillType.ProjectilesFromUser] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + projectile = true, + spell = true, + }, + constantStats = { + { "active_skill_projectile_speed_+%_variation_final", 25 }, + { "base_energy_shield_leech_from_spell_damage_permyriad", 400 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["SoulrendAltMercenaryEncounter"] = { + name = "Soulrend of Reaping", + hidden = true, + mercenary = true, + inheritedFrom = "SoulrendAltX", + color = 3, + baseEffectiveness = 6, + incrementalEffectiveness = 0.046000000089407, + description = "Fires a projectile that deals chaos damage to enemies it hits and leeches some of that damage as energy shield.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.Damage] = true, [SkillType.Chaos] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.CanRapidFire] = true, [SkillType.ProjectilesFromUser] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + projectile = true, + spell = true, + }, + constantStats = { + { "active_skill_projectile_speed_+%_variation_final", 25 }, + { "base_energy_shield_leech_from_spell_damage_permyriad", 400 }, + }, + stats = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_chaos_damage", + "spell_maximum_base_chaos_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 28, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 31, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 34, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 37, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 40, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 42, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 44, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 46, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 48, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 50, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 52, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 54, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 56, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 58, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 60, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 62, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 64, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 66, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 68, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 70, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 72, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 74, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 76, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 78, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 80, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 82, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 84, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 86, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 88, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 90, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 91, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 92, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 93, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 94, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 95, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 96, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 97, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 98, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 99, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, critChance = 7, damageEffectiveness = 4, levelRequirement = 100, statInterpolation = { 3, 3, }, }, + }, +} + +skills["SparkMercenary"] = { + name = "Spark", + hidden = true, + mercenary = true, + inheritedFrom = "Spark", + color = 3, + baseEffectiveness = 3.8399000167847, + incrementalEffectiveness = 0.033100001513958, + description = "Launches unpredictable sparks that move randomly until they hit an enemy or expire.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.65, + baseFlags = { + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "base_number_of_projectiles", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 5, }, }, + [2] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, cost = { Mana = 5, }, }, + [3] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [4] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, cost = { Mana = 7, }, }, + [5] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, cost = { Mana = 7, }, }, + [6] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [7] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [8] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [9] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [10] = { 0.10000000149012, 1.8999999761581, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [11] = { 0.10000000149012, 1.8999999761581, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [12] = { 0.10000000149012, 1.8999999761581, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [13] = { 0.10000000149012, 1.8999999761581, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [14] = { 0.10000000149012, 1.8999999761581, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [15] = { 0.10000000149012, 1.8999999761581, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [16] = { 0.10000000149012, 1.8999999761581, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [17] = { 0.10000000149012, 1.8999999761581, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [18] = { 0.10000000149012, 1.8999999761581, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [19] = { 0.10000000149012, 1.8999999761581, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [20] = { 0.10000000149012, 1.8999999761581, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [21] = { 0.10000000149012, 1.8999999761581, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [22] = { 0.10000000149012, 1.8999999761581, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [23] = { 0.10000000149012, 1.8999999761581, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, cost = { Mana = 23, }, }, + [24] = { 0.10000000149012, 1.8999999761581, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, cost = { Mana = 23, }, }, + [25] = { 0.10000000149012, 1.8999999761581, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [26] = { 0.10000000149012, 1.8999999761581, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [27] = { 0.10000000149012, 1.8999999761581, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [28] = { 0.10000000149012, 1.8999999761581, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [29] = { 0.10000000149012, 1.8999999761581, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [30] = { 0.10000000149012, 1.8999999761581, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [31] = { 0.10000000149012, 1.8999999761581, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [32] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [33] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [34] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [35] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [36] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [37] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [38] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [39] = { 0.10000000149012, 1.8999999761581, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [40] = { 0.10000000149012, 1.8999999761581, 11, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + }, +} + +skills["SparkMercenaryEncounter"] = { + name = "Spark", + hidden = true, + mercenary = true, + inheritedFrom = "Spark", + color = 3, + baseEffectiveness = 2.4500000476837, + incrementalEffectiveness = 0.033100001513958, + description = "Launches unpredictable sparks that move randomly until they hit an enemy or expire.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.65, + baseFlags = { + duration = true, + projectile = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "base_number_of_projectiles", + "base_is_projectile", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 1, statInterpolation = { 3, 3, 1, }, cost = { Mana = 5, }, }, + [2] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 2, statInterpolation = { 3, 3, 1, }, cost = { Mana = 5, }, }, + [3] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 4, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [4] = { 0.10000000149012, 1.8999999761581, 4, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 7, statInterpolation = { 3, 3, 1, }, cost = { Mana = 7, }, }, + [5] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 11, statInterpolation = { 3, 3, 1, }, cost = { Mana = 7, }, }, + [6] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 16, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [7] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 20, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [8] = { 0.10000000149012, 1.8999999761581, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 24, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [9] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 28, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [10] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 32, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [11] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 36, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [12] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 40, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [13] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [14] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 48, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [15] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 52, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [16] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [17] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 60, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [18] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [19] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 67, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [20] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [21] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [22] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [23] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, cost = { Mana = 23, }, }, + [24] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, cost = { Mana = 23, }, }, + [25] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [26] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, cost = { Mana = 24, }, }, + [27] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [28] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, cost = { Mana = 25, }, }, + [29] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [30] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [31] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, cost = { Mana = 26, }, }, + [32] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [33] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [34] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [35] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [36] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, cost = { Mana = 27, }, }, + [37] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [38] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [39] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + [40] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 1.9, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, cost = { Mana = 28, }, }, + }, +} + +skills["SpectralHelixAltMercenary"] = { + name = "Spectral Helix of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "SpectralHelixAltY", + color = 2, + description = "Throws a trap which, once triggered, fires a spectral copy of your melee weapon. It spins around while flying in a large spiral, damaging enemies in its path, and bouncing if it collides with walls. If dual wielding, each Trap thrown will randomly use either the main hand or off hand weapon.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Trapped] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + trap = true, + }, + constantStats = { + { "spectral_spiral_weapon_base_number_of_bounces", 3 }, + { "spectral_helix_rotations_%", 425 }, + { "base_trap_duration", 4000 }, + { "throw_X_additional_traps_if_dual_wielding", 1 }, + { "throw_traps_in_circle_radius", 15 }, + }, + stats = { + "projectiles_nova", + "base_is_projectile", + "is_trap", + "base_skill_is_trapped", + "ignores_trap_and_mine_cooldown_limit", + }, + levels = { + [1] = { baseMultiplier = 1.2, damageEffectiveness = 1.2, levelRequirement = 12, }, + [2] = { baseMultiplier = 1.244, damageEffectiveness = 1.244, levelRequirement = 15, }, + [3] = { baseMultiplier = 1.288, damageEffectiveness = 1.288, levelRequirement = 19, }, + [4] = { baseMultiplier = 1.333, damageEffectiveness = 1.333, levelRequirement = 23, }, + [5] = { baseMultiplier = 1.377, damageEffectiveness = 1.377, levelRequirement = 27, }, + [6] = { baseMultiplier = 1.421, damageEffectiveness = 1.421, levelRequirement = 31, }, + [7] = { baseMultiplier = 1.465, damageEffectiveness = 1.465, levelRequirement = 35, }, + [8] = { baseMultiplier = 1.509, damageEffectiveness = 1.509, levelRequirement = 38, }, + [9] = { baseMultiplier = 1.554, damageEffectiveness = 1.554, levelRequirement = 41, }, + [10] = { baseMultiplier = 1.598, damageEffectiveness = 1.598, levelRequirement = 44, }, + [11] = { baseMultiplier = 1.642, damageEffectiveness = 1.642, levelRequirement = 47, }, + [12] = { baseMultiplier = 1.686, damageEffectiveness = 1.686, levelRequirement = 50, }, + [13] = { baseMultiplier = 1.731, damageEffectiveness = 1.731, levelRequirement = 53, }, + [14] = { baseMultiplier = 1.775, damageEffectiveness = 1.775, levelRequirement = 56, }, + [15] = { baseMultiplier = 1.819, damageEffectiveness = 1.819, levelRequirement = 59, }, + [16] = { baseMultiplier = 1.863, damageEffectiveness = 1.863, levelRequirement = 62, }, + [17] = { baseMultiplier = 1.907, damageEffectiveness = 1.907, levelRequirement = 64, }, + [18] = { baseMultiplier = 1.952, damageEffectiveness = 1.952, levelRequirement = 66, }, + [19] = { baseMultiplier = 1.996, damageEffectiveness = 1.996, levelRequirement = 68, }, + [20] = { baseMultiplier = 2.04, damageEffectiveness = 2.04, levelRequirement = 70, }, + [21] = { baseMultiplier = 2.084, damageEffectiveness = 2.084, levelRequirement = 72, }, + [22] = { baseMultiplier = 2.128, damageEffectiveness = 2.128, levelRequirement = 74, }, + [23] = { baseMultiplier = 2.173, damageEffectiveness = 2.173, levelRequirement = 76, }, + [24] = { baseMultiplier = 2.217, damageEffectiveness = 2.217, levelRequirement = 78, }, + [25] = { baseMultiplier = 2.261, damageEffectiveness = 2.261, levelRequirement = 80, }, + [26] = { baseMultiplier = 2.305, damageEffectiveness = 2.305, levelRequirement = 82, }, + [27] = { baseMultiplier = 2.349, damageEffectiveness = 2.349, levelRequirement = 84, }, + [28] = { baseMultiplier = 2.394, damageEffectiveness = 2.394, levelRequirement = 86, }, + [29] = { baseMultiplier = 2.438, damageEffectiveness = 2.438, levelRequirement = 88, }, + [30] = { baseMultiplier = 2.482, damageEffectiveness = 2.482, levelRequirement = 90, }, + [31] = { baseMultiplier = 2.504, damageEffectiveness = 2.504, levelRequirement = 91, }, + [32] = { baseMultiplier = 2.526, damageEffectiveness = 2.526, levelRequirement = 92, }, + [33] = { baseMultiplier = 2.548, damageEffectiveness = 2.548, levelRequirement = 93, }, + [34] = { baseMultiplier = 2.571, damageEffectiveness = 2.571, levelRequirement = 94, }, + [35] = { baseMultiplier = 2.593, damageEffectiveness = 2.593, levelRequirement = 95, }, + [36] = { baseMultiplier = 2.615, damageEffectiveness = 2.615, levelRequirement = 96, }, + [37] = { baseMultiplier = 2.637, damageEffectiveness = 2.637, levelRequirement = 97, }, + [38] = { baseMultiplier = 2.659, damageEffectiveness = 2.659, levelRequirement = 98, }, + [39] = { baseMultiplier = 2.681, damageEffectiveness = 2.681, levelRequirement = 99, }, + [40] = { baseMultiplier = 2.703, damageEffectiveness = 2.703, levelRequirement = 100, }, + }, +} + +skills["SpectralHelixMercenary"] = { + name = "Spectral Helix", + hidden = true, + mercenary = true, + inheritedFrom = "SpectralHelix", + color = 2, + description = "Throws a spectral copy of your melee weapon. It spins around while flying in a large spiral, damaging enemies in its path, and bouncing if it collides with walls.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "spectral_spiral_weapon_base_number_of_bounces", 3 }, + { "spectral_helix_rotations_%", 425 }, + }, + stats = { + "projectiles_nova", + "base_is_projectile", + }, + levels = { + [1] = { attackSpeedMultiplier = 20, baseMultiplier = 1.0924, damageEffectiveness = 1.0924, levelRequirement = 12, }, + [2] = { attackSpeedMultiplier = 20, baseMultiplier = 1.1072, damageEffectiveness = 1.1072, levelRequirement = 15, }, + [3] = { attackSpeedMultiplier = 20, baseMultiplier = 1.1215, damageEffectiveness = 1.1215, levelRequirement = 19, }, + [4] = { attackSpeedMultiplier = 20, baseMultiplier = 1.1363, damageEffectiveness = 1.1363, levelRequirement = 23, }, + [5] = { attackSpeedMultiplier = 20, baseMultiplier = 1.1506, damageEffectiveness = 1.1506, levelRequirement = 27, }, + [6] = { attackSpeedMultiplier = 20, baseMultiplier = 1.1654, damageEffectiveness = 1.1654, levelRequirement = 31, }, + [7] = { attackSpeedMultiplier = 20, baseMultiplier = 1.1797, damageEffectiveness = 1.1797, levelRequirement = 35, }, + [8] = { attackSpeedMultiplier = 20, baseMultiplier = 1.1945, damageEffectiveness = 1.1945, levelRequirement = 38, }, + [9] = { attackSpeedMultiplier = 20, baseMultiplier = 1.2093, damageEffectiveness = 1.2093, levelRequirement = 41, }, + [10] = { attackSpeedMultiplier = 20, baseMultiplier = 1.2236, damageEffectiveness = 1.2236, levelRequirement = 44, }, + [11] = { attackSpeedMultiplier = 20, baseMultiplier = 1.2384, damageEffectiveness = 1.2384, levelRequirement = 47, }, + [12] = { attackSpeedMultiplier = 20, baseMultiplier = 1.2527, damageEffectiveness = 1.2527, levelRequirement = 50, }, + [13] = { attackSpeedMultiplier = 20, baseMultiplier = 1.2675, damageEffectiveness = 1.2675, levelRequirement = 53, }, + [14] = { attackSpeedMultiplier = 20, baseMultiplier = 1.2823, damageEffectiveness = 1.2823, levelRequirement = 56, }, + [15] = { attackSpeedMultiplier = 20, baseMultiplier = 1.2966, damageEffectiveness = 1.2966, levelRequirement = 59, }, + [16] = { attackSpeedMultiplier = 20, baseMultiplier = 1.3114, damageEffectiveness = 1.3114, levelRequirement = 62, }, + [17] = { attackSpeedMultiplier = 20, baseMultiplier = 1.3257, damageEffectiveness = 1.3257, levelRequirement = 64, }, + [18] = { attackSpeedMultiplier = 20, baseMultiplier = 1.3405, damageEffectiveness = 1.3405, levelRequirement = 66, }, + [19] = { attackSpeedMultiplier = 20, baseMultiplier = 1.3548, damageEffectiveness = 1.3548, levelRequirement = 68, }, + [20] = { attackSpeedMultiplier = 20, baseMultiplier = 1.3696, damageEffectiveness = 1.3696, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = 20, baseMultiplier = 1.3844, damageEffectiveness = 1.3844, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = 20, baseMultiplier = 1.3987, damageEffectiveness = 1.3987, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = 20, baseMultiplier = 1.4135, damageEffectiveness = 1.4135, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = 20, baseMultiplier = 1.4278, damageEffectiveness = 1.4278, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = 20, baseMultiplier = 1.4426, damageEffectiveness = 1.4426, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = 20, baseMultiplier = 1.4569, damageEffectiveness = 1.4569, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = 20, baseMultiplier = 1.4717, damageEffectiveness = 1.4717, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = 20, baseMultiplier = 1.4865, damageEffectiveness = 1.4865, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5008, damageEffectiveness = 1.5008, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5156, damageEffectiveness = 1.5156, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = 20, baseMultiplier = 1.523, damageEffectiveness = 1.523, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5299, damageEffectiveness = 1.5299, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5373, damageEffectiveness = 1.5373, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5447, damageEffectiveness = 1.5447, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5521, damageEffectiveness = 1.5521, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5595, damageEffectiveness = 1.5595, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5664, damageEffectiveness = 1.5664, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5738, damageEffectiveness = 1.5738, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5812, damageEffectiveness = 1.5812, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5886, damageEffectiveness = 1.5886, levelRequirement = 100, }, + }, +} + +skills["SpectralShieldThrowAltMercenary"] = { + name = "Spectral Shield Throw of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "SpectralShieldThrowAltY", + color = 2, + baseEffectiveness = 1.6200000047684, + incrementalEffectiveness = 0.017300000414252, + description = "Throws a spectral copy of your shield as a piercing projectile which deals off-hand damage augmented by the defences of the shield. When it reaches the targeted location it will hover in place, repeatedly firing a number of smaller shards as projectiles in all directions. The rate at which it releases shards will increase until all shards have been fired. Modifiers that cause additional projectiles to be fired will add more shards, not more copies of the shield.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.SingleMainProjectile] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "stationary_shield_throw_firing_interval_ms", 600 }, + { "stationary_shield_throw_projectiles_per_interval", 6 }, + { "number_of_additional_projectiles", 18 }, + { "stationary_shield_throw_interval_acceleration_%_per_interval", 40 }, + { "thrown_shield_secondary_projectile_damage_+%_final", -50 }, + }, + stats = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + "number_of_additional_projectiles", + "off_hand_minimum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "off_hand_maximum_added_physical_damage_per_15_shield_armour_and_evasion_rating", + "base_is_projectile", + }, + notMinionStat = { + "off_hand_local_minimum_added_physical_damage", + "off_hand_local_maximum_added_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, 2, 3, attackTime = 650, critChance = 5, levelRequirement = 28, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 0, 2, 3, attackTime = 650, critChance = 5, levelRequirement = 31, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 0, 2, 3, attackTime = 650, critChance = 5, levelRequirement = 34, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 1, 2, 3, attackTime = 650, critChance = 5, levelRequirement = 37, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 1, 2, 3, attackTime = 650, critChance = 5, levelRequirement = 40, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 1, 2, 4, attackTime = 650, critChance = 5, levelRequirement = 42, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 1, 2, 4, attackTime = 650, critChance = 5, levelRequirement = 44, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 2, 2, 4, attackTime = 650, critChance = 5, levelRequirement = 46, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 2, 2, 4, attackTime = 650, critChance = 5, levelRequirement = 48, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 2, 2, 4, attackTime = 650, critChance = 5, levelRequirement = 50, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 2, 2, 4, attackTime = 650, critChance = 5, levelRequirement = 52, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 3, 3, 4, attackTime = 650, critChance = 5, levelRequirement = 54, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 3, 3, 4, attackTime = 650, critChance = 5, levelRequirement = 56, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 3, 3, 4, attackTime = 650, critChance = 5, levelRequirement = 58, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 3, 3, 4, attackTime = 650, critChance = 5, levelRequirement = 60, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 4, 3, 4, attackTime = 650, critChance = 5, levelRequirement = 62, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 4, 3, 4, attackTime = 650, critChance = 5, levelRequirement = 64, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 4, 3, 5, attackTime = 650, critChance = 5, levelRequirement = 66, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 4, 3, 5, attackTime = 650, critChance = 5, levelRequirement = 68, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 5, 3, 5, attackTime = 650, critChance = 5, levelRequirement = 70, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 5, 3, 5, attackTime = 650, critChance = 5, levelRequirement = 72, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 5, 3, 5, attackTime = 650, critChance = 5, levelRequirement = 74, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 5, 3, 5, attackTime = 650, critChance = 5, levelRequirement = 76, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 6, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 78, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 6, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 80, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 6, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 82, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 6, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 84, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 7, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 86, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 7, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 88, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 7, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 90, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 7, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 91, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 8, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 92, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 8, 3, 6, attackTime = 650, critChance = 5, levelRequirement = 93, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 8, 4, 6, attackTime = 650, critChance = 5, levelRequirement = 94, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8, 4, 6, attackTime = 650, critChance = 5, levelRequirement = 95, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 9, 4, 6, attackTime = 650, critChance = 5, levelRequirement = 96, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 9, 4, 6, attackTime = 650, critChance = 5, levelRequirement = 97, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 9, 4, 6, attackTime = 650, critChance = 5, levelRequirement = 98, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 9, 4, 6, attackTime = 650, critChance = 5, levelRequirement = 99, statInterpolation = { 3, 3, 1, 1, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 10, 4, 6, attackTime = 650, critChance = 5, levelRequirement = 100, statInterpolation = { 3, 3, 1, 1, 1, }, }, + }, +} + +skills["SpectralThrowAltMercenary"] = { + name = "Spectral Throw of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "SpectralThrowAltY", + color = 2, + description = "Throws a trap which, once triggered, fires many spectral copies of your melee weapon. They fly out in all directions and then return to where the trap triggered, in a spinning attack that damages enemies in their path. If dual wielding, each Trap thrown will randomly use either the main hand or off hand weapon.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Trapped] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + trap = true, + }, + constantStats = { + { "spectral_throw_forget_hit_list_time_override", 225 }, + { "base_trap_duration", 4000 }, + { "throw_X_additional_traps_if_dual_wielding", 1 }, + { "throw_traps_in_circle_radius", 15 }, + }, + stats = { + "base_number_of_projectiles", + "base_is_projectile", + "is_trap", + "base_skill_is_trapped", + "projectiles_nova", + "ignores_trap_and_mine_cooldown_limit", + }, + levels = { + [1] = { 3, baseMultiplier = 0.92, damageEffectiveness = 0.92, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 3, baseMultiplier = 0.951, damageEffectiveness = 0.951, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 3, baseMultiplier = 0.981, damageEffectiveness = 0.981, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 3, baseMultiplier = 1.012, damageEffectiveness = 1.012, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 3, baseMultiplier = 1.042, damageEffectiveness = 1.042, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 3, baseMultiplier = 1.073, damageEffectiveness = 1.073, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 3, baseMultiplier = 1.103, damageEffectiveness = 1.103, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 3, baseMultiplier = 1.134, damageEffectiveness = 1.134, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 3, baseMultiplier = 1.164, damageEffectiveness = 1.164, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 4, baseMultiplier = 1.195, damageEffectiveness = 1.195, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 4, baseMultiplier = 1.225, damageEffectiveness = 1.225, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 4, baseMultiplier = 1.256, damageEffectiveness = 1.256, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 4, baseMultiplier = 1.286, damageEffectiveness = 1.286, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 4, baseMultiplier = 1.317, damageEffectiveness = 1.317, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 4, baseMultiplier = 1.347, damageEffectiveness = 1.347, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 4, baseMultiplier = 1.378, damageEffectiveness = 1.378, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 4, baseMultiplier = 1.408, damageEffectiveness = 1.408, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 4, baseMultiplier = 1.439, damageEffectiveness = 1.439, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 4, baseMultiplier = 1.469, damageEffectiveness = 1.469, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 5, baseMultiplier = 1.5, damageEffectiveness = 1.5, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 5, baseMultiplier = 1.531, damageEffectiveness = 1.531, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 5, baseMultiplier = 1.561, damageEffectiveness = 1.561, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 5, baseMultiplier = 1.592, damageEffectiveness = 1.592, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 5, baseMultiplier = 1.622, damageEffectiveness = 1.622, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 5, baseMultiplier = 1.653, damageEffectiveness = 1.653, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 5, baseMultiplier = 1.683, damageEffectiveness = 1.683, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 5, baseMultiplier = 1.714, damageEffectiveness = 1.714, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 5, baseMultiplier = 1.744, damageEffectiveness = 1.744, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 5, baseMultiplier = 1.775, damageEffectiveness = 1.775, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 6, baseMultiplier = 1.805, damageEffectiveness = 1.805, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 6, baseMultiplier = 1.821, damageEffectiveness = 1.821, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 6, baseMultiplier = 1.836, damageEffectiveness = 1.836, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 6, baseMultiplier = 1.851, damageEffectiveness = 1.851, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 6, baseMultiplier = 1.866, damageEffectiveness = 1.866, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 6, baseMultiplier = 1.882, damageEffectiveness = 1.882, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 6, baseMultiplier = 1.897, damageEffectiveness = 1.897, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 6, baseMultiplier = 1.912, damageEffectiveness = 1.912, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 6, baseMultiplier = 1.927, damageEffectiveness = 1.927, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 6, baseMultiplier = 1.943, damageEffectiveness = 1.943, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 7, baseMultiplier = 1.958, damageEffectiveness = 1.958, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["SplitArrowMercenary"] = { + name = "Split Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "SplitArrow", + color = 2, + description = "Fires multiple arrows at different targets.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "active_skill_projectile_speed_+%_variation_final", 50 }, + }, + stats = { + "base_number_of_arrows", + "skill_can_fire_arrows", + "quality_display_base_additional_arrows_is_gem", + }, + levels = { + [1] = { 5, baseMultiplier = 1.2, damageEffectiveness = 1.2, levelRequirement = 1, statInterpolation = { 1, }, }, + [2] = { 5, baseMultiplier = 1.212, damageEffectiveness = 1.212, levelRequirement = 2, statInterpolation = { 1, }, }, + [3] = { 5, baseMultiplier = 1.224, damageEffectiveness = 1.224, levelRequirement = 4, statInterpolation = { 1, }, }, + [4] = { 6, baseMultiplier = 1.236, damageEffectiveness = 1.236, levelRequirement = 7, statInterpolation = { 1, }, }, + [5] = { 6, baseMultiplier = 1.248, damageEffectiveness = 1.248, levelRequirement = 11, statInterpolation = { 1, }, }, + [6] = { 6, baseMultiplier = 1.26, damageEffectiveness = 1.26, levelRequirement = 16, statInterpolation = { 1, }, }, + [7] = { 6, baseMultiplier = 1.272, damageEffectiveness = 1.272, levelRequirement = 20, statInterpolation = { 1, }, }, + [8] = { 7, baseMultiplier = 1.284, damageEffectiveness = 1.284, levelRequirement = 24, statInterpolation = { 1, }, }, + [9] = { 7, baseMultiplier = 1.296, damageEffectiveness = 1.296, levelRequirement = 28, statInterpolation = { 1, }, }, + [10] = { 7, baseMultiplier = 1.308, damageEffectiveness = 1.308, levelRequirement = 32, statInterpolation = { 1, }, }, + [11] = { 7, baseMultiplier = 1.32, damageEffectiveness = 1.32, levelRequirement = 36, statInterpolation = { 1, }, }, + [12] = { 8, baseMultiplier = 1.332, damageEffectiveness = 1.332, levelRequirement = 40, statInterpolation = { 1, }, }, + [13] = { 8, baseMultiplier = 1.344, damageEffectiveness = 1.344, levelRequirement = 44, statInterpolation = { 1, }, }, + [14] = { 8, baseMultiplier = 1.356, damageEffectiveness = 1.356, levelRequirement = 48, statInterpolation = { 1, }, }, + [15] = { 8, baseMultiplier = 1.368, damageEffectiveness = 1.368, levelRequirement = 52, statInterpolation = { 1, }, }, + [16] = { 8, baseMultiplier = 1.38, damageEffectiveness = 1.38, levelRequirement = 56, statInterpolation = { 1, }, }, + [17] = { 9, baseMultiplier = 1.392, damageEffectiveness = 1.392, levelRequirement = 60, statInterpolation = { 1, }, }, + [18] = { 9, baseMultiplier = 1.404, damageEffectiveness = 1.404, levelRequirement = 64, statInterpolation = { 1, }, }, + [19] = { 9, baseMultiplier = 1.416, damageEffectiveness = 1.416, levelRequirement = 67, statInterpolation = { 1, }, }, + [20] = { 9, baseMultiplier = 1.428, damageEffectiveness = 1.428, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 10, baseMultiplier = 1.44, damageEffectiveness = 1.44, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 10, baseMultiplier = 1.452, damageEffectiveness = 1.452, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 10, baseMultiplier = 1.464, damageEffectiveness = 1.464, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 10, baseMultiplier = 1.476, damageEffectiveness = 1.476, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 11, baseMultiplier = 1.488, damageEffectiveness = 1.488, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 11, baseMultiplier = 1.5, damageEffectiveness = 1.5, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 11, baseMultiplier = 1.512, damageEffectiveness = 1.512, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 11, baseMultiplier = 1.524, damageEffectiveness = 1.524, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 11, baseMultiplier = 1.536, damageEffectiveness = 1.536, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 12, baseMultiplier = 1.548, damageEffectiveness = 1.548, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 12, baseMultiplier = 1.554, damageEffectiveness = 1.554, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 12, baseMultiplier = 1.56, damageEffectiveness = 1.56, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 12, baseMultiplier = 1.566, damageEffectiveness = 1.566, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 12, baseMultiplier = 1.572, damageEffectiveness = 1.572, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 12, baseMultiplier = 1.578, damageEffectiveness = 1.578, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 12, baseMultiplier = 1.584, damageEffectiveness = 1.584, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 13, baseMultiplier = 1.59, damageEffectiveness = 1.59, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 13, baseMultiplier = 1.596, damageEffectiveness = 1.596, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 13, baseMultiplier = 1.602, damageEffectiveness = 1.602, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 13, baseMultiplier = 1.608, damageEffectiveness = 1.608, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["SplittingSteelMercenary"] = { + name = "Splitting Steel", + hidden = true, + mercenary = true, + inheritedFrom = "SplittingSteel", + color = 2, + description = "Fire a single projectile that splits on impact or at the targeted location, dealing area damage when it splits and again when the split projectiles explode at the end of their flight. Projectiles from this skill cannot return. Requires a Sword or Axe.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Physical] = true, [SkillType.SingleMainProjectile] = true, [SkillType.ProjectileCannotReturn] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "attacks_impale_on_hit_%_chance", 40 }, + { "active_skill_base_area_of_effect_radius", 8 }, + }, + stats = { + "projectile_number_to_split", + "active_skill_base_area_of_effect_radius", + "modifiers_to_number_of_projectiles_instead_apply_to_splitting", + "projectiles_can_split_at_end_of_range", + "projectiles_can_split_from_terrain", + "base_is_projectile", + "console_skill_dont_chase", + "skill_projectiles_cannot_return", + }, + levels = { + [1] = { 2, 0, attackSpeedMultiplier = -10, baseMultiplier = 1.2, damageEffectiveness = 1.2, levelRequirement = 1, statInterpolation = { 1, 1, }, }, + [2] = { 2, 0, attackSpeedMultiplier = -10, baseMultiplier = 1.341, damageEffectiveness = 1.341, levelRequirement = 2, statInterpolation = { 1, 1, }, }, + [3] = { 2, 0, attackSpeedMultiplier = -10, baseMultiplier = 1.481, damageEffectiveness = 1.481, levelRequirement = 4, statInterpolation = { 1, 1, }, }, + [4] = { 2, 0, attackSpeedMultiplier = -10, baseMultiplier = 1.622, damageEffectiveness = 1.622, levelRequirement = 7, statInterpolation = { 1, 1, }, }, + [5] = { 2, 1, attackSpeedMultiplier = -10, baseMultiplier = 1.762, damageEffectiveness = 1.762, levelRequirement = 11, statInterpolation = { 1, 1, }, }, + [6] = { 2, 1, attackSpeedMultiplier = -10, baseMultiplier = 1.903, damageEffectiveness = 1.903, levelRequirement = 16, statInterpolation = { 1, 1, }, }, + [7] = { 3, 1, attackSpeedMultiplier = -10, baseMultiplier = 2.043, damageEffectiveness = 2.043, levelRequirement = 20, statInterpolation = { 1, 1, }, }, + [8] = { 3, 1, attackSpeedMultiplier = -10, baseMultiplier = 2.184, damageEffectiveness = 2.184, levelRequirement = 24, statInterpolation = { 1, 1, }, }, + [9] = { 3, 2, attackSpeedMultiplier = -10, baseMultiplier = 2.324, damageEffectiveness = 2.324, levelRequirement = 28, statInterpolation = { 1, 1, }, }, + [10] = { 3, 2, attackSpeedMultiplier = -10, baseMultiplier = 2.465, damageEffectiveness = 2.465, levelRequirement = 32, statInterpolation = { 1, 1, }, }, + [11] = { 3, 2, attackSpeedMultiplier = -10, baseMultiplier = 2.605, damageEffectiveness = 2.605, levelRequirement = 36, statInterpolation = { 1, 1, }, }, + [12] = { 3, 2, attackSpeedMultiplier = -10, baseMultiplier = 2.746, damageEffectiveness = 2.746, levelRequirement = 40, statInterpolation = { 1, 1, }, }, + [13] = { 3, 3, attackSpeedMultiplier = -10, baseMultiplier = 2.886, damageEffectiveness = 2.886, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [14] = { 3, 3, attackSpeedMultiplier = -10, baseMultiplier = 3.027, damageEffectiveness = 3.027, levelRequirement = 48, statInterpolation = { 1, 1, }, }, + [15] = { 4, 3, attackSpeedMultiplier = -10, baseMultiplier = 3.167, damageEffectiveness = 3.167, levelRequirement = 52, statInterpolation = { 1, 1, }, }, + [16] = { 4, 3, attackSpeedMultiplier = -10, baseMultiplier = 3.308, damageEffectiveness = 3.308, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [17] = { 4, 4, attackSpeedMultiplier = -10, baseMultiplier = 3.448, damageEffectiveness = 3.448, levelRequirement = 60, statInterpolation = { 1, 1, }, }, + [18] = { 4, 4, attackSpeedMultiplier = -10, baseMultiplier = 3.589, damageEffectiveness = 3.589, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [19] = { 4, 4, attackSpeedMultiplier = -10, baseMultiplier = 3.729, damageEffectiveness = 3.729, levelRequirement = 67, statInterpolation = { 1, 1, }, }, + [20] = { 5, 4, attackSpeedMultiplier = -10, baseMultiplier = 3.87, damageEffectiveness = 3.87, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 5, 5, attackSpeedMultiplier = -10, baseMultiplier = 4.011, damageEffectiveness = 4.011, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 5, 5, attackSpeedMultiplier = -10, baseMultiplier = 4.151, damageEffectiveness = 4.151, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 5, 5, attackSpeedMultiplier = -10, baseMultiplier = 4.292, damageEffectiveness = 4.292, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 5, 5, attackSpeedMultiplier = -10, baseMultiplier = 4.432, damageEffectiveness = 4.432, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 5, 6, attackSpeedMultiplier = -10, baseMultiplier = 4.573, damageEffectiveness = 4.573, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 5, 6, attackSpeedMultiplier = -10, baseMultiplier = 4.713, damageEffectiveness = 4.713, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 5, 6, attackSpeedMultiplier = -10, baseMultiplier = 4.854, damageEffectiveness = 4.854, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 6, 6, attackSpeedMultiplier = -10, baseMultiplier = 4.994, damageEffectiveness = 4.994, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 6, 7, attackSpeedMultiplier = -10, baseMultiplier = 5.135, damageEffectiveness = 5.135, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 6, 7, attackSpeedMultiplier = -10, baseMultiplier = 5.275, damageEffectiveness = 5.275, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 6, 7, attackSpeedMultiplier = -10, baseMultiplier = 5.346, damageEffectiveness = 5.346, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 6, 7, attackSpeedMultiplier = -10, baseMultiplier = 5.416, damageEffectiveness = 5.416, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 6, 7, attackSpeedMultiplier = -10, baseMultiplier = 5.486, damageEffectiveness = 5.486, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 7, 7, attackSpeedMultiplier = -10, baseMultiplier = 5.556, damageEffectiveness = 5.556, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 7, 7, attackSpeedMultiplier = -10, baseMultiplier = 5.627, damageEffectiveness = 5.627, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 7, 8, attackSpeedMultiplier = -10, baseMultiplier = 5.697, damageEffectiveness = 5.697, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 7, 8, attackSpeedMultiplier = -10, baseMultiplier = 5.767, damageEffectiveness = 5.767, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 7, 8, attackSpeedMultiplier = -10, baseMultiplier = 5.837, damageEffectiveness = 5.837, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 7, 8, attackSpeedMultiplier = -10, baseMultiplier = 5.908, damageEffectiveness = 5.908, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 8, 8, attackSpeedMultiplier = -10, baseMultiplier = 5.978, damageEffectiveness = 5.978, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["StaticStrikeMercenary"] = { + name = "Static Strike", + hidden = true, + mercenary = true, + inheritedFrom = "StaticStrike", + color = 1, + description = "Attack with a melee weapon, gaining static energy for a duration if you hit an enemy. While you have static energy, you'll frequently hit a number of nearby enemies with beams, dealing attack damage.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Lightning] = true, [SkillType.Chains] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "number_of_chains", 1 }, + { "static_strike_beam_damage_+%_final", -40 }, + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "static_strike_base_zap_frequency_ms", + "static_strike_number_of_beam_targets", + }, + levels = { + [1] = { 400, 4, baseMultiplier = 1.506, damageEffectiveness = 1.506, levelRequirement = 12, statInterpolation = { 1, 1, }, }, + [2] = { 400, 4, baseMultiplier = 1.574, damageEffectiveness = 1.574, levelRequirement = 15, statInterpolation = { 1, 1, }, }, + [3] = { 390, 4, baseMultiplier = 1.647, damageEffectiveness = 1.647, levelRequirement = 19, statInterpolation = { 1, 1, }, }, + [4] = { 390, 4, baseMultiplier = 1.723, damageEffectiveness = 1.723, levelRequirement = 23, statInterpolation = { 1, 1, }, }, + [5] = { 380, 4, baseMultiplier = 1.805, damageEffectiveness = 1.805, levelRequirement = 27, statInterpolation = { 1, 1, }, }, + [6] = { 380, 4, baseMultiplier = 1.888, damageEffectiveness = 1.888, levelRequirement = 31, statInterpolation = { 1, 1, }, }, + [7] = { 380, 4, baseMultiplier = 1.976, damageEffectiveness = 1.976, levelRequirement = 35, statInterpolation = { 1, 1, }, }, + [8] = { 370, 4, baseMultiplier = 2.064, damageEffectiveness = 2.064, levelRequirement = 38, statInterpolation = { 1, 1, }, }, + [9] = { 370, 4, baseMultiplier = 2.157, damageEffectiveness = 2.157, levelRequirement = 41, statInterpolation = { 1, 1, }, }, + [10] = { 360, 5, baseMultiplier = 2.253, damageEffectiveness = 2.253, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [11] = { 360, 5, baseMultiplier = 2.354, damageEffectiveness = 2.354, levelRequirement = 47, statInterpolation = { 1, 1, }, }, + [12] = { 360, 5, baseMultiplier = 2.458, damageEffectiveness = 2.458, levelRequirement = 50, statInterpolation = { 1, 1, }, }, + [13] = { 350, 5, baseMultiplier = 2.568, damageEffectiveness = 2.568, levelRequirement = 53, statInterpolation = { 1, 1, }, }, + [14] = { 350, 5, baseMultiplier = 2.683, damageEffectiveness = 2.683, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [15] = { 340, 5, baseMultiplier = 2.801, damageEffectiveness = 2.801, levelRequirement = 59, statInterpolation = { 1, 1, }, }, + [16] = { 340, 5, baseMultiplier = 2.927, damageEffectiveness = 2.927, levelRequirement = 62, statInterpolation = { 1, 1, }, }, + [17] = { 340, 5, baseMultiplier = 3.052, damageEffectiveness = 3.052, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [18] = { 330, 5, baseMultiplier = 3.182, damageEffectiveness = 3.182, levelRequirement = 66, statInterpolation = { 1, 1, }, }, + [19] = { 330, 5, baseMultiplier = 3.318, damageEffectiveness = 3.318, levelRequirement = 68, statInterpolation = { 1, 1, }, }, + [20] = { 320, 6, baseMultiplier = 3.46, damageEffectiveness = 3.46, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 320, 6, baseMultiplier = 3.607, damageEffectiveness = 3.607, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 320, 6, baseMultiplier = 3.762, damageEffectiveness = 3.762, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 310, 6, baseMultiplier = 3.922, damageEffectiveness = 3.922, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 310, 6, baseMultiplier = 4.089, damageEffectiveness = 4.089, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 300, 6, baseMultiplier = 4.264, damageEffectiveness = 4.264, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 300, 6, baseMultiplier = 4.445, damageEffectiveness = 4.445, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 300, 6, baseMultiplier = 4.634, damageEffectiveness = 4.634, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 290, 6, baseMultiplier = 4.832, damageEffectiveness = 4.832, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 290, 6, baseMultiplier = 5.037, damageEffectiveness = 5.037, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 280, 7, baseMultiplier = 5.251, damageEffectiveness = 5.251, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 280, 7, baseMultiplier = 5.575, damageEffectiveness = 5.575, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 280, 7, baseMultiplier = 5.692, damageEffectiveness = 5.692, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 280, 7, baseMultiplier = 5.814, damageEffectiveness = 5.814, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 280, 7, baseMultiplier = 5.938, damageEffectiveness = 5.938, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 270, 7, baseMultiplier = 6.063, damageEffectiveness = 6.063, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 270, 7, baseMultiplier = 6.193, damageEffectiveness = 6.193, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 270, 7, baseMultiplier = 6.324, damageEffectiveness = 6.324, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 270, 7, baseMultiplier = 6.457, damageEffectiveness = 6.457, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 270, 7, baseMultiplier = 6.595, damageEffectiveness = 6.595, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 260, 7, baseMultiplier = 6.736, damageEffectiveness = 6.736, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["StaticStrikeMercenaryEncounteer"] = { + name = "Static Strike", + hidden = true, + mercenary = true, + inheritedFrom = "StaticStrike", + color = 1, + description = "Attack with a melee weapon, gaining static energy for a duration if you hit an enemy. While you have static energy, you'll frequently hit a number of nearby enemies with beams, dealing attack damage.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Lightning] = true, [SkillType.Chains] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "number_of_chains", 1 }, + { "static_strike_beam_damage_+%_final", -70 }, + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "static_strike_base_zap_frequency_ms", + "static_strike_number_of_beam_targets", + }, + levels = { + [1] = { 300, 5, baseMultiplier = 2.2, damageEffectiveness = 2.2, levelRequirement = 0, statInterpolation = { 1, 1, }, }, + }, +} + +skills["StormCallAltMercenary"] = { + name = "Storm Call of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "StormCallAltX", + color = 3, + baseEffectiveness = 1.827399969101, + incrementalEffectiveness = 0.044100001454353, + description = "Sets a marker at a location. After a short duration, a bolt strikes the marker, dealing physical damage around it and causing bolts to strike at any other markers you've cast. Bolt impacts will leave behind a pool of boiling blood, which deals physical damage over time to enemies within it for a secondary duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "base_secondary_skill_effect_duration", 4000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 100.66666828096, damageEffectiveness = 2.35, levelRequirement = 12, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 98.499999658515, damageEffectiveness = 2.35, levelRequirement = 15, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 96.50000152116, damageEffectiveness = 2.35, levelRequirement = 19, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 94.333332898716, damageEffectiveness = 2.35, levelRequirement = 23, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 92.333334761361, damageEffectiveness = 2.35, levelRequirement = 27, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 91.000002669791, damageEffectiveness = 2.35, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 89.666670578222, damageEffectiveness = 2.35, levelRequirement = 35, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 88.333338486652, damageEffectiveness = 2.35, levelRequirement = 38, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 87.166668932885, damageEffectiveness = 2.35, levelRequirement = 41, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 85.833336841315, damageEffectiveness = 2.35, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 84.666667287548, damageEffectiveness = 2.35, levelRequirement = 47, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 83.500005681068, damageEffectiveness = 2.35, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 82.333336127301, damageEffectiveness = 2.35, levelRequirement = 53, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 81.166666573534, damageEffectiveness = 2.35, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 80.000004967054, damageEffectiveness = 2.35, levelRequirement = 59, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 78.833335413287, damageEffectiveness = 2.35, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 77.500003321717, damageEffectiveness = 2.35, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 76.166671230147, damageEffectiveness = 2.35, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 75.500005184362, damageEffectiveness = 2.35, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 74.499998168399, damageEffectiveness = 2.35, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 73.499999099721, damageEffectiveness = 2.35, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 72.333337493241, damageEffectiveness = 2.35, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 71.333338424564, damageEffectiveness = 2.35, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 70.3333314086, damageEffectiveness = 2.35, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 69.333332339923, damageEffectiveness = 2.35, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 68.333333271245, damageEffectiveness = 2.35, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 67.333334202568, damageEffectiveness = 2.35, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 66.500001645337, damageEffectiveness = 2.35, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 65.500002576659, damageEffectiveness = 2.35, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 64.499999534339, damageEffectiveness = 2.35, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 64, damageEffectiveness = 2.35, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 63.666666977108, damageEffectiveness = 2.35, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 63.166667442769, damageEffectiveness = 2.35, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 62.66666790843, damageEffectiveness = 2.35, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 62.333334885538, damageEffectiveness = 2.35, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 61.833335351199, damageEffectiveness = 2.35, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 61.33333581686, damageEffectiveness = 2.35, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 61.000002793968, damageEffectiveness = 2.35, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 60.500003259629, damageEffectiveness = 2.35, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 59.999999751647, damageEffectiveness = 2.35, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["StormCallAltMercenaryEncounter"] = { + name = "Storm Call of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "StormCallAltX", + color = 3, + baseEffectiveness = 2, + incrementalEffectiveness = 0.035000000149012, + description = "Sets a marker at a location. After a short duration, a bolt strikes the marker, dealing physical damage around it and causing bolts to strike at any other markers you've cast. Bolt impacts will leave behind a pool of boiling blood, which deals physical damage over time to enemies within it for a secondary duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 2000 }, + { "base_secondary_skill_effect_duration", 2000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 12, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 15, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 19, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 23, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 27, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 35, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 38, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 41, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 47, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 53, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 59, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 33.333334078391, critChance = 5, damageEffectiveness = 1.1, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["StormCallMercenary"] = { + name = "Stormcall", + hidden = true, + mercenary = true, + inheritedFrom = "StormCall", + color = 3, + baseEffectiveness = 3, + incrementalEffectiveness = 0.050000000745058, + description = "Sets a marker at a location. After a short duration, lightning strikes the marker, dealing damage around it and causing lightning strikes at any other markers you've cast.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Lightning] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1500 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.5, 1.5, 0, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [2] = { 0.5, 1.5, 0, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [3] = { 0.5, 1.5, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, cost = { Mana = 7, }, }, + [4] = { 0.5, 1.5, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, cost = { Mana = 8, }, }, + [5] = { 0.5, 1.5, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [6] = { 0.5, 1.5, 2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [7] = { 0.5, 1.5, 2, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [8] = { 0.5, 1.5, 2, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [9] = { 0.5, 1.5, 3, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [10] = { 0.5, 1.5, 3, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [11] = { 0.5, 1.5, 3, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [12] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [13] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [14] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [15] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [16] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [17] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [18] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [19] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [20] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [21] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [22] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [23] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [24] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [25] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [26] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [27] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [28] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [29] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [30] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [31] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [32] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [33] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [34] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [35] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [36] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [37] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [38] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [39] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [40] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + }, +} + +skills["StormCallMercenaryEncounter"] = { + name = "Stormcall", + hidden = true, + mercenary = true, + inheritedFrom = "StormCall", + color = 3, + baseEffectiveness = 1.7999999523163, + incrementalEffectiveness = 0.035999998450279, + description = "Sets a marker at a location. After a short duration, lightning strikes the marker, dealing damage around it and causing lightning strikes at any other markers you've cast.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Multicastable] = true, [SkillType.Lightning] = true, [SkillType.Cascadable] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 1500 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.5, 1.5, 0, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [2] = { 0.5, 1.5, 0, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, cost = { Mana = 6, }, }, + [3] = { 0.5, 1.5, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, cost = { Mana = 7, }, }, + [4] = { 0.5, 1.5, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, cost = { Mana = 8, }, }, + [5] = { 0.5, 1.5, 1, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [6] = { 0.5, 1.5, 2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, cost = { Mana = 9, }, }, + [7] = { 0.5, 1.5, 2, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, cost = { Mana = 10, }, }, + [8] = { 0.5, 1.5, 2, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [9] = { 0.5, 1.5, 3, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, cost = { Mana = 11, }, }, + [10] = { 0.5, 1.5, 3, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [11] = { 0.5, 1.5, 3, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, cost = { Mana = 12, }, }, + [12] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [13] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, cost = { Mana = 13, }, }, + [14] = { 0.5, 1.5, 4, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [15] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, cost = { Mana = 14, }, }, + [16] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [17] = { 0.5, 1.5, 5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, cost = { Mana = 15, }, }, + [18] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [19] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [20] = { 0.5, 1.5, 6, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, cost = { Mana = 16, }, }, + [21] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [22] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, cost = { Mana = 17, }, }, + [23] = { 0.5, 1.5, 7, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [24] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [25] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, cost = { Mana = 18, }, }, + [26] = { 0.5, 1.5, 8, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [27] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [28] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, cost = { Mana = 19, }, }, + [29] = { 0.5, 1.5, 9, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [30] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [31] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [32] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, cost = { Mana = 20, }, }, + [33] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [34] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [35] = { 0.5, 1.5, 10, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [36] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [37] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, cost = { Mana = 21, }, }, + [38] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [39] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + [40] = { 0.5, 1.5, 11, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, cost = { Mana = 22, }, }, + }, +} + +skills["StormRainMercenary"] = { + name = "Storm Rain", + hidden = true, + mercenary = true, + inheritedFrom = "StormRain", + color = 2, + description = "Fires an arrow into the air to land at a targeted location, dealing area damage. The arrow sticks in the ground where it lands, and periodically fires a beam of lightning to another arrow near it, dealing area damage between them.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, [SkillType.Lightning] = true, [SkillType.ProjectileNumber] = true, [SkillType.Damage] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "storm_rain_pulse_count", 4 }, + { "number_of_allowed_storm_arrows", 100 }, + }, + stats = { + "prismatic_rain_beam_base_frequency_ms", + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + "cannot_pierce", + "console_skill_dont_chase", + "skill_can_add_multiple_charges_per_action", + }, + levels = { + [1] = { 500, baseMultiplier = 0.46, damageEffectiveness = 0.46, levelRequirement = 28, statInterpolation = { 1, }, }, + [2] = { 500, baseMultiplier = 0.466, damageEffectiveness = 0.47, levelRequirement = 31, statInterpolation = { 1, }, }, + [3] = { 490, baseMultiplier = 0.473, damageEffectiveness = 0.47, levelRequirement = 34, statInterpolation = { 1, }, }, + [4] = { 490, baseMultiplier = 0.479, damageEffectiveness = 0.48, levelRequirement = 37, statInterpolation = { 1, }, }, + [5] = { 480, baseMultiplier = 0.485, damageEffectiveness = 0.49, levelRequirement = 40, statInterpolation = { 1, }, }, + [6] = { 480, baseMultiplier = 0.492, damageEffectiveness = 0.49, levelRequirement = 42, statInterpolation = { 1, }, }, + [7] = { 470, baseMultiplier = 0.498, damageEffectiveness = 0.5, levelRequirement = 44, statInterpolation = { 1, }, }, + [8] = { 470, baseMultiplier = 0.504, damageEffectiveness = 0.5, levelRequirement = 46, statInterpolation = { 1, }, }, + [9] = { 460, baseMultiplier = 0.511, damageEffectiveness = 0.51, levelRequirement = 48, statInterpolation = { 1, }, }, + [10] = { 460, baseMultiplier = 0.517, damageEffectiveness = 0.52, levelRequirement = 50, statInterpolation = { 1, }, }, + [11] = { 450, baseMultiplier = 0.523, damageEffectiveness = 0.52, levelRequirement = 52, statInterpolation = { 1, }, }, + [12] = { 450, baseMultiplier = 0.529, damageEffectiveness = 0.53, levelRequirement = 54, statInterpolation = { 1, }, }, + [13] = { 440, baseMultiplier = 0.536, damageEffectiveness = 0.54, levelRequirement = 56, statInterpolation = { 1, }, }, + [14] = { 440, baseMultiplier = 0.542, damageEffectiveness = 0.54, levelRequirement = 58, statInterpolation = { 1, }, }, + [15] = { 430, baseMultiplier = 0.548, damageEffectiveness = 0.55, levelRequirement = 60, statInterpolation = { 1, }, }, + [16] = { 430, baseMultiplier = 0.555, damageEffectiveness = 0.55, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 420, baseMultiplier = 0.561, damageEffectiveness = 0.56, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 420, baseMultiplier = 0.567, damageEffectiveness = 0.57, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 410, baseMultiplier = 0.574, damageEffectiveness = 0.57, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 410, baseMultiplier = 0.58, damageEffectiveness = 0.58, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 400, baseMultiplier = 0.586, damageEffectiveness = 0.59, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 400, baseMultiplier = 0.593, damageEffectiveness = 0.59, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 390, baseMultiplier = 0.599, damageEffectiveness = 0.6, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 390, baseMultiplier = 0.605, damageEffectiveness = 0.61, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 380, baseMultiplier = 0.612, damageEffectiveness = 0.61, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 380, baseMultiplier = 0.618, damageEffectiveness = 0.62, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 370, baseMultiplier = 0.624, damageEffectiveness = 0.62, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 370, baseMultiplier = 0.631, damageEffectiveness = 0.63, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 360, baseMultiplier = 0.637, damageEffectiveness = 0.64, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 360, baseMultiplier = 0.643, damageEffectiveness = 0.64, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 350, baseMultiplier = 0.646, damageEffectiveness = 0.65, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 350, baseMultiplier = 0.649, damageEffectiveness = 0.65, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 350, baseMultiplier = 0.653, damageEffectiveness = 0.65, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 350, baseMultiplier = 0.656, damageEffectiveness = 0.66, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 340, baseMultiplier = 0.659, damageEffectiveness = 0.66, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 340, baseMultiplier = 0.662, damageEffectiveness = 0.66, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 340, baseMultiplier = 0.665, damageEffectiveness = 0.67, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 340, baseMultiplier = 0.668, damageEffectiveness = 0.67, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 330, baseMultiplier = 0.672, damageEffectiveness = 0.67, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 330, baseMultiplier = 0.675, damageEffectiveness = 0.67, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["SummonHolyRelicMercenary"] = { + name = "Holy Relic", + hidden = true, + mercenary = true, + inheritedFrom = "SummonHolyRelic", + color = 3, + description = "Summon a Holy Relic that stays near you. When you hit an enemy with an attack, the Holy Relic triggers a nova spell with a short cooldown, that deals physical damage to enemies and grants life regeneration to allies in an area around it. This life regeneration is higher when applied to minions.", + skillTypes = { [SkillType.Triggerable] = true, [SkillType.Mineable] = true, [SkillType.Minion] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Multicastable] = true, [SkillType.Spell] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.CreatesMinion] = true, [SkillType.Cooldown] = true, }, + minionSkillTypes = { [SkillType.Damage] = true, [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Triggered] = true, [SkillType.Duration] = true, [SkillType.Physical] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 1, + baseFlags = { + minion = true, + spell = true, + }, + constantStats = { + { "base_number_of_relics_allowed", 1 }, + { "display_minion_monster_type", 16 }, + }, + stats = { + "active_skill_minion_movement_velocity_+%_final", + "holy_relic_nova_life_regeneration_rate_per_minute", + "holy_relic_nova_minion_life_regeneration_rate_per_second", + "base_display_minion_actor_level", + "minions_cannot_taunt_enemies", + "infinite_minion_duration", + }, + notMinionStat = { + "active_skill_minion_movement_velocity_+%_final", + }, + levels = { + [1] = { 0, 314, 9, 4, cooldown = 2, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [2] = { 4, 374, 12, 6, cooldown = 2, levelRequirement = 6, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [3] = { 8, 476, 17, 9, cooldown = 2, levelRequirement = 9, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [4] = { 12, 602, 21, 12, cooldown = 2, levelRequirement = 12, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [5] = { 16, 801, 27, 16, cooldown = 2, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [6] = { 20, 1046, 38, 20, cooldown = 2, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [7] = { 24, 1337, 50, 24, cooldown = 2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [8] = { 28, 1679, 65, 28, cooldown = 2, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [9] = { 32, 2072, 81, 32, cooldown = 2, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [10] = { 36, 2522, 101, 36, cooldown = 2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [11] = { 40, 3029, 125, 40, cooldown = 2, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [12] = { 44, 3599, 150, 44, cooldown = 2, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [13] = { 48, 4232, 182, 48, cooldown = 2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [14] = { 52, 4932, 216, 52, cooldown = 2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [15] = { 56, 5535, 251, 55, cooldown = 2, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [16] = { 60, 6183, 285, 58, cooldown = 2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [17] = { 64, 6881, 323, 61, cooldown = 2, levelRequirement = 61, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [18] = { 68, 7628, 366, 64, cooldown = 2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [19] = { 72, 8424, 413, 67, cooldown = 2, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [20] = { 76, 9275, 464, 70, cooldown = 2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [21] = { 80, 9938, 497, 72, cooldown = 2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [22] = { 84, 10424, 521, 74, cooldown = 2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [23] = { 88, 10922, 546, 76, cooldown = 2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [24] = { 92, 11432, 572, 78, cooldown = 2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [25] = { 96, 11954, 597, 80, cooldown = 2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [26] = { 100, 12488, 624, 82, cooldown = 2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [27] = { 104, 13034, 651, 84, cooldown = 2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [28] = { 108, 13590, 680, 86, cooldown = 2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [29] = { 112, 14160, 708, 88, cooldown = 2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [30] = { 116, 14742, 737, 90, cooldown = 2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [31] = { 118, 14889, 744, 91, cooldown = 2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [32] = { 120, 15039, 752, 92, cooldown = 2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [33] = { 122, 15191, 759, 93, cooldown = 2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [34] = { 124, 15344, 767, 94, cooldown = 2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [35] = { 126, 15497, 774, 95, cooldown = 2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [36] = { 128, 15654, 782, 96, cooldown = 2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [37] = { 130, 15812, 791, 97, cooldown = 2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [38] = { 132, 15969, 798, 98, cooldown = 2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [39] = { 134, 16131, 807, 99, cooldown = 2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + [40] = { 136, 16293, 815, 100, cooldown = 2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, + }, +} + +skills["SummonRagingSpiritMercenary"] = { + name = "Summon Raging Spirit", + hidden = true, + mercenary = true, + inheritedFrom = "SummonRagingSpirit", + color = 3, + description = "Summons a short-lived flaming skull that rushes at nearby enemies and attacks them rapidly, converting all its physical damage to fire. Enemies will not directly engage these spirits, and can pass through them.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.Duration] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 5000 }, + { "base_number_of_raging_spirits_allowed", 20 }, + { "display_minion_monster_type", 20 }, + }, + stats = { + "minions_cannot_taunt_enemies", + }, + levels = { + [1] = { levelRequirement = 4, }, + [2] = { levelRequirement = 6, }, + [3] = { levelRequirement = 9, }, + [4] = { levelRequirement = 12, }, + [5] = { levelRequirement = 16, }, + [6] = { levelRequirement = 20, }, + [7] = { levelRequirement = 24, }, + [8] = { levelRequirement = 28, }, + [9] = { levelRequirement = 32, }, + [10] = { levelRequirement = 36, }, + [11] = { levelRequirement = 40, }, + [12] = { levelRequirement = 44, }, + [13] = { levelRequirement = 48, }, + [14] = { levelRequirement = 52, }, + [15] = { levelRequirement = 55, }, + [16] = { levelRequirement = 58, }, + [17] = { levelRequirement = 61, }, + [18] = { levelRequirement = 64, }, + [19] = { levelRequirement = 67, }, + [20] = { levelRequirement = 70, }, + [21] = { levelRequirement = 72, }, + [22] = { levelRequirement = 74, }, + [23] = { levelRequirement = 76, }, + [24] = { levelRequirement = 78, }, + [25] = { levelRequirement = 80, }, + [26] = { levelRequirement = 82, }, + [27] = { levelRequirement = 84, }, + [28] = { levelRequirement = 86, }, + [29] = { levelRequirement = 88, }, + [30] = { levelRequirement = 90, }, + [31] = { levelRequirement = 91, }, + [32] = { levelRequirement = 92, }, + [33] = { levelRequirement = 93, }, + [34] = { levelRequirement = 94, }, + [35] = { levelRequirement = 95, }, + [36] = { levelRequirement = 96, }, + [37] = { levelRequirement = 97, }, + [38] = { levelRequirement = 98, }, + [39] = { levelRequirement = 99, }, + [40] = { levelRequirement = 100, }, + }, +} + +skills["SummonSkeletonsMercenary"] = { + name = "Summon Skeletons", + hidden = true, + mercenary = true, + inheritedFrom = "SummonSkeletons", + color = 3, + baseEffectiveness = 0, + description = "Summon Skeleton Warrior minions at the targeted location. They use a melee attack and die after a duration. If made aggressive, Skeleton Warriors will also dash towards nearby enemies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Minion] = true, [SkillType.Duration] = true, [SkillType.MinionsCanExplode] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.CreatesMinion] = true, [SkillType.Cooldown] = true, }, + minionSkillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.ProjectilesFromUser] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + duration = true, + minion = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 20000 }, + { "display_minion_monster_type", 2 }, + }, + stats = { + "number_of_melee_skeletons_to_summon", + "base_number_of_skeletons_allowed", + "base_display_minion_actor_level", + }, + levels = { + [1] = { 2, 5, 10, levelRequirement = 10, statInterpolation = { 1, 1, 1, }, }, + [2] = { 2, 5, 13, levelRequirement = 13, statInterpolation = { 1, 1, 1, }, }, + [3] = { 2, 5, 17, levelRequirement = 17, statInterpolation = { 1, 1, 1, }, }, + [4] = { 2, 5, 21, levelRequirement = 21, statInterpolation = { 1, 1, 1, }, }, + [5] = { 2, 5, 25, levelRequirement = 25, statInterpolation = { 1, 1, 1, }, }, + [6] = { 2, 6, 29, levelRequirement = 29, statInterpolation = { 1, 1, 1, }, }, + [7] = { 2, 6, 33, levelRequirement = 33, statInterpolation = { 1, 1, 1, }, }, + [8] = { 2, 6, 36, levelRequirement = 36, statInterpolation = { 1, 1, 1, }, }, + [9] = { 2, 6, 39, levelRequirement = 39, statInterpolation = { 1, 1, 1, }, }, + [10] = { 2, 6, 42, levelRequirement = 42, statInterpolation = { 1, 1, 1, }, }, + [11] = { 3, 6, 45, levelRequirement = 45, statInterpolation = { 1, 1, 1, }, }, + [12] = { 3, 6, 48, levelRequirement = 48, statInterpolation = { 1, 1, 1, }, }, + [13] = { 3, 6, 51, levelRequirement = 51, statInterpolation = { 1, 1, 1, }, }, + [14] = { 3, 6, 54, levelRequirement = 54, statInterpolation = { 1, 1, 1, }, }, + [15] = { 3, 6, 57, levelRequirement = 57, statInterpolation = { 1, 1, 1, }, }, + [16] = { 3, 7, 60, levelRequirement = 60, statInterpolation = { 1, 1, 1, }, }, + [17] = { 3, 7, 63, levelRequirement = 63, statInterpolation = { 1, 1, 1, }, }, + [18] = { 3, 7, 66, levelRequirement = 66, statInterpolation = { 1, 1, 1, }, }, + [19] = { 3, 7, 68, levelRequirement = 68, statInterpolation = { 1, 1, 1, }, }, + [20] = { 3, 7, 70, levelRequirement = 70, statInterpolation = { 1, 1, 1, }, }, + [21] = { 4, 7, 72, levelRequirement = 72, statInterpolation = { 1, 1, 1, }, }, + [22] = { 4, 7, 74, levelRequirement = 74, statInterpolation = { 1, 1, 1, }, }, + [23] = { 4, 7, 76, levelRequirement = 76, statInterpolation = { 1, 1, 1, }, }, + [24] = { 4, 7, 78, levelRequirement = 78, statInterpolation = { 1, 1, 1, }, }, + [25] = { 4, 8, 80, levelRequirement = 80, statInterpolation = { 1, 1, 1, }, }, + [26] = { 4, 8, 82, levelRequirement = 82, statInterpolation = { 1, 1, 1, }, }, + [27] = { 4, 8, 84, levelRequirement = 84, statInterpolation = { 1, 1, 1, }, }, + [28] = { 4, 8, 86, levelRequirement = 86, statInterpolation = { 1, 1, 1, }, }, + [29] = { 4, 8, 88, levelRequirement = 88, statInterpolation = { 1, 1, 1, }, }, + [30] = { 4, 8, 90, levelRequirement = 90, statInterpolation = { 1, 1, 1, }, }, + [31] = { 5, 8, 91, levelRequirement = 91, statInterpolation = { 1, 1, 1, }, }, + [32] = { 5, 8, 92, levelRequirement = 92, statInterpolation = { 1, 1, 1, }, }, + [33] = { 5, 8, 93, levelRequirement = 93, statInterpolation = { 1, 1, 1, }, }, + [34] = { 5, 8, 94, levelRequirement = 94, statInterpolation = { 1, 1, 1, }, }, + [35] = { 5, 8, 95, levelRequirement = 95, statInterpolation = { 1, 1, 1, }, }, + [36] = { 5, 8, 96, levelRequirement = 96, statInterpolation = { 1, 1, 1, }, }, + [37] = { 5, 8, 97, levelRequirement = 97, statInterpolation = { 1, 1, 1, }, }, + [38] = { 5, 8, 98, levelRequirement = 98, statInterpolation = { 1, 1, 1, }, }, + [39] = { 5, 9, 99, levelRequirement = 99, statInterpolation = { 1, 1, 1, }, }, + [40] = { 5, 9, 100, levelRequirement = 100, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["SummonSkitterbotsMercenary"] = { + name = "Summon Skitterbots", + hidden = true, + mercenary = true, + inheritedFrom = "SummonSkitterbots", + color = 3, + description = "Summon a Chilling Skitterbot and a Shocking Skitterbot, which will trigger your traps and detonate your mines. Mines detonated by Skitterbots will re-arm and can then be detonated again. The Skitterbots grant you more trap and mine damage, and cannot be targeted or damaged.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Instant] = true, [SkillType.Minion] = true, [SkillType.CreatesMinion] = true, [SkillType.MinionsAreUndamagable] = true, [SkillType.HasReservation] = true, [SkillType.Cold] = true, [SkillType.Lightning] = true, [SkillType.NonHitChill] = true, [SkillType.ElementalStatus] = true, [SkillType.Area] = true, [SkillType.Aura] = true, [SkillType.AuraAffectsEnemies] = true, [SkillType.AuraNotOnCaster] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "minion_spell_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + minion = true, + spell = true, + }, + constantStats = { + { "skitterbots_trap_mine_damage_+%_final", 10 }, + }, + stats = { + "shock_effect_+%", + "chill_effect_+%", + "minion_movement_speed_+%", + "infinite_minion_duration", + }, + levels = { + [1] = { 0, 0, 0, cooldown = 1.2, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 1, 1, 4, cooldown = 1.2, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 2, 2, 8, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 3, 3, 12, cooldown = 1.2, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 4, 4, 16, cooldown = 1.2, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 5, 5, 20, cooldown = 1.2, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 6, 6, 24, cooldown = 1.2, levelRequirement = 37, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 7, 7, 28, cooldown = 1.2, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 8, 8, 32, cooldown = 1.2, levelRequirement = 43, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 9, 9, 36, cooldown = 1.2, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 10, 10, 40, cooldown = 1.2, levelRequirement = 49, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 11, 11, 44, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 12, 12, 48, cooldown = 1.2, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 13, 13, 52, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 14, 14, 56, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 15, 15, 60, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 16, 16, 64, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 17, 17, 68, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 18, 18, 72, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 19, 19, 76, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 20, 20, 80, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 21, 21, 84, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 22, 22, 88, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 23, 23, 92, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 24, 24, 96, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 25, 25, 100, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 26, 26, 104, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 27, 27, 108, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 28, 28, 112, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 29, 29, 116, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 30, 30, 120, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 31, 31, 124, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 32, 32, 128, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 33, 33, 132, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 34, 34, 136, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 35, 35, 140, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 36, 36, 144, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 37, 37, 148, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 38, 38, 152, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 39, 39, 156, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["SunderAltMercenary"] = { + name = "Sunder of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "SunderAltY", + color = 1, + description = "Slams the ground, creating a slow wave of churning terrain that damages enemies in a sequence of areas in front of you. A number of enemies hit by the wave will release a shockwave, damaging other enemies around them. Using the skill again will stop the previous wave. When the wave reaches a target or terrain, it can restart aiming towards an enemy, if one is in range. Requires a Mace, Sceptre, Axe, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "shockwave_slam_explosion_damage_+%_final", -40 }, + { "base_sunder_wave_delay_ms", 300 }, + { "sunder_wave_radius_+_per_step", 1 }, + { "sunder_wave_max_steps", 4 }, + { "sunder_wave_min_steps", 2 }, + { "sunder_shockwave_limit_per_cascade", 5 }, + { "sunder_number_of_fake_chains", 2 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 2.05, damageEffectiveness = 2.05, levelRequirement = 12, }, + [2] = { baseMultiplier = 2.19, damageEffectiveness = 2.19, levelRequirement = 15, }, + [3] = { baseMultiplier = 2.33, damageEffectiveness = 2.33, levelRequirement = 19, }, + [4] = { baseMultiplier = 2.47, damageEffectiveness = 2.47, levelRequirement = 23, }, + [5] = { baseMultiplier = 2.61, damageEffectiveness = 2.61, levelRequirement = 27, }, + [6] = { baseMultiplier = 2.75, damageEffectiveness = 2.75, levelRequirement = 31, }, + [7] = { baseMultiplier = 2.89, damageEffectiveness = 2.89, levelRequirement = 35, }, + [8] = { baseMultiplier = 3.03, damageEffectiveness = 3.03, levelRequirement = 38, }, + [9] = { baseMultiplier = 3.17, damageEffectiveness = 3.17, levelRequirement = 41, }, + [10] = { baseMultiplier = 3.31, damageEffectiveness = 3.31, levelRequirement = 44, }, + [11] = { baseMultiplier = 3.45, damageEffectiveness = 3.45, levelRequirement = 47, }, + [12] = { baseMultiplier = 3.59, damageEffectiveness = 3.59, levelRequirement = 50, }, + [13] = { baseMultiplier = 3.73, damageEffectiveness = 3.73, levelRequirement = 53, }, + [14] = { baseMultiplier = 3.87, damageEffectiveness = 3.87, levelRequirement = 56, }, + [15] = { baseMultiplier = 4.01, damageEffectiveness = 4.01, levelRequirement = 59, }, + [16] = { baseMultiplier = 4.15, damageEffectiveness = 4.15, levelRequirement = 62, }, + [17] = { baseMultiplier = 4.29, damageEffectiveness = 4.29, levelRequirement = 64, }, + [18] = { baseMultiplier = 4.43, damageEffectiveness = 4.43, levelRequirement = 66, }, + [19] = { baseMultiplier = 4.57, damageEffectiveness = 4.57, levelRequirement = 68, }, + [20] = { baseMultiplier = 4.71, damageEffectiveness = 4.71, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.85, damageEffectiveness = 4.85, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.99, damageEffectiveness = 4.99, levelRequirement = 74, }, + [23] = { baseMultiplier = 5.13, damageEffectiveness = 5.13, levelRequirement = 76, }, + [24] = { baseMultiplier = 5.27, damageEffectiveness = 5.27, levelRequirement = 78, }, + [25] = { baseMultiplier = 5.41, damageEffectiveness = 5.41, levelRequirement = 80, }, + [26] = { baseMultiplier = 5.55, damageEffectiveness = 5.55, levelRequirement = 82, }, + [27] = { baseMultiplier = 5.69, damageEffectiveness = 5.69, levelRequirement = 84, }, + [28] = { baseMultiplier = 5.83, damageEffectiveness = 5.83, levelRequirement = 86, }, + [29] = { baseMultiplier = 5.97, damageEffectiveness = 5.97, levelRequirement = 88, }, + [30] = { baseMultiplier = 6.11, damageEffectiveness = 6.11, levelRequirement = 90, }, + [31] = { baseMultiplier = 6.18, damageEffectiveness = 6.18, levelRequirement = 91, }, + [32] = { baseMultiplier = 6.25, damageEffectiveness = 6.25, levelRequirement = 92, }, + [33] = { baseMultiplier = 6.32, damageEffectiveness = 6.32, levelRequirement = 93, }, + [34] = { baseMultiplier = 6.39, damageEffectiveness = 6.39, levelRequirement = 94, }, + [35] = { baseMultiplier = 6.46, damageEffectiveness = 6.46, levelRequirement = 95, }, + [36] = { baseMultiplier = 6.53, damageEffectiveness = 6.53, levelRequirement = 96, }, + [37] = { baseMultiplier = 6.6, damageEffectiveness = 6.6, levelRequirement = 97, }, + [38] = { baseMultiplier = 6.67, damageEffectiveness = 6.67, levelRequirement = 98, }, + [39] = { baseMultiplier = 6.74, damageEffectiveness = 6.74, levelRequirement = 99, }, + [40] = { baseMultiplier = 6.81, damageEffectiveness = 6.81, levelRequirement = 100, }, + }, +} + +skills["SunderAltMercenaryEncounter"] = { + name = "Sunder of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "SunderAltY", + color = 1, + description = "Slams the ground, creating a slow wave of churning terrain that damages enemies in a sequence of areas in front of you. A number of enemies hit by the wave will release a shockwave, damaging other enemies around them. Using the skill again will stop the previous wave. When the wave reaches a target or terrain, it can restart aiming towards an enemy, if one is in range. Requires a Mace, Sceptre, Axe, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "shockwave_slam_explosion_damage_+%_final", -40 }, + { "base_sunder_wave_delay_ms", 300 }, + { "sunder_wave_radius_+_per_step", 1 }, + { "sunder_wave_max_steps", 4 }, + { "sunder_wave_min_steps", 2 }, + { "sunder_shockwave_limit_per_cascade", 5 }, + { "sunder_number_of_fake_chains", 2 }, + { "active_skill_attack_speed_+%_final", -20 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 1.735, damageEffectiveness = 1.735, levelRequirement = 12, }, + [2] = { baseMultiplier = 1.833, damageEffectiveness = 1.833, levelRequirement = 15, }, + [3] = { baseMultiplier = 1.931, damageEffectiveness = 1.931, levelRequirement = 19, }, + [4] = { baseMultiplier = 2.029, damageEffectiveness = 2.029, levelRequirement = 23, }, + [5] = { baseMultiplier = 2.127, damageEffectiveness = 2.127, levelRequirement = 27, }, + [6] = { baseMultiplier = 2.225, damageEffectiveness = 2.225, levelRequirement = 31, }, + [7] = { baseMultiplier = 2.323, damageEffectiveness = 2.323, levelRequirement = 35, }, + [8] = { baseMultiplier = 2.421, damageEffectiveness = 2.421, levelRequirement = 38, }, + [9] = { baseMultiplier = 2.519, damageEffectiveness = 2.519, levelRequirement = 41, }, + [10] = { baseMultiplier = 2.617, damageEffectiveness = 2.617, levelRequirement = 44, }, + [11] = { baseMultiplier = 2.715, damageEffectiveness = 2.715, levelRequirement = 47, }, + [12] = { baseMultiplier = 2.813, damageEffectiveness = 2.813, levelRequirement = 50, }, + [13] = { baseMultiplier = 2.911, damageEffectiveness = 2.911, levelRequirement = 53, }, + [14] = { baseMultiplier = 3.009, damageEffectiveness = 3.009, levelRequirement = 56, }, + [15] = { baseMultiplier = 3.107, damageEffectiveness = 3.107, levelRequirement = 59, }, + [16] = { baseMultiplier = 3.205, damageEffectiveness = 3.205, levelRequirement = 62, }, + [17] = { baseMultiplier = 3.303, damageEffectiveness = 3.303, levelRequirement = 64, }, + [18] = { baseMultiplier = 3.401, damageEffectiveness = 3.401, levelRequirement = 66, }, + [19] = { baseMultiplier = 3.499, damageEffectiveness = 3.499, levelRequirement = 68, }, + [20] = { baseMultiplier = 3.597, damageEffectiveness = 3.597, levelRequirement = 70, }, + [21] = { baseMultiplier = 3.695, damageEffectiveness = 3.695, levelRequirement = 72, }, + [22] = { baseMultiplier = 3.793, damageEffectiveness = 3.793, levelRequirement = 74, }, + [23] = { baseMultiplier = 3.891, damageEffectiveness = 3.891, levelRequirement = 76, }, + [24] = { baseMultiplier = 3.989, damageEffectiveness = 3.989, levelRequirement = 78, }, + [25] = { baseMultiplier = 4.087, damageEffectiveness = 4.087, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.185, damageEffectiveness = 4.185, levelRequirement = 82, }, + [27] = { baseMultiplier = 4.283, damageEffectiveness = 4.283, levelRequirement = 84, }, + [28] = { baseMultiplier = 4.381, damageEffectiveness = 4.381, levelRequirement = 86, }, + [29] = { baseMultiplier = 4.479, damageEffectiveness = 4.479, levelRequirement = 88, }, + [30] = { baseMultiplier = 4.577, damageEffectiveness = 4.577, levelRequirement = 90, }, + [31] = { baseMultiplier = 4.626, damageEffectiveness = 4.626, levelRequirement = 91, }, + [32] = { baseMultiplier = 4.675, damageEffectiveness = 4.675, levelRequirement = 92, }, + [33] = { baseMultiplier = 4.724, damageEffectiveness = 4.724, levelRequirement = 93, }, + [34] = { baseMultiplier = 4.773, damageEffectiveness = 4.773, levelRequirement = 94, }, + [35] = { baseMultiplier = 4.822, damageEffectiveness = 4.822, levelRequirement = 95, }, + [36] = { baseMultiplier = 4.871, damageEffectiveness = 4.871, levelRequirement = 96, }, + [37] = { baseMultiplier = 4.92, damageEffectiveness = 4.92, levelRequirement = 97, }, + [38] = { baseMultiplier = 4.969, damageEffectiveness = 4.969, levelRequirement = 98, }, + [39] = { baseMultiplier = 5.018, damageEffectiveness = 5.018, levelRequirement = 99, }, + [40] = { baseMultiplier = 5.067, damageEffectiveness = 5.067, levelRequirement = 100, }, + }, +} + +skills["SweepMercenary"] = { + name = "Holy Sweep", + hidden = true, + mercenary = true, + inheritedFrom = "Sweep", + color = 1, + description = "Swings a two handed mace or a staff in a circle, calling down holy hammers to land randomly on a number of enemies struck. Hits from these holy hammers cannot be evaded.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Lightning] = true, }, + weaponTypes = { + ["Staff"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1.15, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "active_skill_base_secondary_area_of_effect_radius", 12 }, + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "active_skill_secondary_area_of_effect_description_mode", 9 }, + { "base_from_skill_shock_art_variation", 2 }, + { "holy_sweep_hammerfall_damage_+%_final", -35 }, + }, + stats = { + "active_skill_base_area_of_effect_radius", + "holy_sweep_number_of_holy_bolts_to_create", + "is_area_damage", + "console_skill_dont_chase", + "visual_hit_effect_elemental_is_holy", + }, + levels = { + [1] = { 24, 3, attackSpeedMultiplier = -30, baseMultiplier = 2.13, damageEffectiveness = 2.13, levelRequirement = 12, statInterpolation = { 1, 1, }, }, + [2] = { 24, 3, attackSpeedMultiplier = -30, baseMultiplier = 2.249, damageEffectiveness = 2.249, levelRequirement = 15, statInterpolation = { 1, 1, }, }, + [3] = { 24, 3, attackSpeedMultiplier = -30, baseMultiplier = 2.369, damageEffectiveness = 2.369, levelRequirement = 19, statInterpolation = { 1, 1, }, }, + [4] = { 24, 3, attackSpeedMultiplier = -30, baseMultiplier = 2.488, damageEffectiveness = 2.488, levelRequirement = 23, statInterpolation = { 1, 1, }, }, + [5] = { 25, 3, attackSpeedMultiplier = -30, baseMultiplier = 2.608, damageEffectiveness = 2.608, levelRequirement = 27, statInterpolation = { 1, 1, }, }, + [6] = { 25, 4, attackSpeedMultiplier = -30, baseMultiplier = 2.727, damageEffectiveness = 2.727, levelRequirement = 31, statInterpolation = { 1, 1, }, }, + [7] = { 25, 4, attackSpeedMultiplier = -30, baseMultiplier = 2.847, damageEffectiveness = 2.847, levelRequirement = 35, statInterpolation = { 1, 1, }, }, + [8] = { 25, 4, attackSpeedMultiplier = -30, baseMultiplier = 2.966, damageEffectiveness = 2.966, levelRequirement = 38, statInterpolation = { 1, 1, }, }, + [9] = { 25, 4, attackSpeedMultiplier = -30, baseMultiplier = 3.086, damageEffectiveness = 3.086, levelRequirement = 41, statInterpolation = { 1, 1, }, }, + [10] = { 26, 4, attackSpeedMultiplier = -30, baseMultiplier = 3.205, damageEffectiveness = 3.205, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [11] = { 26, 4, attackSpeedMultiplier = -30, baseMultiplier = 3.325, damageEffectiveness = 3.325, levelRequirement = 47, statInterpolation = { 1, 1, }, }, + [12] = { 26, 4, attackSpeedMultiplier = -30, baseMultiplier = 3.444, damageEffectiveness = 3.444, levelRequirement = 50, statInterpolation = { 1, 1, }, }, + [13] = { 26, 4, attackSpeedMultiplier = -30, baseMultiplier = 3.564, damageEffectiveness = 3.564, levelRequirement = 53, statInterpolation = { 1, 1, }, }, + [14] = { 26, 5, attackSpeedMultiplier = -30, baseMultiplier = 3.683, damageEffectiveness = 3.683, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [15] = { 27, 5, attackSpeedMultiplier = -30, baseMultiplier = 3.803, damageEffectiveness = 3.803, levelRequirement = 59, statInterpolation = { 1, 1, }, }, + [16] = { 27, 5, attackSpeedMultiplier = -30, baseMultiplier = 3.922, damageEffectiveness = 3.922, levelRequirement = 62, statInterpolation = { 1, 1, }, }, + [17] = { 27, 5, attackSpeedMultiplier = -30, baseMultiplier = 4.042, damageEffectiveness = 4.042, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [18] = { 27, 5, attackSpeedMultiplier = -30, baseMultiplier = 4.161, damageEffectiveness = 4.161, levelRequirement = 66, statInterpolation = { 1, 1, }, }, + [19] = { 27, 5, attackSpeedMultiplier = -30, baseMultiplier = 4.281, damageEffectiveness = 4.281, levelRequirement = 68, statInterpolation = { 1, 1, }, }, + [20] = { 28, 5, attackSpeedMultiplier = -30, baseMultiplier = 4.4, damageEffectiveness = 4.4, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 28, 5, attackSpeedMultiplier = -30, baseMultiplier = 4.519, damageEffectiveness = 4.519, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 28, 6, attackSpeedMultiplier = -30, baseMultiplier = 4.639, damageEffectiveness = 4.639, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 28, 6, attackSpeedMultiplier = -30, baseMultiplier = 4.758, damageEffectiveness = 4.758, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 28, 6, attackSpeedMultiplier = -30, baseMultiplier = 4.878, damageEffectiveness = 4.878, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 29, 6, attackSpeedMultiplier = -30, baseMultiplier = 4.997, damageEffectiveness = 4.997, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 29, 6, attackSpeedMultiplier = -30, baseMultiplier = 5.117, damageEffectiveness = 5.117, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 29, 6, attackSpeedMultiplier = -30, baseMultiplier = 5.236, damageEffectiveness = 5.236, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 29, 6, attackSpeedMultiplier = -30, baseMultiplier = 5.356, damageEffectiveness = 5.356, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 29, 6, attackSpeedMultiplier = -30, baseMultiplier = 5.475, damageEffectiveness = 5.475, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 30, 6, attackSpeedMultiplier = -30, baseMultiplier = 5.595, damageEffectiveness = 5.595, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 5.654, damageEffectiveness = 5.654, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 5.714, damageEffectiveness = 5.714, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 5.774, damageEffectiveness = 5.774, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 5.834, damageEffectiveness = 5.834, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 5.893, damageEffectiveness = 5.893, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 5.953, damageEffectiveness = 5.953, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 6.013, damageEffectiveness = 6.013, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 30, 7, attackSpeedMultiplier = -30, baseMultiplier = 6.073, damageEffectiveness = 6.073, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 30, 8, attackSpeedMultiplier = -30, baseMultiplier = 6.132, damageEffectiveness = 6.132, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 31, 8, attackSpeedMultiplier = -30, baseMultiplier = 6.192, damageEffectiveness = 6.192, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["TalismanDegenMapBoss"] = { + name = "Talisman Degen", + hidden = true, + mercenary = true, + color = 4, + baseEffectiveness = 0.60000002384186, + incrementalEffectiveness = 0.029999999329448, + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Damage] = true, [SkillType.AreaSpell] = true, [SkillType.Triggerable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "upheaval_number_of_spikes", 40 }, + { "base_skill_effect_duration", 5000 }, + { "base_secondary_skill_effect_duration", 3000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_taken_per_minute_per_talisman_degen_stack", + "cannot_stun", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 50, cooldown = 10, levelRequirement = 3, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 100, cooldown = 10, levelRequirement = 5, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 150, cooldown = 10, levelRequirement = 8, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 200, cooldown = 10, levelRequirement = 10, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 275, cooldown = 10, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 350, cooldown = 10, levelRequirement = 14, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 450, cooldown = 10, levelRequirement = 17, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 500, cooldown = 10, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 550, cooldown = 10, levelRequirement = 25, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 675, cooldown = 10, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 750, cooldown = 10, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 850, cooldown = 10, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 975, cooldown = 10, levelRequirement = 41, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 1100, cooldown = 10, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 1200, cooldown = 10, levelRequirement = 51, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 1300, cooldown = 10, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 1473, cooldown = 10, levelRequirement = 57, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 2450, cooldown = 10, levelRequirement = 65, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 2721, cooldown = 10, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 3071, cooldown = 10, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 3421, cooldown = 10, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 3770, cooldown = 10, levelRequirement = 69, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 4120, cooldown = 10, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 4524, cooldown = 10, levelRequirement = 71, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 4929, cooldown = 10, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 5333, cooldown = 10, levelRequirement = 73, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 5737, cooldown = 10, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 6142, cooldown = 10, levelRequirement = 75, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 6546, cooldown = 10, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 6950, cooldown = 10, levelRequirement = 77, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 7355, cooldown = 10, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 7759, cooldown = 10, levelRequirement = 79, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 8164, cooldown = 10, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 8568, cooldown = 10, levelRequirement = 81, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 8973, cooldown = 10, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["TectonicSlamFireMercenary"] = { + name = "Tectonic Slam", + hidden = true, + mercenary = true, + inheritedFrom = "TectonicSlam", + color = 1, + description = "Slam the ground, unleashing a fiery fissure in front of you, dealing area damage and randomly releasing a number of smaller fissures branching off from it. Consume an Endurance Charge every third time you slam the ground with this skill. Requires a Mace, Sceptre, Sword, Axe, Staff, or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Fire] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "tectonic_slam_side_crack_additional_chance_%_per_endurance_charge", 5 }, + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + { "active_skill_area_of_effect_+%_final_per_endurance_charge", 5 }, + { "tectonic_slam_side_crack_additional_chance_%", 30 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 2.951, damageEffectiveness = 2.951, levelRequirement = 28, }, + [2] = { baseMultiplier = 3.053, damageEffectiveness = 3.053, levelRequirement = 31, }, + [3] = { baseMultiplier = 3.156, damageEffectiveness = 3.156, levelRequirement = 34, }, + [4] = { baseMultiplier = 3.264, damageEffectiveness = 3.264, levelRequirement = 37, }, + [5] = { baseMultiplier = 3.374, damageEffectiveness = 3.374, levelRequirement = 40, }, + [6] = { baseMultiplier = 3.484, damageEffectiveness = 3.484, levelRequirement = 42, }, + [7] = { baseMultiplier = 3.595, damageEffectiveness = 3.595, levelRequirement = 44, }, + [8] = { baseMultiplier = 3.711, damageEffectiveness = 3.711, levelRequirement = 46, }, + [9] = { baseMultiplier = 3.83, damageEffectiveness = 3.83, levelRequirement = 48, }, + [10] = { baseMultiplier = 3.954, damageEffectiveness = 3.954, levelRequirement = 50, }, + [11] = { baseMultiplier = 4.081, damageEffectiveness = 4.081, levelRequirement = 52, }, + [12] = { baseMultiplier = 4.211, damageEffectiveness = 4.211, levelRequirement = 54, }, + [13] = { baseMultiplier = 4.346, damageEffectiveness = 4.346, levelRequirement = 56, }, + [14] = { baseMultiplier = 4.486, damageEffectiveness = 4.486, levelRequirement = 58, }, + [15] = { baseMultiplier = 4.631, damageEffectiveness = 4.631, levelRequirement = 60, }, + [16] = { baseMultiplier = 4.779, damageEffectiveness = 4.779, levelRequirement = 62, }, + [17] = { baseMultiplier = 4.932, damageEffectiveness = 4.932, levelRequirement = 64, }, + [18] = { baseMultiplier = 5.09, damageEffectiveness = 5.09, levelRequirement = 66, }, + [19] = { baseMultiplier = 5.253, damageEffectiveness = 5.253, levelRequirement = 68, }, + [20] = { baseMultiplier = 5.422, damageEffectiveness = 5.422, levelRequirement = 70, }, + [21] = { baseMultiplier = 5.596, damageEffectiveness = 5.596, levelRequirement = 72, }, + [22] = { baseMultiplier = 5.774, damageEffectiveness = 5.774, levelRequirement = 74, }, + [23] = { baseMultiplier = 5.959, damageEffectiveness = 5.959, levelRequirement = 76, }, + [24] = { baseMultiplier = 6.15, damageEffectiveness = 6.15, levelRequirement = 78, }, + [25] = { baseMultiplier = 6.346, damageEffectiveness = 6.346, levelRequirement = 80, }, + [26] = { baseMultiplier = 6.55, damageEffectiveness = 6.55, levelRequirement = 82, }, + [27] = { baseMultiplier = 6.759, damageEffectiveness = 6.759, levelRequirement = 84, }, + [28] = { baseMultiplier = 6.975, damageEffectiveness = 6.975, levelRequirement = 86, }, + [29] = { baseMultiplier = 7.198, damageEffectiveness = 7.198, levelRequirement = 88, }, + [30] = { baseMultiplier = 7.427, damageEffectiveness = 7.427, levelRequirement = 90, }, + [31] = { baseMultiplier = 7.762, damageEffectiveness = 7.762, levelRequirement = 91, }, + [32] = { baseMultiplier = 7.885, damageEffectiveness = 7.885, levelRequirement = 92, }, + [33] = { baseMultiplier = 8.011, damageEffectiveness = 8.011, levelRequirement = 93, }, + [34] = { baseMultiplier = 8.139, damageEffectiveness = 8.139, levelRequirement = 94, }, + [35] = { baseMultiplier = 8.268, damageEffectiveness = 8.268, levelRequirement = 95, }, + [36] = { baseMultiplier = 8.4, damageEffectiveness = 8.4, levelRequirement = 96, }, + [37] = { baseMultiplier = 8.534, damageEffectiveness = 8.534, levelRequirement = 97, }, + [38] = { baseMultiplier = 8.669, damageEffectiveness = 8.669, levelRequirement = 98, }, + [39] = { baseMultiplier = 8.808, damageEffectiveness = 8.808, levelRequirement = 99, }, + [40] = { baseMultiplier = 8.948, damageEffectiveness = 8.948, levelRequirement = 100, }, + }, +} + +skills["TectonicSlamPhysMercenary"] = { + name = "Tectonic Cascade", + hidden = true, + mercenary = true, + inheritedFrom = "TectonicSlam", + color = 1, + description = "Slam the ground, unleashing a fiery fissure in front of you, dealing area damage and randomly releasing a number of smaller fissures branching off from it. Consume an Endurance Charge every third time you slam the ground with this skill. Requires a Mace, Sceptre, Sword, Axe, Staff, or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Fire] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "active_skill_attack_speed_+%_final", -50 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { baseMultiplier = 2.951, cooldown = 4, damageEffectiveness = 2.951, levelRequirement = 28, storedUses = 1, }, + [2] = { baseMultiplier = 3.053, cooldown = 4, damageEffectiveness = 3.053, levelRequirement = 31, storedUses = 1, }, + [3] = { baseMultiplier = 3.156, cooldown = 4, damageEffectiveness = 3.156, levelRequirement = 34, storedUses = 1, }, + [4] = { baseMultiplier = 3.264, cooldown = 4, damageEffectiveness = 3.264, levelRequirement = 37, storedUses = 1, }, + [5] = { baseMultiplier = 3.374, cooldown = 4, damageEffectiveness = 3.374, levelRequirement = 40, storedUses = 1, }, + [6] = { baseMultiplier = 3.484, cooldown = 4, damageEffectiveness = 3.484, levelRequirement = 42, storedUses = 1, }, + [7] = { baseMultiplier = 3.595, cooldown = 4, damageEffectiveness = 3.595, levelRequirement = 44, storedUses = 1, }, + [8] = { baseMultiplier = 3.711, cooldown = 4, damageEffectiveness = 3.711, levelRequirement = 46, storedUses = 1, }, + [9] = { baseMultiplier = 3.83, cooldown = 4, damageEffectiveness = 3.83, levelRequirement = 48, storedUses = 1, }, + [10] = { baseMultiplier = 3.954, cooldown = 4, damageEffectiveness = 3.954, levelRequirement = 50, storedUses = 1, }, + [11] = { baseMultiplier = 4.081, cooldown = 4, damageEffectiveness = 4.081, levelRequirement = 52, storedUses = 1, }, + [12] = { baseMultiplier = 4.211, cooldown = 4, damageEffectiveness = 4.211, levelRequirement = 54, storedUses = 1, }, + [13] = { baseMultiplier = 4.346, cooldown = 4, damageEffectiveness = 4.346, levelRequirement = 56, storedUses = 1, }, + [14] = { baseMultiplier = 4.486, cooldown = 4, damageEffectiveness = 4.486, levelRequirement = 58, storedUses = 1, }, + [15] = { baseMultiplier = 4.631, cooldown = 4, damageEffectiveness = 4.631, levelRequirement = 60, storedUses = 1, }, + [16] = { baseMultiplier = 4.779, cooldown = 4, damageEffectiveness = 4.779, levelRequirement = 62, storedUses = 1, }, + [17] = { baseMultiplier = 4.932, cooldown = 4, damageEffectiveness = 4.932, levelRequirement = 64, storedUses = 1, }, + [18] = { baseMultiplier = 5.09, cooldown = 4, damageEffectiveness = 5.09, levelRequirement = 66, storedUses = 1, }, + [19] = { baseMultiplier = 5.253, cooldown = 4, damageEffectiveness = 5.253, levelRequirement = 68, storedUses = 1, }, + [20] = { baseMultiplier = 5.422, cooldown = 4, damageEffectiveness = 5.422, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 5.596, cooldown = 4, damageEffectiveness = 5.596, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 5.774, cooldown = 4, damageEffectiveness = 5.774, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 5.959, cooldown = 4, damageEffectiveness = 5.959, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 6.15, cooldown = 4, damageEffectiveness = 6.15, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 6.346, cooldown = 4, damageEffectiveness = 6.346, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 6.55, cooldown = 4, damageEffectiveness = 6.55, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 6.759, cooldown = 4, damageEffectiveness = 6.759, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 6.975, cooldown = 4, damageEffectiveness = 6.975, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 7.198, cooldown = 4, damageEffectiveness = 7.198, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 7.427, cooldown = 4, damageEffectiveness = 7.427, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 7.762, cooldown = 4, damageEffectiveness = 7.762, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 7.885, cooldown = 4, damageEffectiveness = 7.885, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 8.011, cooldown = 4, damageEffectiveness = 8.011, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 8.139, cooldown = 4, damageEffectiveness = 8.139, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 8.268, cooldown = 4, damageEffectiveness = 8.268, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 8.4, cooldown = 4, damageEffectiveness = 8.4, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 8.534, cooldown = 4, damageEffectiveness = 8.534, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 8.669, cooldown = 4, damageEffectiveness = 8.669, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 8.808, cooldown = 4, damageEffectiveness = 8.808, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 8.948, cooldown = 4, damageEffectiveness = 8.948, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["TempestShieldMercenary"] = { + name = "Tempest Shield", + hidden = true, + mercenary = true, + inheritedFrom = "TempestShield", + color = 3, + baseEffectiveness = 4.6932997703552, + incrementalEffectiveness = 0.038199998438358, + description = "Enchants your shield with the power of storms, which lashes out to deal arcing lightning damage to attackers when you block them.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.RequiresShield] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Lightning] = true, [SkillType.Chains] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.Cooldown] = true, [SkillType.Totemable] = true, [SkillType.Instant] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "skill_override_pvp_scaling_time_ms", 700 }, + { "number_of_chains", 1 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "shield_spell_block_%", + "skill_can_add_multiple_charges_per_action", + "base_skill_show_average_damage_instead_of_dps", + "skill_display_buff_grants_shock_immunity", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, 18, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.5, 1.5, 18, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.5, 1.5, 19, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.5, 1.5, 19, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.5, 1.5, 19, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.5, 1.5, 20, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.5, 1.5, 20, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.5, 1.5, 21, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.5, 1.5, 21, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.5, 1.5, 21, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.5, 1.5, 22, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.5, 1.5, 22, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.5, 1.5, 23, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.5, 1.5, 23, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.5, 1.5, 23, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.5, 1.5, 24, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.5, 1.5, 24, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.5, 1.5, 25, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.5, 1.5, 25, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.5, 1.5, 25, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.5, 1.5, 26, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.5, 1.5, 26, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.5, 1.5, 27, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.5, 1.5, 27, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.5, 1.5, 27, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.5, 1.5, 28, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.5, 1.5, 28, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.5, 1.5, 29, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.5, 1.5, 29, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.5, 1.5, 29, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.5, 1.5, 30, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.5, 1.5, 30, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.5, 1.5, 30, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.5, 1.5, 30, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.5, 1.5, 31, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.5, 1.5, 31, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.5, 1.5, 31, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.5, 1.5, 31, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.5, 1.5, 31, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.5, 1.5, 31, cooldown = 1.2, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["TempestShieldMercenaryEncounter"] = { + name = "Tempest Shield", + hidden = true, + mercenary = true, + inheritedFrom = "TempestShield", + color = 3, + baseEffectiveness = 4, + incrementalEffectiveness = 0.035000000149012, + description = "Enchants your shield with the power of storms, which lashes out to deal arcing lightning damage to attackers when you block them.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.RequiresShield] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Lightning] = true, [SkillType.Chains] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.Cooldown] = true, [SkillType.Totemable] = true, [SkillType.Instant] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + spell = true, + }, + constantStats = { + { "skill_override_pvp_scaling_time_ms", 700 }, + { "number_of_chains", 1 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "shield_spell_block_%", + "skill_can_add_multiple_charges_per_action", + "base_skill_show_average_damage_instead_of_dps", + "skill_display_buff_grants_shock_immunity", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, 25, cooldown = 1.2, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 0, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["TemporalAnomalyMercenary"] = { + name = "Clutches of the Damned", + hidden = true, + mercenary = true, + color = 4, + description = "Creates an Eternity Sphere at your location, which reduces the Action Speed of enemies within it. The amount of Action Speed reduction applied by the sphere decreases to zero over its duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Triggerable] = true, [SkillType.Triggered] = true, [SkillType.InbuiltTrigger] = true, [SkillType.Duration] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + { "ground_temporal_anomaly_art_variation", 2 }, + }, + stats = { + "action_speed_-%", + }, + levels = { + [1] = { 25, levelRequirement = 1, statInterpolation = { 1, }, }, + }, +} + +skills["TemporalChainsBossCurseAura"] = { + name = "Temporal Chains", + hidden = true, + mercenary = true, + inheritedFrom = "TemporalChains", + color = 4, + baseEffectiveness = 0, + description = "Curses all enemies in an area, lowering their action speed and making other effects on them expire more slowly.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 1.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "temporal_chains_action_speed_+%_final", -20 }, + { "buff_time_passed_+%_other_than_temporal_chains", -25 }, + { "temporal_chains_action_speed_+%_vs_rare_or_unique_final", -10 }, + { "active_skill_area_of_effect_radius_+%_final", 50 }, + }, + stats = { + "curse_apply_as_aura", + }, + levels = { + [1] = { cooldown = 5, levelRequirement = 0, storedUses = 1, cost = { Mana = 50, }, }, + }, +} + +skills["TemporalChainsMercenary"] = { + name = "Temporal Chains", + hidden = true, + mercenary = true, + inheritedFrom = "TemporalChains", + color = 2, + baseEffectiveness = 0, + description = "Curses all enemies in an area, lowering their action speed and making other effects on them expire more slowly.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "buff_time_passed_+%_other_than_temporal_chains", -25 }, + { "curse_effect_+%_final_vs_players", -50 }, + }, + stats = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + "temporal_chains_action_speed_+%_final", + "temporal_chains_action_speed_+%_vs_rare_or_unique_final", + "base_deal_no_damage", + }, + notMinionStat = { + "base_skill_effect_duration", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 5000, 0, -15, -9, levelRequirement = 24, statInterpolation = { 1, 1, 1, 1, }, }, + [2] = { 5200, 1, -15, -9, levelRequirement = 27, statInterpolation = { 1, 1, 1, 1, }, }, + [3] = { 5400, 1, -16, -10, levelRequirement = 30, statInterpolation = { 1, 1, 1, 1, }, }, + [4] = { 5600, 2, -17, -10, levelRequirement = 33, statInterpolation = { 1, 1, 1, 1, }, }, + [5] = { 5800, 2, -18, -11, levelRequirement = 36, statInterpolation = { 1, 1, 1, 1, }, }, + [6] = { 6000, 3, -18, -11, levelRequirement = 39, statInterpolation = { 1, 1, 1, 1, }, }, + [7] = { 6200, 3, -19, -12, levelRequirement = 42, statInterpolation = { 1, 1, 1, 1, }, }, + [8] = { 6400, 4, -20, -12, levelRequirement = 45, statInterpolation = { 1, 1, 1, 1, }, }, + [9] = { 6600, 4, -21, -13, levelRequirement = 48, statInterpolation = { 1, 1, 1, 1, }, }, + [10] = { 6800, 5, -21, -13, levelRequirement = 50, statInterpolation = { 1, 1, 1, 1, }, }, + [11] = { 7000, 5, -22, -14, levelRequirement = 52, statInterpolation = { 1, 1, 1, 1, }, }, + [12] = { 7200, 6, -23, -14, levelRequirement = 54, statInterpolation = { 1, 1, 1, 1, }, }, + [13] = { 7400, 6, -24, -15, levelRequirement = 56, statInterpolation = { 1, 1, 1, 1, }, }, + [14] = { 7600, 7, -24, -15, levelRequirement = 58, statInterpolation = { 1, 1, 1, 1, }, }, + [15] = { 7800, 7, -25, -16, levelRequirement = 60, statInterpolation = { 1, 1, 1, 1, }, }, + [16] = { 8000, 8, -26, -16, levelRequirement = 62, statInterpolation = { 1, 1, 1, 1, }, }, + [17] = { 8200, 8, -27, -17, levelRequirement = 64, statInterpolation = { 1, 1, 1, 1, }, }, + [18] = { 8400, 9, -27, -17, levelRequirement = 66, statInterpolation = { 1, 1, 1, 1, }, }, + [19] = { 8600, 9, -28, -18, levelRequirement = 68, statInterpolation = { 1, 1, 1, 1, }, }, + [20] = { 8800, 10, -29, -18, levelRequirement = 70, statInterpolation = { 1, 1, 1, 1, }, }, + [21] = { 9000, 10, -30, -19, levelRequirement = 72, statInterpolation = { 1, 1, 1, 1, }, }, + [22] = { 9200, 11, -30, -19, levelRequirement = 74, statInterpolation = { 1, 1, 1, 1, }, }, + [23] = { 9400, 11, -30, -20, levelRequirement = 76, statInterpolation = { 1, 1, 1, 1, }, }, + [24] = { 9600, 12, -30, -20, levelRequirement = 78, statInterpolation = { 1, 1, 1, 1, }, }, + [25] = { 9800, 12, -31, -21, levelRequirement = 80, statInterpolation = { 1, 1, 1, 1, }, }, + [26] = { 10000, 13, -31, -21, levelRequirement = 82, statInterpolation = { 1, 1, 1, 1, }, }, + [27] = { 10200, 13, -31, -22, levelRequirement = 84, statInterpolation = { 1, 1, 1, 1, }, }, + [28] = { 10400, 14, -31, -22, levelRequirement = 86, statInterpolation = { 1, 1, 1, 1, }, }, + [29] = { 10600, 14, -32, -23, levelRequirement = 88, statInterpolation = { 1, 1, 1, 1, }, }, + [30] = { 10800, 15, -32, -23, levelRequirement = 90, statInterpolation = { 1, 1, 1, 1, }, }, + [31] = { 10900, 15, -32, -23, levelRequirement = 91, statInterpolation = { 1, 1, 1, 1, }, }, + [32] = { 11000, 15, -32, -24, levelRequirement = 92, statInterpolation = { 1, 1, 1, 1, }, }, + [33] = { 11100, 15, -33, -24, levelRequirement = 93, statInterpolation = { 1, 1, 1, 1, }, }, + [34] = { 11200, 16, -33, -24, levelRequirement = 94, statInterpolation = { 1, 1, 1, 1, }, }, + [35] = { 11300, 16, -33, -24, levelRequirement = 95, statInterpolation = { 1, 1, 1, 1, }, }, + [36] = { 11400, 16, -33, -25, levelRequirement = 96, statInterpolation = { 1, 1, 1, 1, }, }, + [37] = { 11500, 16, -34, -25, levelRequirement = 97, statInterpolation = { 1, 1, 1, 1, }, }, + [38] = { 11600, 17, -34, -25, levelRequirement = 98, statInterpolation = { 1, 1, 1, 1, }, }, + [39] = { 11700, 17, -34, -25, levelRequirement = 99, statInterpolation = { 1, 1, 1, 1, }, }, + [40] = { 11800, 17, -34, -26, levelRequirement = 100, statInterpolation = { 1, 1, 1, 1, }, }, + }, +} + +skills["TornadoAltMercenary"] = { + name = "Tornado of Elemental Turbulence", + hidden = true, + mercenary = true, + inheritedFrom = "TornadoAltY", + color = 2, + baseEffectiveness = 0.80000001192093, + incrementalEffectiveness = 0.050000000745058, + description = "Create a Tornado of a random element that hinders and repeatedly damages enemies around it, converting physical damage to its element. The Tornado will chase down enemies for a duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Damage] = true, [SkillType.Physical] = true, [SkillType.Area] = true, [SkillType.Orb] = true, [SkillType.AreaSpell] = true, [SkillType.Fire] = true, [SkillType.Cold] = true, [SkillType.Lightning] = true, [SkillType.RandomElement] = true, [SkillType.Multicastable] = true, [SkillType.CanRapidFire] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "elemental_strike_physical_damage_%_to_convert", 100 }, + { "number_of_tornados_allowed", 2 }, + { "base_skill_effect_duration", 3000 }, + { "tornado_base_damage_interval_ms", 250 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "tornado_movement_speed_+%", + "skill_can_add_multiple_charges_per_action", + "damage_cannot_be_reflected_or_leech_if_used_by_other_object", + "is_area_damage", + "tornado_hinder", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 0, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 3, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 6, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 9, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 12, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 15, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 18, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 21, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 24, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 27, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 30, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 33, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 36, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 39, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 42, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 45, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 48, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 51, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 54, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 69, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 57, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 60, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 63, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 66, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 69, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 72, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 75, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 78, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 81, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 84, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 87, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 88, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 90, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 91, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 93, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 94, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 96, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 97, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 99, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 100, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 102, cooldown = 6, critChance = 5, damageEffectiveness = 0.65, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["TornadoShotMercenary"] = { + name = "Tornado Shot", + hidden = true, + mercenary = true, + inheritedFrom = "TornadoShot", + color = 2, + description = "Fires a piercing shot that travels until it reaches the targeted location. It will then fire projectiles out in all directions from that point, which will travel for a short time before disappearing.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Triggerable] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "tornado_shot_num_of_secondary_projectiles", 3 }, + }, + stats = { + "base_is_projectile", + "skill_can_fire_arrows", + }, + levels = { + [1] = { levelRequirement = 28, }, + [2] = { baseMultiplier = 1.011, damageEffectiveness = 1.01, levelRequirement = 31, }, + [3] = { baseMultiplier = 1.021, damageEffectiveness = 1.02, levelRequirement = 34, }, + [4] = { baseMultiplier = 1.032, damageEffectiveness = 1.03, levelRequirement = 37, }, + [5] = { baseMultiplier = 1.042, damageEffectiveness = 1.04, levelRequirement = 40, }, + [6] = { baseMultiplier = 1.053, damageEffectiveness = 1.05, levelRequirement = 42, }, + [7] = { baseMultiplier = 1.063, damageEffectiveness = 1.06, levelRequirement = 44, }, + [8] = { baseMultiplier = 1.074, damageEffectiveness = 1.07, levelRequirement = 46, }, + [9] = { baseMultiplier = 1.084, damageEffectiveness = 1.08, levelRequirement = 48, }, + [10] = { baseMultiplier = 1.095, damageEffectiveness = 1.09, levelRequirement = 50, }, + [11] = { baseMultiplier = 1.105, damageEffectiveness = 1.11, levelRequirement = 52, }, + [12] = { baseMultiplier = 1.116, damageEffectiveness = 1.12, levelRequirement = 54, }, + [13] = { baseMultiplier = 1.126, damageEffectiveness = 1.13, levelRequirement = 56, }, + [14] = { baseMultiplier = 1.137, damageEffectiveness = 1.14, levelRequirement = 58, }, + [15] = { baseMultiplier = 1.147, damageEffectiveness = 1.15, levelRequirement = 60, }, + [16] = { baseMultiplier = 1.158, damageEffectiveness = 1.16, levelRequirement = 62, }, + [17] = { baseMultiplier = 1.168, damageEffectiveness = 1.17, levelRequirement = 64, }, + [18] = { baseMultiplier = 1.179, damageEffectiveness = 1.18, levelRequirement = 66, }, + [19] = { baseMultiplier = 1.189, damageEffectiveness = 1.19, levelRequirement = 68, }, + [20] = { baseMultiplier = 1.2, damageEffectiveness = 1.2, levelRequirement = 70, }, + [21] = { baseMultiplier = 1.211, damageEffectiveness = 1.21, levelRequirement = 72, }, + [22] = { baseMultiplier = 1.221, damageEffectiveness = 1.22, levelRequirement = 74, }, + [23] = { baseMultiplier = 1.232, damageEffectiveness = 1.23, levelRequirement = 76, }, + [24] = { baseMultiplier = 1.242, damageEffectiveness = 1.24, levelRequirement = 78, }, + [25] = { baseMultiplier = 1.253, damageEffectiveness = 1.25, levelRequirement = 80, }, + [26] = { baseMultiplier = 1.263, damageEffectiveness = 1.26, levelRequirement = 82, }, + [27] = { baseMultiplier = 1.274, damageEffectiveness = 1.27, levelRequirement = 84, }, + [28] = { baseMultiplier = 1.284, damageEffectiveness = 1.28, levelRequirement = 86, }, + [29] = { baseMultiplier = 1.295, damageEffectiveness = 1.29, levelRequirement = 88, }, + [30] = { baseMultiplier = 1.305, damageEffectiveness = 1.31, levelRequirement = 90, }, + [31] = { baseMultiplier = 1.311, damageEffectiveness = 1.31, levelRequirement = 91, }, + [32] = { baseMultiplier = 1.316, damageEffectiveness = 1.32, levelRequirement = 92, }, + [33] = { baseMultiplier = 1.321, damageEffectiveness = 1.32, levelRequirement = 93, }, + [34] = { baseMultiplier = 1.326, damageEffectiveness = 1.33, levelRequirement = 94, }, + [35] = { baseMultiplier = 1.332, damageEffectiveness = 1.33, levelRequirement = 95, }, + [36] = { baseMultiplier = 1.337, damageEffectiveness = 1.34, levelRequirement = 96, }, + [37] = { baseMultiplier = 1.342, damageEffectiveness = 1.34, levelRequirement = 97, }, + [38] = { baseMultiplier = 1.347, damageEffectiveness = 1.35, levelRequirement = 98, }, + [39] = { baseMultiplier = 1.353, damageEffectiveness = 1.35, levelRequirement = 99, }, + [40] = { baseMultiplier = 1.358, damageEffectiveness = 1.36, levelRequirement = 100, }, + }, +} + +skills["ToxicRainMercenary"] = { + name = "Toxic Rain", + hidden = true, + mercenary = true, + inheritedFrom = "ToxicRain", + color = 2, + baseEffectiveness = 2, + incrementalEffectiveness = 0.035999998450279, + description = "Fire arrows into the air that rain down around the targeted area, dealing damage to enemies they hit and creating spore pods where they land. Each spore pod deals chaos damage over time to nearby enemies and slows their movement speed. The pods last for a duration before bursting, dealing area damage.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.MirageArcherCanUse] = true, [SkillType.Area] = true, [SkillType.ProjectileSpeed] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Damage] = true, [SkillType.Chaos] = true, [SkillType.Duration] = true, [SkillType.DamageOverTime] = true, [SkillType.ProjectileNumber] = true, [SkillType.Chaos] = true, [SkillType.Triggerable] = true, [SkillType.Rain] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + }, + constantStats = { + { "base_skill_effect_duration", 1000 }, + { "base_number_of_arrows", 3 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "rain_of_spores_vines_movement_speed_+%_final", -5 }, + { "minimum_rain_of_spores_movement_speed_+%_final_cap", -30 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "base_is_projectile", + "is_area_damage", + "skill_can_fire_arrows", + "cannot_pierce", + "projectile_damage_modifiers_apply_to_skill_dot", + "visual_hit_effect_chaos_is_green", + }, + levels = { + [1] = { 20.000001241763, baseMultiplier = 0.5, damageEffectiveness = 0.5, levelRequirement = 12, statInterpolation = { 3, }, }, + [2] = { 20.000001241763, baseMultiplier = 0.512, damageEffectiveness = 0.51, levelRequirement = 15, statInterpolation = { 3, }, }, + [3] = { 20.000001241763, baseMultiplier = 0.524, damageEffectiveness = 0.52, levelRequirement = 19, statInterpolation = { 3, }, }, + [4] = { 20.000001241763, baseMultiplier = 0.536, damageEffectiveness = 0.54, levelRequirement = 23, statInterpolation = { 3, }, }, + [5] = { 20.000001241763, baseMultiplier = 0.548, damageEffectiveness = 0.55, levelRequirement = 27, statInterpolation = { 3, }, }, + [6] = { 20.000001241763, baseMultiplier = 0.56, damageEffectiveness = 0.56, levelRequirement = 31, statInterpolation = { 3, }, }, + [7] = { 20.000001241763, baseMultiplier = 0.572, damageEffectiveness = 0.57, levelRequirement = 35, statInterpolation = { 3, }, }, + [8] = { 20.000001241763, baseMultiplier = 0.584, damageEffectiveness = 0.58, levelRequirement = 38, statInterpolation = { 3, }, }, + [9] = { 20.000001241763, baseMultiplier = 0.596, damageEffectiveness = 0.6, levelRequirement = 41, statInterpolation = { 3, }, }, + [10] = { 20.000001241763, baseMultiplier = 0.608, damageEffectiveness = 0.61, levelRequirement = 44, statInterpolation = { 3, }, }, + [11] = { 20.000001241763, baseMultiplier = 0.62, damageEffectiveness = 0.62, levelRequirement = 47, statInterpolation = { 3, }, }, + [12] = { 20.000001241763, baseMultiplier = 0.632, damageEffectiveness = 0.63, levelRequirement = 50, statInterpolation = { 3, }, }, + [13] = { 20.000001241763, baseMultiplier = 0.644, damageEffectiveness = 0.64, levelRequirement = 53, statInterpolation = { 3, }, }, + [14] = { 20.000001241763, baseMultiplier = 0.656, damageEffectiveness = 0.66, levelRequirement = 56, statInterpolation = { 3, }, }, + [15] = { 20.000001241763, baseMultiplier = 0.668, damageEffectiveness = 0.67, levelRequirement = 59, statInterpolation = { 3, }, }, + [16] = { 20.000001241763, baseMultiplier = 0.68, damageEffectiveness = 0.68, levelRequirement = 62, statInterpolation = { 3, }, }, + [17] = { 20.000001241763, baseMultiplier = 0.692, damageEffectiveness = 0.69, levelRequirement = 64, statInterpolation = { 3, }, }, + [18] = { 20.000001241763, baseMultiplier = 0.704, damageEffectiveness = 0.7, levelRequirement = 66, statInterpolation = { 3, }, }, + [19] = { 20.000001241763, baseMultiplier = 0.716, damageEffectiveness = 0.72, levelRequirement = 68, statInterpolation = { 3, }, }, + [20] = { 20.000001241763, baseMultiplier = 0.728, damageEffectiveness = 0.73, levelRequirement = 70, statInterpolation = { 3, }, }, + [21] = { 20.000001241763, baseMultiplier = 0.74, damageEffectiveness = 0.74, levelRequirement = 72, statInterpolation = { 3, }, }, + [22] = { 20.000001241763, baseMultiplier = 0.752, damageEffectiveness = 0.75, levelRequirement = 74, statInterpolation = { 3, }, }, + [23] = { 20.000001241763, baseMultiplier = 0.764, damageEffectiveness = 0.76, levelRequirement = 76, statInterpolation = { 3, }, }, + [24] = { 20.000001241763, baseMultiplier = 0.776, damageEffectiveness = 0.78, levelRequirement = 78, statInterpolation = { 3, }, }, + [25] = { 20.000001241763, baseMultiplier = 0.788, damageEffectiveness = 0.79, levelRequirement = 80, statInterpolation = { 3, }, }, + [26] = { 20.000001241763, baseMultiplier = 0.8, damageEffectiveness = 0.8, levelRequirement = 82, statInterpolation = { 3, }, }, + [27] = { 20.000001241763, baseMultiplier = 0.812, damageEffectiveness = 0.81, levelRequirement = 84, statInterpolation = { 3, }, }, + [28] = { 20.000001241763, baseMultiplier = 0.824, damageEffectiveness = 0.82, levelRequirement = 86, statInterpolation = { 3, }, }, + [29] = { 20.000001241763, baseMultiplier = 0.836, damageEffectiveness = 0.84, levelRequirement = 88, statInterpolation = { 3, }, }, + [30] = { 20.000001241763, baseMultiplier = 0.848, damageEffectiveness = 0.85, levelRequirement = 90, statInterpolation = { 3, }, }, + [31] = { 20.000001241763, baseMultiplier = 0.854, damageEffectiveness = 0.85, levelRequirement = 91, statInterpolation = { 3, }, }, + [32] = { 20.000001241763, baseMultiplier = 0.86, damageEffectiveness = 0.86, levelRequirement = 92, statInterpolation = { 3, }, }, + [33] = { 20.000001241763, baseMultiplier = 0.866, damageEffectiveness = 0.87, levelRequirement = 93, statInterpolation = { 3, }, }, + [34] = { 20.000001241763, baseMultiplier = 0.872, damageEffectiveness = 0.87, levelRequirement = 94, statInterpolation = { 3, }, }, + [35] = { 20.000001241763, baseMultiplier = 0.878, damageEffectiveness = 0.88, levelRequirement = 95, statInterpolation = { 3, }, }, + [36] = { 20.000001241763, baseMultiplier = 0.884, damageEffectiveness = 0.88, levelRequirement = 96, statInterpolation = { 3, }, }, + [37] = { 20.000001241763, baseMultiplier = 0.89, damageEffectiveness = 0.89, levelRequirement = 97, statInterpolation = { 3, }, }, + [38] = { 20.000001241763, baseMultiplier = 0.896, damageEffectiveness = 0.9, levelRequirement = 98, statInterpolation = { 3, }, }, + [39] = { 20.000001241763, baseMultiplier = 0.902, damageEffectiveness = 0.9, levelRequirement = 99, statInterpolation = { 3, }, }, + [40] = { 20.000001241763, baseMultiplier = 0.908, damageEffectiveness = 0.91, levelRequirement = 100, statInterpolation = { 3, }, }, + }, +} + +skills["TriggeredFireSlamMercenary"] = { + name = "Triggerslam", + hidden = true, + mercenary = true, + inheritedFrom = "AfflictionMinionPhysSlamCircleBig", + color = 4, + skillTypes = { [SkillType.Triggerable] = true, [SkillType.Attack] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 80 }, + { "add_endurance_charge_on_skill_hit_%", 100 }, + }, + stats = { + "is_area_damage", + }, + levels = { + [1] = { levelRequirement = 1, }, + }, +} + +skills["VaalAncestralWarchiefMercenary"] = { + name = "Vaal Ancestral Warchief", + hidden = true, + mercenary = true, + color = 1, + description = "Summons an Ancestor Totem which attacks enemies with a powerful cascading slam while you're near it. If the enemies are far away, it will leap toward them as it slams. Being near it grants you more melee damage. Requires a Melee Weapon or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.SummonsTotem] = true, [SkillType.Melee] = true, [SkillType.Area] = true, [SkillType.Vaal] = true, [SkillType.NeverExertable] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + skillTotemId = 16, + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + totem = true, + }, + constantStats = { + { "base_totem_duration", 6000 }, + { "base_totem_range", 50 }, + { "ancestor_totem_parent_activiation_range", 120 }, + { "summon_totem_cast_speed_+%", 50 }, + { "slam_ancestor_totem_grant_owner_melee_damage_+%_final", 32 }, + { "number_of_additional_totems_allowed", 1 }, + }, + stats = { + "is_area_damage", + "base_skill_is_totemified", + "is_totem", + "totem_ignores_vaal_skill_cost", + "modifiers_to_totem_duration_also_affect_soul_prevention_duration", + "cannot_cancel_skill_before_contact_point", + "totem_ignores_cooldown", + }, + levels = { + [1] = { cooldown = 10, levelRequirement = 28, storedUses = 1, }, + [2] = { baseMultiplier = 1.028, cooldown = 10, damageEffectiveness = 1.03, levelRequirement = 31, storedUses = 1, }, + [3] = { baseMultiplier = 1.057, cooldown = 10, damageEffectiveness = 1.06, levelRequirement = 34, storedUses = 1, }, + [4] = { baseMultiplier = 1.085, cooldown = 10, damageEffectiveness = 1.09, levelRequirement = 37, storedUses = 1, }, + [5] = { baseMultiplier = 1.114, cooldown = 10, damageEffectiveness = 1.11, levelRequirement = 40, storedUses = 1, }, + [6] = { baseMultiplier = 1.142, cooldown = 10, damageEffectiveness = 1.14, levelRequirement = 42, storedUses = 1, }, + [7] = { baseMultiplier = 1.171, cooldown = 10, damageEffectiveness = 1.17, levelRequirement = 44, storedUses = 1, }, + [8] = { baseMultiplier = 1.199, cooldown = 10, damageEffectiveness = 1.2, levelRequirement = 46, storedUses = 1, }, + [9] = { baseMultiplier = 1.227, cooldown = 10, damageEffectiveness = 1.23, levelRequirement = 48, storedUses = 1, }, + [10] = { baseMultiplier = 1.256, cooldown = 10, damageEffectiveness = 1.26, levelRequirement = 50, storedUses = 1, }, + [11] = { baseMultiplier = 1.284, cooldown = 10, damageEffectiveness = 1.28, levelRequirement = 52, storedUses = 1, }, + [12] = { baseMultiplier = 1.313, cooldown = 10, damageEffectiveness = 1.31, levelRequirement = 54, storedUses = 1, }, + [13] = { baseMultiplier = 1.341, cooldown = 10, damageEffectiveness = 1.34, levelRequirement = 56, storedUses = 1, }, + [14] = { baseMultiplier = 1.369, cooldown = 10, damageEffectiveness = 1.37, levelRequirement = 58, storedUses = 1, }, + [15] = { baseMultiplier = 1.398, cooldown = 10, damageEffectiveness = 1.4, levelRequirement = 60, storedUses = 1, }, + [16] = { baseMultiplier = 1.426, cooldown = 10, damageEffectiveness = 1.43, levelRequirement = 62, storedUses = 1, }, + [17] = { baseMultiplier = 1.455, cooldown = 10, damageEffectiveness = 1.45, levelRequirement = 64, storedUses = 1, }, + [18] = { baseMultiplier = 1.483, cooldown = 10, damageEffectiveness = 1.48, levelRequirement = 66, storedUses = 1, }, + [19] = { baseMultiplier = 1.512, cooldown = 10, damageEffectiveness = 1.51, levelRequirement = 68, storedUses = 1, }, + [20] = { baseMultiplier = 1.54, cooldown = 10, damageEffectiveness = 1.54, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 1.568, cooldown = 10, damageEffectiveness = 1.57, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 1.597, cooldown = 10, damageEffectiveness = 1.6, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 1.625, cooldown = 10, damageEffectiveness = 1.63, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 1.654, cooldown = 10, damageEffectiveness = 1.65, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 1.682, cooldown = 10, damageEffectiveness = 1.68, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 1.711, cooldown = 10, damageEffectiveness = 1.71, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 1.739, cooldown = 10, damageEffectiveness = 1.74, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 1.767, cooldown = 10, damageEffectiveness = 1.77, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 1.796, cooldown = 10, damageEffectiveness = 1.8, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 1.824, cooldown = 10, damageEffectiveness = 1.82, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 1.838, cooldown = 10, damageEffectiveness = 1.84, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 1.853, cooldown = 10, damageEffectiveness = 1.85, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 1.867, cooldown = 10, damageEffectiveness = 1.87, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 1.881, cooldown = 10, damageEffectiveness = 1.88, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 1.895, cooldown = 10, damageEffectiveness = 1.9, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 1.909, cooldown = 10, damageEffectiveness = 1.91, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 1.924, cooldown = 10, damageEffectiveness = 1.92, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 1.938, cooldown = 10, damageEffectiveness = 1.94, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 1.952, cooldown = 10, damageEffectiveness = 1.95, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 1.966, cooldown = 10, damageEffectiveness = 1.97, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["VaalArcticArmourMercenary"] = { + name = "Vaal Arctic Armour", + hidden = true, + mercenary = true, + inheritedFrom = "VaalArcticArmour", + color = 2, + description = "Immediately encases you in ice, protecting you for a duration or until you take damage from a number of hits, and also grants a buff once the cast time has finished. You cannot move or perform non-instant actions while in the ice. When the ice breaks, the buff is also removed.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Duration] = true, [SkillType.Cold] = true, [SkillType.Vaal] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + duration = true, + spell = true, + }, + constantStats = { + { "vaal_arctic_armour_damage_taken_+%_final_from_hits", -90 }, + { "vaal_arctic_armour_number_of_hits_absorbed", 3 }, + }, + stats = { + "base_skill_effect_duration", + "base_energy_shield_regeneration_rate_per_minute", + "base_mana_regeneration_rate_per_minute", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 5000, 1200, 300, cooldown = 20, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 5000, 1404, 330, cooldown = 20, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 5000, 1643, 363, cooldown = 20, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 5000, 1922, 399, cooldown = 20, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 5000, 2249, 439, cooldown = 20, levelRequirement = 31, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 5000, 2631, 483, cooldown = 20, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 5000, 3078, 532, cooldown = 20, levelRequirement = 37, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 5000, 3602, 585, cooldown = 20, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 5000, 4214, 643, cooldown = 20, levelRequirement = 43, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 5000, 4930, 707, cooldown = 20, levelRequirement = 46, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 5000, 5768, 778, cooldown = 20, levelRequirement = 49, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 5000, 6749, 856, cooldown = 20, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 5000, 7896, 942, cooldown = 20, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 5000, 9238, 1036, cooldown = 20, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 5000, 10809, 1139, cooldown = 20, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 5000, 12647, 1253, cooldown = 20, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 5000, 14796, 1379, cooldown = 20, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 5000, 17312, 1516, cooldown = 20, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 5000, 20255, 1668, cooldown = 20, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 5000, 23698, 1835, cooldown = 20, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 5000, 27727, 2018, cooldown = 20, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 5000, 32440, 2220, cooldown = 20, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 5000, 37955, 2442, cooldown = 20, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 5000, 44408, 2686, cooldown = 20, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 5000, 51957, 2955, cooldown = 20, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 5000, 60789, 3250, cooldown = 20, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 5000, 71124, 3576, cooldown = 20, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 5000, 83215, 3933, cooldown = 20, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 5000, 97361, 4326, cooldown = 20, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 5000, 113913, 4759, cooldown = 20, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 5000, 123595, 4997, cooldown = 20, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 5000, 134101, 5247, cooldown = 20, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 5000, 145499, 5509, cooldown = 20, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 5000, 157867, 5785, cooldown = 20, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 5000, 171285, 6074, cooldown = 20, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 5000, 185845, 6377, cooldown = 20, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 5000, 201641, 6696, cooldown = 20, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 5000, 218781, 7031, cooldown = 20, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 5000, 237377, 7383, cooldown = 20, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 5000, 257554, 7752, cooldown = 20, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["VaalBurningArrowMercenary"] = { + name = "Vaal Burning Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "VaalBurningArrow", + color = 2, + description = "Fires an arrow that explodes, dealing fire damage to its target and other nearby enemies, with an increased chance of igniting them.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Area] = true, [SkillType.Vaal] = true, [SkillType.Fire] = true, [SkillType.ThresholdJewelDuration] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "base_chance_to_ignite_%", 50 }, + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + { "projectile_base_number_of_targets_to_pierce", 3 }, + }, + stats = { + "vaal_burning_arrow_explode_on_hit", + "global_always_hit", + "skill_can_fire_arrows", + "cannot_cancel_skill_before_contact_point", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { baseMultiplier = 3.9, cooldown = 10, damageEffectiveness = 3.9, levelRequirement = 1, storedUses = 1, }, + [2] = { baseMultiplier = 3.989, cooldown = 10, damageEffectiveness = 3.989, levelRequirement = 2, storedUses = 1, }, + [3] = { baseMultiplier = 4.079, cooldown = 10, damageEffectiveness = 4.079, levelRequirement = 4, storedUses = 1, }, + [4] = { baseMultiplier = 4.168, cooldown = 10, damageEffectiveness = 4.168, levelRequirement = 7, storedUses = 1, }, + [5] = { baseMultiplier = 4.258, cooldown = 10, damageEffectiveness = 4.258, levelRequirement = 11, storedUses = 1, }, + [6] = { baseMultiplier = 4.347, cooldown = 10, damageEffectiveness = 4.347, levelRequirement = 16, storedUses = 1, }, + [7] = { baseMultiplier = 4.437, cooldown = 10, damageEffectiveness = 4.437, levelRequirement = 20, storedUses = 1, }, + [8] = { baseMultiplier = 4.526, cooldown = 10, damageEffectiveness = 4.526, levelRequirement = 24, storedUses = 1, }, + [9] = { baseMultiplier = 4.616, cooldown = 10, damageEffectiveness = 4.616, levelRequirement = 28, storedUses = 1, }, + [10] = { baseMultiplier = 4.705, cooldown = 10, damageEffectiveness = 4.705, levelRequirement = 32, storedUses = 1, }, + [11] = { baseMultiplier = 4.795, cooldown = 10, damageEffectiveness = 4.795, levelRequirement = 36, storedUses = 1, }, + [12] = { baseMultiplier = 4.884, cooldown = 10, damageEffectiveness = 4.884, levelRequirement = 40, storedUses = 1, }, + [13] = { baseMultiplier = 4.974, cooldown = 10, damageEffectiveness = 4.974, levelRequirement = 44, storedUses = 1, }, + [14] = { baseMultiplier = 5.063, cooldown = 10, damageEffectiveness = 5.063, levelRequirement = 48, storedUses = 1, }, + [15] = { baseMultiplier = 5.153, cooldown = 10, damageEffectiveness = 5.153, levelRequirement = 52, storedUses = 1, }, + [16] = { baseMultiplier = 5.242, cooldown = 10, damageEffectiveness = 5.242, levelRequirement = 56, storedUses = 1, }, + [17] = { baseMultiplier = 5.332, cooldown = 10, damageEffectiveness = 5.332, levelRequirement = 60, storedUses = 1, }, + [18] = { baseMultiplier = 5.421, cooldown = 10, damageEffectiveness = 5.421, levelRequirement = 64, storedUses = 1, }, + [19] = { baseMultiplier = 5.511, cooldown = 10, damageEffectiveness = 5.511, levelRequirement = 67, storedUses = 1, }, + [20] = { baseMultiplier = 5.6, cooldown = 10, damageEffectiveness = 5.6, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 5.689, cooldown = 10, damageEffectiveness = 5.689, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 5.779, cooldown = 10, damageEffectiveness = 5.779, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 5.868, cooldown = 10, damageEffectiveness = 5.868, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 5.958, cooldown = 10, damageEffectiveness = 5.958, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 6.047, cooldown = 10, damageEffectiveness = 6.047, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 6.137, cooldown = 10, damageEffectiveness = 6.137, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 6.226, cooldown = 10, damageEffectiveness = 6.226, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 6.316, cooldown = 10, damageEffectiveness = 6.316, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 6.405, cooldown = 10, damageEffectiveness = 6.405, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 6.495, cooldown = 10, damageEffectiveness = 6.495, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 6.539, cooldown = 10, damageEffectiveness = 6.539, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 6.584, cooldown = 10, damageEffectiveness = 6.584, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 6.629, cooldown = 10, damageEffectiveness = 6.629, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 6.674, cooldown = 10, damageEffectiveness = 6.674, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 6.718, cooldown = 10, damageEffectiveness = 6.718, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 6.763, cooldown = 10, damageEffectiveness = 6.763, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 6.808, cooldown = 10, damageEffectiveness = 6.808, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 6.853, cooldown = 10, damageEffectiveness = 6.853, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 6.897, cooldown = 10, damageEffectiveness = 6.897, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 6.942, cooldown = 10, damageEffectiveness = 6.942, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["VaalBurningArrowMercenaryEncounter"] = { + name = "Vaal Burning Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "VaalBurningArrow", + color = 2, + description = "Fires an arrow that explodes, dealing fire damage to its target and other nearby enemies, with an increased chance of igniting them.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Area] = true, [SkillType.Vaal] = true, [SkillType.Fire] = true, [SkillType.ThresholdJewelDuration] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "base_chance_to_ignite_%", 50 }, + { "skill_physical_damage_%_to_convert_to_fire", 100 }, + { "projectile_base_number_of_targets_to_pierce", 3 }, + }, + stats = { + "vaal_burning_arrow_explode_on_hit", + "skill_can_fire_arrows", + "cannot_cancel_skill_before_contact_point", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { baseMultiplier = 3.5, cooldown = 10, damageEffectiveness = 3.5, levelRequirement = 0, storedUses = 1, }, + }, +} + +skills["VaalCausticArrowMercenary"] = { + name = "Vaal Caustic Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "VaalCausticArrow", + color = 2, + baseEffectiveness = 19.590000152588, + incrementalEffectiveness = 0.050299998372793, + description = "Fires a slow-moving serpentine arrow which deals chaos damage while piercing enemies, and leaves a trail of caustic ground. Enemies standing on the caustic ground take chaos damage over time.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Vaal] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "vaal_caustic_arrow_ground_art_variation", 14 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "base_is_projectile", + "skill_can_fire_arrows", + "projectile_damage_modifiers_apply_to_skill_dot", + "visual_hit_effect_chaos_is_green", + "modifiers_to_skill_effect_duration_also_affect_soul_prevention_duration", + "always_pierce", + "global_always_hit", + "cannot_cancel_skill_before_contact_point", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { 16.666667039196, baseMultiplier = 1.9, cooldown = 10, damageEffectiveness = 1.9, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, }, }, + [2] = { 16.666667039196, baseMultiplier = 1.93, cooldown = 10, damageEffectiveness = 1.93, levelRequirement = 2, storedUses = 1, statInterpolation = { 3, }, }, + [3] = { 16.666667039196, baseMultiplier = 1.965, cooldown = 10, damageEffectiveness = 1.965, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, }, }, + [4] = { 16.666667039196, baseMultiplier = 1.995, cooldown = 10, damageEffectiveness = 1.995, levelRequirement = 7, storedUses = 1, statInterpolation = { 3, }, }, + [5] = { 16.666667039196, baseMultiplier = 2.025, cooldown = 10, damageEffectiveness = 2.025, levelRequirement = 11, storedUses = 1, statInterpolation = { 3, }, }, + [6] = { 16.666667039196, baseMultiplier = 2.06, cooldown = 10, damageEffectiveness = 2.06, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, }, }, + [7] = { 16.666667039196, baseMultiplier = 2.09, cooldown = 10, damageEffectiveness = 2.09, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, }, }, + [8] = { 16.666667039196, baseMultiplier = 2.12, cooldown = 10, damageEffectiveness = 2.12, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, }, }, + [9] = { 16.666667039196, baseMultiplier = 2.155, cooldown = 10, damageEffectiveness = 2.155, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, }, }, + [10] = { 16.666667039196, baseMultiplier = 2.185, cooldown = 10, damageEffectiveness = 2.185, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, }, }, + [11] = { 16.666667039196, baseMultiplier = 2.215, cooldown = 10, damageEffectiveness = 2.215, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, }, }, + [12] = { 16.666667039196, baseMultiplier = 2.245, cooldown = 10, damageEffectiveness = 2.245, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, }, }, + [13] = { 16.666667039196, baseMultiplier = 2.28, cooldown = 10, damageEffectiveness = 2.28, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, }, }, + [14] = { 16.666667039196, baseMultiplier = 2.31, cooldown = 10, damageEffectiveness = 2.31, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, }, }, + [15] = { 16.666667039196, baseMultiplier = 2.34, cooldown = 10, damageEffectiveness = 2.34, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, }, }, + [16] = { 16.666667039196, baseMultiplier = 2.375, cooldown = 10, damageEffectiveness = 2.375, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, }, }, + [17] = { 16.666667039196, baseMultiplier = 2.405, cooldown = 10, damageEffectiveness = 2.405, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, }, }, + [18] = { 16.666667039196, baseMultiplier = 2.435, cooldown = 10, damageEffectiveness = 2.435, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, }, }, + [19] = { 16.666667039196, baseMultiplier = 2.47, cooldown = 10, damageEffectiveness = 2.47, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, }, }, + [20] = { 16.666667039196, baseMultiplier = 2.5, cooldown = 10, damageEffectiveness = 2.5, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, }, }, + [21] = { 16.666667039196, baseMultiplier = 2.53, cooldown = 10, damageEffectiveness = 2.53, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, }, }, + [22] = { 16.666667039196, baseMultiplier = 2.565, cooldown = 10, damageEffectiveness = 2.565, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, }, }, + [23] = { 16.666667039196, baseMultiplier = 2.595, cooldown = 10, damageEffectiveness = 2.595, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, }, }, + [24] = { 16.666667039196, baseMultiplier = 2.625, cooldown = 10, damageEffectiveness = 2.625, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, }, }, + [25] = { 16.666667039196, baseMultiplier = 2.66, cooldown = 10, damageEffectiveness = 2.66, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, }, }, + [26] = { 16.666667039196, baseMultiplier = 2.69, cooldown = 10, damageEffectiveness = 2.69, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, }, }, + [27] = { 16.666667039196, baseMultiplier = 2.72, cooldown = 10, damageEffectiveness = 2.72, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, }, }, + [28] = { 16.666667039196, baseMultiplier = 2.755, cooldown = 10, damageEffectiveness = 2.755, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, }, }, + [29] = { 16.666667039196, baseMultiplier = 2.785, cooldown = 10, damageEffectiveness = 2.785, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, }, }, + [30] = { 16.666667039196, baseMultiplier = 2.815, cooldown = 10, damageEffectiveness = 2.815, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, }, }, + [31] = { 16.666667039196, baseMultiplier = 2.83, cooldown = 10, damageEffectiveness = 2.83, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, }, }, + [32] = { 16.666667039196, baseMultiplier = 2.845, cooldown = 10, damageEffectiveness = 2.845, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, }, }, + [33] = { 16.666667039196, baseMultiplier = 2.865, cooldown = 10, damageEffectiveness = 2.865, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, }, }, + [34] = { 16.666667039196, baseMultiplier = 2.88, cooldown = 10, damageEffectiveness = 2.88, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, }, }, + [35] = { 16.666667039196, baseMultiplier = 2.895, cooldown = 10, damageEffectiveness = 2.895, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, }, }, + [36] = { 16.666667039196, baseMultiplier = 2.91, cooldown = 10, damageEffectiveness = 2.91, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, }, }, + [37] = { 16.666667039196, baseMultiplier = 2.925, cooldown = 10, damageEffectiveness = 2.925, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, }, }, + [38] = { 16.666667039196, baseMultiplier = 2.94, cooldown = 10, damageEffectiveness = 2.94, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, }, }, + [39] = { 16.666667039196, baseMultiplier = 2.96, cooldown = 10, damageEffectiveness = 2.96, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, }, }, + [40] = { 16.666667039196, baseMultiplier = 2.975, cooldown = 10, damageEffectiveness = 2.975, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["VaalCausticArrowMercenaryEncounter"] = { + name = "Vaal Caustic Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "VaalCausticArrow", + color = 2, + baseEffectiveness = 5, + incrementalEffectiveness = 0.046000000089407, + description = "Fires a slow-moving serpentine arrow which deals chaos damage while piercing enemies, and leaves a trail of caustic ground. Enemies standing on the caustic ground take chaos damage over time.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Totemable] = true, [SkillType.DamageOverTime] = true, [SkillType.Chaos] = true, [SkillType.Vaal] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "base_skill_effect_duration", 6000 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "vaal_caustic_arrow_ground_art_variation", 14 }, + }, + stats = { + "base_chaos_damage_to_deal_per_minute", + "base_is_projectile", + "skill_can_fire_arrows", + "projectile_damage_modifiers_apply_to_skill_dot", + "visual_hit_effect_chaos_is_green", + "modifiers_to_skill_effect_duration_also_affect_soul_prevention_duration", + "always_pierce", + "global_always_hit", + "cannot_cancel_skill_before_contact_point", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, }, }, + [2] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 2, storedUses = 1, statInterpolation = { 3, }, }, + [3] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 4, storedUses = 1, statInterpolation = { 3, }, }, + [4] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 7, storedUses = 1, statInterpolation = { 3, }, }, + [5] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 11, storedUses = 1, statInterpolation = { 3, }, }, + [6] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, }, }, + [7] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, }, }, + [8] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, }, }, + [9] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, }, }, + [10] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 32, storedUses = 1, statInterpolation = { 3, }, }, + [11] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, }, }, + [12] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, }, }, + [13] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, }, }, + [14] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, }, }, + [15] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, }, }, + [16] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, }, }, + [17] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, }, }, + [18] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, }, }, + [19] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 67, storedUses = 1, statInterpolation = { 3, }, }, + [20] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, }, }, + [21] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, }, }, + [22] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, }, }, + [23] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, }, }, + [24] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, }, }, + [25] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, }, }, + [26] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, }, }, + [27] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, }, }, + [28] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, }, }, + [29] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, }, }, + [30] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, }, }, + [31] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, }, }, + [32] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, }, }, + [33] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, }, }, + [34] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, }, }, + [35] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, }, }, + [36] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, }, }, + [37] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, }, }, + [38] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, }, }, + [39] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, }, }, + [40] = { 10.000000620882, baseMultiplier = 1.5925, cooldown = 10, damageEffectiveness = 1.5925, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, }, }, + }, +} + +skills["VaalCleaveMercenary"] = { + name = "Vaal Cleave", + hidden = true, + mercenary = true, + inheritedFrom = "VaalCleave", + color = 1, + description = "The character swings their weapon (or both weapons if dual wielding) in an arc, damaging monsters in an area in front of them. Killing Blows on Rare or Unique enemies grant a buff that improves Cleave for a duration. Killing Blows on Rare Enemies also steal their modifiers for a secondary duration. Only works with Axes and Swords.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.ThresholdJewelArea] = true, [SkillType.Vaal] = true, [SkillType.Duration] = true, [SkillType.Buff] = true, [SkillType.NeverExertable] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "active_skill_merged_damage_+%_final_while_dual_wielding", -40 }, + { "base_skill_effect_duration", 20000 }, + { "base_secondary_skill_effect_duration", 20000 }, + { "vaal_cleave_executioner_area_of_effect_+%", 60 }, + { "vaal_cleave_executioner_damage_against_enemies_on_low_life_+%", 60 }, + { "additional_weapon_base_attack_time_ms", 800 }, + }, + stats = { + "active_skill_base_radius_+", + "is_area_damage", + "skill_double_hits_when_dual_wielding", + "console_skill_dont_chase", + "vaal_cleave_steal_mods_on_kill", + "cannot_cancel_skill_before_contact_point", + "modifiers_to_skill_effect_duration_also_affect_soul_prevention_duration", + "global_always_hit", + "skill_cannot_be_stunned_before_contact_point", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 15, baseMultiplier = 3.3438, cooldown = 6, damageEffectiveness = 3.3438, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 15, baseMultiplier = 3.5238, cooldown = 6, damageEffectiveness = 3.5238, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 16, baseMultiplier = 3.7125, cooldown = 6, damageEffectiveness = 3.7125, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 16, baseMultiplier = 3.91, cooldown = 6, damageEffectiveness = 3.91, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 17, baseMultiplier = 4.1188, cooldown = 6, damageEffectiveness = 4.1188, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 17, baseMultiplier = 4.3363, cooldown = 6, damageEffectiveness = 4.3363, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 18, baseMultiplier = 4.5663, cooldown = 6, damageEffectiveness = 4.5663, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 18, baseMultiplier = 4.8063, cooldown = 6, damageEffectiveness = 4.8063, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 19, baseMultiplier = 5.06, cooldown = 6, damageEffectiveness = 5.06, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 19, baseMultiplier = 5.325, cooldown = 6, damageEffectiveness = 5.325, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 20, baseMultiplier = 5.6038, cooldown = 6, damageEffectiveness = 5.6038, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 20, baseMultiplier = 5.8963, cooldown = 6, damageEffectiveness = 5.8963, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 21, baseMultiplier = 6.2038, cooldown = 6, damageEffectiveness = 6.2038, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 21, baseMultiplier = 6.5263, cooldown = 6, damageEffectiveness = 6.5263, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 22, baseMultiplier = 6.865, cooldown = 6, damageEffectiveness = 6.865, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 22, baseMultiplier = 7.2213, cooldown = 6, damageEffectiveness = 7.2213, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 23, baseMultiplier = 7.595, cooldown = 6, damageEffectiveness = 7.595, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 23, baseMultiplier = 7.9875, cooldown = 6, damageEffectiveness = 7.9875, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 24, baseMultiplier = 8.3988, cooldown = 6, damageEffectiveness = 8.3988, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 24, baseMultiplier = 8.8313, cooldown = 6, damageEffectiveness = 8.8313, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 25, baseMultiplier = 9.285, cooldown = 6, damageEffectiveness = 9.285, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 25, baseMultiplier = 9.7625, cooldown = 6, damageEffectiveness = 9.7625, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 26, baseMultiplier = 10.2625, cooldown = 6, damageEffectiveness = 10.2625, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 26, baseMultiplier = 10.7888, cooldown = 6, damageEffectiveness = 10.7888, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 27, baseMultiplier = 11.34, cooldown = 6, damageEffectiveness = 11.34, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 27, baseMultiplier = 11.92, cooldown = 6, damageEffectiveness = 11.92, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 28, baseMultiplier = 12.5288, cooldown = 6, damageEffectiveness = 12.5288, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 28, baseMultiplier = 13.1675, cooldown = 6, damageEffectiveness = 13.1675, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 29, baseMultiplier = 13.8375, cooldown = 6, damageEffectiveness = 13.8375, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 29, baseMultiplier = 14.5425, cooldown = 6, damageEffectiveness = 14.5425, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 29, baseMultiplier = 15.67, cooldown = 6, damageEffectiveness = 15.67, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 30, baseMultiplier = 16.0688, cooldown = 6, damageEffectiveness = 16.0688, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 30, baseMultiplier = 16.4763, cooldown = 6, damageEffectiveness = 16.4763, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 30, baseMultiplier = 16.895, cooldown = 6, damageEffectiveness = 16.895, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 30, baseMultiplier = 17.3225, cooldown = 6, damageEffectiveness = 17.3225, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 31, baseMultiplier = 17.7625, cooldown = 6, damageEffectiveness = 17.7625, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 31, baseMultiplier = 18.2125, cooldown = 6, damageEffectiveness = 18.2125, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 31, baseMultiplier = 18.6738, cooldown = 6, damageEffectiveness = 18.6738, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 31, baseMultiplier = 19.1475, cooldown = 6, damageEffectiveness = 19.1475, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 32, baseMultiplier = 19.6325, cooldown = 6, damageEffectiveness = 19.6325, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["VaalCleaveMercenaryEncounter"] = { + name = "Vaal Cleave", + hidden = true, + mercenary = true, + inheritedFrom = "VaalCleave", + color = 1, + description = "The character swings their weapon (or both weapons if dual wielding) in an arc, damaging monsters in an area in front of them. Killing Blows on Rare or Unique enemies grant a buff that improves Cleave for a duration. Killing Blows on Rare Enemies also steal their modifiers for a secondary duration. Only works with Axes and Swords.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.ThresholdJewelArea] = true, [SkillType.Vaal] = true, [SkillType.Duration] = true, [SkillType.Buff] = true, [SkillType.NeverExertable] = true, }, + weaponTypes = { + ["One Handed Axe"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "active_skill_merged_damage_+%_final_while_dual_wielding", -40 }, + { "base_skill_effect_duration", 20000 }, + { "base_secondary_skill_effect_duration", 20000 }, + { "vaal_cleave_executioner_area_of_effect_+%", 60 }, + { "vaal_cleave_executioner_damage_against_enemies_on_low_life_+%", 60 }, + { "additional_weapon_base_attack_time_ms", 800 }, + }, + stats = { + "active_skill_base_radius_+", + "is_area_damage", + "skill_double_hits_when_dual_wielding", + "console_skill_dont_chase", + "vaal_cleave_steal_mods_on_kill", + "cannot_cancel_skill_before_contact_point", + "modifiers_to_skill_effect_duration_also_affect_soul_prevention_duration", + "global_always_hit", + "skill_cannot_be_stunned_before_contact_point", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 15, baseMultiplier = 2.875, cooldown = 6, damageEffectiveness = 2.875, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 15, baseMultiplier = 3.019, cooldown = 6, damageEffectiveness = 3.019, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 16, baseMultiplier = 3.17, cooldown = 6, damageEffectiveness = 3.17, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 16, baseMultiplier = 3.328, cooldown = 6, damageEffectiveness = 3.328, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 17, baseMultiplier = 3.495, cooldown = 6, damageEffectiveness = 3.495, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 17, baseMultiplier = 3.669, cooldown = 6, damageEffectiveness = 3.669, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 18, baseMultiplier = 3.853, cooldown = 6, damageEffectiveness = 3.853, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 18, baseMultiplier = 4.045, cooldown = 6, damageEffectiveness = 4.045, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 19, baseMultiplier = 4.248, cooldown = 6, damageEffectiveness = 4.248, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 19, baseMultiplier = 4.46, cooldown = 6, damageEffectiveness = 4.46, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 20, baseMultiplier = 4.683, cooldown = 6, damageEffectiveness = 4.683, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 20, baseMultiplier = 4.917, cooldown = 6, damageEffectiveness = 4.917, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 21, baseMultiplier = 5.163, cooldown = 6, damageEffectiveness = 5.163, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 21, baseMultiplier = 5.421, cooldown = 6, damageEffectiveness = 5.421, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 22, baseMultiplier = 5.692, cooldown = 6, damageEffectiveness = 5.692, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 22, baseMultiplier = 5.977, cooldown = 6, damageEffectiveness = 5.977, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 23, baseMultiplier = 6.276, cooldown = 6, damageEffectiveness = 6.276, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 23, baseMultiplier = 6.59, cooldown = 6, damageEffectiveness = 6.59, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 24, baseMultiplier = 6.919, cooldown = 6, damageEffectiveness = 6.919, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 24, baseMultiplier = 7.265, cooldown = 6, damageEffectiveness = 7.265, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 25, baseMultiplier = 7.628, cooldown = 6, damageEffectiveness = 7.628, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 25, baseMultiplier = 8.01, cooldown = 6, damageEffectiveness = 8.01, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 26, baseMultiplier = 8.41, cooldown = 6, damageEffectiveness = 8.41, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 26, baseMultiplier = 8.831, cooldown = 6, damageEffectiveness = 8.831, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 27, baseMultiplier = 9.272, cooldown = 6, damageEffectiveness = 9.272, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 27, baseMultiplier = 9.736, cooldown = 6, damageEffectiveness = 9.736, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 28, baseMultiplier = 10.223, cooldown = 6, damageEffectiveness = 10.223, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 28, baseMultiplier = 10.734, cooldown = 6, damageEffectiveness = 10.734, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 29, baseMultiplier = 11.27, cooldown = 6, damageEffectiveness = 11.27, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 29, baseMultiplier = 11.834, cooldown = 6, damageEffectiveness = 11.834, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 29, baseMultiplier = 12.736, cooldown = 6, damageEffectiveness = 12.736, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 30, baseMultiplier = 13.055, cooldown = 6, damageEffectiveness = 13.055, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 30, baseMultiplier = 13.381, cooldown = 6, damageEffectiveness = 13.381, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 30, baseMultiplier = 13.716, cooldown = 6, damageEffectiveness = 13.716, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 30, baseMultiplier = 14.058, cooldown = 6, damageEffectiveness = 14.058, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 31, baseMultiplier = 14.41, cooldown = 6, damageEffectiveness = 14.41, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 31, baseMultiplier = 14.77, cooldown = 6, damageEffectiveness = 14.77, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 31, baseMultiplier = 15.139, cooldown = 6, damageEffectiveness = 15.139, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 31, baseMultiplier = 15.518, cooldown = 6, damageEffectiveness = 15.518, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 32, baseMultiplier = 15.906, cooldown = 6, damageEffectiveness = 15.906, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["VaalDoubleStrikeMercenary"] = { + name = "Vaal Double Strike", + hidden = true, + mercenary = true, + inheritedFrom = "VaalDoubleStrike", + color = 2, + description = "Performs two fast strikes with a melee weapon, each of which summons a double of you for a duration to continuously attack monsters in this fashion.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Melee] = true, [SkillType.Duration] = true, [SkillType.Vaal] = true, [SkillType.Physical] = true, [SkillType.NeverExertable] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "base_skill_number_of_additional_hits", 1 }, + { "base_skill_effect_duration", 6000 }, + { "number_of_monsters_to_summon", 1 }, + { "bleed_on_hit_with_attacks_%", 25 }, + { "maximum_number_of_summoned_doubles", 8 }, + }, + stats = { + "doubles_have_movement_speed_+%", + "cannot_cancel_skill_before_contact_point", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { 0, baseMultiplier = 0.403, cooldown = 10, damageEffectiveness = 0.403, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 3, baseMultiplier = 0.423, cooldown = 10, damageEffectiveness = 0.423, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 6, baseMultiplier = 0.444, cooldown = 10, damageEffectiveness = 0.444, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 9, baseMultiplier = 0.466, cooldown = 10, damageEffectiveness = 0.466, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 12, baseMultiplier = 0.489, cooldown = 10, damageEffectiveness = 0.489, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 15, baseMultiplier = 0.514, cooldown = 10, damageEffectiveness = 0.514, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 18, baseMultiplier = 0.539, cooldown = 10, damageEffectiveness = 0.539, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 21, baseMultiplier = 0.566, cooldown = 10, damageEffectiveness = 0.566, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 24, baseMultiplier = 0.595, cooldown = 10, damageEffectiveness = 0.595, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 27, baseMultiplier = 0.624, cooldown = 10, damageEffectiveness = 0.624, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 30, baseMultiplier = 0.656, cooldown = 10, damageEffectiveness = 0.656, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 33, baseMultiplier = 0.688, cooldown = 10, damageEffectiveness = 0.688, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 36, baseMultiplier = 0.723, cooldown = 10, damageEffectiveness = 0.723, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 39, baseMultiplier = 0.759, cooldown = 10, damageEffectiveness = 0.759, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 42, baseMultiplier = 0.797, cooldown = 10, damageEffectiveness = 0.797, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 45, baseMultiplier = 0.837, cooldown = 10, damageEffectiveness = 0.837, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 48, baseMultiplier = 0.879, cooldown = 10, damageEffectiveness = 0.879, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 51, baseMultiplier = 0.923, cooldown = 10, damageEffectiveness = 0.923, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 54, baseMultiplier = 0.969, cooldown = 10, damageEffectiveness = 0.969, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 57, baseMultiplier = 1.017, cooldown = 10, damageEffectiveness = 1.017, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 60, baseMultiplier = 1.068, cooldown = 10, damageEffectiveness = 1.068, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 63, baseMultiplier = 1.121, cooldown = 10, damageEffectiveness = 1.121, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 66, baseMultiplier = 1.177, cooldown = 10, damageEffectiveness = 1.177, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 69, baseMultiplier = 1.236, cooldown = 10, damageEffectiveness = 1.236, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 72, baseMultiplier = 1.298, cooldown = 10, damageEffectiveness = 1.298, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 75, baseMultiplier = 1.363, cooldown = 10, damageEffectiveness = 1.363, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 78, baseMultiplier = 1.431, cooldown = 10, damageEffectiveness = 1.431, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 81, baseMultiplier = 1.503, cooldown = 10, damageEffectiveness = 1.503, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 84, baseMultiplier = 1.578, cooldown = 10, damageEffectiveness = 1.578, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 87, baseMultiplier = 1.657, cooldown = 10, damageEffectiveness = 1.657, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 89, baseMultiplier = 1.783, cooldown = 10, damageEffectiveness = 1.783, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 90, baseMultiplier = 1.828, cooldown = 10, damageEffectiveness = 1.828, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 92, baseMultiplier = 1.873, cooldown = 10, damageEffectiveness = 1.873, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 93, baseMultiplier = 1.92, cooldown = 10, damageEffectiveness = 1.92, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 95, baseMultiplier = 1.968, cooldown = 10, damageEffectiveness = 1.968, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 96, baseMultiplier = 2.017, cooldown = 10, damageEffectiveness = 2.017, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 98, baseMultiplier = 2.068, cooldown = 10, damageEffectiveness = 2.068, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 99, baseMultiplier = 2.12, cooldown = 10, damageEffectiveness = 2.12, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 101, baseMultiplier = 2.172, cooldown = 10, damageEffectiveness = 2.172, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 102, baseMultiplier = 2.227, cooldown = 10, damageEffectiveness = 2.227, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["VaalFlameblastMercenary"] = { + name = "Vaal Flameblast", + hidden = true, + mercenary = true, + inheritedFrom = "VaalFlameblast", + color = 3, + baseEffectiveness = 1.2000000476837, + incrementalEffectiveness = 0.035199999809265, + description = "Targets an area and builds up stages in that area based on cast speed. It explodes every 3 stages, until it reaches a maximum of 15. As it gains more stages, the area gets smaller but the damage gets higher.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.Vaal] = true, [SkillType.Fire] = true, [SkillType.AreaSpell] = true, [SkillType.Multicastable] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + spell = true, + }, + constantStats = { + { "charged_blast_spell_damage_+%_final_per_stack", 10 }, + { "flameblast_ailment_damage_+%_final_per_stack", 10 }, + { "base_chance_to_ignite_%", 50 }, + { "vaal_flameblast_radius_+_per_stage", -2 }, + }, + stats = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + "is_area_damage", + "skill_cannot_be_stunned", + "skill_cannot_be_interrupted", + }, + notMinionStat = { + "spell_minimum_base_fire_damage", + "spell_maximum_base_fire_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, cooldown = 10, critChance = 5, damageEffectiveness = 0.6, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["VaalGlacialHammerMercenary"] = { + name = "Vaal Glacial Hammer", + hidden = true, + mercenary = true, + inheritedFrom = "VaalGlacialHammer", + color = 1, + description = "Hits enemies, converting some of your physical damage to cold damage. It traps enemies with you in a circle of ice so that they can't escape. Requires a Mace, Sceptre or Staff.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Melee] = true, [SkillType.Duration] = true, [SkillType.Area] = true, [SkillType.Vaal] = true, [SkillType.Cold] = true, [SkillType.NeverExertable] = true, }, + weaponTypes = { + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_cold", 100 }, + { "base_chance_to_freeze_%", 25 }, + { "cold_ailment_duration_+%", 35 }, + }, + stats = { + "base_skill_effect_duration", + "cold_ailment_effect_+%", + "freeze_as_though_dealt_damage_+%", + "global_always_hit", + "modifiers_to_skill_effect_duration_also_affect_soul_prevention_duration", + "cannot_cancel_skill_before_contact_point", + "skill_cannot_be_stunned_before_contact_point", + }, + notMinionStat = { + "base_skill_effect_duration", + }, + levels = { + [1] = { 3400, 10, 200, baseMultiplier = 2.185, cooldown = 7, damageEffectiveness = 2.185, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 3450, 11, 210, baseMultiplier = 2.294, cooldown = 7, damageEffectiveness = 2.294, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 3500, 12, 220, baseMultiplier = 2.409, cooldown = 7, damageEffectiveness = 2.409, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 3550, 13, 230, baseMultiplier = 2.529, cooldown = 7, damageEffectiveness = 2.529, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 3600, 14, 240, baseMultiplier = 2.656, cooldown = 7, damageEffectiveness = 2.656, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 3650, 15, 250, baseMultiplier = 2.789, cooldown = 7, damageEffectiveness = 2.789, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 3700, 16, 260, baseMultiplier = 2.928, cooldown = 7, damageEffectiveness = 2.928, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 3750, 17, 270, baseMultiplier = 3.075, cooldown = 7, damageEffectiveness = 3.075, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 3800, 18, 280, baseMultiplier = 3.228, cooldown = 7, damageEffectiveness = 3.228, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 3850, 19, 290, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 3900, 20, 300, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 3950, 21, 310, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 4000, 22, 320, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 4050, 23, 330, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 4100, 24, 340, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 4150, 25, 350, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 4200, 26, 360, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 4250, 27, 370, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 4300, 28, 380, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 4350, 29, 390, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 4400, 30, 400, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 4450, 31, 410, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 4500, 32, 420, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 4550, 33, 430, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 4600, 34, 440, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 4650, 35, 450, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 4700, 36, 460, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 4750, 37, 470, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 4800, 38, 480, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 4850, 39, 490, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 4850, 39, 495, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 4900, 40, 500, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 4900, 40, 505, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 4950, 41, 510, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 4950, 41, 515, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 5000, 42, 520, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 5000, 42, 525, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 5050, 43, 530, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 5050, 43, 535, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 5100, 44, 540, baseMultiplier = 3.39, cooldown = 7, damageEffectiveness = 3.39, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["VaalGraceMercenary"] = { + name = "Vaal Grace", + hidden = true, + mercenary = true, + inheritedFrom = "VaalGrace", + color = 2, + description = "Casts a temporary aura that grants you and your allies additional chance to evade attacks, and makes suppressed spell damage unlucky against you.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Duration] = true, [SkillType.Vaal] = true, [SkillType.Aura] = true, [SkillType.AreaSpell] = true, [SkillType.Instant] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + aura = true, + duration = true, + spell = true, + }, + constantStats = { + { "chance_to_evade_attacks_%", 10 }, + { "base_skill_effect_duration", 6000 }, + }, + stats = { + "active_skill_base_radius_+", + "base_deal_no_damage", + "modifiers_to_buff_effect_duration_also_affect_soul_prevention_duration", + "damage_taken_from_suppressed_hits_is_unlucky", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, cooldown = 12, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 1, cooldown = 12, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 2, cooldown = 12, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 3, cooldown = 12, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 4, cooldown = 12, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 5, cooldown = 12, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 6, cooldown = 12, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 7, cooldown = 12, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 8, cooldown = 12, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 9, cooldown = 12, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 10, cooldown = 12, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 11, cooldown = 12, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 12, cooldown = 12, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 13, cooldown = 12, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 14, cooldown = 12, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 15, cooldown = 12, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 16, cooldown = 12, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 17, cooldown = 12, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 18, cooldown = 12, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 19, cooldown = 12, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 20, cooldown = 12, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 21, cooldown = 12, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 22, cooldown = 12, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 23, cooldown = 12, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 24, cooldown = 12, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 25, cooldown = 12, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 26, cooldown = 12, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 27, cooldown = 12, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 28, cooldown = 12, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 29, cooldown = 12, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 29, cooldown = 12, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 30, cooldown = 12, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 30, cooldown = 12, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 31, cooldown = 12, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 31, cooldown = 12, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 32, cooldown = 12, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 32, cooldown = 12, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 33, cooldown = 12, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 33, cooldown = 12, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 34, cooldown = 12, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["VaalGroundSlamMercenary"] = { + name = "Vaal Ground Slam", + hidden = true, + mercenary = true, + inheritedFrom = "VaalGroundSlam", + color = 1, + baseEffectiveness = 0.6700000166893, + incrementalEffectiveness = 0.023299999535084, + description = "Slams the ground in front of you, creating a wave that travels in all directions that damages enemies with an increased chance to stun. The wave deals more damage to closer enemies. Requires an Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Vaal] = true, [SkillType.Slam] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + constantStats = { + { "base_stun_duration_+%", 200 }, + { "base_stun_threshold_reduction_+%", 25 }, + { "active_skill_attack_speed_+%_final", -40 }, + }, + stats = { + "active_skill_base_radius_+", + "groundslam_damage_to_close_targets_+%_final", + "is_area_damage", + "global_always_hit", + "cannot_cancel_skill_before_contact_point", + "vaal_skill_exertable", + "skill_cannot_be_stunned_before_contact_point", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, 40, baseMultiplier = 2.185, cooldown = 7, damageEffectiveness = 2.185, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 0, 40, baseMultiplier = 2.288, cooldown = 7, damageEffectiveness = 2.288, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 1, 41, baseMultiplier = 2.395, cooldown = 7, damageEffectiveness = 2.395, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 1, 41, baseMultiplier = 2.508, cooldown = 7, damageEffectiveness = 2.508, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 2, 42, baseMultiplier = 2.626, cooldown = 7, damageEffectiveness = 2.626, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 2, 42, baseMultiplier = 2.749, cooldown = 7, damageEffectiveness = 2.749, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 3, 43, baseMultiplier = 2.878, cooldown = 7, damageEffectiveness = 2.878, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 3, 43, baseMultiplier = 3.014, cooldown = 7, damageEffectiveness = 3.014, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 4, 44, baseMultiplier = 3.155, cooldown = 7, damageEffectiveness = 3.155, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 4, 44, baseMultiplier = 3.303, cooldown = 7, damageEffectiveness = 3.303, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 5, 45, baseMultiplier = 3.459, cooldown = 7, damageEffectiveness = 3.459, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 5, 45, baseMultiplier = 3.621, cooldown = 7, damageEffectiveness = 3.621, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 6, 46, baseMultiplier = 3.792, cooldown = 7, damageEffectiveness = 3.792, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 6, 46, baseMultiplier = 3.97, cooldown = 7, damageEffectiveness = 3.97, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 7, 47, baseMultiplier = 4.156, cooldown = 7, damageEffectiveness = 4.156, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 7, 47, baseMultiplier = 4.352, cooldown = 7, damageEffectiveness = 4.352, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 8, 48, baseMultiplier = 4.556, cooldown = 7, damageEffectiveness = 4.556, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 8, 48, baseMultiplier = 4.77, cooldown = 7, damageEffectiveness = 4.77, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 9, 49, baseMultiplier = 4.994, cooldown = 7, damageEffectiveness = 4.994, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 9, 49, baseMultiplier = 5.229, cooldown = 7, damageEffectiveness = 5.229, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 10, 50, baseMultiplier = 5.475, cooldown = 7, damageEffectiveness = 5.475, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 10, 50, baseMultiplier = 5.732, cooldown = 7, damageEffectiveness = 5.732, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 11, 51, baseMultiplier = 6.002, cooldown = 7, damageEffectiveness = 6.002, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 11, 51, baseMultiplier = 6.284, cooldown = 7, damageEffectiveness = 6.284, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 12, 52, baseMultiplier = 6.579, cooldown = 7, damageEffectiveness = 6.579, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 12, 52, baseMultiplier = 6.888, cooldown = 7, damageEffectiveness = 6.888, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 13, 53, baseMultiplier = 7.212, cooldown = 7, damageEffectiveness = 7.212, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 13, 53, baseMultiplier = 7.551, cooldown = 7, damageEffectiveness = 7.551, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 14, 54, baseMultiplier = 7.906, cooldown = 7, damageEffectiveness = 7.906, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 14, 54, baseMultiplier = 8.278, cooldown = 7, damageEffectiveness = 8.278, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 14, 54, baseMultiplier = 8.87, cooldown = 7, damageEffectiveness = 8.87, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 15, 55, baseMultiplier = 9.079, cooldown = 7, damageEffectiveness = 9.079, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 15, 55, baseMultiplier = 9.292, cooldown = 7, damageEffectiveness = 9.292, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 15, 55, baseMultiplier = 9.51, cooldown = 7, damageEffectiveness = 9.51, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 15, 55, baseMultiplier = 9.734, cooldown = 7, damageEffectiveness = 9.734, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 16, 56, baseMultiplier = 9.963, cooldown = 7, damageEffectiveness = 9.963, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 16, 56, baseMultiplier = 10.197, cooldown = 7, damageEffectiveness = 10.197, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 16, 56, baseMultiplier = 10.436, cooldown = 7, damageEffectiveness = 10.436, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 16, 56, baseMultiplier = 10.682, cooldown = 7, damageEffectiveness = 10.682, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 17, 57, baseMultiplier = 10.933, cooldown = 7, damageEffectiveness = 10.933, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["VaalIceShotMercenary"] = { + name = "Vaal Ice Shot", + hidden = true, + mercenary = true, + inheritedFrom = "VaalIceShot", + color = 2, + description = "Fires an arrow that converts some physical damage to cold on its target and converts all physical damage to cold in a cone behind that target. When you use this skill, it summons a squad of Mirage Sharpshooters for a duration. Cannot be used by Totems, Traps, or Mines.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Area] = true, [SkillType.Cold] = true, [SkillType.Vaal] = true, [SkillType.Duration] = true, [SkillType.ProjectilesNumberModifiersNotApplied] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_cold", 60 }, + { "base_skill_effect_duration", 6000 }, + { "maximum_number_of_vaal_ice_shot_mirages", 6 }, + }, + stats = { + "skill_can_fire_arrows", + "modifiers_to_skill_effect_duration_also_affect_soul_prevention_duration", + "vaal_ice_shot_modifiers_to_projectile_count_do_not_apply_to_mirages", + "cannot_cancel_skill_before_contact_point", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { baseMultiplier = 0.747, cooldown = 5, damageEffectiveness = 0.747, levelRequirement = 1, storedUses = 1, }, + [2] = { baseMultiplier = 0.76, cooldown = 5, damageEffectiveness = 0.76, levelRequirement = 2, storedUses = 1, }, + [3] = { baseMultiplier = 0.774, cooldown = 5, damageEffectiveness = 0.774, levelRequirement = 4, storedUses = 1, }, + [4] = { baseMultiplier = 0.787, cooldown = 5, damageEffectiveness = 0.787, levelRequirement = 7, storedUses = 1, }, + [5] = { baseMultiplier = 0.8, cooldown = 5, damageEffectiveness = 0.8, levelRequirement = 11, storedUses = 1, }, + [6] = { baseMultiplier = 0.814, cooldown = 5, damageEffectiveness = 0.814, levelRequirement = 16, storedUses = 1, }, + [7] = { baseMultiplier = 0.827, cooldown = 5, damageEffectiveness = 0.827, levelRequirement = 20, storedUses = 1, }, + [8] = { baseMultiplier = 0.841, cooldown = 5, damageEffectiveness = 0.841, levelRequirement = 24, storedUses = 1, }, + [9] = { baseMultiplier = 0.853, cooldown = 5, damageEffectiveness = 0.853, levelRequirement = 28, storedUses = 1, }, + [10] = { baseMultiplier = 0.867, cooldown = 5, damageEffectiveness = 0.867, levelRequirement = 32, storedUses = 1, }, + [11] = { baseMultiplier = 0.881, cooldown = 5, damageEffectiveness = 0.881, levelRequirement = 36, storedUses = 1, }, + [12] = { baseMultiplier = 0.894, cooldown = 5, damageEffectiveness = 0.894, levelRequirement = 40, storedUses = 1, }, + [13] = { baseMultiplier = 0.907, cooldown = 5, damageEffectiveness = 0.907, levelRequirement = 44, storedUses = 1, }, + [14] = { baseMultiplier = 0.92, cooldown = 5, damageEffectiveness = 0.92, levelRequirement = 48, storedUses = 1, }, + [15] = { baseMultiplier = 0.934, cooldown = 5, damageEffectiveness = 0.934, levelRequirement = 52, storedUses = 1, }, + [16] = { baseMultiplier = 0.946, cooldown = 5, damageEffectiveness = 0.946, levelRequirement = 56, storedUses = 1, }, + [17] = { baseMultiplier = 0.96, cooldown = 5, damageEffectiveness = 0.96, levelRequirement = 60, storedUses = 1, }, + [18] = { baseMultiplier = 0.974, cooldown = 5, damageEffectiveness = 0.974, levelRequirement = 64, storedUses = 1, }, + [19] = { baseMultiplier = 0.987, cooldown = 5, damageEffectiveness = 0.987, levelRequirement = 67, storedUses = 1, }, + [20] = { baseMultiplier = 1.001, cooldown = 5, damageEffectiveness = 1.001, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 1.013, cooldown = 5, damageEffectiveness = 1.013, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 1.027, cooldown = 5, damageEffectiveness = 1.027, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 1.04, cooldown = 5, damageEffectiveness = 1.04, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 1.053, cooldown = 5, damageEffectiveness = 1.053, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 1.067, cooldown = 5, damageEffectiveness = 1.067, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 1.08, cooldown = 5, damageEffectiveness = 1.08, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 1.094, cooldown = 5, damageEffectiveness = 1.094, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 1.106, cooldown = 5, damageEffectiveness = 1.106, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 1.12, cooldown = 5, damageEffectiveness = 1.12, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 1.134, cooldown = 5, damageEffectiveness = 1.134, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 1.14, cooldown = 5, damageEffectiveness = 1.14, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 1.147, cooldown = 5, damageEffectiveness = 1.147, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 1.153, cooldown = 5, damageEffectiveness = 1.153, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 1.16, cooldown = 5, damageEffectiveness = 1.16, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 1.167, cooldown = 5, damageEffectiveness = 1.167, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 1.174, cooldown = 5, damageEffectiveness = 1.174, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 1.181, cooldown = 5, damageEffectiveness = 1.181, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 1.187, cooldown = 5, damageEffectiveness = 1.187, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 1.194, cooldown = 5, damageEffectiveness = 1.194, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 1.201, cooldown = 5, damageEffectiveness = 1.201, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["VaalLightningArrowMercenary"] = { + name = "Vaal Lightning Arrow", + hidden = true, + mercenary = true, + inheritedFrom = "VaalLightningArrow", + color = 2, + description = "Fires charged arrows, which repeatedly travel for a short time before changing direction. When they hit enemies, they are struck by a bolt of lightning which damages a number of surrounding enemies.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Area] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Lightning] = true, [SkillType.Vaal] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "lightning_arrow_maximum_number_of_extra_targets", 3 }, + { "base_number_of_arrows", 5 }, + { "projectile_random_angle_based_on_distance_to_target_location_%", 35 }, + { "vaal_lightning_arrow_number_of_redirects", 9 }, + }, + stats = { + "skill_can_fire_arrows", + "always_pierce", + "vaal_lightning_arrow_fork_and_chain_modifiers_apply_to_number_of_redirects", + "projectiles_cannot_split", + "projectiles_barrage", + "cannot_cancel_skill_before_contact_point", + "skill_can_add_multiple_charges_per_action", + "quality_display_base_additional_arrows_is_gem", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { baseMultiplier = 0.713, cooldown = 8.5, damageEffectiveness = 0.713, levelRequirement = 12, storedUses = 1, }, + [2] = { baseMultiplier = 0.726, cooldown = 8.5, damageEffectiveness = 0.726, levelRequirement = 15, storedUses = 1, }, + [3] = { baseMultiplier = 0.737, cooldown = 8.5, damageEffectiveness = 0.737, levelRequirement = 19, storedUses = 1, }, + [4] = { baseMultiplier = 0.749, cooldown = 8.5, damageEffectiveness = 0.749, levelRequirement = 23, storedUses = 1, }, + [5] = { baseMultiplier = 0.76, cooldown = 8.5, damageEffectiveness = 0.76, levelRequirement = 27, storedUses = 1, }, + [6] = { baseMultiplier = 0.772, cooldown = 8.5, damageEffectiveness = 0.772, levelRequirement = 31, storedUses = 1, }, + [7] = { baseMultiplier = 0.782, cooldown = 8.5, damageEffectiveness = 0.782, levelRequirement = 35, storedUses = 1, }, + [8] = { baseMultiplier = 0.792, cooldown = 8.5, damageEffectiveness = 0.792, levelRequirement = 38, storedUses = 1, }, + [9] = { baseMultiplier = 0.803, cooldown = 8.5, damageEffectiveness = 0.803, levelRequirement = 41, storedUses = 1, }, + [10] = { baseMultiplier = 0.813, cooldown = 8.5, damageEffectiveness = 0.813, levelRequirement = 44, storedUses = 1, }, + [11] = { baseMultiplier = 0.822, cooldown = 8.5, damageEffectiveness = 0.822, levelRequirement = 47, storedUses = 1, }, + [12] = { baseMultiplier = 0.831, cooldown = 8.5, damageEffectiveness = 0.831, levelRequirement = 50, storedUses = 1, }, + [13] = { baseMultiplier = 0.841, cooldown = 8.5, damageEffectiveness = 0.841, levelRequirement = 53, storedUses = 1, }, + [14] = { baseMultiplier = 0.85, cooldown = 8.5, damageEffectiveness = 0.85, levelRequirement = 56, storedUses = 1, }, + [15] = { baseMultiplier = 0.858, cooldown = 8.5, damageEffectiveness = 0.858, levelRequirement = 59, storedUses = 1, }, + [16] = { baseMultiplier = 0.866, cooldown = 8.5, damageEffectiveness = 0.866, levelRequirement = 62, storedUses = 1, }, + [17] = { baseMultiplier = 0.874, cooldown = 8.5, damageEffectiveness = 0.874, levelRequirement = 64, storedUses = 1, }, + [18] = { baseMultiplier = 0.882, cooldown = 8.5, damageEffectiveness = 0.882, levelRequirement = 66, storedUses = 1, }, + [19] = { baseMultiplier = 0.89, cooldown = 8.5, damageEffectiveness = 0.89, levelRequirement = 68, storedUses = 1, }, + [20] = { baseMultiplier = 0.897, cooldown = 8.5, damageEffectiveness = 0.897, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 0.904, cooldown = 8.5, damageEffectiveness = 0.904, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 0.911, cooldown = 8.5, damageEffectiveness = 0.911, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 0.918, cooldown = 8.5, damageEffectiveness = 0.918, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 0.925, cooldown = 8.5, damageEffectiveness = 0.925, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 0.931, cooldown = 8.5, damageEffectiveness = 0.931, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 0.937, cooldown = 8.5, damageEffectiveness = 0.937, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 0.943, cooldown = 8.5, damageEffectiveness = 0.943, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 0.949, cooldown = 8.5, damageEffectiveness = 0.949, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 0.954, cooldown = 8.5, damageEffectiveness = 0.954, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 0.96, cooldown = 8.5, damageEffectiveness = 0.96, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 0.963, cooldown = 8.5, damageEffectiveness = 0.963, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 0.965, cooldown = 8.5, damageEffectiveness = 0.965, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 0.967, cooldown = 8.5, damageEffectiveness = 0.967, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 0.969, cooldown = 8.5, damageEffectiveness = 0.969, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 0.972, cooldown = 8.5, damageEffectiveness = 0.972, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 0.974, cooldown = 8.5, damageEffectiveness = 0.974, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 0.976, cooldown = 8.5, damageEffectiveness = 0.976, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 0.979, cooldown = 8.5, damageEffectiveness = 0.979, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 0.981, cooldown = 8.5, damageEffectiveness = 0.981, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 0.983, cooldown = 8.5, damageEffectiveness = 0.983, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["VaalLightningTrapMercenary"] = { + name = "Vaal Lightning Trap", + hidden = true, + mercenary = true, + inheritedFrom = "VaalLightningTrap", + color = 3, + baseEffectiveness = 4.6251997947693, + incrementalEffectiveness = 0.034400001168251, + description = "Throws a trap that launches a ring of projectiles through the enemy that set it off, dealing lightning damage to them and subsequent targets and leaving a trail of shocked ground.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Trapped] = true, [SkillType.Mineable] = true, [SkillType.Duration] = true, [SkillType.Vaal] = true, [SkillType.Lightning] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + duration = true, + projectile = true, + spell = true, + trap = true, + }, + constantStats = { + { "base_trap_duration", 4000 }, + { "base_number_of_projectiles", 9 }, + { "base_skill_effect_duration", 4000 }, + { "shocked_ground_base_magnitude_override", 15 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "projectiles_nova", + "is_trap", + "base_skill_is_trapped", + "base_is_projectile", + "base_skill_show_average_damage_instead_of_dps", + "lightning_trap_projectiles_leave_shocking_ground", + "always_pierce", + "modifiers_to_skill_effect_duration_also_affect_soul_prevention_duration", + "cannot_cancel_skill_before_contact_point", + "quality_display_trap_duration_is_gem", + "quality_display_base_number_of_projectiles_is_gem", + "skill_cannot_be_stunned_before_contact_point", + "ignores_trap_and_mine_cooldown_limit", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + }, + levels = { + [1] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 12, storedUses = 1, statInterpolation = { 3, 3, }, }, + [2] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 15, storedUses = 1, statInterpolation = { 3, 3, }, }, + [3] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 19, storedUses = 1, statInterpolation = { 3, 3, }, }, + [4] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 23, storedUses = 1, statInterpolation = { 3, 3, }, }, + [5] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, 3, }, }, + [6] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, }, }, + [7] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 35, storedUses = 1, statInterpolation = { 3, 3, }, }, + [8] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, 3, }, }, + [9] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 41, storedUses = 1, statInterpolation = { 3, 3, }, }, + [10] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, }, }, + [11] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 47, storedUses = 1, statInterpolation = { 3, 3, }, }, + [12] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, }, }, + [13] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 53, storedUses = 1, statInterpolation = { 3, 3, }, }, + [14] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, }, }, + [15] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 59, storedUses = 1, statInterpolation = { 3, 3, }, }, + [16] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, }, }, + [17] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, }, }, + [18] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, }, }, + [19] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, }, }, + [20] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, }, }, + [21] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, }, }, + [22] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, }, }, + [23] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, }, }, + [24] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, }, }, + [25] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, }, }, + [26] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, }, }, + [27] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, }, }, + [28] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, }, }, + [29] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, }, }, + [30] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, }, }, + [31] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, }, }, + [32] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, }, }, + [33] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, }, }, + [34] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, }, }, + [35] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, }, }, + [36] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, }, }, + [37] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, }, }, + [38] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, }, }, + [39] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, }, }, + [40] = { 0.5, 1.5, cooldown = 8.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, }, }, + }, +} + +skills["VaalMoltenStrikeMercenary"] = { + name = "Vaal Molten Strike", + hidden = true, + mercenary = true, + inheritedFrom = "VaalMoltenStrike", + color = 1, + description = "Infuses your melee weapon with molten energies to attack with physical and fire damage. This attack causes balls of molten magma to launch forth causing area attack damage to enemies where they land.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Fire] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.Chains] = true, [SkillType.Vaal] = true, [SkillType.NeverExertable] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + { "base_number_of_projectiles", 9 }, + { "number_of_chains", 8 }, + { "active_skill_projectile_speed_+%_variation_final", 20 }, + { "active_skill_base_radius_+", 4 }, + { "active_skill_projectile_damage_+%_final", -33 }, + }, + stats = { + "show_number_of_projectiles", + "molten_strike_projectiles_chain_when_impacting_ground", + "global_always_hit", + "cannot_cancel_skill_before_contact_point", + "quality_display_base_number_of_projectiles_is_gem", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 1, storedUses = 1, }, + [2] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 2, storedUses = 1, }, + [3] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 4, storedUses = 1, }, + [4] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 7, storedUses = 1, }, + [5] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 11, storedUses = 1, }, + [6] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 16, storedUses = 1, }, + [7] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 20, storedUses = 1, }, + [8] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 24, storedUses = 1, }, + [9] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 28, storedUses = 1, }, + [10] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 32, storedUses = 1, }, + [11] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 36, storedUses = 1, }, + [12] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 40, storedUses = 1, }, + [13] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 44, storedUses = 1, }, + [14] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 48, storedUses = 1, }, + [15] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 52, storedUses = 1, }, + [16] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 56, storedUses = 1, }, + [17] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 60, storedUses = 1, }, + [18] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 64, storedUses = 1, }, + [19] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 67, storedUses = 1, }, + [20] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 70, storedUses = 1, }, + [21] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 72, storedUses = 1, }, + [22] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 74, storedUses = 1, }, + [23] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 76, storedUses = 1, }, + [24] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 78, storedUses = 1, }, + [25] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 80, storedUses = 1, }, + [26] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 82, storedUses = 1, }, + [27] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 84, storedUses = 1, }, + [28] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 86, storedUses = 1, }, + [29] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 88, storedUses = 1, }, + [30] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 90, storedUses = 1, }, + [31] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 91, storedUses = 1, }, + [32] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 92, storedUses = 1, }, + [33] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 93, storedUses = 1, }, + [34] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 94, storedUses = 1, }, + [35] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 95, storedUses = 1, }, + [36] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 96, storedUses = 1, }, + [37] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 97, storedUses = 1, }, + [38] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 98, storedUses = 1, }, + [39] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 99, storedUses = 1, }, + [40] = { attackSpeedMultiplier = -30, baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["VaalMoltenStrikeMercenaryEncounter"] = { + name = "Vaal Molten Strike", + hidden = true, + mercenary = true, + inheritedFrom = "VaalMoltenStrike", + color = 1, + description = "Infuses your melee weapon with molten energies to attack with physical and fire damage. This attack causes balls of molten magma to launch forth causing area attack damage to enemies where they land.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Fire] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.Chains] = true, [SkillType.Vaal] = true, [SkillType.NeverExertable] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + { "base_number_of_projectiles", 9 }, + { "number_of_chains", 8 }, + { "active_skill_projectile_speed_+%_variation_final", 20 }, + { "active_skill_base_radius_+", 4 }, + }, + stats = { + "show_number_of_projectiles", + "molten_strike_projectiles_chain_when_impacting_ground", + "global_always_hit", + "cannot_cancel_skill_before_contact_point", + "quality_display_base_number_of_projectiles_is_gem", + "skill_cannot_be_stunned_before_contact_point", + }, + levels = { + [1] = { baseMultiplier = 0.863, cooldown = 8.5, damageEffectiveness = 0.863, levelRequirement = 1, storedUses = 1, }, + [2] = { baseMultiplier = 0.901, cooldown = 8.5, damageEffectiveness = 0.901, levelRequirement = 2, storedUses = 1, }, + [3] = { baseMultiplier = 0.942, cooldown = 8.5, damageEffectiveness = 0.942, levelRequirement = 4, storedUses = 1, }, + [4] = { baseMultiplier = 0.984, cooldown = 8.5, damageEffectiveness = 0.984, levelRequirement = 7, storedUses = 1, }, + [5] = { baseMultiplier = 1.029, cooldown = 8.5, damageEffectiveness = 1.029, levelRequirement = 11, storedUses = 1, }, + [6] = { baseMultiplier = 1.075, cooldown = 8.5, damageEffectiveness = 1.075, levelRequirement = 16, storedUses = 1, }, + [7] = { baseMultiplier = 1.123, cooldown = 8.5, damageEffectiveness = 1.123, levelRequirement = 20, storedUses = 1, }, + [8] = { baseMultiplier = 1.174, cooldown = 8.5, damageEffectiveness = 1.174, levelRequirement = 24, storedUses = 1, }, + [9] = { baseMultiplier = 1.227, cooldown = 8.5, damageEffectiveness = 1.227, levelRequirement = 28, storedUses = 1, }, + [10] = { baseMultiplier = 1.282, cooldown = 8.5, damageEffectiveness = 1.282, levelRequirement = 32, storedUses = 1, }, + [11] = { baseMultiplier = 1.339, cooldown = 8.5, damageEffectiveness = 1.339, levelRequirement = 36, storedUses = 1, }, + [12] = { baseMultiplier = 1.4, cooldown = 8.5, damageEffectiveness = 1.4, levelRequirement = 40, storedUses = 1, }, + [13] = { baseMultiplier = 1.463, cooldown = 8.5, damageEffectiveness = 1.463, levelRequirement = 44, storedUses = 1, }, + [14] = { baseMultiplier = 1.529, cooldown = 8.5, damageEffectiveness = 1.529, levelRequirement = 48, storedUses = 1, }, + [15] = { baseMultiplier = 1.597, cooldown = 8.5, damageEffectiveness = 1.597, levelRequirement = 52, storedUses = 1, }, + [16] = { baseMultiplier = 1.669, cooldown = 8.5, damageEffectiveness = 1.669, levelRequirement = 56, storedUses = 1, }, + [17] = { baseMultiplier = 1.744, cooldown = 8.5, damageEffectiveness = 1.744, levelRequirement = 60, storedUses = 1, }, + [18] = { baseMultiplier = 1.823, cooldown = 8.5, damageEffectiveness = 1.823, levelRequirement = 64, storedUses = 1, }, + [19] = { baseMultiplier = 1.905, cooldown = 8.5, damageEffectiveness = 1.905, levelRequirement = 67, storedUses = 1, }, + [20] = { baseMultiplier = 1.991, cooldown = 8.5, damageEffectiveness = 1.991, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 2.08, cooldown = 8.5, damageEffectiveness = 2.08, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 2.174, cooldown = 8.5, damageEffectiveness = 2.174, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 2.272, cooldown = 8.5, damageEffectiveness = 2.272, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 2.374, cooldown = 8.5, damageEffectiveness = 2.374, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 2.481, cooldown = 8.5, damageEffectiveness = 2.481, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 2.592, cooldown = 8.5, damageEffectiveness = 2.592, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 2.709, cooldown = 8.5, damageEffectiveness = 2.709, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 2.831, cooldown = 8.5, damageEffectiveness = 2.831, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 2.958, cooldown = 8.5, damageEffectiveness = 2.958, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 3.091, cooldown = 8.5, damageEffectiveness = 3.091, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 3.303, cooldown = 8.5, damageEffectiveness = 3.303, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 3.377, cooldown = 8.5, damageEffectiveness = 3.377, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 3.453, cooldown = 8.5, damageEffectiveness = 3.453, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 3.531, cooldown = 8.5, damageEffectiveness = 3.531, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 3.61, cooldown = 8.5, damageEffectiveness = 3.61, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 3.692, cooldown = 8.5, damageEffectiveness = 3.692, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 3.775, cooldown = 8.5, damageEffectiveness = 3.775, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 3.86, cooldown = 8.5, damageEffectiveness = 3.86, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 3.947, cooldown = 8.5, damageEffectiveness = 3.947, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 4.035, cooldown = 8.5, damageEffectiveness = 4.035, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["VaalReapMercenary"] = { + name = "Vaal Reap", + hidden = true, + mercenary = true, + inheritedFrom = "VaalReap", + color = 1, + baseEffectiveness = 1.5360000133514, + incrementalEffectiveness = 0.053599998354912, + description = "Bloody scythes swipe around a selected area, hitting enemies with physical damage. An area of boiling blood is left beneath them for a duration which deals physical damage over time. Also gives a bonus to maximum Blood Charges for a secondary duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Physical] = true, [SkillType.DamageOverTime] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Vaal] = true, [SkillType.Multicastable] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1.2, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "blood_ground_leaving_area_lasts_for_ms", 2000 }, + { "base_secondary_skill_effect_duration", 8000 }, + { "base_skill_effect_duration", 5000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.1, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.4, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.5, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.6, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.6, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.7, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.8, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.1, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.3, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.4, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.5, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.6, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.7, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 75.000001676381, cooldown = 15, critChance = 6, damageEffectiveness = 4.8, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["VaalReapMercenaryEncounter"] = { + name = "Vaal Reap", + hidden = true, + mercenary = true, + inheritedFrom = "VaalReap", + color = 1, + baseEffectiveness = 1.5499999523163, + incrementalEffectiveness = 0.03999999910593, + description = "Bloody scythes swipe around a selected area, hitting enemies with physical damage. An area of boiling blood is left beneath them for a duration which deals physical damage over time. Also gives a bonus to maximum Blood Charges for a secondary duration.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Physical] = true, [SkillType.DamageOverTime] = true, [SkillType.Area] = true, [SkillType.AreaSpell] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Vaal] = true, [SkillType.Multicastable] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1.2, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "blood_ground_leaving_area_lasts_for_ms", 2000 }, + { "base_secondary_skill_effect_duration", 8000 }, + { "base_skill_effect_duration", 5000 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_physical_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 12.500000279397, cooldown = 15, critChance = 6, damageEffectiveness = 3.9, levelRequirement = 0, storedUses = 1, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["VaalSplitArrowMercenary"] = { + name = "Greater Split Arrow", + hidden = true, + mercenary = true, + color = 2, + baseEffectiveness = 0.80000001192093, + incrementalEffectiveness = 0.023299999535084, + description = "DNT Fires multiple arrows which continuously fork as they fly.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.ProjectilesFromUser] = true, [SkillType.Totemable] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Vaal] = true, }, + weaponTypes = { + ["Bow"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + projectile = true, + }, + constantStats = { + { "projectiles_fork_after_traveling_X_units_distance", 10 }, + { "number_of_additional_forks_base", 3 }, + }, + stats = { + "number_of_additional_projectiles", + "skill_can_fire_arrows", + "always_pierce", + "skill_cannot_be_stunned_before_contact_point", + "base_is_projectile", + }, + levels = { + [1] = { 0, baseMultiplier = 1.6, cooldown = 5, damageEffectiveness = 1.6, levelRequirement = 1, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 0, baseMultiplier = 1.62, cooldown = 5, damageEffectiveness = 1.62, levelRequirement = 2, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 0, baseMultiplier = 1.63, cooldown = 5, damageEffectiveness = 1.63, levelRequirement = 4, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 0, baseMultiplier = 1.65, cooldown = 5, damageEffectiveness = 1.65, levelRequirement = 7, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 0, baseMultiplier = 1.66, cooldown = 5, damageEffectiveness = 1.66, levelRequirement = 11, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 0, baseMultiplier = 1.68, cooldown = 5, damageEffectiveness = 1.68, levelRequirement = 16, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 0, baseMultiplier = 1.7, cooldown = 5, damageEffectiveness = 1.7, levelRequirement = 20, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 0, baseMultiplier = 1.71, cooldown = 5, damageEffectiveness = 1.71, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 0, baseMultiplier = 1.73, cooldown = 5, damageEffectiveness = 1.73, levelRequirement = 28, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 1, baseMultiplier = 1.74, cooldown = 5, damageEffectiveness = 1.74, levelRequirement = 32, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 1, baseMultiplier = 1.76, cooldown = 5, damageEffectiveness = 1.76, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 1, baseMultiplier = 1.78, cooldown = 5, damageEffectiveness = 1.78, levelRequirement = 40, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 1, baseMultiplier = 1.79, cooldown = 5, damageEffectiveness = 1.79, levelRequirement = 44, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 1, baseMultiplier = 1.81, cooldown = 5, damageEffectiveness = 1.81, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 1, baseMultiplier = 1.82, cooldown = 5, damageEffectiveness = 1.82, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 1, baseMultiplier = 1.84, cooldown = 5, damageEffectiveness = 1.84, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 1, baseMultiplier = 1.86, cooldown = 5, damageEffectiveness = 1.86, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 1, baseMultiplier = 1.87, cooldown = 5, damageEffectiveness = 1.87, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 1, baseMultiplier = 1.89, cooldown = 5, damageEffectiveness = 1.89, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 2, baseMultiplier = 1.9, cooldown = 5, damageEffectiveness = 1.9, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 2, baseMultiplier = 1.92, cooldown = 5, damageEffectiveness = 1.92, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 2, baseMultiplier = 1.94, cooldown = 5, damageEffectiveness = 1.94, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 2, baseMultiplier = 1.95, cooldown = 5, damageEffectiveness = 1.95, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 2, baseMultiplier = 1.97, cooldown = 5, damageEffectiveness = 1.97, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 2, baseMultiplier = 1.98, cooldown = 5, damageEffectiveness = 1.98, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 2, baseMultiplier = 2, cooldown = 5, damageEffectiveness = 2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 2, baseMultiplier = 2.02, cooldown = 5, damageEffectiveness = 2.02, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 2, baseMultiplier = 2.03, cooldown = 5, damageEffectiveness = 2.03, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 2, baseMultiplier = 2.05, cooldown = 5, damageEffectiveness = 2.05, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 3, baseMultiplier = 2.06, cooldown = 5, damageEffectiveness = 2.06, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 3, baseMultiplier = 2.08, cooldown = 5, damageEffectiveness = 2.08, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 3, baseMultiplier = 2.08, cooldown = 5, damageEffectiveness = 2.08, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 3, baseMultiplier = 2.1, cooldown = 5, damageEffectiveness = 2.1, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 3, baseMultiplier = 2.1, cooldown = 5, damageEffectiveness = 2.1, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 3, baseMultiplier = 2.11, cooldown = 5, damageEffectiveness = 2.11, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 3, baseMultiplier = 2.11, cooldown = 5, damageEffectiveness = 2.11, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 3, baseMultiplier = 2.13, cooldown = 5, damageEffectiveness = 2.13, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 3, baseMultiplier = 2.13, cooldown = 5, damageEffectiveness = 2.13, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 3, baseMultiplier = 2.14, cooldown = 5, damageEffectiveness = 2.14, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 4, baseMultiplier = 2.14, cooldown = 5, damageEffectiveness = 2.14, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["VaalVitalityMercenary"] = { + name = "Vaal Vitality", + hidden = true, + mercenary = true, + color = 1, + description = "Casts a temporary aura that grants life regeneration to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Buff] = true, [SkillType.Area] = true, [SkillType.Totemable] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Duration] = true, [SkillType.Vaal] = true, [SkillType.Aura] = true, [SkillType.AreaSpell] = true, [SkillType.Instant] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.6, + baseFlags = { + area = true, + aura = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 5000 }, + { "active_skill_area_of_effect_radius_+%_final", 200 }, + }, + stats = { + "life_regeneration_rate_per_minute_%", + "base_deal_no_damage", + }, + levels = { + [1] = { 80, cooldown = 10, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 100, cooldown = 10, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 120, cooldown = 10, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 140, cooldown = 10, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, }, }, + [5] = { 160, cooldown = 10, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, }, }, + [6] = { 180, cooldown = 10, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, }, }, + [7] = { 200, cooldown = 10, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, }, }, + [8] = { 220, cooldown = 10, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, }, }, + [9] = { 240, cooldown = 10, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, }, }, + [10] = { 260, cooldown = 10, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, }, }, + [11] = { 280, cooldown = 10, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, }, }, + [12] = { 300, cooldown = 10, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, }, }, + [13] = { 320, cooldown = 10, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, }, }, + [14] = { 340, cooldown = 10, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, }, }, + [15] = { 360, cooldown = 10, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, }, }, + [16] = { 380, cooldown = 10, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, }, }, + [17] = { 400, cooldown = 10, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, }, }, + [18] = { 420, cooldown = 10, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, }, }, + [19] = { 440, cooldown = 10, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + [20] = { 460, cooldown = 10, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, }, }, + [21] = { 480, cooldown = 10, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, }, }, + [22] = { 500, cooldown = 10, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, }, }, + [23] = { 520, cooldown = 10, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, }, }, + [24] = { 540, cooldown = 10, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, }, }, + [25] = { 560, cooldown = 10, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, }, }, + [26] = { 580, cooldown = 10, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, }, }, + [27] = { 600, cooldown = 10, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, }, }, + [28] = { 620, cooldown = 10, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, }, }, + [29] = { 640, cooldown = 10, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, }, }, + [30] = { 660, cooldown = 10, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, }, }, + [31] = { 680, cooldown = 10, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, }, }, + [32] = { 700, cooldown = 10, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, }, }, + [33] = { 720, cooldown = 10, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, }, }, + [34] = { 740, cooldown = 10, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, }, }, + [35] = { 760, cooldown = 10, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, }, }, + [36] = { 780, cooldown = 10, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, }, }, + [37] = { 800, cooldown = 10, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, }, }, + [38] = { 820, cooldown = 10, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, }, }, + [39] = { 840, cooldown = 10, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, }, }, + [40] = { 860, cooldown = 10, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["VenomGyreMercenary"] = { + name = "Venom Gyre", + hidden = true, + mercenary = true, + inheritedFrom = "VenomGyre", + color = 2, + description = "Fires a returning projectile that can be caught. Caught projectiles spiral outwards when you use Whirling Blades and do not return. Requires a Dagger or Claw.", + skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Chaos] = true, [SkillType.Duration] = true, [SkillType.ProjectilesFromUser] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + projectile = true, + }, + constantStats = { + { "maximum_number_of_snapping_adder_projectiles", 30 }, + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "base_chance_to_poison_on_hit_%", 40 }, + { "projectile_speed_variation_+%", 15 }, + { "snapping_adder_maximum_projectiles_released", 30 }, + { "active_skill_returning_projectile_damage_+%_final", -75 }, + { "snapping_adder_%_chance_to_retain_projectile_on_release", 40 }, + { "base_skill_effect_duration", 12000 }, + }, + stats = { + "base_is_projectile", + "returning_projectiles_always_pierce", + "projectiles_return", + "visual_hit_effect_chaos_is_green", + }, + levels = { + [1] = { attackSpeedMultiplier = 20, baseMultiplier = 1.5, damageEffectiveness = 1.5, levelRequirement = 12, }, + [2] = { attackSpeedMultiplier = 20, baseMultiplier = 1.526, damageEffectiveness = 1.526, levelRequirement = 15, }, + [3] = { attackSpeedMultiplier = 20, baseMultiplier = 1.553, damageEffectiveness = 1.553, levelRequirement = 19, }, + [4] = { attackSpeedMultiplier = 20, baseMultiplier = 1.579, damageEffectiveness = 1.579, levelRequirement = 23, }, + [5] = { attackSpeedMultiplier = 20, baseMultiplier = 1.605, damageEffectiveness = 1.605, levelRequirement = 27, }, + [6] = { attackSpeedMultiplier = 20, baseMultiplier = 1.632, damageEffectiveness = 1.632, levelRequirement = 31, }, + [7] = { attackSpeedMultiplier = 20, baseMultiplier = 1.658, damageEffectiveness = 1.658, levelRequirement = 35, }, + [8] = { attackSpeedMultiplier = 20, baseMultiplier = 1.684, damageEffectiveness = 1.684, levelRequirement = 38, }, + [9] = { attackSpeedMultiplier = 20, baseMultiplier = 1.711, damageEffectiveness = 1.711, levelRequirement = 41, }, + [10] = { attackSpeedMultiplier = 20, baseMultiplier = 1.737, damageEffectiveness = 1.737, levelRequirement = 44, }, + [11] = { attackSpeedMultiplier = 20, baseMultiplier = 1.763, damageEffectiveness = 1.763, levelRequirement = 47, }, + [12] = { attackSpeedMultiplier = 20, baseMultiplier = 1.789, damageEffectiveness = 1.789, levelRequirement = 50, }, + [13] = { attackSpeedMultiplier = 20, baseMultiplier = 1.816, damageEffectiveness = 1.816, levelRequirement = 53, }, + [14] = { attackSpeedMultiplier = 20, baseMultiplier = 1.842, damageEffectiveness = 1.842, levelRequirement = 56, }, + [15] = { attackSpeedMultiplier = 20, baseMultiplier = 1.868, damageEffectiveness = 1.868, levelRequirement = 59, }, + [16] = { attackSpeedMultiplier = 20, baseMultiplier = 1.895, damageEffectiveness = 1.895, levelRequirement = 62, }, + [17] = { attackSpeedMultiplier = 20, baseMultiplier = 1.921, damageEffectiveness = 1.921, levelRequirement = 64, }, + [18] = { attackSpeedMultiplier = 20, baseMultiplier = 1.947, damageEffectiveness = 1.947, levelRequirement = 66, }, + [19] = { attackSpeedMultiplier = 20, baseMultiplier = 1.974, damageEffectiveness = 1.974, levelRequirement = 68, }, + [20] = { attackSpeedMultiplier = 20, baseMultiplier = 2, damageEffectiveness = 2, levelRequirement = 70, }, + [21] = { attackSpeedMultiplier = 20, baseMultiplier = 2.026, damageEffectiveness = 2.026, levelRequirement = 72, }, + [22] = { attackSpeedMultiplier = 20, baseMultiplier = 2.053, damageEffectiveness = 2.053, levelRequirement = 74, }, + [23] = { attackSpeedMultiplier = 20, baseMultiplier = 2.079, damageEffectiveness = 2.079, levelRequirement = 76, }, + [24] = { attackSpeedMultiplier = 20, baseMultiplier = 2.105, damageEffectiveness = 2.105, levelRequirement = 78, }, + [25] = { attackSpeedMultiplier = 20, baseMultiplier = 2.132, damageEffectiveness = 2.132, levelRequirement = 80, }, + [26] = { attackSpeedMultiplier = 20, baseMultiplier = 2.158, damageEffectiveness = 2.158, levelRequirement = 82, }, + [27] = { attackSpeedMultiplier = 20, baseMultiplier = 2.184, damageEffectiveness = 2.184, levelRequirement = 84, }, + [28] = { attackSpeedMultiplier = 20, baseMultiplier = 2.211, damageEffectiveness = 2.211, levelRequirement = 86, }, + [29] = { attackSpeedMultiplier = 20, baseMultiplier = 2.237, damageEffectiveness = 2.237, levelRequirement = 88, }, + [30] = { attackSpeedMultiplier = 20, baseMultiplier = 2.263, damageEffectiveness = 2.263, levelRequirement = 90, }, + [31] = { attackSpeedMultiplier = 20, baseMultiplier = 2.276, damageEffectiveness = 2.276, levelRequirement = 91, }, + [32] = { attackSpeedMultiplier = 20, baseMultiplier = 2.289, damageEffectiveness = 2.289, levelRequirement = 92, }, + [33] = { attackSpeedMultiplier = 20, baseMultiplier = 2.303, damageEffectiveness = 2.303, levelRequirement = 93, }, + [34] = { attackSpeedMultiplier = 20, baseMultiplier = 2.316, damageEffectiveness = 2.316, levelRequirement = 94, }, + [35] = { attackSpeedMultiplier = 20, baseMultiplier = 2.329, damageEffectiveness = 2.329, levelRequirement = 95, }, + [36] = { attackSpeedMultiplier = 20, baseMultiplier = 2.342, damageEffectiveness = 2.342, levelRequirement = 96, }, + [37] = { attackSpeedMultiplier = 20, baseMultiplier = 2.355, damageEffectiveness = 2.355, levelRequirement = 97, }, + [38] = { attackSpeedMultiplier = 20, baseMultiplier = 2.368, damageEffectiveness = 2.368, levelRequirement = 98, }, + [39] = { attackSpeedMultiplier = 20, baseMultiplier = 2.382, damageEffectiveness = 2.382, levelRequirement = 99, }, + [40] = { attackSpeedMultiplier = 20, baseMultiplier = 2.395, damageEffectiveness = 2.395, levelRequirement = 100, }, + }, +} + +skills["VigilantStrikeMercenary"] = { + name = "Vigilant Strike", + hidden = true, + mercenary = true, + inheritedFrom = "VigilantStrike", + color = 1, + description = "Attacks enemies with a powerful melee strike which grants Fortification, reducing damage you take from hits. The cooldown can be bypassed by expending an Endurance Charge. Requires a Melee Weapon.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Buff] = true, [SkillType.Melee] = true, [SkillType.Multistrikeable] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.ThresholdJewelArea] = true, [SkillType.Cooldown] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + melee = true, + }, + constantStats = { + { "gain_fortify_on_melee_hit_ms", 8000 }, + }, + stats = { + }, + levels = { + [1] = { baseMultiplier = 2.902, cooldown = 4, damageEffectiveness = 2.902, levelRequirement = 4, storedUses = 1, }, + [2] = { baseMultiplier = 3.043, cooldown = 4, damageEffectiveness = 3.043, levelRequirement = 6, storedUses = 1, }, + [3] = { baseMultiplier = 3.197, cooldown = 4, damageEffectiveness = 3.197, levelRequirement = 9, storedUses = 1, }, + [4] = { baseMultiplier = 3.357, cooldown = 4, damageEffectiveness = 3.357, levelRequirement = 12, storedUses = 1, }, + [5] = { baseMultiplier = 3.532, cooldown = 4, damageEffectiveness = 3.532, levelRequirement = 16, storedUses = 1, }, + [6] = { baseMultiplier = 3.716, cooldown = 4, damageEffectiveness = 3.716, levelRequirement = 20, storedUses = 1, }, + [7] = { baseMultiplier = 3.911, cooldown = 4, damageEffectiveness = 3.911, levelRequirement = 24, storedUses = 1, }, + [8] = { baseMultiplier = 4.114, cooldown = 4, damageEffectiveness = 4.114, levelRequirement = 28, storedUses = 1, }, + [9] = { baseMultiplier = 4.328, cooldown = 4, damageEffectiveness = 4.328, levelRequirement = 32, storedUses = 1, }, + [10] = { baseMultiplier = 4.552, cooldown = 4, damageEffectiveness = 4.552, levelRequirement = 36, storedUses = 1, }, + [11] = { baseMultiplier = 4.788, cooldown = 4, damageEffectiveness = 4.788, levelRequirement = 40, storedUses = 1, }, + [12] = { baseMultiplier = 5.036, cooldown = 4, damageEffectiveness = 5.036, levelRequirement = 44, storedUses = 1, }, + [13] = { baseMultiplier = 5.298, cooldown = 4, damageEffectiveness = 5.298, levelRequirement = 48, storedUses = 1, }, + [14] = { baseMultiplier = 5.571, cooldown = 4, damageEffectiveness = 5.571, levelRequirement = 52, storedUses = 1, }, + [15] = { baseMultiplier = 5.849, cooldown = 4, damageEffectiveness = 5.849, levelRequirement = 55, storedUses = 1, }, + [16] = { baseMultiplier = 6.142, cooldown = 4, damageEffectiveness = 6.142, levelRequirement = 58, storedUses = 1, }, + [17] = { baseMultiplier = 6.447, cooldown = 4, damageEffectiveness = 6.447, levelRequirement = 61, storedUses = 1, }, + [18] = { baseMultiplier = 6.769, cooldown = 4, damageEffectiveness = 6.769, levelRequirement = 64, storedUses = 1, }, + [19] = { baseMultiplier = 7.106, cooldown = 4, damageEffectiveness = 7.106, levelRequirement = 67, storedUses = 1, }, + [20] = { baseMultiplier = 7.459, cooldown = 4, damageEffectiveness = 7.459, levelRequirement = 70, storedUses = 1, }, + [21] = { baseMultiplier = 7.819, cooldown = 4, damageEffectiveness = 7.819, levelRequirement = 72, storedUses = 1, }, + [22] = { baseMultiplier = 8.194, cooldown = 4, damageEffectiveness = 8.194, levelRequirement = 74, storedUses = 1, }, + [23] = { baseMultiplier = 8.587, cooldown = 4, damageEffectiveness = 8.587, levelRequirement = 76, storedUses = 1, }, + [24] = { baseMultiplier = 9, cooldown = 4, damageEffectiveness = 9, levelRequirement = 78, storedUses = 1, }, + [25] = { baseMultiplier = 9.432, cooldown = 4, damageEffectiveness = 9.432, levelRequirement = 80, storedUses = 1, }, + [26] = { baseMultiplier = 9.884, cooldown = 4, damageEffectiveness = 9.884, levelRequirement = 82, storedUses = 1, }, + [27] = { baseMultiplier = 10.359, cooldown = 4, damageEffectiveness = 10.359, levelRequirement = 84, storedUses = 1, }, + [28] = { baseMultiplier = 10.856, cooldown = 4, damageEffectiveness = 10.856, levelRequirement = 86, storedUses = 1, }, + [29] = { baseMultiplier = 11.376, cooldown = 4, damageEffectiveness = 11.376, levelRequirement = 88, storedUses = 1, }, + [30] = { baseMultiplier = 11.921, cooldown = 4, damageEffectiveness = 11.921, levelRequirement = 90, storedUses = 1, }, + [31] = { baseMultiplier = 12.752, cooldown = 4, damageEffectiveness = 12.752, levelRequirement = 91, storedUses = 1, }, + [32] = { baseMultiplier = 13.057, cooldown = 4, damageEffectiveness = 13.057, levelRequirement = 92, storedUses = 1, }, + [33] = { baseMultiplier = 13.37, cooldown = 4, damageEffectiveness = 13.37, levelRequirement = 93, storedUses = 1, }, + [34] = { baseMultiplier = 13.69, cooldown = 4, damageEffectiveness = 13.69, levelRequirement = 94, storedUses = 1, }, + [35] = { baseMultiplier = 14.018, cooldown = 4, damageEffectiveness = 14.018, levelRequirement = 95, storedUses = 1, }, + [36] = { baseMultiplier = 14.352, cooldown = 4, damageEffectiveness = 14.352, levelRequirement = 96, storedUses = 1, }, + [37] = { baseMultiplier = 14.695, cooldown = 4, damageEffectiveness = 14.695, levelRequirement = 97, storedUses = 1, }, + [38] = { baseMultiplier = 15.047, cooldown = 4, damageEffectiveness = 15.047, levelRequirement = 98, storedUses = 1, }, + [39] = { baseMultiplier = 15.407, cooldown = 4, damageEffectiveness = 15.407, levelRequirement = 99, storedUses = 1, }, + [40] = { baseMultiplier = 15.775, cooldown = 4, damageEffectiveness = 15.775, levelRequirement = 100, storedUses = 1, }, + }, +} + +skills["ViperStrikeMercenary"] = { + name = "Viper Strike", + hidden = true, + mercenary = true, + inheritedFrom = "ViperStrike", + color = 2, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.023299999535084, + description = "Hits enemies, converting some of your physical damage to chaos damage and inflicting poison which will be affected by modifiers to skill duration. If dual wielding, will strike with both weapons. Requires a claw, dagger or sword.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Duration] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Chaos] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_chaos", 60 }, + { "base_chance_to_poison_on_hit_%", 60 }, + { "base_skill_effect_duration", 4000 }, + { "viper_strike_dual_wield_damage_+%_final", -20 }, + { "viper_strike_dual_wield_attack_speed_+%_final", -30 }, + }, + stats = { + "poison_duration_is_skill_duration", + "skill_double_hits_when_dual_wielding", + "visual_hit_effect_chaos_is_green", + }, + levels = { + [1] = { baseMultiplier = 1.553, damageEffectiveness = 1.553, levelRequirement = 1, }, + [2] = { baseMultiplier = 1.633, damageEffectiveness = 1.633, levelRequirement = 2, }, + [3] = { baseMultiplier = 1.722, damageEffectiveness = 1.722, levelRequirement = 4, }, + [4] = { baseMultiplier = 1.817, damageEffectiveness = 1.817, levelRequirement = 7, }, + [5] = { baseMultiplier = 1.922, damageEffectiveness = 1.922, levelRequirement = 11, }, + [6] = { baseMultiplier = 2.036, damageEffectiveness = 2.036, levelRequirement = 16, }, + [7] = { baseMultiplier = 2.153, damageEffectiveness = 2.153, levelRequirement = 20, }, + [8] = { baseMultiplier = 2.278, damageEffectiveness = 2.278, levelRequirement = 24, }, + [9] = { baseMultiplier = 2.409, damageEffectiveness = 2.409, levelRequirement = 28, }, + [10] = { baseMultiplier = 2.546, damageEffectiveness = 2.546, levelRequirement = 32, }, + [11] = { baseMultiplier = 2.693, damageEffectiveness = 2.693, levelRequirement = 36, }, + [12] = { baseMultiplier = 2.847, damageEffectiveness = 2.847, levelRequirement = 40, }, + [13] = { baseMultiplier = 3.01, damageEffectiveness = 3.01, levelRequirement = 44, }, + [14] = { baseMultiplier = 3.182, damageEffectiveness = 3.182, levelRequirement = 48, }, + [15] = { baseMultiplier = 3.364, damageEffectiveness = 3.364, levelRequirement = 52, }, + [16] = { baseMultiplier = 3.556, damageEffectiveness = 3.556, levelRequirement = 56, }, + [17] = { baseMultiplier = 3.759, damageEffectiveness = 3.759, levelRequirement = 60, }, + [18] = { baseMultiplier = 3.973, damageEffectiveness = 3.973, levelRequirement = 64, }, + [19] = { baseMultiplier = 4.192, damageEffectiveness = 4.192, levelRequirement = 67, }, + [20] = { baseMultiplier = 4.424, damageEffectiveness = 4.424, levelRequirement = 70, }, + [21] = { baseMultiplier = 4.66, damageEffectiveness = 4.66, levelRequirement = 72, }, + [22] = { baseMultiplier = 4.909, damageEffectiveness = 4.909, levelRequirement = 74, }, + [23] = { baseMultiplier = 5.171, damageEffectiveness = 5.171, levelRequirement = 76, }, + [24] = { baseMultiplier = 5.448, damageEffectiveness = 5.448, levelRequirement = 78, }, + [25] = { baseMultiplier = 5.739, damageEffectiveness = 5.739, levelRequirement = 80, }, + [26] = { baseMultiplier = 6.045, damageEffectiveness = 6.045, levelRequirement = 82, }, + [27] = { baseMultiplier = 6.368, damageEffectiveness = 6.368, levelRequirement = 84, }, + [28] = { baseMultiplier = 6.707, damageEffectiveness = 6.707, levelRequirement = 86, }, + [29] = { baseMultiplier = 7.066, damageEffectiveness = 7.066, levelRequirement = 88, }, + [30] = { baseMultiplier = 7.442, damageEffectiveness = 7.442, levelRequirement = 90, }, + [31] = { baseMultiplier = 8.023, damageEffectiveness = 8.023, levelRequirement = 91, }, + [32] = { baseMultiplier = 8.236, damageEffectiveness = 8.236, levelRequirement = 92, }, + [33] = { baseMultiplier = 8.456, damageEffectiveness = 8.456, levelRequirement = 93, }, + [34] = { baseMultiplier = 8.68, damageEffectiveness = 8.68, levelRequirement = 94, }, + [35] = { baseMultiplier = 8.912, damageEffectiveness = 8.912, levelRequirement = 95, }, + [36] = { baseMultiplier = 9.149, damageEffectiveness = 9.149, levelRequirement = 96, }, + [37] = { baseMultiplier = 9.393, damageEffectiveness = 9.393, levelRequirement = 97, }, + [38] = { baseMultiplier = 9.642, damageEffectiveness = 9.642, levelRequirement = 98, }, + [39] = { baseMultiplier = 9.899, damageEffectiveness = 9.899, levelRequirement = 99, }, + [40] = { baseMultiplier = 10.162, damageEffectiveness = 10.162, levelRequirement = 100, }, + }, +} + +skills["ViperStrikeMercenaryEncounter"] = { + name = "Viper Strike", + hidden = true, + mercenary = true, + inheritedFrom = "ViperStrike", + color = 2, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.023299999535084, + description = "Hits enemies, converting some of your physical damage to chaos damage and inflicting poison which will be affected by modifiers to skill duration. If dual wielding, will strike with both weapons. Requires a claw, dagger or sword.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Duration] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Chaos] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 1, + baseFlags = { + attack = true, + duration = true, + melee = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_chaos", 40 }, + { "base_chance_to_poison_on_hit_%", 60 }, + { "base_skill_effect_duration", 4000 }, + { "viper_strike_dual_wield_damage_+%_final", -20 }, + { "viper_strike_dual_wield_attack_speed_+%_final", -30 }, + { "active_skill_poison_damage_+%_final", 0 }, + }, + stats = { + "poison_duration_is_skill_duration", + "skill_double_hits_when_dual_wielding", + "visual_hit_effect_chaos_is_green", + }, + levels = { + [1] = { baseMultiplier = 2.546, damageEffectiveness = 2.546, levelRequirement = 0, }, + }, +} + +skills["VitalityMercenary"] = { + name = "Vitality", + hidden = true, + mercenary = true, + inheritedFrom = "Vitality", + color = 1, + description = "Casts an aura that grants life regeneration to you and your allies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "base_life_regeneration_rate_per_minute", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 600, 0, cooldown = 1.2, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, 1, }, }, + [2] = { 725, 1, cooldown = 1.2, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, 1, }, }, + [3] = { 977, 2, cooldown = 1.2, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, 1, }, }, + [4] = { 1184, 3, cooldown = 1.2, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, 1, }, }, + [5] = { 1370, 4, cooldown = 1.2, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, 1, }, }, + [6] = { 1760, 5, cooldown = 1.2, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, 1, }, }, + [7] = { 2284, 6, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, }, }, + [8] = { 2556, 7, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, }, }, + [9] = { 2831, 8, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, }, }, + [10] = { 3370, 9, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, }, }, + [11] = { 3915, 10, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, }, }, + [12] = { 4730, 11, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, }, }, + [13] = { 5557, 12, cooldown = 1.2, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, 1, }, }, + [14] = { 6394, 13, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, }, }, + [15] = { 7241, 14, cooldown = 1.2, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, 1, }, }, + [16] = { 8100, 15, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, }, }, + [17] = { 9241, 16, cooldown = 1.2, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, 1, }, }, + [18] = { 10397, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, }, }, + [19] = { 10992, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, }, }, + [20] = { 11592, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, }, }, + [21] = { 12197, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, }, }, + [22] = { 12806, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, }, }, + [23] = { 13421, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, }, }, + [24] = { 14040, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, }, }, + [25] = { 14664, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, }, }, + [26] = { 15293, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, }, }, + [27] = { 15926, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, }, }, + [28] = { 16565, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, }, }, + [29] = { 17208, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, }, }, + [30] = { 17856, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, }, }, + [31] = { 18182, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, }, }, + [32] = { 18509, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, }, }, + [33] = { 18837, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, }, }, + [34] = { 19166, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, }, }, + [35] = { 19497, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, }, }, + [36] = { 19829, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, }, }, + [37] = { 20162, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, }, }, + [38] = { 20496, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, }, }, + [39] = { 20831, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, }, }, + [40] = { 21168, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} + +skills["VoidSphereMercenary"] = { + name = "Void Sphere", + hidden = true, + mercenary = true, + inheritedFrom = "VoidSphere", + color = 3, + baseEffectiveness = 0.35989999771118, + incrementalEffectiveness = 0.055500000715256, + description = "Creates a Void Sphere which Hinders enemies in an area around it, with the debuff being stronger on enemies closer to the sphere. It also regularly releases pulses of area damage. The Void Sphere will consume the corpses of any enemies which die in its area. Can only have one Void Sphere at a time.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.AreaSpell] = true, [SkillType.Cooldown] = true, [SkillType.Totemable] = true, [SkillType.Physical] = true, [SkillType.Damage] = true, [SkillType.Chaos] = true, [SkillType.Orb] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.8, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_chaos", 40 }, + { "base_blackhole_tick_rate_ms", 400 }, + { "base_skill_effect_duration", 5000 }, + { "active_skill_base_area_of_effect_radius", 38 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "blackhole_hinder_%", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, -30, cooldown = 10, critChance = 7, damageEffectiveness = 0.5, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, -30, cooldown = 10, critChance = 7, damageEffectiveness = 0.5, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, -31, cooldown = 10, critChance = 7, damageEffectiveness = 0.5, levelRequirement = 38, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, -31, cooldown = 10, critChance = 7, damageEffectiveness = 0.5, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, -32, cooldown = 10, critChance = 7, damageEffectiveness = 0.55, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, -32, cooldown = 10, critChance = 7, damageEffectiveness = 0.55, levelRequirement = 44, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, -33, cooldown = 10, critChance = 7, damageEffectiveness = 0.55, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, -33, cooldown = 10, critChance = 7, damageEffectiveness = 0.6, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, -34, cooldown = 10, critChance = 7, damageEffectiveness = 0.6, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, -34, cooldown = 10, critChance = 7, damageEffectiveness = 0.6, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, -35, cooldown = 10, critChance = 7, damageEffectiveness = 0.65, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, -35, cooldown = 10, critChance = 7, damageEffectiveness = 0.65, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, -36, cooldown = 10, critChance = 7, damageEffectiveness = 0.65, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, -36, cooldown = 10, critChance = 7, damageEffectiveness = 0.7, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, -37, cooldown = 10, critChance = 7, damageEffectiveness = 0.7, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, -37, cooldown = 10, critChance = 7, damageEffectiveness = 0.7, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, -38, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, -38, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, -39, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 69, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, -39, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, -40, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, -40, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, -41, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, -41, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, -42, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, -42, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, -43, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, -43, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, -44, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, -44, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, -44, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, -45, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, -45, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, -45, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, -45, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, -46, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, -46, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, -46, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, -46, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, -47, cooldown = 10, critChance = 7, damageEffectiveness = 0.75, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["VolcanicFissureAltMercenary"] = { + name = "Volcanic Fissure of Snaking", + hidden = true, + mercenary = true, + inheritedFrom = "VolcanicFissure", + color = 1, + description = "Slam the ground, creating a winding fissure that deals area damage while travelling outwards. When it reaches the target location it erupts, releasing a burst of molten projectiles. Requires an Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Slam] = true, [SkillType.Fire] = true, [SkillType.Multistrikeable] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + }, + stats = { + "vaal_volcanic_fissure_crack_repeat_count", + "is_area_damage", + }, + levels = { + [1] = { 0, baseMultiplier = 1.643, damageEffectiveness = 1.643, levelRequirement = 12, statInterpolation = { 1, }, }, + [2] = { 0, baseMultiplier = 1.701, damageEffectiveness = 1.701, levelRequirement = 15, statInterpolation = { 1, }, }, + [3] = { 0, baseMultiplier = 1.765, damageEffectiveness = 1.765, levelRequirement = 19, statInterpolation = { 1, }, }, + [4] = { 0, baseMultiplier = 1.831, damageEffectiveness = 1.831, levelRequirement = 23, statInterpolation = { 1, }, }, + [5] = { 0, baseMultiplier = 1.899, damageEffectiveness = 1.899, levelRequirement = 27, statInterpolation = { 1, }, }, + [6] = { 0, baseMultiplier = 1.97, damageEffectiveness = 1.97, levelRequirement = 31, statInterpolation = { 1, }, }, + [7] = { 0, baseMultiplier = 2.043, damageEffectiveness = 2.043, levelRequirement = 35, statInterpolation = { 1, }, }, + [8] = { 1, baseMultiplier = 2.116, damageEffectiveness = 2.116, levelRequirement = 38, statInterpolation = { 1, }, }, + [9] = { 1, baseMultiplier = 2.19, damageEffectiveness = 2.19, levelRequirement = 41, statInterpolation = { 1, }, }, + [10] = { 1, baseMultiplier = 2.268, damageEffectiveness = 2.268, levelRequirement = 44, statInterpolation = { 1, }, }, + [11] = { 1, baseMultiplier = 2.348, damageEffectiveness = 2.348, levelRequirement = 47, statInterpolation = { 1, }, }, + [12] = { 1, baseMultiplier = 2.43, damageEffectiveness = 2.43, levelRequirement = 50, statInterpolation = { 1, }, }, + [13] = { 1, baseMultiplier = 2.516, damageEffectiveness = 2.516, levelRequirement = 53, statInterpolation = { 1, }, }, + [14] = { 1, baseMultiplier = 2.605, damageEffectiveness = 2.605, levelRequirement = 56, statInterpolation = { 1, }, }, + [15] = { 2, baseMultiplier = 2.696, damageEffectiveness = 2.696, levelRequirement = 59, statInterpolation = { 1, }, }, + [16] = { 2, baseMultiplier = 2.791, damageEffectiveness = 2.791, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 2, baseMultiplier = 2.884, damageEffectiveness = 2.884, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 2, baseMultiplier = 2.981, damageEffectiveness = 2.981, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 2, baseMultiplier = 3.081, damageEffectiveness = 3.081, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 2, baseMultiplier = 3.183, damageEffectiveness = 3.183, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 2, baseMultiplier = 3.29, damageEffectiveness = 3.29, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 2, baseMultiplier = 3.399, damageEffectiveness = 3.399, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 2, baseMultiplier = 3.513, damageEffectiveness = 3.513, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 2, baseMultiplier = 3.63, damageEffectiveness = 3.63, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 2, baseMultiplier = 3.751, damageEffectiveness = 3.751, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 2, baseMultiplier = 3.876, damageEffectiveness = 3.876, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 2, baseMultiplier = 4.005, damageEffectiveness = 4.005, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 2, baseMultiplier = 4.138, damageEffectiveness = 4.138, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 2, baseMultiplier = 4.276, damageEffectiveness = 4.276, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 2, baseMultiplier = 4.419, damageEffectiveness = 4.419, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 2, baseMultiplier = 4.626, damageEffectiveness = 4.626, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 2, baseMultiplier = 4.704, damageEffectiveness = 4.704, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 2, baseMultiplier = 4.781, damageEffectiveness = 4.781, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 2, baseMultiplier = 4.86, damageEffectiveness = 4.86, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 2, baseMultiplier = 4.942, damageEffectiveness = 4.942, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 2, baseMultiplier = 5.024, damageEffectiveness = 5.024, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 2, baseMultiplier = 5.107, damageEffectiveness = 5.107, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 2, baseMultiplier = 5.192, damageEffectiveness = 5.192, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 2, baseMultiplier = 5.278, damageEffectiveness = 5.278, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 2, baseMultiplier = 5.366, damageEffectiveness = 5.366, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["VolcanicFissureAltMercenaryEncounter"] = { + name = "Volcanic Fissure of Snaking", + hidden = true, + mercenary = true, + inheritedFrom = "VolcanicFissure", + color = 1, + description = "Slam the ground, creating a winding fissure that deals area damage while travelling outwards. When it reaches the target location it erupts, releasing a burst of molten projectiles. Requires an Axe, Mace, Sceptre, Staff or Unarmed.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Melee] = true, [SkillType.Slam] = true, [SkillType.Fire] = true, [SkillType.Multistrikeable] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.Totemable] = true, }, + weaponTypes = { + ["None"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 60 }, + }, + stats = { + "vaal_volcanic_fissure_crack_repeat_count", + "is_area_damage", + }, + levels = { + [1] = { 0, baseMultiplier = 1.418, damageEffectiveness = 1.418, levelRequirement = 12, statInterpolation = { 1, }, }, + [2] = { 0, baseMultiplier = 1.4557, damageEffectiveness = 1.4557, levelRequirement = 15, statInterpolation = { 1, }, }, + [3] = { 0, baseMultiplier = 1.4973, damageEffectiveness = 1.4973, levelRequirement = 19, statInterpolation = { 1, }, }, + [4] = { 0, baseMultiplier = 1.5402, damageEffectiveness = 1.5402, levelRequirement = 23, statInterpolation = { 1, }, }, + [5] = { 0, baseMultiplier = 1.5844, damageEffectiveness = 1.5844, levelRequirement = 27, statInterpolation = { 1, }, }, + [6] = { 0, baseMultiplier = 1.6305, damageEffectiveness = 1.6305, levelRequirement = 31, statInterpolation = { 1, }, }, + [7] = { 0, baseMultiplier = 1.678, damageEffectiveness = 1.678, levelRequirement = 35, statInterpolation = { 1, }, }, + [8] = { 1, baseMultiplier = 1.7254, damageEffectiveness = 1.7254, levelRequirement = 38, statInterpolation = { 1, }, }, + [9] = { 1, baseMultiplier = 1.7735, damageEffectiveness = 1.7735, levelRequirement = 41, statInterpolation = { 1, }, }, + [10] = { 1, baseMultiplier = 1.8242, damageEffectiveness = 1.8242, levelRequirement = 44, statInterpolation = { 1, }, }, + [11] = { 1, baseMultiplier = 1.8762, damageEffectiveness = 1.8762, levelRequirement = 47, statInterpolation = { 1, }, }, + [12] = { 1, baseMultiplier = 1.9295, damageEffectiveness = 1.9295, levelRequirement = 50, statInterpolation = { 1, }, }, + [13] = { 1, baseMultiplier = 1.9854, damageEffectiveness = 1.9854, levelRequirement = 53, statInterpolation = { 1, }, }, + [14] = { 1, baseMultiplier = 2.0433, damageEffectiveness = 2.0433, levelRequirement = 56, statInterpolation = { 1, }, }, + [15] = { 2, baseMultiplier = 2.1024, damageEffectiveness = 2.1024, levelRequirement = 59, statInterpolation = { 1, }, }, + [16] = { 2, baseMultiplier = 2.1642, damageEffectiveness = 2.1642, levelRequirement = 62, statInterpolation = { 1, }, }, + [17] = { 2, baseMultiplier = 2.2246, damageEffectiveness = 2.2246, levelRequirement = 64, statInterpolation = { 1, }, }, + [18] = { 2, baseMultiplier = 2.2877, damageEffectiveness = 2.2877, levelRequirement = 66, statInterpolation = { 1, }, }, + [19] = { 2, baseMultiplier = 2.3527, damageEffectiveness = 2.3527, levelRequirement = 68, statInterpolation = { 1, }, }, + [20] = { 2, baseMultiplier = 2.419, damageEffectiveness = 2.419, levelRequirement = 70, statInterpolation = { 1, }, }, + [21] = { 2, baseMultiplier = 2.4885, damageEffectiveness = 2.4885, levelRequirement = 72, statInterpolation = { 1, }, }, + [22] = { 2, baseMultiplier = 2.5594, damageEffectiveness = 2.5594, levelRequirement = 74, statInterpolation = { 1, }, }, + [23] = { 2, baseMultiplier = 2.6335, damageEffectiveness = 2.6335, levelRequirement = 76, statInterpolation = { 1, }, }, + [24] = { 2, baseMultiplier = 2.7095, damageEffectiveness = 2.7095, levelRequirement = 78, statInterpolation = { 1, }, }, + [25] = { 2, baseMultiplier = 2.7882, damageEffectiveness = 2.7882, levelRequirement = 80, statInterpolation = { 1, }, }, + [26] = { 2, baseMultiplier = 2.8694, damageEffectiveness = 2.8694, levelRequirement = 82, statInterpolation = { 1, }, }, + [27] = { 2, baseMultiplier = 2.9533, damageEffectiveness = 2.9533, levelRequirement = 84, statInterpolation = { 1, }, }, + [28] = { 2, baseMultiplier = 3.0397, damageEffectiveness = 3.0397, levelRequirement = 86, statInterpolation = { 1, }, }, + [29] = { 2, baseMultiplier = 3.1294, damageEffectiveness = 3.1294, levelRequirement = 88, statInterpolation = { 1, }, }, + [30] = { 2, baseMultiplier = 3.2224, damageEffectiveness = 3.2224, levelRequirement = 90, statInterpolation = { 1, }, }, + [31] = { 2, baseMultiplier = 3.3569, damageEffectiveness = 3.3569, levelRequirement = 91, statInterpolation = { 1, }, }, + [32] = { 2, baseMultiplier = 3.4076, damageEffectiveness = 3.4076, levelRequirement = 92, statInterpolation = { 1, }, }, + [33] = { 2, baseMultiplier = 3.4577, damageEffectiveness = 3.4577, levelRequirement = 93, statInterpolation = { 1, }, }, + [34] = { 2, baseMultiplier = 3.509, damageEffectiveness = 3.509, levelRequirement = 94, statInterpolation = { 1, }, }, + [35] = { 2, baseMultiplier = 3.5623, damageEffectiveness = 3.5623, levelRequirement = 95, statInterpolation = { 1, }, }, + [36] = { 2, baseMultiplier = 3.6156, damageEffectiveness = 3.6156, levelRequirement = 96, statInterpolation = { 1, }, }, + [37] = { 2, baseMultiplier = 3.6696, damageEffectiveness = 3.6696, levelRequirement = 97, statInterpolation = { 1, }, }, + [38] = { 2, baseMultiplier = 3.7248, damageEffectiveness = 3.7248, levelRequirement = 98, statInterpolation = { 1, }, }, + [39] = { 2, baseMultiplier = 3.7807, damageEffectiveness = 3.7807, levelRequirement = 99, statInterpolation = { 1, }, }, + [40] = { 2, baseMultiplier = 3.8379, damageEffectiveness = 3.8379, levelRequirement = 100, statInterpolation = { 1, }, }, + }, +} + +skills["VollCharge"] = { + name = "VollCharge", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Attack] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 2.75, + baseFlags = { + attack = true, + }, + constantStats = { + { "active_skill_damage_+%_final", 30 }, + }, + stats = { + }, + levels = { + [1] = { cooldown = 4, levelRequirement = 2, storedUses = 1, }, + }, +} + +skills["VollReviveUndead"] = { + name = "VollReviveUndead", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 2.7, + baseFlags = { + spell = true, + }, + stats = { + }, + levels = { + [1] = { cooldown = 8, levelRequirement = 1, storedUses = 1, }, + }, +} + +skills["VollReviveUndeadWithMinions"] = { + name = "VollReviveUndeadWithMinions", + hidden = true, + mercenary = true, + color = 4, + skillTypes = { [SkillType.Spell] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 2.7, + baseFlags = { + spell = true, + }, + stats = { + "number_of_monsters_to_summon", + }, + notMinionStat = { + "number_of_monsters_to_summon", + }, + levels = { + [1] = { 6, cooldown = 8, levelRequirement = 34, storedUses = 1, statInterpolation = { 1, }, }, + [2] = { 7, cooldown = 8, levelRequirement = 55, storedUses = 1, statInterpolation = { 1, }, }, + [3] = { 8, cooldown = 8, levelRequirement = 67, storedUses = 1, statInterpolation = { 1, }, }, + [4] = { 10, cooldown = 8, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, }, }, + }, +} + +skills["VollSlamMercenary"] = { + name = "VollSlamMercenary", + hidden = true, + mercenary = true, + inheritedFrom = "AzmeriGeofriSlam", + color = 4, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + }, + constantStats = { + { "active_skill_attack_speed_+%_final", -47 }, + { "voll_slam_damage_+%_final_at_centre", 100 }, + }, + stats = { + "active_skill_damage_+%_final", + "is_area_damage", + }, + notMinionStat = { + "active_skill_damage_+%_final", + }, + levels = { + [1] = { 1, baseMultiplier = 0.95, cooldown = 5, damageEffectiveness = 0.95, levelRequirement = 1, storedUses = 1, statInterpolation = { 2, }, }, + [84] = { 100, baseMultiplier = 0.95, cooldown = 5, damageEffectiveness = 0.95, levelRequirement = 84, storedUses = 1, statInterpolation = { 2, }, }, + }, +} + +skills["VoltaxicBurstMercenary"] = { + name = "Voltaxic Burst", + hidden = true, + mercenary = true, + inheritedFrom = "VoltaxicBurst", + color = 3, + baseEffectiveness = 2.3076000213623, + incrementalEffectiveness = 0.043999999761581, + description = "Each cast of this spell waits for a short duration, releasing a burst of lightning and chaos spell damage in an area around you when that duration ends. Enemies killed by this damage, or shortly after, will explode. The explosions of the corpses are not affected by modifiers to spell damage, and cannot be reflected.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Chaos] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, [SkillType.Duration] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.5, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "skill_lightning_damage_%_to_convert_to_chaos", 40 }, + { "corpse_explosion_monster_life_%_lightning", 6 }, + { "voltaxic_burst_hit_and_ailment_damage_+%_final_per_stack", 1 }, + { "base_skill_effect_duration", 2500 }, + }, + stats = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + "is_area_damage", + }, + notMinionStat = { + "spell_minimum_base_lightning_damage", + "spell_maximum_base_lightning_damage", + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.69999998807907, 1.2999999523163, 0, critChance = 6.5, damageEffectiveness = 2.1, levelRequirement = 12, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.69999998807907, 1.2999999523163, 0, critChance = 6.5, damageEffectiveness = 2.1, levelRequirement = 15, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.69999998807907, 1.2999999523163, 0, critChance = 6.5, damageEffectiveness = 2.1, levelRequirement = 19, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.69999998807907, 1.2999999523163, 0, critChance = 6.5, damageEffectiveness = 2.1, levelRequirement = 23, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.69999998807907, 1.2999999523163, 0, critChance = 6.5, damageEffectiveness = 2.1, levelRequirement = 27, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.69999998807907, 1.2999999523163, 0, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 31, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.69999998807907, 1.2999999523163, 1, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 35, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.69999998807907, 1.2999999523163, 1, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 38, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.69999998807907, 1.2999999523163, 1, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 41, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.69999998807907, 1.2999999523163, 1, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 44, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.69999998807907, 1.2999999523163, 1, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 47, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.69999998807907, 1.2999999523163, 1, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 50, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.69999998807907, 1.2999999523163, 2, critChance = 6.5, damageEffectiveness = 2.2, levelRequirement = 53, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.69999998807907, 1.2999999523163, 2, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 56, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.69999998807907, 1.2999999523163, 2, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 59, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.69999998807907, 1.2999999523163, 2, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 62, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.69999998807907, 1.2999999523163, 2, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 64, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.69999998807907, 1.2999999523163, 2, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 66, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.69999998807907, 1.2999999523163, 3, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 68, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.69999998807907, 1.2999999523163, 3, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 70, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.69999998807907, 1.2999999523163, 3, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 72, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.69999998807907, 1.2999999523163, 3, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 74, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.69999998807907, 1.2999999523163, 3, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 76, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.69999998807907, 1.2999999523163, 3, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 78, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.69999998807907, 1.2999999523163, 4, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 80, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.69999998807907, 1.2999999523163, 4, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 82, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.69999998807907, 1.2999999523163, 4, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 84, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.69999998807907, 1.2999999523163, 4, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 86, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.69999998807907, 1.2999999523163, 4, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 88, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.69999998807907, 1.2999999523163, 4, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 90, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 91, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 92, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 93, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 94, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 95, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 96, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 97, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 98, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 99, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.69999998807907, 1.2999999523163, 5, critChance = 6.5, damageEffectiveness = 2.3, levelRequirement = 100, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["VortexMercenary"] = { + name = "Vortex", + hidden = true, + mercenary = true, + inheritedFrom = "Vortex", + color = 3, + baseEffectiveness = 1.2086000442505, + incrementalEffectiveness = 0.049499999731779, + description = "An icy blast explodes around the caster, dealing cold damage to enemies, and leaving behind a whirling vortex which deals cold damage over time and chills enemies caught in it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Cold] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.ChillingArea] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, [SkillType.CanRapidFire] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "active_skill_base_area_of_effect_radius", 20 }, + { "active_skill_base_secondary_area_of_effect_radius", 20 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_cold_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + "cover_in_frost_on_hit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 114.83333367482, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 28, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 116.83333975946, critChance = 6, damageEffectiveness = 1.3, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 118.50000487392, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 34, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 120.50000301128, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 37, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 122.33333861083, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 40, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 123.33333767951, critChance = 6, damageEffectiveness = 1.4, levelRequirement = 42, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 124.83333230888, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 126.16667234773, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 46, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 127.5000044393, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 48, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 128.83333653087, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 130.16666862244, critChance = 6, damageEffectiveness = 1.5, levelRequirement = 52, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 131.50000071401, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 54, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 132.66667026778, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 133.83333187426, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 58, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 135.50000493601, critChance = 6, damageEffectiveness = 1.6, levelRequirement = 60, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 136.66666654249, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 138.16666911915, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 139.66667169581, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 141.33332886298, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 142.66667684913, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 144.16666353121, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 145.66666610787, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 146.99999819944, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 148.33333029101, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 150.16667383785, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 151.50000592942, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 153.33333358169, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 155.16667712852, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 156.16666824992, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 157.99999590218, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 158.83333243305, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 159.66666896393, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 160.5000054948, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 161.33334202568, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 162.16666266198, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 162.99999919285, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 163.83333572373, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 164.6666722546, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 165.50000878548, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 166.16667483126, critChance = 6, damageEffectiveness = 1.7, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["VortexMercenaryEncounter"] = { + name = "Vortex", + hidden = true, + mercenary = true, + inheritedFrom = "Vortex", + color = 3, + baseEffectiveness = 1.2000000476837, + incrementalEffectiveness = 0.041999999433756, + description = "An icy blast explodes around the caster, dealing cold damage to enemies, and leaving behind a whirling vortex which deals cold damage over time and chills enemies caught in it.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Damage] = true, [SkillType.Area] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Cold] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.ChillingArea] = true, [SkillType.AreaSpell] = true, [SkillType.Nova] = true, [SkillType.CanRapidFire] = true, [SkillType.DamageOverTime] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0.75, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + { "active_skill_base_area_of_effect_radius", 20 }, + { "active_skill_base_secondary_area_of_effect_radius", 20 }, + }, + stats = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + "base_cold_damage_to_deal_per_minute", + "is_area_damage", + "spell_damage_modifiers_apply_to_skill_dot", + "cover_in_frost_on_hit", + }, + notMinionStat = { + "spell_minimum_base_cold_damage", + "spell_maximum_base_cold_damage", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.3, levelRequirement = 28, statInterpolation = { 3, 3, 3, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.3, levelRequirement = 31, statInterpolation = { 3, 3, 3, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 34, statInterpolation = { 3, 3, 3, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 37, statInterpolation = { 3, 3, 3, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 40, statInterpolation = { 3, 3, 3, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.4, levelRequirement = 42, statInterpolation = { 3, 3, 3, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.5, levelRequirement = 44, statInterpolation = { 3, 3, 3, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.5, levelRequirement = 46, statInterpolation = { 3, 3, 3, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.5, levelRequirement = 48, statInterpolation = { 3, 3, 3, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.5, levelRequirement = 50, statInterpolation = { 3, 3, 3, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.5, levelRequirement = 52, statInterpolation = { 3, 3, 3, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.6, levelRequirement = 54, statInterpolation = { 3, 3, 3, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.6, levelRequirement = 56, statInterpolation = { 3, 3, 3, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.6, levelRequirement = 58, statInterpolation = { 3, 3, 3, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.6, levelRequirement = 60, statInterpolation = { 3, 3, 3, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 62, statInterpolation = { 3, 3, 3, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 64, statInterpolation = { 3, 3, 3, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 66, statInterpolation = { 3, 3, 3, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 68, statInterpolation = { 3, 3, 3, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 70, statInterpolation = { 3, 3, 3, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 72, statInterpolation = { 3, 3, 3, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 74, statInterpolation = { 3, 3, 3, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 76, statInterpolation = { 3, 3, 3, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 78, statInterpolation = { 3, 3, 3, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 80, statInterpolation = { 3, 3, 3, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 82, statInterpolation = { 3, 3, 3, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 84, statInterpolation = { 3, 3, 3, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 86, statInterpolation = { 3, 3, 3, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 88, statInterpolation = { 3, 3, 3, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 90, statInterpolation = { 3, 3, 3, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 91, statInterpolation = { 3, 3, 3, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 92, statInterpolation = { 3, 3, 3, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 93, statInterpolation = { 3, 3, 3, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 94, statInterpolation = { 3, 3, 3, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 95, statInterpolation = { 3, 3, 3, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 96, statInterpolation = { 3, 3, 3, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 97, statInterpolation = { 3, 3, 3, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 98, statInterpolation = { 3, 3, 3, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 99, statInterpolation = { 3, 3, 3, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 41.666667597989, critChance = 5, damageEffectiveness = 1.7, levelRequirement = 100, statInterpolation = { 3, 3, 3, }, }, + }, +} + +skills["VulnerabilityAuraMapBoss"] = { + name = "Vulnerability", + hidden = true, + mercenary = true, + inheritedFrom = "Vulnerability", + color = 4, + baseEffectiveness = 0, + description = "Curse all targets in an area, causing them to take increased physical damage. Attacks against the cursed enemies have a chance to inflict bleeding.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Multicastable] = true, [SkillType.Triggerable] = true, [SkillType.Cascadable] = true, [SkillType.AppliesCurse] = true, [SkillType.CanRapidFire] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Hex] = true, }, + statDescriptionScope = "curse_skill_stat_descriptions", + castTime = 1.5, + baseFlags = { + area = true, + duration = true, + hex = true, + spell = true, + }, + constantStats = { + { "physical_damage_taken_+%", 50 }, + { "receive_bleeding_chance_%_when_hit_by_attack", 25 }, + { "active_skill_area_of_effect_radius_+%_final", 50 }, + }, + stats = { + "curse_apply_as_aura", + }, + levels = { + [1] = { cooldown = 5, levelRequirement = 1, storedUses = 1, cost = { Mana = 50, }, }, + }, +} + +skills["WaveOfConvictionAltMercenary"] = { + name = "Wave of Conviction of Trarthus", + hidden = true, + mercenary = true, + inheritedFrom = "WaveOfConvictionAltY", + color = 3, + baseEffectiveness = 1.8079999685287, + incrementalEffectiveness = 0.049699999392033, + description = "An expanding wave of energy surges outwards from you, damaging enemies in a ring-shaped area over a duration. The ring then returns, damaging enemies again on the way back. Only one Wave of Conviction can be active at a time", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.CanRapidFire] = true, [SkillType.Multicastable] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, [SkillType.Fire] = true, [SkillType.Nova] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_fire", 50 }, + { "base_secondary_skill_effect_duration", 4000 }, + { "shock_art_variation", 2 }, + { "ignite_art_variation", 7 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_skill_effect_duration", + "is_area_damage", + "visual_hit_effect_elemental_is_holy", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_skill_effect_duration", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 400, cooldown = 3, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 410, cooldown = 3, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 410, cooldown = 3, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 420, cooldown = 3, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 420, cooldown = 3, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 430, cooldown = 3, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 430, cooldown = 3, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 440, cooldown = 3, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 440, cooldown = 3, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 450, cooldown = 3, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 450, cooldown = 3, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 460, cooldown = 3, critChance = 6, damageEffectiveness = 2.9, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 460, cooldown = 3, critChance = 6, damageEffectiveness = 3, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 470, cooldown = 3, critChance = 6, damageEffectiveness = 3, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 470, cooldown = 3, critChance = 6, damageEffectiveness = 3.1, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 480, cooldown = 3, critChance = 6, damageEffectiveness = 3.1, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 480, cooldown = 3, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 490, cooldown = 3, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 490, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 500, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 500, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 510, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 510, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 520, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 520, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 530, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 530, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 540, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 540, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 550, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 550, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 550, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 550, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 560, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 560, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 560, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 560, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 570, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 570, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 570, cooldown = 3, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["WaveOfConvictionLightningMercenary"] = { + name = "Wave of Conviction", + hidden = true, + mercenary = true, + inheritedFrom = "WaveOfConviction", + color = 3, + baseEffectiveness = 2.2999999523163, + incrementalEffectiveness = 0.0489999987185, + description = "An expanding wave of energy surges forward, damaging enemies in a cone-shaped area over a duration. Each enemy hit is inflicted with Exposure matching the element of which they took the highest damage. Only one Wave of Conviction can be active at a time", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Damage] = true, [SkillType.Duration] = true, [SkillType.Trappable] = true, [SkillType.Totemable] = true, [SkillType.Mineable] = true, [SkillType.Triggerable] = true, [SkillType.Fire] = true, [SkillType.Lightning] = true, [SkillType.CanRapidFire] = true, [SkillType.Multicastable] = true, [SkillType.AreaSpell] = true, [SkillType.Physical] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.7, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "skill_physical_damage_%_to_convert_to_lightning", 50 }, + { "base_secondary_skill_effect_duration", 6000 }, + { "shock_art_variation", 2 }, + { "ignite_art_variation", 7 }, + { "purge_expose_resist_%_matching_highest_element_damage", -15 }, + }, + stats = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_skill_effect_duration", + "is_area_damage", + "visual_hit_effect_elemental_is_holy", + }, + notMinionStat = { + "spell_minimum_base_physical_damage", + "spell_maximum_base_physical_damage", + "base_skill_effect_duration", + }, + levels = { + [1] = { 0.80000001192093, 1.2000000476837, 500, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.2, levelRequirement = 16, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [2] = { 0.80000001192093, 1.2000000476837, 510, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.3, levelRequirement = 20, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [3] = { 0.80000001192093, 1.2000000476837, 520, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [4] = { 0.80000001192093, 1.2000000476837, 530, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.4, levelRequirement = 28, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [5] = { 0.80000001192093, 1.2000000476837, 540, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 31, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [6] = { 0.80000001192093, 1.2000000476837, 550, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.5, levelRequirement = 34, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [7] = { 0.80000001192093, 1.2000000476837, 560, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.6, levelRequirement = 37, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [8] = { 0.80000001192093, 1.2000000476837, 570, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 40, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [9] = { 0.80000001192093, 1.2000000476837, 580, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.7, levelRequirement = 43, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [10] = { 0.80000001192093, 1.2000000476837, 590, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 46, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [11] = { 0.80000001192093, 1.2000000476837, 600, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.8, levelRequirement = 49, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [12] = { 0.80000001192093, 1.2000000476837, 610, cooldown = 4.5, critChance = 6, damageEffectiveness = 2.9, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [13] = { 0.80000001192093, 1.2000000476837, 620, cooldown = 4.5, critChance = 6, damageEffectiveness = 3, levelRequirement = 55, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [14] = { 0.80000001192093, 1.2000000476837, 630, cooldown = 4.5, critChance = 6, damageEffectiveness = 3, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [15] = { 0.80000001192093, 1.2000000476837, 640, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.1, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [16] = { 0.80000001192093, 1.2000000476837, 650, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.1, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [17] = { 0.80000001192093, 1.2000000476837, 660, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [18] = { 0.80000001192093, 1.2000000476837, 670, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [19] = { 0.80000001192093, 1.2000000476837, 680, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [20] = { 0.80000001192093, 1.2000000476837, 690, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [21] = { 0.80000001192093, 1.2000000476837, 700, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [22] = { 0.80000001192093, 1.2000000476837, 710, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [23] = { 0.80000001192093, 1.2000000476837, 720, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [24] = { 0.80000001192093, 1.2000000476837, 730, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [25] = { 0.80000001192093, 1.2000000476837, 740, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [26] = { 0.80000001192093, 1.2000000476837, 750, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [27] = { 0.80000001192093, 1.2000000476837, 760, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [28] = { 0.80000001192093, 1.2000000476837, 770, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [29] = { 0.80000001192093, 1.2000000476837, 780, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [30] = { 0.80000001192093, 1.2000000476837, 790, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [31] = { 0.80000001192093, 1.2000000476837, 795, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [32] = { 0.80000001192093, 1.2000000476837, 800, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [33] = { 0.80000001192093, 1.2000000476837, 805, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [34] = { 0.80000001192093, 1.2000000476837, 810, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [35] = { 0.80000001192093, 1.2000000476837, 815, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [36] = { 0.80000001192093, 1.2000000476837, 820, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [37] = { 0.80000001192093, 1.2000000476837, 825, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [38] = { 0.80000001192093, 1.2000000476837, 830, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [39] = { 0.80000001192093, 1.2000000476837, 835, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + [40] = { 0.80000001192093, 1.2000000476837, 840, cooldown = 4.5, critChance = 6, damageEffectiveness = 3.3, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, }, }, + }, +} + +skills["WhirlingBladesMercenary"] = { + name = "Whirling Blades", + hidden = true, + mercenary = true, + inheritedFrom = "WhirlingBlades", + color = 2, + baseEffectiveness = 0, + description = "Dive through enemies, dealing weapon damage. If dual wielding attacks with both weapons, dealing the damage of both in one hit. Only works with Daggers, Claws, and One-Handed Swords.", + skillTypes = { [SkillType.Attack] = true, [SkillType.Melee] = true, [SkillType.Movement] = true, [SkillType.Travel] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Sword"] = true, + ["Thrusting One Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 2.6, + baseFlags = { + attack = true, + melee = true, + movement = true, + }, + constantStats = { + { "additional_weapon_base_attack_time_ms", 600 }, + { "animation_effect_variation", -1 }, + { "active_skill_merged_damage_+%_final_while_dual_wielding", -25 }, + }, + stats = { + "ignores_proximity_shield", + "base_skill_show_average_damage_instead_of_dps", + "skill_double_hits_when_dual_wielding", + }, + levels = { + [1] = { baseMultiplier = 1.364, damageEffectiveness = 1.364, levelRequirement = 10, }, + [2] = { baseMultiplier = 1.425, damageEffectiveness = 1.425, levelRequirement = 13, }, + [3] = { baseMultiplier = 1.492, damageEffectiveness = 1.492, levelRequirement = 17, }, + [4] = { baseMultiplier = 1.562, damageEffectiveness = 1.562, levelRequirement = 21, }, + [5] = { baseMultiplier = 1.634, damageEffectiveness = 1.634, levelRequirement = 25, }, + [6] = { baseMultiplier = 1.71, damageEffectiveness = 1.71, levelRequirement = 29, }, + [7] = { baseMultiplier = 1.79, damageEffectiveness = 1.79, levelRequirement = 33, }, + [8] = { baseMultiplier = 1.871, damageEffectiveness = 1.871, levelRequirement = 36, }, + [9] = { baseMultiplier = 1.954, damageEffectiveness = 1.954, levelRequirement = 39, }, + [10] = { baseMultiplier = 2.041, damageEffectiveness = 2.041, levelRequirement = 42, }, + [11] = { baseMultiplier = 2.133, damageEffectiveness = 2.133, levelRequirement = 45, }, + [12] = { baseMultiplier = 2.227, damageEffectiveness = 2.227, levelRequirement = 48, }, + [13] = { baseMultiplier = 2.327, damageEffectiveness = 2.327, levelRequirement = 51, }, + [14] = { baseMultiplier = 2.431, damageEffectiveness = 2.431, levelRequirement = 54, }, + [15] = { baseMultiplier = 2.538, damageEffectiveness = 2.538, levelRequirement = 57, }, + [16] = { baseMultiplier = 2.652, damageEffectiveness = 2.652, levelRequirement = 60, }, + [17] = { baseMultiplier = 2.77, damageEffectiveness = 2.77, levelRequirement = 63, }, + [18] = { baseMultiplier = 2.892, damageEffectiveness = 2.892, levelRequirement = 66, }, + [19] = { baseMultiplier = 3.017, damageEffectiveness = 3.017, levelRequirement = 68, }, + [20] = { baseMultiplier = 3.145, damageEffectiveness = 3.145, levelRequirement = 70, }, + [21] = { baseMultiplier = 3.28, damageEffectiveness = 3.28, levelRequirement = 72, }, + [22] = { baseMultiplier = 3.419, damageEffectiveness = 3.419, levelRequirement = 74, }, + [23] = { baseMultiplier = 3.565, damageEffectiveness = 3.565, levelRequirement = 76, }, + [24] = { baseMultiplier = 3.718, damageEffectiveness = 3.718, levelRequirement = 78, }, + [25] = { baseMultiplier = 3.875, damageEffectiveness = 3.875, levelRequirement = 80, }, + [26] = { baseMultiplier = 4.041, damageEffectiveness = 4.041, levelRequirement = 82, }, + [27] = { baseMultiplier = 4.213, damageEffectiveness = 4.213, levelRequirement = 84, }, + [28] = { baseMultiplier = 4.393, damageEffectiveness = 4.393, levelRequirement = 86, }, + [29] = { baseMultiplier = 4.58, damageEffectiveness = 4.58, levelRequirement = 88, }, + [30] = { baseMultiplier = 4.775, damageEffectiveness = 4.775, levelRequirement = 90, }, + [31] = { baseMultiplier = 5.067, damageEffectiveness = 5.067, levelRequirement = 91, }, + [32] = { baseMultiplier = 5.175, damageEffectiveness = 5.175, levelRequirement = 92, }, + [33] = { baseMultiplier = 5.285, damageEffectiveness = 5.285, levelRequirement = 93, }, + [34] = { baseMultiplier = 5.397, damageEffectiveness = 5.397, levelRequirement = 94, }, + [35] = { baseMultiplier = 5.513, damageEffectiveness = 5.513, levelRequirement = 95, }, + [36] = { baseMultiplier = 5.629, damageEffectiveness = 5.629, levelRequirement = 96, }, + [37] = { baseMultiplier = 5.749, damageEffectiveness = 5.749, levelRequirement = 97, }, + [38] = { baseMultiplier = 5.871, damageEffectiveness = 5.871, levelRequirement = 98, }, + [39] = { baseMultiplier = 5.995, damageEffectiveness = 5.995, levelRequirement = 99, }, + [40] = { baseMultiplier = 6.123, damageEffectiveness = 6.123, levelRequirement = 100, }, + }, +} + +skills["WildStrikeMercenary"] = { + name = "Wild Strike", + hidden = true, + mercenary = true, + inheritedFrom = "WildStrike", + color = 2, + description = "Your melee weapon strikes enemies, converting physical damage to a random element. Then, depending on the element chosen, it releases a fiery explosion, an arcing bolt of lightning, or an icy wave. It will avoid choosing the same element twice in a row.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Lightning] = true, [SkillType.Cold] = true, [SkillType.Fire] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Chains] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.RandomElement] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "elemental_strike_physical_damage_%_to_convert", 100 }, + { "fixed_projectile_spread", 70 }, + { "base_number_of_projectiles", 3 }, + }, + stats = { + "additional_beam_only_chains", + "base_skill_area_of_effect_+%", + "show_number_of_projectiles", + "always_pierce", + }, + levels = { + [1] = { 4, 0, baseMultiplier = 2.6716, damageEffectiveness = 2.6716, levelRequirement = 28, statInterpolation = { 1, 1, }, }, + [2] = { 4, 1, baseMultiplier = 2.7766, damageEffectiveness = 2.7766, levelRequirement = 31, statInterpolation = { 1, 1, }, }, + [3] = { 4, 2, baseMultiplier = 2.8858, damageEffectiveness = 2.8858, levelRequirement = 34, statInterpolation = { 1, 1, }, }, + [4] = { 4, 3, baseMultiplier = 2.9978, damageEffectiveness = 2.9978, levelRequirement = 37, statInterpolation = { 1, 1, }, }, + [5] = { 4, 4, baseMultiplier = 3.1126, damageEffectiveness = 3.1126, levelRequirement = 40, statInterpolation = { 1, 1, }, }, + [6] = { 4, 5, baseMultiplier = 3.226, damageEffectiveness = 3.226, levelRequirement = 42, statInterpolation = { 1, 1, }, }, + [7] = { 5, 6, baseMultiplier = 3.3422, damageEffectiveness = 3.3422, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [8] = { 5, 7, baseMultiplier = 3.4626, damageEffectiveness = 3.4626, levelRequirement = 46, statInterpolation = { 1, 1, }, }, + [9] = { 5, 8, baseMultiplier = 3.5872, damageEffectiveness = 3.5872, levelRequirement = 48, statInterpolation = { 1, 1, }, }, + [10] = { 5, 9, baseMultiplier = 3.7146, damageEffectiveness = 3.7146, levelRequirement = 50, statInterpolation = { 1, 1, }, }, + [11] = { 5, 10, baseMultiplier = 3.849, damageEffectiveness = 3.849, levelRequirement = 52, statInterpolation = { 1, 1, }, }, + [12] = { 5, 11, baseMultiplier = 3.9848, damageEffectiveness = 3.9848, levelRequirement = 54, statInterpolation = { 1, 1, }, }, + [13] = { 6, 12, baseMultiplier = 4.1262, damageEffectiveness = 4.1262, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [14] = { 6, 13, baseMultiplier = 4.2704, damageEffectiveness = 4.2704, levelRequirement = 58, statInterpolation = { 1, 1, }, }, + [15] = { 6, 14, baseMultiplier = 4.4202, damageEffectiveness = 4.4202, levelRequirement = 60, statInterpolation = { 1, 1, }, }, + [16] = { 6, 15, baseMultiplier = 4.5742, damageEffectiveness = 4.5742, levelRequirement = 62, statInterpolation = { 1, 1, }, }, + [17] = { 6, 16, baseMultiplier = 4.7352, damageEffectiveness = 4.7352, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [18] = { 6, 17, baseMultiplier = 4.899, damageEffectiveness = 4.899, levelRequirement = 66, statInterpolation = { 1, 1, }, }, + [19] = { 7, 18, baseMultiplier = 5.0698, damageEffectiveness = 5.0698, levelRequirement = 68, statInterpolation = { 1, 1, }, }, + [20] = { 7, 19, baseMultiplier = 5.2434, damageEffectiveness = 5.2434, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 7, 20, baseMultiplier = 5.4254, damageEffectiveness = 5.4254, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 7, 21, baseMultiplier = 5.6116, damageEffectiveness = 5.6116, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 7, 22, baseMultiplier = 5.8034, damageEffectiveness = 5.8034, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 7, 23, baseMultiplier = 6.0022, damageEffectiveness = 6.0022, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 8, 24, baseMultiplier = 6.2066, damageEffectiveness = 6.2066, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 8, 25, baseMultiplier = 6.418, damageEffectiveness = 6.418, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 8, 26, baseMultiplier = 6.6364, damageEffectiveness = 6.6364, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 8, 27, baseMultiplier = 6.8618, damageEffectiveness = 6.8618, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 8, 28, baseMultiplier = 7.0928, damageEffectiveness = 7.0928, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 8, 29, baseMultiplier = 7.3322, damageEffectiveness = 7.3322, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 8, 29, baseMultiplier = 7.6808, damageEffectiveness = 7.6808, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 9, 30, baseMultiplier = 7.8096, damageEffectiveness = 7.8096, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 9, 30, baseMultiplier = 7.9398, damageEffectiveness = 7.9398, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 9, 31, baseMultiplier = 8.0714, damageEffectiveness = 8.0714, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 9, 31, baseMultiplier = 8.2072, damageEffectiveness = 8.2072, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 9, 32, baseMultiplier = 8.3444, damageEffectiveness = 8.3444, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 9, 32, baseMultiplier = 8.4844, damageEffectiveness = 8.4844, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 9, 33, baseMultiplier = 8.6258, damageEffectiveness = 8.6258, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 9, 33, baseMultiplier = 8.7686, damageEffectiveness = 8.7686, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 9, 34, baseMultiplier = 8.9142, damageEffectiveness = 8.9142, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["WildStrikeMercenaryEncounter"] = { + name = "Wild Strike", + hidden = true, + mercenary = true, + inheritedFrom = "WildStrike", + color = 2, + description = "Your melee weapon strikes enemies, converting physical damage to a random element. Then, depending on the element chosen, it releases a fiery explosion, an arcing bolt of lightning, or an icy wave. It will avoid choosing the same element twice in a row.", + skillTypes = { [SkillType.Attack] = true, [SkillType.MeleeSingleTarget] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, [SkillType.Lightning] = true, [SkillType.Cold] = true, [SkillType.Fire] = true, [SkillType.Projectile] = true, [SkillType.Area] = true, [SkillType.Chains] = true, [SkillType.RangedAttack] = true, [SkillType.ProjectilesNotFromUser] = true, [SkillType.RandomElement] = true, }, + weaponTypes = { + ["Claw"] = true, + ["Dagger"] = true, + ["One Handed Axe"] = true, + ["One Handed Mace"] = true, + ["One Handed Sword"] = true, + ["Sceptre"] = true, + ["Staff"] = true, + ["Thrusting One Handed Sword"] = true, + ["Two Handed Axe"] = true, + ["Two Handed Mace"] = true, + ["Two Handed Sword"] = true, + }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + projectile = true, + }, + constantStats = { + { "elemental_strike_physical_damage_%_to_convert", 100 }, + { "fixed_projectile_spread", 70 }, + { "base_number_of_projectiles", 3 }, + }, + stats = { + "additional_beam_only_chains", + "base_skill_area_of_effect_+%", + "show_number_of_projectiles", + "always_pierce", + }, + levels = { + [1] = { 4, 0, baseMultiplier = 1.1393, damageEffectiveness = 1.1393, levelRequirement = 28, statInterpolation = { 1, 1, }, }, + [2] = { 4, 1, baseMultiplier = 1.1519, damageEffectiveness = 1.1519, levelRequirement = 31, statInterpolation = { 1, 1, }, }, + [3] = { 4, 2, baseMultiplier = 1.1658, damageEffectiveness = 1.1658, levelRequirement = 34, statInterpolation = { 1, 1, }, }, + [4] = { 4, 3, baseMultiplier = 1.1801, damageEffectiveness = 1.1801, levelRequirement = 37, statInterpolation = { 1, 1, }, }, + [5] = { 4, 4, baseMultiplier = 1.1948, damageEffectiveness = 1.1948, levelRequirement = 40, statInterpolation = { 1, 1, }, }, + [6] = { 4, 5, baseMultiplier = 1.2102, damageEffectiveness = 1.2102, levelRequirement = 42, statInterpolation = { 1, 1, }, }, + [7] = { 5, 6, baseMultiplier = 1.226, damageEffectiveness = 1.226, levelRequirement = 44, statInterpolation = { 1, 1, }, }, + [8] = { 5, 7, baseMultiplier = 1.2418, damageEffectiveness = 1.2418, levelRequirement = 46, statInterpolation = { 1, 1, }, }, + [9] = { 5, 8, baseMultiplier = 1.2578, damageEffectiveness = 1.2578, levelRequirement = 48, statInterpolation = { 1, 1, }, }, + [10] = { 5, 9, baseMultiplier = 1.2747, damageEffectiveness = 1.2747, levelRequirement = 50, statInterpolation = { 1, 1, }, }, + [11] = { 5, 10, baseMultiplier = 1.2921, damageEffectiveness = 1.2921, levelRequirement = 52, statInterpolation = { 1, 1, }, }, + [12] = { 5, 11, baseMultiplier = 1.3098, damageEffectiveness = 1.3098, levelRequirement = 54, statInterpolation = { 1, 1, }, }, + [13] = { 6, 12, baseMultiplier = 1.3285, damageEffectiveness = 1.3285, levelRequirement = 56, statInterpolation = { 1, 1, }, }, + [14] = { 6, 13, baseMultiplier = 1.3478, damageEffectiveness = 1.3478, levelRequirement = 58, statInterpolation = { 1, 1, }, }, + [15] = { 6, 14, baseMultiplier = 1.3675, damageEffectiveness = 1.3675, levelRequirement = 60, statInterpolation = { 1, 1, }, }, + [16] = { 6, 15, baseMultiplier = 1.3881, damageEffectiveness = 1.3881, levelRequirement = 62, statInterpolation = { 1, 1, }, }, + [17] = { 6, 16, baseMultiplier = 1.4082, damageEffectiveness = 1.4082, levelRequirement = 64, statInterpolation = { 1, 1, }, }, + [18] = { 6, 17, baseMultiplier = 1.4292, damageEffectiveness = 1.4292, levelRequirement = 66, statInterpolation = { 1, 1, }, }, + [19] = { 7, 18, baseMultiplier = 1.4509, damageEffectiveness = 1.4509, levelRequirement = 68, statInterpolation = { 1, 1, }, }, + [20] = { 7, 19, baseMultiplier = 1.473, damageEffectiveness = 1.473, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { 7, 20, baseMultiplier = 1.4962, damageEffectiveness = 1.4962, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { 7, 21, baseMultiplier = 1.5198, damageEffectiveness = 1.5198, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { 7, 22, baseMultiplier = 1.5445, damageEffectiveness = 1.5445, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { 7, 23, baseMultiplier = 1.5698, damageEffectiveness = 1.5698, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { 8, 24, baseMultiplier = 1.5961, damageEffectiveness = 1.5961, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { 8, 25, baseMultiplier = 1.6231, damageEffectiveness = 1.6231, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { 8, 26, baseMultiplier = 1.6511, damageEffectiveness = 1.6511, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { 8, 27, baseMultiplier = 1.6799, damageEffectiveness = 1.6799, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { 8, 28, baseMultiplier = 1.7098, damageEffectiveness = 1.7098, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { 8, 29, baseMultiplier = 1.7408, damageEffectiveness = 1.7408, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { 8, 29, baseMultiplier = 1.7856, damageEffectiveness = 1.7856, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { 9, 30, baseMultiplier = 1.8025, damageEffectiveness = 1.8025, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { 9, 30, baseMultiplier = 1.8192, damageEffectiveness = 1.8192, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { 9, 31, baseMultiplier = 1.8363, damageEffectiveness = 1.8363, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { 9, 31, baseMultiplier = 1.8541, damageEffectiveness = 1.8541, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { 9, 32, baseMultiplier = 1.8719, damageEffectiveness = 1.8719, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { 9, 32, baseMultiplier = 1.8899, damageEffectiveness = 1.8899, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { 9, 33, baseMultiplier = 1.9083, damageEffectiveness = 1.9083, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { 9, 33, baseMultiplier = 1.9269, damageEffectiveness = 1.9269, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { 9, 34, baseMultiplier = 1.946, damageEffectiveness = 1.946, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["WindSlashMercenary"] = { + name = "Slicing Wind", + hidden = true, + mercenary = true, + color = 1, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + stats = { + "active_skill_attack_speed_+%_final", + "active_skill_area_of_effect_+%_final", + "active_skill_damage_+%_final", + "is_area_damage", + }, + notMinionStat = { + "active_skill_attack_speed_+%_final", + "active_skill_area_of_effect_+%_final", + "active_skill_damage_+%_final", + }, + levels = { + [1] = { -30, 30, 40, baseMultiplier = 1.1, damageEffectiveness = 1.1, levelRequirement = 1, statInterpolation = { 1, 1, 2, }, }, + [30] = { -30, 40, 60, baseMultiplier = 1.3, damageEffectiveness = 1.3, levelRequirement = 30, statInterpolation = { 1, 1, 2, }, }, + [50] = { -30, 50, 80, baseMultiplier = 1.6, damageEffectiveness = 1.6, levelRequirement = 50, statInterpolation = { 1, 1, 2, }, }, + [67] = { -20, 60, 100, baseMultiplier = 2.2, damageEffectiveness = 2.2, levelRequirement = 67, statInterpolation = { 1, 1, 2, }, }, + [80] = { -10, 60, 150, baseMultiplier = 2.6, damageEffectiveness = 2.6, levelRequirement = 80, statInterpolation = { 1, 1, 2, }, }, + }, +} + +skills["WindSlashMercenaryEncounter"] = { + name = "Slicing Wind", + hidden = true, + mercenary = true, + color = 1, + skillTypes = { [SkillType.Attack] = true, [SkillType.Area] = true, [SkillType.Multistrikeable] = true, [SkillType.Melee] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 1, + baseFlags = { + area = true, + attack = true, + melee = true, + }, + stats = { + "active_skill_attack_speed_+%_final", + "active_skill_area_of_effect_+%_final", + "active_skill_damage_+%_final", + "is_area_damage", + }, + notMinionStat = { + "active_skill_attack_speed_+%_final", + "active_skill_area_of_effect_+%_final", + "active_skill_damage_+%_final", + }, + levels = { + [1] = { -50, 30, 0, baseMultiplier = 1.1, damageEffectiveness = 1.1, levelRequirement = 1, statInterpolation = { 1, 1, 2, }, }, + [30] = { -40, 40, 50, baseMultiplier = 1.3, damageEffectiveness = 1.3, levelRequirement = 30, statInterpolation = { 1, 1, 2, }, }, + [50] = { -30, 50, 100, baseMultiplier = 1.5, damageEffectiveness = 1.5, levelRequirement = 50, statInterpolation = { 1, 1, 2, }, }, + [67] = { -20, 60, 150, baseMultiplier = 1.8, damageEffectiveness = 1.8, levelRequirement = 67, statInterpolation = { 1, 1, 2, }, }, + [80] = { -10, 60, 200, baseMultiplier = 2.1, damageEffectiveness = 2.1, levelRequirement = 80, statInterpolation = { 1, 1, 2, }, }, + }, +} + +skills["WitherTotemMercenary"] = { + name = "Wither Totem", + hidden = true, + mercenary = true, + inheritedFrom = "Wither", + color = 3, + description = "Casts a debilitating debuff on enemies in an area, hindering their movement and also inflicts the Withered debuff, which increases the Chaos Damage they take and can stack up to 15 times.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Duration] = true, [SkillType.Totemable] = true, [SkillType.Chaos] = true, [SkillType.Channel] = true, [SkillType.AreaSpell] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0.28, + baseFlags = { + area = true, + duration = true, + spell = true, + }, + constantStats = { + { "chaos_damage_taken_+%", 6 }, + { "base_skill_effect_duration", 500 }, + { "active_skill_withered_base_duration_ms", 2000 }, + { "base_totem_duration", 8000 }, + { "base_totem_range", 45 }, + }, + stats = { + "base_movement_velocity_+%", + "base_skill_area_of_effect_+%", + "base_skill_is_totemified", + "is_totem", + }, + levels = { + [1] = { -30, 0, levelRequirement = 10, statInterpolation = { 1, 1, }, }, + [2] = { -30, 1, levelRequirement = 13, statInterpolation = { 1, 1, }, }, + [3] = { -30, 2, levelRequirement = 17, statInterpolation = { 1, 1, }, }, + [4] = { -31, 3, levelRequirement = 21, statInterpolation = { 1, 1, }, }, + [5] = { -31, 4, levelRequirement = 25, statInterpolation = { 1, 1, }, }, + [6] = { -31, 5, levelRequirement = 29, statInterpolation = { 1, 1, }, }, + [7] = { -32, 6, levelRequirement = 33, statInterpolation = { 1, 1, }, }, + [8] = { -32, 7, levelRequirement = 36, statInterpolation = { 1, 1, }, }, + [9] = { -32, 8, levelRequirement = 39, statInterpolation = { 1, 1, }, }, + [10] = { -33, 9, levelRequirement = 42, statInterpolation = { 1, 1, }, }, + [11] = { -33, 10, levelRequirement = 45, statInterpolation = { 1, 1, }, }, + [12] = { -33, 11, levelRequirement = 48, statInterpolation = { 1, 1, }, }, + [13] = { -34, 12, levelRequirement = 51, statInterpolation = { 1, 1, }, }, + [14] = { -34, 13, levelRequirement = 54, statInterpolation = { 1, 1, }, }, + [15] = { -34, 14, levelRequirement = 57, statInterpolation = { 1, 1, }, }, + [16] = { -35, 15, levelRequirement = 60, statInterpolation = { 1, 1, }, }, + [17] = { -35, 16, levelRequirement = 63, statInterpolation = { 1, 1, }, }, + [18] = { -35, 17, levelRequirement = 66, statInterpolation = { 1, 1, }, }, + [19] = { -36, 18, levelRequirement = 68, statInterpolation = { 1, 1, }, }, + [20] = { -36, 19, levelRequirement = 70, statInterpolation = { 1, 1, }, }, + [21] = { -36, 20, levelRequirement = 72, statInterpolation = { 1, 1, }, }, + [22] = { -37, 21, levelRequirement = 74, statInterpolation = { 1, 1, }, }, + [23] = { -37, 22, levelRequirement = 76, statInterpolation = { 1, 1, }, }, + [24] = { -37, 23, levelRequirement = 78, statInterpolation = { 1, 1, }, }, + [25] = { -38, 24, levelRequirement = 80, statInterpolation = { 1, 1, }, }, + [26] = { -38, 25, levelRequirement = 82, statInterpolation = { 1, 1, }, }, + [27] = { -38, 26, levelRequirement = 84, statInterpolation = { 1, 1, }, }, + [28] = { -39, 27, levelRequirement = 86, statInterpolation = { 1, 1, }, }, + [29] = { -39, 28, levelRequirement = 88, statInterpolation = { 1, 1, }, }, + [30] = { -39, 29, levelRequirement = 90, statInterpolation = { 1, 1, }, }, + [31] = { -39, 29, levelRequirement = 91, statInterpolation = { 1, 1, }, }, + [32] = { -40, 30, levelRequirement = 92, statInterpolation = { 1, 1, }, }, + [33] = { -40, 30, levelRequirement = 93, statInterpolation = { 1, 1, }, }, + [34] = { -40, 31, levelRequirement = 94, statInterpolation = { 1, 1, }, }, + [35] = { -40, 31, levelRequirement = 95, statInterpolation = { 1, 1, }, }, + [36] = { -40, 32, levelRequirement = 96, statInterpolation = { 1, 1, }, }, + [37] = { -40, 32, levelRequirement = 97, statInterpolation = { 1, 1, }, }, + [38] = { -41, 33, levelRequirement = 98, statInterpolation = { 1, 1, }, }, + [39] = { -41, 33, levelRequirement = 99, statInterpolation = { 1, 1, }, }, + [40] = { -41, 34, levelRequirement = 100, statInterpolation = { 1, 1, }, }, + }, +} + +skills["WitheringStepMercenary"] = { + name = "Withering Step", + hidden = true, + mercenary = true, + inheritedFrom = "WitheringStep", + color = 2, + baseEffectiveness = 0, + description = "Grants Elusive and a buff that grants Phasing. While you have this buff, monsters that enter an area around you will be Withered. Using a skill or losing the Elusive buff ends this skill's effects. Shares a cooldown with other Blink skills. Cannot be used while already Elusive.", + skillTypes = { [SkillType.Travel] = true, [SkillType.Buff] = true, [SkillType.Instant] = true, [SkillType.Area] = true, [SkillType.Chaos] = true, [SkillType.Movement] = true, [SkillType.Blink] = true, [SkillType.Spell] = true, [SkillType.Triggerable] = true, [SkillType.Duration] = true, [SkillType.Cooldown] = true, [SkillType.Totemable] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + duration = true, + movement = true, + spell = true, + }, + constantStats = { + { "active_skill_withered_base_duration_ms", 3000 }, + }, + stats = { + "active_skill_base_radius_+", + "slither_wither_stacks", + "elusive_effect_+%", + "base_deal_no_damage", + "phase_through_objects", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0, 4, 0, cooldown = 3, levelRequirement = 10, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 0, 4, 2, cooldown = 3, levelRequirement = 13, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 1, 4, 4, cooldown = 3, levelRequirement = 17, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 1, 4, 6, cooldown = 3, levelRequirement = 21, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 1, 4, 8, cooldown = 3, levelRequirement = 25, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 2, 4, 10, cooldown = 3, levelRequirement = 29, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 2, 5, 12, cooldown = 3, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 2, 5, 14, cooldown = 3, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 3, 5, 16, cooldown = 3, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 3, 5, 18, cooldown = 3, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 3, 5, 20, cooldown = 3, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 4, 5, 22, cooldown = 3, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 4, 5, 24, cooldown = 3, levelRequirement = 51, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 4, 6, 26, cooldown = 3, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 5, 6, 28, cooldown = 3, levelRequirement = 57, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 5, 6, 30, cooldown = 3, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 5, 6, 32, cooldown = 3, levelRequirement = 63, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 6, 6, 34, cooldown = 3, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 6, 6, 36, cooldown = 3, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 6, 6, 38, cooldown = 3, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 7, 7, 40, cooldown = 3, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 7, 7, 42, cooldown = 3, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 7, 7, 44, cooldown = 3, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 8, 7, 46, cooldown = 3, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 8, 7, 48, cooldown = 3, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 8, 7, 50, cooldown = 3, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 9, 7, 52, cooldown = 3, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 9, 8, 54, cooldown = 3, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 9, 8, 56, cooldown = 3, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 10, 8, 58, cooldown = 3, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 10, 8, 59, cooldown = 3, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 10, 8, 60, cooldown = 3, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 11, 8, 61, cooldown = 3, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 11, 8, 62, cooldown = 3, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 11, 8, 63, cooldown = 3, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 12, 8, 64, cooldown = 3, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 12, 8, 65, cooldown = 3, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 12, 8, 66, cooldown = 3, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 13, 8, 67, cooldown = 3, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 13, 9, 68, cooldown = 3, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} + +skills["WrathMercenary"] = { + name = "Wrath", + hidden = true, + mercenary = true, + inheritedFrom = "Wrath", + color = 3, + baseEffectiveness = 2.25, + incrementalEffectiveness = 0.023000000044703, + description = "Casts an aura that adds lightning damage to the attacks of you and your allies, and makes your spells deal more lightning damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Lightning] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "attack_minimum_added_lightning_damage", + "attack_maximum_added_lightning_damage", + "active_skill_base_radius_+", + "wrath_aura_spell_lightning_damage_+%_final", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.050000000745058, 0.80000001192093, 0, 15, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [2] = { 0.050000000745058, 0.80000001192093, 1, 15, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [3] = { 0.050000000745058, 0.80000001192093, 2, 15, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [4] = { 0.050000000745058, 0.80000001192093, 3, 16, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [5] = { 0.050000000745058, 0.80000001192093, 4, 16, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [6] = { 0.050000000745058, 0.80000001192093, 5, 16, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [7] = { 0.050000000745058, 0.80000001192093, 6, 17, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [8] = { 0.050000000745058, 0.80000001192093, 7, 17, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [9] = { 0.050000000745058, 0.80000001192093, 8, 17, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [10] = { 0.050000000745058, 0.80000001192093, 9, 18, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [11] = { 0.050000000745058, 0.80000001192093, 10, 18, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [12] = { 0.050000000745058, 0.80000001192093, 11, 18, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [13] = { 0.050000000745058, 0.80000001192093, 12, 19, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [14] = { 0.050000000745058, 0.80000001192093, 13, 19, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [15] = { 0.050000000745058, 0.80000001192093, 14, 19, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [16] = { 0.050000000745058, 0.80000001192093, 15, 20, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [17] = { 0.050000000745058, 0.80000001192093, 16, 20, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [18] = { 0.050000000745058, 0.80000001192093, 17, 20, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [19] = { 0.050000000745058, 0.80000001192093, 18, 21, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [20] = { 0.050000000745058, 0.80000001192093, 19, 21, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [21] = { 0.050000000745058, 0.80000001192093, 20, 21, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [22] = { 0.050000000745058, 0.80000001192093, 21, 22, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [23] = { 0.050000000745058, 0.80000001192093, 22, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [24] = { 0.050000000745058, 0.80000001192093, 23, 22, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [25] = { 0.050000000745058, 0.80000001192093, 24, 23, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [26] = { 0.050000000745058, 0.80000001192093, 25, 23, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [27] = { 0.050000000745058, 0.80000001192093, 26, 23, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [28] = { 0.050000000745058, 0.80000001192093, 27, 24, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [29] = { 0.050000000745058, 0.80000001192093, 28, 24, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [30] = { 0.050000000745058, 0.80000001192093, 29, 24, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [31] = { 0.050000000745058, 0.80000001192093, 29, 24, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [32] = { 0.050000000745058, 0.80000001192093, 30, 25, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [33] = { 0.050000000745058, 0.80000001192093, 30, 25, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [34] = { 0.050000000745058, 0.80000001192093, 31, 25, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [35] = { 0.050000000745058, 0.80000001192093, 31, 25, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [36] = { 0.050000000745058, 0.80000001192093, 32, 25, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [37] = { 0.050000000745058, 0.80000001192093, 32, 25, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [38] = { 0.050000000745058, 0.80000001192093, 33, 26, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [39] = { 0.050000000745058, 0.80000001192093, 33, 26, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + [40] = { 0.050000000745058, 0.80000001192093, 34, 26, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 1, 1, }, }, + }, +} + +skills["WrathMercenaryEncounter"] = { + name = "Wrath", + hidden = true, + mercenary = true, + inheritedFrom = "Wrath", + color = 3, + baseEffectiveness = 2.25, + incrementalEffectiveness = 0.023000000044703, + description = "Casts an aura that adds lightning damage to the attacks of you and your allies, and makes your spells deal more lightning damage.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Lightning] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + stats = { + "attack_minimum_added_lightning_damage", + "attack_maximum_added_lightning_damage", + "active_skill_base_radius_+", + "wrath_aura_spell_lightning_damage_+%_final", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 0.0099999997764826, 0.15999999642372, 0, 10, cooldown = 1.2, levelRequirement = 1, storedUses = 1, statInterpolation = { 3, 3, 2, 2, }, }, + [2] = { 0.0099999997764826, 0.15999999642372, 34, 30, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 3, 3, 2, 2, }, }, + }, +} + +skills["ZealotryMercenary"] = { + name = "Zealotry", + hidden = true, + mercenary = true, + inheritedFrom = "Zealotry", + color = 3, + baseEffectiveness = 1.5, + incrementalEffectiveness = 0.025000000372529, + description = "Casts an aura that grants bonuses to damage and critical strike chance of spells to you and your allies, and gives a chance to create Consecrated Ground against stronger enemies.", + skillTypes = { [SkillType.Spell] = true, [SkillType.Area] = true, [SkillType.Buff] = true, [SkillType.HasReservation] = true, [SkillType.TotemCastsAlone] = true, [SkillType.Totemable] = true, [SkillType.Aura] = true, [SkillType.Instant] = true, [SkillType.AreaSpell] = true, [SkillType.CanHaveBlessing] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "aura_skill_stat_descriptions", + castTime = 0.3, + baseFlags = { + area = true, + aura = true, + spell = true, + }, + constantStats = { + { "create_consecrated_ground_on_hit_%_vs_rare_or_unique_enemy", 10 }, + }, + stats = { + "spell_damage_aura_spell_damage_+%_final", + "spell_critical_strike_chance_+%", + "active_skill_base_radius_+", + "base_deal_no_damage", + }, + notMinionStat = { + "active_skill_base_radius_+", + }, + levels = { + [1] = { 10, 20, 0, cooldown = 1.2, levelRequirement = 24, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [2] = { 10, 21, 1, cooldown = 1.2, levelRequirement = 27, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [3] = { 10, 22, 2, cooldown = 1.2, levelRequirement = 30, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [4] = { 11, 23, 3, cooldown = 1.2, levelRequirement = 33, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [5] = { 11, 24, 4, cooldown = 1.2, levelRequirement = 36, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [6] = { 11, 25, 5, cooldown = 1.2, levelRequirement = 39, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [7] = { 12, 26, 6, cooldown = 1.2, levelRequirement = 42, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [8] = { 12, 27, 7, cooldown = 1.2, levelRequirement = 45, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [9] = { 12, 28, 8, cooldown = 1.2, levelRequirement = 48, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [10] = { 12, 29, 9, cooldown = 1.2, levelRequirement = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [11] = { 13, 30, 10, cooldown = 1.2, levelRequirement = 52, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [12] = { 13, 31, 11, cooldown = 1.2, levelRequirement = 54, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [13] = { 13, 32, 12, cooldown = 1.2, levelRequirement = 56, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [14] = { 14, 33, 13, cooldown = 1.2, levelRequirement = 58, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [15] = { 14, 34, 14, cooldown = 1.2, levelRequirement = 60, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [16] = { 14, 35, 15, cooldown = 1.2, levelRequirement = 62, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [17] = { 14, 36, 16, cooldown = 1.2, levelRequirement = 64, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [18] = { 15, 37, 17, cooldown = 1.2, levelRequirement = 66, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [19] = { 15, 38, 18, cooldown = 1.2, levelRequirement = 68, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [20] = { 15, 39, 19, cooldown = 1.2, levelRequirement = 70, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [21] = { 16, 40, 20, cooldown = 1.2, levelRequirement = 72, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [22] = { 16, 41, 21, cooldown = 1.2, levelRequirement = 74, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [23] = { 16, 42, 22, cooldown = 1.2, levelRequirement = 76, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [24] = { 16, 43, 23, cooldown = 1.2, levelRequirement = 78, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [25] = { 17, 44, 24, cooldown = 1.2, levelRequirement = 80, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [26] = { 17, 45, 25, cooldown = 1.2, levelRequirement = 82, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [27] = { 17, 46, 26, cooldown = 1.2, levelRequirement = 84, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [28] = { 18, 47, 27, cooldown = 1.2, levelRequirement = 86, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [29] = { 18, 48, 28, cooldown = 1.2, levelRequirement = 88, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [30] = { 18, 49, 29, cooldown = 1.2, levelRequirement = 90, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [31] = { 18, 49, 29, cooldown = 1.2, levelRequirement = 91, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [32] = { 18, 50, 30, cooldown = 1.2, levelRequirement = 92, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [33] = { 19, 50, 30, cooldown = 1.2, levelRequirement = 93, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [34] = { 19, 51, 31, cooldown = 1.2, levelRequirement = 94, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [35] = { 19, 51, 31, cooldown = 1.2, levelRequirement = 95, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [36] = { 19, 52, 32, cooldown = 1.2, levelRequirement = 96, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [37] = { 19, 52, 32, cooldown = 1.2, levelRequirement = 97, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [38] = { 19, 53, 33, cooldown = 1.2, levelRequirement = 98, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [39] = { 19, 53, 33, cooldown = 1.2, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + [40] = { 20, 54, 34, cooldown = 1.2, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, }, }, + }, +} +end diff --git a/src/Export/Classes/GGPKData.lua b/src/Export/Classes/GGPKData.lua index 7e4e21c1a6c..dd9b5772ef8 100644 --- a/src/Export/Classes/GGPKData.lua +++ b/src/Export/Classes/GGPKData.lua @@ -274,7 +274,9 @@ function GGPKClass:GetNeededFiles() "Data/DivinationBuffTemplates.dat", "Data/MinionDoublingStatTypes.dat", "Data/MercenaryAttributes.dat", + "Data/MercenaryBuildExtraStats.dat", "Data/MercenaryBuilds.dat", + "Data/MercenaryBuildStatsCategories.dat", "Data/MercenaryClasses.dat", "Data/MercenarySkillFamilies.dat", "Data/MercenarySkills.dat", diff --git a/src/Export/MercenaryExport.lua b/src/Export/MercenaryExport.lua new file mode 100644 index 00000000000..a50aba9d953 --- /dev/null +++ b/src/Export/MercenaryExport.lua @@ -0,0 +1,125 @@ +-- Path of Building +-- +-- Exporter: MercenaryExport +-- Exporter-only validation helpers for Mercenary data. The running calculator +-- does not load this module. + +local MercenaryExport = { } + +MercenaryExport.MONSTER_SPEED_DAMAGE_FIXUP_STAT = "monster_base_type_attack_cast_speed_+%_and_damage_-%_final" + +function MercenaryExport.monsterSpeedAndDamageFixup(modId, stats) + if type(modId) ~= "string" or not modId:find("SpeedAndDamageFixup", 1, true) then + return nil + end + for _, stat in ipairs(stats or { }) do + if stat.id == MercenaryExport.MONSTER_SPEED_DAMAGE_FIXUP_STAT and tonumber(stat.value) then + return tonumber(stat.value) / 100 + end + end + error("Unrecognized monster speed/damage fixup: "..modId) +end + +function MercenaryExport.considerRankedCandidate(current, id, rank) + if not current or rank < current.rank then + return { id = id, rank = rank, ids = { id } } + end + if rank > current.rank then + return current + end + local ids = { } + for _, existing in ipairs(current.ids) do + ids[#ids + 1] = existing + end + ids[#ids + 1] = id + return { + id = id < current.id and id or current.id, + rank = rank, + ids = ids, + } +end + +function MercenaryExport.requireUniqueRankedCandidate(current, context) + if not current then + return nil + end + if #current.ids > 1 then + local ids = { } + for _, id in ipairs(current.ids) do + ids[#ids + 1] = id + end + table.sort(ids) + error("Ambiguous "..context..": "..table.concat(ids, ", ")) + end + return current +end + +function MercenaryExport.uniqueCandidate(candidate) + return candidate and candidate.ids and #candidate.ids == 1 and candidate or nil +end + +-- Unique ActiveSkill/name matches win. Remaining ties require an explicit +-- override. There is no fallback to a previously generated mercenary.lua. +function MercenaryExport.resolveBaseSkill(context) + local byActiveSkill = context.byActiveSkill + local byDisplayName = context.byDisplayName + local base = MercenaryExport.uniqueCandidate(byActiveSkill) + if MercenaryExport.uniqueCandidate(byDisplayName) and (not base or byDisplayName.rank < base.rank) then + base = byDisplayName + end + if base == byActiveSkill and base ~= nil then + return { id = base.id, source = "activeSkill" } + end + if base then + return { id = base.id, source = "displayName" } + end + local overrideId = context.overrideId + if overrideId then + if not context.isExportedSkill or not context.isExportedSkill(overrideId) then + error("Mercenary base-skill override is not an exported skill: "..context.effectId.." -> "..overrideId) + end + return { id = overrideId, source = "override" } + end + if byActiveSkill then + MercenaryExport.requireUniqueRankedCandidate(byActiveSkill, "Mercenary base skill ActiveSkill '"..context.activeSkillId.."'") + end + if byDisplayName then + MercenaryExport.requireUniqueRankedCandidate(byDisplayName, "Mercenary base skill display name '"..context.displayName.."'") + end +end + +function MercenaryExport.shieldPolicyError(builds, shieldPolicy) + local function hasShield(weaponTypes) + for _, itemType in ipairs(weaponTypes or { }) do + if itemType == "Shield" then + return true + end + end + return false + end + for buildId, mercBuild in pairs(builds or { }) do + if hasShield(mercBuild.weaponTypes) then + local policy = shieldPolicy and shieldPolicy[buildId] + if not policy then + return "missing shield policy for Mercenary build: "..buildId + end + if policy ~= "required" and policy ~= "optional" then + return "unknown shield policy for Mercenary build: "..buildId + end + end + end + for buildId, policy in pairs(shieldPolicy or { }) do + if policy ~= "required" and policy ~= "optional" then + return "unknown shield policy for Mercenary build: "..buildId + end + local mercBuild = builds and builds[buildId] + if not mercBuild then + return "shield policy references unknown Mercenary build: "..buildId + end + if not hasShield(mercBuild.weaponTypes) then + return "shield policy for "..buildId.." does not include a Shield" + end + end +end + +return MercenaryExport diff --git a/src/Export/Scripts/mercenaries.lua b/src/Export/Scripts/mercenaries.lua new file mode 100644 index 00000000000..a23aeb41361 --- /dev/null +++ b/src/Export/Scripts/mercenaries.lua @@ -0,0 +1,549 @@ +local function sortedRows(name, key) + local rows = { } + for row in dat(name):Rows() do + table.insert(rows, row) + end + table.sort(rows, function(a, b) + return tostring(key(a)) < tostring(key(b)) + end) + return rows +end + +local function rowId(row) + return row and (row.Id.Id or row.Id) +end + +local function rowIds(rows) + local ids = { } + for _, row in ipairs(rows or { }) do + table.insert(ids, rowId(row)) + end + table.sort(ids) + return ids +end + +local function uniqueSorted(values) + local seen, result = { }, { } + for _, value in ipairs(values) do + if value and not seen[value] then + seen[value] = true + table.insert(result, value) + end + end + table.sort(result) + return result +end + +local function getOTStats(objectType, stats, visited) + if not objectType or objectType == "" or objectType == "Metadata/Monsters/Monster" or objectType == "nothing" then + return + end + visited = visited or { } + if visited[objectType] then + return + end + visited[objectType] = true + local text = getFile(objectType..".ot") + if not text then + error("Missing Mercenary object template: "..objectType..".ot") + end + text = convertUTF16to8(text) + local parent = text:match('extends "([^"]+)"') + getOTStats(parent, stats, visited) + local inStats = false + for line in text:gmatch("[^\r\n]+") do + if line:match("^Stats") then + inStats = true + elseif inStats and line:match("^}") then + inStats = false + elseif inStats and line:find("=") and not line:find("//") then + local id, value = line:gsub("%s+", ""):match("^([^=]+)=(.+)$") + if id and tonumber(value) then + table.insert(stats, { id = id, value = tonumber(value), source = objectType }) + end + end + end +end + +-- The `Monster { }` block of an object template holds engine flags rather than +-- stats, so it needs its own pass. +local function getOTMonsterProperties(objectType, properties, visited) + if not objectType or objectType == "" or objectType == "Metadata/Monsters/Monster" or objectType == "nothing" then + return + end + visited = visited or { } + if visited[objectType] then + return + end + visited[objectType] = true + local text = getFile(objectType..".ot") + if not text then + error("Missing Mercenary object template: "..objectType..".ot") + end + text = convertUTF16to8(text) + getOTMonsterProperties(text:match('extends "([^"]+)"'), properties, visited) + local inMonster = false + for line in text:gmatch("[^\r\n]+") do + if line:match("^Monster") then + inMonster = true + elseif inMonster and line:match("^}") then + inMonster = false + elseif inMonster and line:find("=") and not line:find("//") then + local id, value = line:gsub("%s+", ""):match("^([^=]+)=(.+)$") + if id then + properties[id] = tonumber(value) or value == "true" or value + end + end + end +end + +local function appendModStats(mods, stats) + for _, modRow in ipairs(mods or { }) do + for index = 1, 6 do + local stat = modRow["Stat"..index] + local values = modRow["Stat"..index.."Value"] + if stat and values and values[1] then + table.insert(stats, { id = stat.Id, value = values[1], source = modRow.Id }) + end + end + end +end + +local itemClassMap = { + ["Claw"] = "Claw", + ["Dagger"] = "Dagger", + ["Rune Dagger"] = "Dagger", + ["Wand"] = "Wand", + ["One Hand Sword"] = "One Handed Sword", + ["Thrusting One Hand Sword"] = "Thrusting One Handed Sword", + ["One Hand Axe"] = "One Handed Axe", + ["One Hand Mace"] = "One Handed Mace", + ["Bow"] = "Bow", + ["Quiver"] = "Quiver", + ["Fishing Rod"] = "Fishing Rod", + ["Staff"] = "Staff", + ["Warstaff"] = "Staff", + ["Two Hand Sword"] = "Two Handed Sword", + ["Two Hand Axe"] = "Two Handed Axe", + ["Two Hand Mace"] = "Two Handed Mace", + ["Shield"] = "Shield", + ["Sceptre"] = "Sceptre", + ["Unarmed"] = "None", +} + +local passiveStatFormats = { + base_strength = { format = "+%s to Strength" }, + base_dexterity = { format = "+%s to Dexterity" }, + base_intelligence = { format = "+%s to Intelligence" }, + ["physical_damage_reduction_rating_+%"] = { format = "%s%% increased Armour" }, + ["evasion_rating_+%"] = { format = "%s%% increased Evasion Rating" }, + ["maximum_energy_shield_+%"] = { format = "%s%% increased maximum Energy Shield" }, + ["life_regeneration_rate_per_minute_%"] = { format = "Regenerate %s%% of Life per second", divisor = 60 }, + ["energy_shield_recharge_rate_+%"] = { format = "%s%% increased Energy Shield Recharge Rate" }, + ["energy_shield_delay_-%"] = { format = "%s%% faster start of Energy Shield Recharge" }, + ["base_spell_suppression_chance_%"] = { format = "+%s%% chance to Suppress Spell Damage" }, + ["maximum_life_+%"] = { format = "%s%% increased maximum Life" }, + ["damage_+%"] = { format = "%s%% increased Damage" }, + ["critical_strike_chance_+%"] = { format = "%s%% increased Critical Strike Chance" }, + ["base_critical_strike_multiplier_+"] = { format = "+%s%% to Critical Strike Multiplier" }, + ["dot_multiplier_+"] = { format = "+%s%% to Damage over Time Multiplier" }, + ["attack_speed_+%"] = { format = "%s%% increased Attack Speed" }, + ["base_cast_speed_+%"] = { format = "%s%% increased Cast Speed" }, + ["trap_throwing_speed_+%"] = { format = "%s%% increased Trap Throwing Speed" }, + ["accuracy_rating_+%"] = { format = "%s%% increased Accuracy Rating" }, + resolute_technique = { line = "Resolute Technique" }, + ["base_chance_to_freeze_%"] = { format = "%s%% chance to Freeze" }, + ["chill_effect_+%"] = { format = "%s%% increased Effect of Chill" }, + ["base_chance_to_ignite_%"] = { format = "%s%% chance to Ignite" }, + ["ignite_duration_+%"] = { format = "%s%% increased Ignite Duration" }, + ["base_chance_to_shock_%"] = { format = "%s%% chance to Shock" }, + ["shock_effect_+%"] = { format = "%s%% increased Effect of Shock" }, + ["base_chance_to_poison_on_hit_%"] = { format = "%s%% chance to Poison on Hit" }, + ["base_poison_duration_+%"] = { format = "%s%% increased Poison Duration" }, + ["bleed_on_hit_with_attacks_%"] = { format = "%s%% chance to cause Bleeding" }, + ["base_bleed_duration_+%"] = { format = "%s%% increased Bleed Duration" }, + ["attacks_impale_on_hit_%_chance"] = { format = "%s%% chance to Impale Enemies on Hit with Attacks" }, + ["impale_debuff_effect_+%"] = { format = "%s%% increased Impale Effect" }, + ["base_stun_threshold_reduction_+%"] = { format = "%s%% reduced Enemy Stun Threshold" }, + ["base_stun_duration_+%"] = { format = "%s%% increased Stun Duration on Enemies" }, + ["hits_ignore_enemy_monster_physical_damage_reduction_%_chance"] = { format = "Hits have %s%% chance to ignore Enemy Physical Damage Reduction" }, + ["minion_damage_+%"] = { format = "Minions deal %s%% increased Damage" }, + ["minion_maximum_life_+%"] = { format = "Minions have %s%% increased maximum Life" }, + ["minion_life_regeneration_rate_per_minute_%"] = { format = "Minions Regenerate %s%% of Life per second", divisor = 60 }, + ["minion_critical_strike_chance_+%"] = { format = "Minions have %s%% increased Critical Strike Chance" }, + ["minion_critical_strike_multiplier_+"] = { format = "Minions have +%s%% to Critical Strike Multiplier" }, + ["minion_attack_speed_+%"] = { format = "Minions have %s%% increased Attack Speed" }, + ["minion_cast_speed_+%"] = { format = "Minions have %s%% increased Cast Speed" }, + minion_damage_increases_and_reductions_also_affects_you = { line = "Increases and Reductions to Minion Damage also affect you" }, + keystone_minion_instability = { line = "Minion Instability" }, + base_phasing_without_visual = { line = "Phasing" }, + ["monster_base_block_%"] = { format = "+%s%% Chance to Block Attack Damage" }, + ["base_spell_block_%"] = { format = "+%s%% Chance to Block Spell Damage" }, +} + +-- Hand-authored Mercenary policy lives with the rest of the hand-authored data +-- rather than in the extraction path. Only the policy tables are read here, so the +-- stat map's mod constructors do not need real implementations, but its mod flags +-- are still evaluated as the file loads. +dofile("../Data/Global.lua") +local function stubMod() return { } end +local mercenaryStatData = LoadModule("../Data/MercenaryStatMap.lua")(stubMod, stubMod, stubMod) +local MercenaryExport = LoadModule("MercenaryExport") +local shieldPolicy = mercenaryStatData.shieldPolicy +local supportCounts = mercenaryStatData.supportCounts +for _, row in ipairs(sortedRows("MercenarySupportCounts", function(value) return value.Id end)) do + if not supportCounts[row.Id] then + error("Missing support-count policy for: "..tostring(row.Id)) + end +end + +-- Every stat a permanent Mercenary gains from its object template is either +-- exported or listed here with the reason it is not, so that a stat GGG adds later +-- fails the export instead of disappearing. +local mercenaryAdditionStatUses = { + life_per_level = true, + mana_per_level = true, + accuracy_rating_per_level = true, + -- Cancels the Life a monster gains from being Rare. PoB models the Mercenary as + -- a normalized actor that never receives that bonus, so applying the correction + -- on its own would remove Life the actor never had. + ["monster_life_+%_final_from_rarity"] = false, + -- Only governs whether kills by the Mercenary grant experience and drops. + eligible_to_grant_kill_bonuses = false, +} + +local mercenaryAdditionStats = { } +getOTStats("Metadata/Monsters/Mercenaries/MercenaryAdditions", mercenaryAdditionStats) +local mercenaryAdditionStatsById = { } +for _, stat in ipairs(mercenaryAdditionStats) do + if mercenaryAdditionStatUses[stat.id] == nil then + error("Unhandled permanent Mercenary base stat: "..stat.id) + end + mercenaryAdditionStatsById[stat.id] = stat.value +end +for statId, exported in pairs(mercenaryAdditionStatUses) do + if exported and not mercenaryAdditionStatsById[statId] then error("Missing permanent Mercenary base stat: "..statId) end +end + +local mercenaryAdditionProperties = { } +getOTMonsterProperties("Metadata/Monsters/Mercenaries/MercenaryAdditions", mercenaryAdditionProperties) +if mercenaryAdditionProperties.disable_default_monster_stats ~= true then + error("Permanent Mercenaries no longer disable the default monster stats") +end + +for row in dat("MercenaryBuildExtraStats"):Rows() do + if not row.Stat or not passiveStatFormats[row.Stat.Id] then + error("Unsupported Mercenary passive stat: "..tostring(row.Stat and row.Stat.Id or row.Id)) + end +end + +local permanentMercenaryDamageMore +for passive in dat("PassiveSkills"):Rows() do + for index, stat in ipairs(passive.Stats or { }) do + if stat.Id == "permanenet_mercenary_damage_+%_final_and_minion_damage_+%_final_from_luminary" then + if permanentMercenaryDamageMore ~= nil then + error("Permanent Mercenary damage stat is present on more than one passive") + end + -- This is the maximum MORE penalty. 3.29.1 tapers it in by Mercenary + -- level; `MercenaryTools.permanentDamageMore` applies that curve. + permanentMercenaryDamageMore = passive["Stat"..index] + end + end +end +if permanentMercenaryDamageMore == nil then error("Missing permanent Mercenary damage stat") end + +local function exportMonster(variety) + if not variety then + error("Mercenary class has no allied MonsterVariety") + end + local stats = { } + appendModStats(variety.Mods, stats) + appendModStats(variety.SpecialMods, stats) + getOTStats(variety.ObjectType, stats) + -- Sort by stat id, then by the mod or object template that granted it, so that a + -- stat granted twice keeps a stable order across re-exports. + table.sort(stats, function(a, b) + if a.id ~= b.id then + return a.id < b.id + end + return tostring(a.source) < tostring(b.source) + end) + local monster = { + id = variety.Id, + name = variety.Name, + life = variety.LifeMultiplier / 100, + -- Monsters get 40% of the Energy Shield their type states; `minions.lua` applies + -- the same conversion when exporting Spectres. + energyShield = variety.Type.EnergyShield == 0 and 0 or 0.4 * variety.Type.EnergyShield / 100, + armour = variety.Type.Armour / 100, + evasion = variety.Type.Evasion / 100, + fireResist = variety.Type.Resistances.FireMerciless, + coldResist = variety.Type.Resistances.ColdMerciless, + lightningResist = variety.Type.Resistances.LightningMerciless, + chaosResist = variety.Type.Resistances.ChaosMerciless, + damage = variety.DamageMultiplier / 100, + damageSpread = variety.Type.DamageSpread / 100, + attackTime = variety.AttackDuration / 1000, + attackRange = variety.MaximumAttackRange, + accuracy = variety.Type.Accuracy / 100, + baseDamageIgnoresAttackSpeed = variety.Type.BaseDamageIgnoresAttackSpeed or nil, + lifeScaling = variety.Type.AltLife1 and "AltLife1" or variety.Type.AltLife2 and "AltLife2" or nil, + weaponType1 = variety.MainHandItemClass and itemClassMap[variety.MainHandItemClass.Id] or nil, + weaponType2 = variety.OffHandItemClass and itemClassMap[variety.OffHandItemClass.Id] or nil, + skillIds = rowIds(variety.GrantedEffects), + stats = stats, + } + for _, modRow in ipairs(variety.Mods or { }) do + local modStats = { } + for index = 1, 6 do + local stat = modRow["Stat"..index] + local values = modRow["Stat"..index.."Value"] + if stat and values and values[1] then + table.insert(modStats, { id = stat.Id, value = values[1] }) + end + end + local fixup = MercenaryExport.monsterSpeedAndDamageFixup(modRow.Id, modStats) + if fixup then + monster.damageFixup = fixup + end + end + return monster +end + +local function constantStatValue(grantedEffect, wantedStatId) + for index, stat in ipairs(grantedEffect.GrantedEffectStatSets.ConstantStats or { }) do + if stat.Id == wantedStatId then + return grantedEffect.GrantedEffectStatSets.ConstantStatsValues[index] + end + end +end + +local mercenaries = { + baseStats = { + lifePerLevel = mercenaryAdditionStatsById.life_per_level, + manaPerLevel = mercenaryAdditionStatsById.mana_per_level, + accuracyPerLevel = mercenaryAdditionStatsById.accuracy_rating_per_level, + -- MercenaryAdditions sets `disable_default_monster_stats`, so Life, Mana and + -- Accuracy come from the per-level grants above rather than the monster level + -- tables. Armour, Evasion and Energy Shield have no per-level replacement, + -- which leaves the Mercenary with none of them until it equips items. + disableDefaultMonsterStats = true, + }, + permanentMercenaryDamageMore = permanentMercenaryDamageMore, + classes = { }, + classOrder = { }, + builds = { }, + buildOrder = { }, + skills = { }, + supports = { }, + minions = { }, + summonedMinions = { }, + skillFamilies = { }, + supportFamilies = { }, + skillsByHash = { }, + supportsByHash = { }, +} + +local supportCount = 0 + +for _, row in ipairs(sortedRows("MercenarySupports", function(value) return value.Id end)) do + local familyId = rowId(row.SupportFamily) + if row.HASH16 == nil then error("Mercenary support is missing hash data: "..row.Id) end + local stats = { } + if #row.Stat ~= #row.StatValues then + error("Mercenary support stat/value count mismatch: "..row.Id) + end + for index, stat in ipairs(row.Stat) do + table.insert(stats, { id = stat.Id, value = row.StatValues[index] }) + end + mercenaries.supports[row.Id] = { + id = row.Id, + name = row.Name, + familyId = familyId, + hash = row.HASH16, + variant = row.Variant, + icon = row.GemIcon, + stats = stats, + } + if familyId then mercenaries.supportFamilies[familyId] = { id = familyId } end + supportCount = supportCount + 1 + local hash = tostring(row.HASH16) + mercenaries.supportsByHash[hash] = mercenaries.supportsByHash[hash] or { } + table.insert(mercenaries.supportsByHash[hash], row.Id) +end + +local skillCount = 0 +for _, row in ipairs(sortedRows("MercenarySkills", function(value) return rowId(value.Id) end)) do + local id = rowId(row.Id) + local familyId = rowId(row.SkillFamily) + local supportCountId = rowId(row.SupportCount) + if row.HASH16 == nil or not supportCounts[supportCountId] then + error("Mercenary skill is missing hash or support-count data: "..tostring(id)) + end + mercenaries.skills[id] = { + id = id, + name = row.Name, + description = row.Description, + familyId = familyId, + hash = row.HASH16, + supportCountId = supportCountId, + possibleSupportIds = rowIds(row.PossibleSupports), + secondarySkillId = rowId(row.SecondaryGrantedEffect), + icon = row.HouseSkillIcon, + } + for _, effect in ipairs({ row.Id, row.SecondaryGrantedEffect }) do + if effect then + local summonedId = constantStatValue(effect, "alternate_minion") + if summonedId then + local summoned = dat("SummonedSpecificMonsters"):GetRow("Id", summonedId) + local variety = summoned and summoned.MonsterVarietiesKey + if not variety then error("Mercenary skill references missing summoned monster: "..effect.Id.." -> "..summonedId) end + mercenaries.summonedMinions[effect.Id] = variety.Id + mercenaries.minions[variety.Id] = mercenaries.minions[variety.Id] or exportMonster(variety) + end + end + end + if familyId then mercenaries.skillFamilies[familyId] = { id = familyId } end + skillCount = skillCount + 1 + local hash = tostring(row.HASH16) + mercenaries.skillsByHash[hash] = mercenaries.skillsByHash[hash] or { } + table.insert(mercenaries.skillsByHash[hash], id) +end + +for skillId, skill in pairs(mercenaries.skills) do + for _, supportId in ipairs(skill.possibleSupportIds) do + if not mercenaries.supports[supportId] then + error("Mercenary skill references missing support: "..skillId.." -> "..supportId) + end + end + if skill.secondarySkillId and not dat("GrantedEffects"):GetRow("Id", skill.secondarySkillId) then + error("Mercenary skill references missing secondary effect: "..skillId.." -> "..skill.secondarySkillId) + end +end + +for _, row in ipairs(sortedRows("MercenaryClasses", function(value) return value.Id end)) do + local class = { + id = row.Id, + name = row.MonsterVarietyAllied.Name ~= "" and row.MonsterVarietyAllied.Name or row.MonsterVariety.Name, + attributeId = rowId(row.Attribute), + attributeName = row.Attribute.Name, + attributeTags = rowIds(row.Attribute.Tag), + icon = row.Icon, + houseIcon = row.HouseIcon, + buffIcon = row.BuffIcon, + monster = exportMonster(row.MonsterVarietyAllied), + buildIds = { }, + skillIds = { }, + } + mercenaries.classes[row.Id] = class + table.insert(mercenaries.classOrder, row.Id) +end + +for _, row in ipairs(sortedRows("MercenaryBuilds", function(value) return value.Id end)) do + local idleSkillId = row.IdleSkill and rowId(row.IdleSkill.Id) + if idleSkillId ~= "DoLiterallyNothing" then + error("Unsupported Mercenary idle skill: "..row.Id.." -> "..tostring(idleSkillId)) + end + local pools = { + { skillIds = rowIds(row.Skill1), countMax = row.Skill1CountMax }, + { skillIds = rowIds(row.Skill2), countMax = row.Skill2CountMax }, + { skillIds = rowIds(row.Skill3) }, + } + local allSkills = { } + for _, pool in ipairs(pools) do + for _, id in ipairs(pool.skillIds) do + table.insert(allSkills, id) + end + end + local weaponTypes = { } + for _, wieldableType in ipairs(row.WeaponTypes) do + local itemClassId = rowId(wieldableType.ItemClasses) + local itemType = itemClassMap[itemClassId] + if not itemType then error("Unsupported Mercenary item class: "..tostring(itemClassId)) end + table.insert(weaponTypes, itemType) + end + weaponTypes = uniqueSorted(weaponTypes) + local mainHandTypes = { } + local requiresShield, requiresQuiver = false, false + for _, itemType in ipairs(weaponTypes) do + if itemType == "Shield" then + requiresShield = true + elseif itemType == "Quiver" then + requiresQuiver = true + else + table.insert(mainHandTypes, itemType) + end + end + local optionalShield = requiresShield and shieldPolicy[row.Id] == "optional" + local offHandTypes = requiresShield and (optionalShield and uniqueSorted({ "Shield", unpack(mainHandTypes) }) or { "Shield" }) or requiresQuiver and { "Quiver" } or mainHandTypes + local passiveStats = { } + for _, statRow in ipairs(row.BuildStats or { }) do + local statId = statRow.Stat.Id + local definition = passiveStatFormats[statId] + table.insert(passiveStats, { + id = statRow.Id, + statId = statId, + categoryId = statRow.Category and statRow.Category.Id or nil, + categoryName = statRow.Category and statRow.Category.Name or nil, + values = { statRow.Value1, statRow.Value2, statRow.Value3 }, + format = definition.format, + line = definition.line, + divisor = definition.divisor, + }) + end + table.sort(passiveStats, function(a, b) return a.id < b.id end) + local build = { + id = row.Id, + classId = row.Class.Id, + name = row.BuildName, + infamous = row.Infamous, + hash = row.HASH16, + tags = rowIds(row.Tags), + skillPools = pools, + skillIds = uniqueSorted(allSkills), + weaponTypes = weaponTypes, + weaponConfiguration = { + mainHandTypes = mainHandTypes, + offHandTypes = offHandTypes, + offHandRequired = requiresQuiver or requiresShield and not optionalShield, + }, + passiveStats = passiveStats, + } + if not mercenaries.classes[build.classId] then + error("Mercenary build references missing class: "..build.id) + end + for _, skillId in ipairs(build.skillIds) do + if not mercenaries.skills[skillId] then + error("Mercenary build references missing skill: "..build.id.." -> "..skillId) + end + end + mercenaries.builds[build.id] = build + table.insert(mercenaries.buildOrder, build.id) + table.insert(mercenaries.classes[build.classId].buildIds, build.id) + for _, skillId in ipairs(build.skillIds) do + table.insert(mercenaries.classes[build.classId].skillIds, skillId) + end +end + +for _, class in pairs(mercenaries.classes) do + class.skillIds = uniqueSorted(class.skillIds) +end +local shieldPolicyError = MercenaryExport.shieldPolicyError(mercenaries.builds, shieldPolicy) +if shieldPolicyError then + error(shieldPolicyError) +end +for _, ids in pairs(mercenaries.skillsByHash) do + table.sort(ids) +end +for _, ids in pairs(mercenaries.supportsByHash) do + table.sort(ids) +end + +local out = assert(io.open("../Data/Mercenaries.lua", "w")) +out:write("-- This file is automatically generated, do not edit!\n") +out:write("-- Mercenary data (c) Grinding Gear Games\n\nreturn ") +writeLuaTable(out, mercenaries, 1) +out:write("\n") +out:close() + +print(string.format("Mercenary data exported: %d classes, %d builds, %d skills, %d supports.", #mercenaries.classOrder, #mercenaries.buildOrder, skillCount, supportCount)) diff --git a/src/Export/Scripts/skills.lua b/src/Export/Scripts/skills.lua index 8a7e6b89952..8139bccc3f7 100644 --- a/src/Export/Scripts/skills.lua +++ b/src/Export/Scripts/skills.lua @@ -136,6 +136,14 @@ directiveTable.skill = function(state, args, out) out:write('\tname = "', displayName, '",\n') out:write('\thidden = true,\n') end + if state.mercenary then + out:write('\tmercenary = true,\n') + if state.mercenaryBaseSkillId then + out:write('\tinheritedFrom = "', state.mercenaryBaseSkillId, '",\n') + end + end + state.mercenary = nil + state.mercenaryBaseSkillId = nil if skillGem and skillGem.BaseItemType and skillGem.BaseItemType.FlavourTextKey then out:write('\tflavourText = {') for _, line in ipairs(cleanAndSplit(skillGem.BaseItemType.FlavourTextKey.Text)) do @@ -543,6 +551,190 @@ for _, name in pairs({"act_str","act_dex","act_int","other","glove","minion","sp processTemplateFile(name, "Skills/", "../Data/Skills/", directiveTable) end +do + local out = assert(io.open("../Data/Skills/mercenary.lua", "w")) + out:write("-- This file is automatically generated, do not edit!\n") + out:write("-- Mercenary skill data (c) Grinding Gear Games\n\nreturn function(skills, mod, flag, skill)\n") + local emitted = { } + for _, templateName in ipairs({"act_str","act_dex","act_int","other","glove","minion","spectre","sup_str","sup_dex","sup_int"}) do + for line in io.lines("Skills/"..templateName..".txt") do + local id = line:match("^#skill%s+(%S+)") + if id then + emitted[id] = true + end + end + end + -- A Mercenary Granted Effect reuses the implementation of the player skill it + -- was derived from. Resolve that base here, from the shared ActiveSkill where + -- possible and from the shared display name otherwise, and emit it as + -- `inheritedFrom` so the runtime inherits from exactly one recorded skill. + -- An ActiveSkill and a display name are both shared by the skill gem the player + -- uses and by the NPC and monster copies of it, and only the gem's entry is + -- maintained as a player skill, so the gem is preferred. Display-name fallback + -- requires a unique best-rank candidate; equal-rank ties need an override. + -- A shared ActiveSkill is stronger evidence than a shared name, but equal-rank + -- ActiveSkill ties are still ambiguous and also require an override. + local MercenaryExport = LoadModule("MercenaryExport") + local baseSkillByActiveSkill = { } + local baseSkillByDisplayName = { } + local function baseRank(effect) + if effect.IsSupport then return 2 end + local gemEffect = dat("GemEffects"):GetRow("GrantedEffect", effect) or dat("GemEffects"):GetRow("GrantedEffect2", effect) + return gemEffect and 0 or 1 + end + local function considerBase(bases, key, id, rank) + bases[key] = MercenaryExport.considerRankedCandidate(bases[key], id, rank) + end + for id in pairs(emitted) do + local effect = dat("GrantedEffects"):GetRow("Id", id) + if effect and effect.ActiveSkill then + local rank = baseRank(effect) + considerBase(baseSkillByActiveSkill, effect.ActiveSkill.Id, id, rank) + local displayName = effect.ActiveSkill.DisplayName + if displayName ~= "" then + considerBase(baseSkillByDisplayName, displayName, id, rank) + end + end + end + local flagBySkillType = { + Attack = "attack", + Spell = "spell", + Area = "area", + Projectile = "projectile", + Duration = "duration", + Melee = "melee", + Minion = "minion", + Totem = "totem", + SummonsTotem = "totem", + Trap = "trap", + Trapped = "trap", + Mine = "mine", + RemoteMined = "mine", + Movement = "movement", + Travel = "movement", + Warcry = "warcry", + Aura = "aura", + Curse = "curse", + Hex = "hex", + Chaining = "chaining", + Link = "link", + } + local rows = { } + for row in dat("MercenarySkills"):Rows() do + table.insert(rows, row) + end + table.sort(rows, function(a, b) return a.Id.Id < b.Id.Id end) + local effectNames, effects = { }, { } + for _, row in ipairs(rows) do + for _, effect in ipairs({ row.Id, row.SecondaryGrantedEffect }) do + if effect then + effects[effect.Id] = effect + effectNames[effect.Id] = row.Name ~= "" and row.Name or effect.ActiveSkill.DisplayName ~= "" and effect.ActiveSkill.DisplayName or effect.Id + for index, stat in ipairs(effect.GrantedEffectStatSets.ConstantStats or { }) do + if stat.Id == "alternate_minion" then + local summonedId = effect.GrantedEffectStatSets.ConstantStatsValues[index] + local summoned = dat("SummonedSpecificMonsters"):GetRow("Id", summonedId) + local variety = summoned and summoned.MonsterVarietiesKey + if not variety then error("Mercenary skill references missing summoned monster: "..effect.Id.." -> "..summonedId) end + for _, minionEffect in ipairs(variety.GrantedEffects or { }) do + effects[minionEffect.Id] = minionEffect + effectNames[minionEffect.Id] = minionEffect.ActiveSkill.DisplayName ~= "" and minionEffect.ActiveSkill.DisplayName or minionEffect.Id + end + end + end + end + end + end + local effectIds = { } + for effectId in pairs(effects) do table.insert(effectIds, effectId) end + table.sort(effectIds) + local baseSkillOverrides = { + -- AtlasEyrieArcherSnipe shares the Mercenary effect's ActiveSkill, but is an + -- NPC copy; Snipe is the maintained gem implementation. + SkeletonLargeMapBoneProjectile = "Snipe", + -- Blood Mortar shares monster_mortar_attack with Herald of Agony's minion + -- mortar; there is no gem, so inherit the spectre blood-projectile mortar. + BloodMortarMercenary = "BirdmanBloodProjectileMortar", + -- These triggered area hits share the generic geometry_attack ActiveSkill + -- with dozens of spectre slams; keep the previously chosen implementation. + DeceleratingProjectileMercenaryExplode = "AfflictionMinionPhysSlamCircleBig", + DonutBladesMercenary = "AfflictionMinionPhysSlamCircleBig", + TriggeredFireSlamMercenary = "AfflictionMinionPhysSlamCircleBig", + -- Shares geometry_spell with many spectre spells and has no display name. + GSRitualChaosPulse = "AtlasExileCrusaderMageguardBombExplodeSpectre", + -- Shares inspiring_cry with other NPC warcries; there is no gem. + InspiringCryMercenary = "DropBearSummonedRallyingCry", + -- Shares offering_of_judgement with the Azmeri fire and chaos pillars. + OfferingOfJudgementChaosMercenary = "AzmeriGoddessOfferingOfJudgement", + -- Shares sandstorm with the summoned chaos elemental auras. + SandstormChaosMercenary = "SandstormChaosElementalSummoned", + } + -- Unique ActiveSkill/name matches win. Remaining ties require an explicit + -- override so a generic shared ActiveSkill cannot silently pick a new base. + -- Skills with no unique match and no override still fail closed. + local resolvedByActiveSkill, resolvedByDisplayName, resolvedByOverride, withoutBase = 0, 0, 0, { } + local wroteSkill = false + for _, effectId in ipairs(effectIds) do + local effect = effects[effectId] + if not emitted[effect.Id] then + emitted[effect.Id] = true + local byActiveSkill = baseSkillByActiveSkill[effect.ActiveSkill.Id] + local byDisplayName = baseSkillByDisplayName[effect.ActiveSkill.DisplayName] or baseSkillByDisplayName[effectNames[effect.Id]] + -- A shared ActiveSkill is stronger evidence than a shared display name, + -- but a gem found by name still beats an NPC copy found by ActiveSkill. + -- Tied ActiveSkill matches are not evidence; fall through to a unique name. + local displayName = effect.ActiveSkill.DisplayName ~= "" and effect.ActiveSkill.DisplayName or effectNames[effect.Id] + local resolved = MercenaryExport.resolveBaseSkill({ + effectId = effect.Id, + activeSkillId = effect.ActiveSkill.Id, + displayName = displayName, + byActiveSkill = byActiveSkill, + byDisplayName = byDisplayName, + overrideId = baseSkillOverrides[effect.Id], + isExportedSkill = function(id) + return emitted[id] and dat("GrantedEffects"):GetRow("Id", id) + end, + }) + if baseSkillOverrides[effect.Id] then + baseSkillOverrides[effect.Id] = nil + end + if resolved then + if resolved.source == "activeSkill" then + resolvedByActiveSkill = resolvedByActiveSkill + 1 + elseif resolved.source == "displayName" then + resolvedByDisplayName = resolvedByDisplayName + 1 + else + resolvedByOverride = resolvedByOverride + 1 + end + else + table.insert(withoutBase, effect.Id) + end + if wroteSkill then out:write("\n") end + wroteSkill = true + local state = { noGem = true, mercenary = true, mercenaryBaseSkillId = resolved and resolved.id } + directiveTable.skill(state, effect.Id.." "..effectNames[effect.Id], out) + local flags = { } + for _, skillType in ipairs(effect.ActiveSkill.SkillTypes) do + if flagBySkillType[skillType.Id] then + flags[flagBySkillType[skillType.Id]] = true + end + end + local orderedFlags = { } + for flagName in pairsSortByKey(flags) do + table.insert(orderedFlags, flagName) + end + directiveTable.flags(state, table.concat(orderedFlags, " "), out) + directiveTable.mods(state, "", out) + out:write("\n") + end + end + for effectId in pairs(baseSkillOverrides) do error("Mercenary base-skill override references missing effect: "..effectId) end + out:write("end\n") + out:close() + print(string.format("Mercenary skill bases: %d from a shared ActiveSkill, %d from a shared display name, %d overridden, %d without a base (%s).", + resolvedByActiveSkill, resolvedByDisplayName, resolvedByOverride, #withoutBase, table.concat(withoutBase, ", "))) +end + local out = io.open("../Data/Gems.lua", "w") out:write('-- This file is automatically generated, do not edit!\n') out:write('-- Gem data (c) Grinding Gear Games\n\nreturn {\n') diff --git a/src/Export/spec.lua b/src/Export/spec.lua index 696a2d8d2dc..eae02e2b1f5 100644 --- a/src/Export/spec.lua +++ b/src/Export/spec.lua @@ -7725,6 +7725,50 @@ return { width=500 } }, + mercenarybuildextrastats={ + [1]={ + list=false, + name="Id", + refTo="", + type="String", + width=220 + }, + [2]={ + list=false, + name="Stat", + refTo="Stats", + type="Key", + width=280 + }, + [3]={ + list=false, + name="Value1", + refTo="", + type="Int", + width=80 + }, + [4]={ + list=false, + name="Value2", + refTo="", + type="Int", + width=80 + }, + [5]={ + list=false, + name="Value3", + refTo="", + type="Int", + width=80 + }, + [6]={ + list=false, + name="Category", + refTo="MercenaryBuildStatsCategories", + type="Key", + width=160 + } + }, mercenarybuilds={ [1]={ list=false, @@ -7840,10 +7884,10 @@ return { }, [17]={ list=false, - name="", - refTo="", + name="IdleSkill", + refTo="MercenarySkills", type="Key", - width=20 + width=150 }, [18]={ list=false, @@ -7872,6 +7916,29 @@ return { refTo="MercenaryWieldableTypes", type="Key", width=220 + }, + [22]={ + list=true, + name="BuildStats", + refTo="MercenaryBuildExtraStats", + type="Key", + width=400 + } + }, + mercenarybuildstatscategories={ + [1]={ + list=false, + name="Id", + refTo="", + type="String", + width=150 + }, + [2]={ + list=false, + name="Name", + refTo="", + type="String", + width=150 } }, mercenaryclasses={ @@ -7951,6 +8018,27 @@ return { refTo="MonsterVarieties", type="Key", width=420 + }, + [12]={ + list=true, + name="HouseSpawnChanceStats", + refTo="Stats", + type="Key", + width=250 + }, + [13]={ + list=true, + name="AttributeSpawnChanceStats", + refTo="Stats", + type="Key", + width=250 + }, + [14]={ + list=false, + name="HouseName", + refTo="", + type="String", + width=150 } }, mercenaryinventories={ @@ -14372,4 +14460,4 @@ return { }, zanaquests={ } -} \ No newline at end of file +} diff --git a/src/Modules/Build.lua b/src/Modules/Build.lua index 3ad9d8eafff..444005a9745 100644 --- a/src/Modules/Build.lua +++ b/src/Modules/Build.lua @@ -14,6 +14,7 @@ local m_huge = math.huge local m_floor = math.floor local m_abs = math.abs local s_format = string.format +local MercenaryTools = require("Modules.MercenaryTools") ---@class Build: ControlHost ---@field spec PassiveSpec added by TreeTab @@ -29,6 +30,26 @@ local function InsertIfNew(t, val) table.insert(t, val) end +-- first identifier inside braces. SyncLoadouts lists comma-separated ids as +-- separate dropdown rows ("Name {1}"), so lookups take the first id. +local function loadoutLinkId(value) + local linkIdentifier = value and string.match(value, "%{([%w,]+)%}") + return linkIdentifier and string.match(linkIdentifier, "[^%,]+") +end + +local function titleHasLoadoutLinkId(title, linkId) + local linkIdentifier = title and string.match(title, "%{([%w,]+)%}") + if not linkIdentifier or not linkId then + return false + end + for id in string.gmatch(linkIdentifier, "[^%,]+") do + if id == linkId then + return true + end + end + return false +end + ---matchFlags --- Compares the skill flags table against the line flag settings --- Required enabling flags check takes precedence over disabling flags check @@ -330,7 +351,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin newSpec.title = loadout t_insert(self.treeTab.specList, newSpec) - local itemSet = self.itemsTab:NewItemSet(#self.itemsTab.itemSets + 1) + local itemSet = self.itemsTab:NewItemSet() t_insert(self.itemsTab.itemSetOrderList, itemSet.id) itemSet.title = loadout @@ -356,20 +377,17 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin return end - -- item, skill, and config sets have identical structure + -- item, skill, config, and mercenary sets have identical structure -- return id as soon as it's found local function findSetId(setOrderList, value, sets, setSpecialLinks) for _, setOrder in ipairs(setOrderList) do if value == (sets[setOrder].title or "Default") then return setOrder - else - local linkMatch = string.match(value, "%{(%w+)%}") - if linkMatch then - return setSpecialLinks[linkMatch]["setId"] - end end end - return nil + local linkId = loadoutLinkId(value) + local linked = linkId and setSpecialLinks[linkId] + return linked and linked["setId"] end -- trees have a different structure with id/name pairs @@ -378,24 +396,36 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin for id, spec in ipairs(treeList) do if value == spec then return id - else - local linkMatch = string.match(value, "%{(%w+)%}") - if linkMatch then - return setSpecialLinks[linkMatch]["setId"] - end end end - return nil + local linkId = loadoutLinkId(value) + local linked = linkId and setSpecialLinks[linkId] + return linked and linked["setId"] end local oneSkill = self.skillsTab and #self.skillsTab.skillSetOrderList == 1 - local oneItem = self.itemsTab and #self.itemsTab.itemSetOrderList == 1 + local itemSetOrderList = self:GetPlayerItemSetOrderList() + local oneItem = self.itemsTab and #itemSetOrderList == 1 local oneConfig = self.configTab and #self.configTab.configSetOrderList == 1 + local mercenarySetOrderList = self.mercenaryTab and self.mercenaryTab.mercenarySetOrderList or { } + local oneMercenary = not self.mercenaryTab or #mercenarySetOrderList <= 1 local newSpecId = findNamedSetId(self.treeTab:GetSpecList(), value, self.treeListSpecialLinks) - local newItemId = oneItem and 1 or findSetId(self.itemsTab.itemSetOrderList, value, self.itemsTab.itemSets, self.itemListSpecialLinks) + local newItemId = oneItem and itemSetOrderList[1] or findSetId(itemSetOrderList, value, self.itemsTab.itemSets, self.itemListSpecialLinks) local newSkillId = oneSkill and 1 or findSetId(self.skillsTab.skillSetOrderList, value, self.skillsTab.skillSets, self.skillListSpecialLinks) local newConfigId = oneConfig and 1 or findSetId(self.configTab.configSetOrderList, value, self.configTab.configSets, self.configListSpecialLinks) + local newMercenaryId + if self.mercenaryTab then + self.mercenaryTab:DropInvalidConfigBindings(true) + local namedId + if not oneMercenary then + namedId = findSetId(mercenarySetOrderList, value, self.mercenaryTab.mercenarySets, self.mercenaryListSpecialLinks) + end + local configSet = self.configTab and self.configTab.configSets[newConfigId] + local storedId = configSet and configSet.mercenarySetId + -- Bound hire on this loadout, else a same-named Mercenary set, else the default hire. + newMercenaryId = storedId or namedId or mercenarySetOrderList[1] + end -- if exact match nor special grouping cannot find setIds, bail if newSpecId == nil or newItemId == nil or newSkillId == nil or newConfigId == nil then @@ -414,6 +444,9 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin if newConfigId ~= self.configTab.activeConfigSetId then self.configTab:SetActiveConfigSet(newConfigId) end + if newMercenaryId and newMercenaryId ~= self.mercenaryTab.activeMercenarySetId then + self.mercenaryTab:SetActiveMercenarySet(newMercenaryId, false, false) + end self.controls.buildLoadouts:SelByValue(value) end) @@ -432,6 +465,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin self.displayStats = displayStatsModule.displayStats self.minionDisplayStats = displayStatsModule.minionDisplayStats self.extraSaveStats = displayStatsModule.extraSaveStats + self.mercenaryDisplayStats = displayStatsModule.mercenaryDisplayStats -- Controls: Side bar self.anchorSideBar = new("Control"):Control(nil, {4, 60, 0, 0}) @@ -452,22 +486,25 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin self.viewMode = "CONFIG" end) self.controls.modeConfig.locked = function() return self.viewMode == "CONFIG" end - self.controls.modeTree = new("ButtonControl"):ButtonControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 26, 72, 20}, "Tree", function() + self.controls.modeTree = new("ButtonControl"):ButtonControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 26, 64, 20}, "Tree", function() self.viewMode = "TREE" end) self.controls.modeTree.locked = function() return self.viewMode == "TREE" end - self.controls.modeSkills = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeTree,"RIGHT"}, {4, 0, 72, 20}, "Skills", function() + self.controls.modeSkills = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeTree,"RIGHT"}, {4, 0, 64, 20}, "Skills", function() self.viewMode = "SKILLS" end) self.controls.modeSkills.locked = function() return self.viewMode == "SKILLS" end - self.controls.modeItems = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeSkills,"RIGHT"}, {4, 0, 72, 20}, "Items", function() + self.controls.modeItems = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeSkills,"RIGHT"}, {4, 0, 64, 20}, "Items", function() self.viewMode = "ITEMS" end) self.controls.modeItems.locked = function() return self.viewMode == "ITEMS" end - self.controls.modeCalcs = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeItems,"RIGHT"}, {4, 0, 72, 20}, "Calcs", function() - self.viewMode = "CALCS" + self.controls.modeMercenary = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeItems,"RIGHT"}, {4, 0, 96, 20}, "Mercenary", function() + self.viewMode = "MERCENARY" end) - self.controls.modeCalcs.locked = function() return self.viewMode == "CALCS" end + self.controls.modeMercenary.shown = function() + return MercenaryTools.tabVisible(self) + end + self.controls.modeMercenary.locked = function() return self.viewMode == "MERCENARY" end self.controls.modeParty = new("ButtonControl"):ButtonControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 52, 72, 20}, "Party", function() self.viewMode = "PARTY" end) @@ -476,6 +513,10 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin self.viewMode = "COMPARE" end) self.controls.modeCompare.locked = function() return self.viewMode == "COMPARE" end + self.controls.modeCalcs = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeCompare,"RIGHT"}, {4, 0, 72, 20}, "Calcs", function() + self.viewMode = "CALCS" + end) + self.controls.modeCalcs.locked = function() return self.viewMode == "CALCS" end -- Skills self.controls.mainSkillLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 80, 300, 16}, "^7Main Skill:") self.controls.mainSocketGroup = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.mainSkillLabel,"BOTTOMLEFT"}, {0, 2, 300, 18}, nil, function(index, value) @@ -612,6 +653,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin self.itemsTab = new("ItemsTab"):ItemsTab(self) self.treeTab = new("TreeTab"):TreeTab(self) self.skillsTab = new("SkillsTab"):SkillsTab(self) + self.mercenaryTab = new("MercenaryTab"):MercenaryTab(self) self.calcsTab = new("CalcsTab"):CalcsTab(self) self.controls.breakdown = new("CalcBreakdownControl"):CalcBreakdownControl(self.calcsTab) self.controls.breakdown.pinnedColour = hexToRGB(colorCodes.CUSTOM) or error("failed to set breakdown pin colour") @@ -634,6 +676,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin ["TreeView"] = self.treeTab.viewer, ["Items"] = self.itemsTab, ["Skills"] = self.skillsTab, + ["Mercenary"] = self.mercenaryTab, ["Calcs"] = self.calcsTab, ["Import"] = self.importTab, } @@ -768,6 +811,23 @@ local function actExtra(act, extra) return act > 2 and extra or 0 end +function buildMode:GetPlayerItemSetOrderList() + local orderList = self.itemsTab and self.itemsTab.itemSetOrderList or { } + local mercenaryTab = self.mercenaryTab + if not mercenaryTab then + return orderList + end + local filtered = { } + for _, itemSetId in ipairs(orderList) do + if not mercenaryTab:ItemSetOwnedByAnyMercenary(itemSetId) then + t_insert(filtered, itemSetId) + end + end + -- Empty if every item set is mercenary-owned; loadout switch then bails on nil + -- rather than treating merc gear as a player set. + return filtered +end + function buildMode:SyncLoadouts() self.controls.buildLoadouts.list = {"No Loadouts"} @@ -776,12 +836,16 @@ function buildMode:SyncLoadouts() local itemList = {} local skillList = {} local configList = {} + local mercenaryList = {} -- used when clicking on the dropdown to set the correct setId for each SetActiveSet() - self.treeListSpecialLinks, self.itemListSpecialLinks, self.skillListSpecialLinks, self.configListSpecialLinks = {}, {}, {}, {} + self.treeListSpecialLinks, self.itemListSpecialLinks, self.skillListSpecialLinks, self.configListSpecialLinks, self.mercenaryListSpecialLinks = {}, {}, {}, {}, {} local oneSkill = self.skillsTab and #self.skillsTab.skillSetOrderList == 1 - local oneItem = self.itemsTab and #self.itemsTab.itemSetOrderList == 1 + local itemSetOrderList = self:GetPlayerItemSetOrderList() + local oneItem = self.itemsTab and #itemSetOrderList == 1 local oneConfig = self.configTab and #self.configTab.configSetOrderList == 1 + local mercenarySetOrderList = self.mercenaryTab and self.mercenaryTab.mercenarySetOrderList or { } + local oneMercenary = not self.mercenaryTab or #mercenarySetOrderList <= 1 if self.treeTab ~= nil and self.itemsTab ~= nil and self.skillsTab ~= nil and self.configTab ~= nil then local transferTable = {} @@ -813,7 +877,7 @@ function buildMode:SyncLoadouts() end end - -- item, skill, and config sets have identical structure + -- item, skill, config, and mercenary sets have identical structure local function identifyLinks(setOrderList, tabSets, setList, specialLinks, treeLinks) for id, set in ipairs(setOrderList) do local setTitle = tabSets[set].title or "Default" @@ -838,11 +902,16 @@ function buildMode:SyncLoadouts() end end end - identifyLinks(self.itemsTab.itemSetOrderList, self.itemsTab.itemSets, itemList, self.itemListSpecialLinks, self.treeListSpecialLinks) + identifyLinks(itemSetOrderList, self.itemsTab.itemSets, itemList, self.itemListSpecialLinks, self.treeListSpecialLinks) identifyLinks(self.skillsTab.skillSetOrderList, self.skillsTab.skillSets, skillList, self.skillListSpecialLinks, self.treeListSpecialLinks) identifyLinks(self.configTab.configSetOrderList, self.configTab.configSets, configList, self.configListSpecialLinks, self.treeListSpecialLinks) + if self.mercenaryTab then + identifyLinks(mercenarySetOrderList, self.mercenaryTab.mercenarySets, mercenaryList, self.mercenaryListSpecialLinks, self.treeListSpecialLinks) + end -- loop over all for exact match loadouts + -- Mercenary sets are optional here: extra unmatched hires must not hide a + -- tree/item/skill/config loadout. findSetId still switches the merc when names match. for id, tree in ipairs(treeList) do if (oneItem or itemList[tree]) and (oneSkill or skillList[tree]) and (oneConfig or configList[tree]) then t_insert(filteredList, tree) @@ -872,19 +941,25 @@ function buildMode:SyncLoadouts() local treeName = self.treeTab.specList[self.treeTab.activeSpec].title or "Default" for i, loadout in ipairs(filteredList) do if loadout == treeName then - local linkMatch = string.match(treeName, "%{(%w+)%}") or treeName - if linkMatch then - local skillName = self.skillsTab.skillSets[self.skillsTab.activeSkillSetId].title or "Default" - local skillMatch = oneSkill or skillName:find(linkMatch, 1, true) - local itemName = self.itemsTab.itemSets[self.itemsTab.activeItemSetId].title or "Default" - local itemMatch = oneItem or itemName:find(linkMatch, 1, true) - local configName = self.configTab.configSets[self.configTab.activeConfigSetId].title or "Default" - local configMatch = oneConfig or configName:find(linkMatch, 1, true) - - if skillMatch and itemMatch and configMatch then - self.controls.buildLoadouts:SetSel(i) - return treeList, itemList, skillList, configList - end + local treeLinkId = loadoutLinkId(treeName) + local linkMatch = treeLinkId or treeName + local skillName = self.skillsTab.skillSets[self.skillsTab.activeSkillSetId].title or "Default" + local skillMatch = oneSkill or skillName:find(linkMatch, 1, true) + local itemName = self.itemsTab.itemSets[self.itemsTab.activeItemSetId].title or "Default" + local itemMatch = oneItem or itemName:find(linkMatch, 1, true) + local configName = self.configTab.configSets[self.configTab.activeConfigSetId].title or "Default" + local configMatch = oneConfig or configName:find(linkMatch, 1, true) + local mercenaryName = self.mercenaryTab and self.mercenaryTab.profile and (self.mercenaryTab.profile.title or "Default") or "Default" + -- Exact loadouts key mercenaryList by full tree title + local configSet = self.configTab.configSets[self.configTab.activeConfigSetId] + local boundMatch = self.mercenaryTab and configSet and configSet.mercenarySetId == self.mercenaryTab.activeMercenarySetId + local mercenaryLinked = mercenaryList[treeName] or (treeLinkId and self.mercenaryListSpecialLinks[treeLinkId]) + local mercenaryNameMatch = mercenaryName == treeName or titleHasLoadoutLinkId(mercenaryName, treeLinkId) + local mercenaryMatch = oneMercenary or boundMatch or mercenaryNameMatch or not mercenaryLinked + + if skillMatch and itemMatch and configMatch and mercenaryMatch then + self.controls.buildLoadouts:SetSel(i) + return treeList, itemList, skillList, configList, mercenaryList end break end @@ -892,7 +967,7 @@ function buildMode:SyncLoadouts() end self.controls.buildLoadouts:SetSel(1) - return treeList, itemList, skillList, configList + return treeList, itemList, skillList, configList, mercenaryList end function buildMode:EstimatePlayerProgress() @@ -1107,6 +1182,7 @@ function buildMode:ResetModFlags() self.spec.modFlag = false self.skillsTab.modFlag = false self.itemsTab.modFlag = false + self.mercenaryTab.modFlag = false self.calcsTab.modFlag = false end @@ -1203,6 +1279,10 @@ function buildMode:OnFrame(inputEvents) self.viewMode = "NOTES" elseif event.key == "7" then self.viewMode = "PARTY" + elseif event.key == "8" then + if MercenaryTools.tabVisible(self) then + self.viewMode = "MERCENARY" + end end end end @@ -1269,7 +1349,7 @@ function buildMode:OnFrame(inputEvents) self.controls.breakdown:SetBreakdownData(unpack(self.breakdownInputs)) end self:RefreshStatList() - self.configTab.calcFunc, self.configTab.calcBase = self.calcsTab:GetMiscCalculator() + self.configTab.calcFunc, self.configTab.calcBase, self.configTab.calcActorOutputs = self.calcsTab:GetMiscCalculator() end if main.showThousandsSeparators ~= self.lastShowThousandsSeparators then self:RefreshStatList() @@ -1289,6 +1369,7 @@ function buildMode:OnFrame(inputEvents) -- Update contents of main skill dropdowns self:RefreshSkillSelectControls(self.controls, self.mainSocketGroup, "") + self:SyncMercenaryUi() -- Draw contents of current tab local sideBarWidth = 312 local tabViewPort = { @@ -1311,6 +1392,8 @@ function buildMode:OnFrame(inputEvents) self.skillsTab:Draw(tabViewPort, inputEvents) elseif self.viewMode == "ITEMS" then self.itemsTab:Draw(tabViewPort, inputEvents) + elseif self.viewMode == "MERCENARY" then + self.mercenaryTab:Draw(tabViewPort, inputEvents) elseif self.viewMode == "CALCS" then self.calcsTab:Draw(tabViewPort, inputEvents) elseif self.viewMode == "COMPARE" then @@ -1324,7 +1407,7 @@ function buildMode:OnFrame(inputEvents) end end - self.unsaved = self.modFlag or self.notesTab.modFlag or self.partyTab.modFlag or self.configTab.modFlag or self.treeTab.modFlag or self.treeTab.searchFlag or self.spec.modFlag or self.skillsTab.modFlag or self.itemsTab.modFlag or self.calcsTab.modFlag + self.unsaved = self.modFlag or self.notesTab.modFlag or self.partyTab.modFlag or self.configTab.modFlag or self.treeTab.modFlag or self.treeTab.searchFlag or self.spec.modFlag or self.skillsTab.modFlag or self.itemsTab.modFlag or self.mercenaryTab.modFlag or self.calcsTab.modFlag SetDrawLayer(5) @@ -2058,6 +2141,23 @@ function buildMode:AddDisplayStatList(statList, actor, actorName) end end +function buildMode:SyncMercenaryUi() + MercenaryTools.applyHiddenState(self) + local visible = MercenaryTools.tabVisible(self) + if visible == self.mercenaryUiVisible then + return + end + self.mercenaryUiVisible = visible + if visible then + self.controls.modeCalcs:SetAnchor("LEFT", self.controls.modeCompare, "RIGHT") + self.configTab:RefreshActorSelect() + else + self.controls.modeCalcs:SetAnchor("LEFT", self.controls.modeItems, "RIGHT") + self.configTab:UpdateControls() + end + self.calcsTab:SyncActorList() +end + function buildMode:InsertItemWarnings() if self.calcsTab.mainEnv.itemWarnings.jewelLimitWarning then for _, warning in ipairs(self.calcsTab.mainEnv.itemWarnings.jewelLimitWarning) do @@ -2072,6 +2172,11 @@ function buildMode:InsertItemWarnings() if self.calcsTab.mainEnv.itemWarnings.missingAnointWarning then InsertIfNew(self.controls.warnings.lines, "You have eligible items missing an anoint: "..table.concat(self.calcsTab.mainEnv.itemWarnings.missingAnointWarning, ", ")) end + if MercenaryTools.includeInBuildWarnings(self) then + for _, errorText in ipairs(self.mercenaryTab:GetErrors()) do + InsertIfNew(self.controls.warnings.lines, "Mercenary: "..errorText) + end + end end -- Build list of side bar stats @@ -2107,6 +2212,14 @@ function buildMode:RefreshStatList() end self:AddDisplayStatList(self.minionDisplayStats, self.calcsTab.mainEnv.minion, "minion") t_insert(statBoxList, { height = 10 }) + if not self.calcsTab.mainEnv.mercenary then + t_insert(statBoxList, { height = 18, "^7Player:" }) + end + end + if self.calcsTab.mainEnv.mercenary then + t_insert(statBoxList, { height = 18, "^7Mercenary Stats:" }) + self:AddDisplayStatList(self.mercenaryDisplayStats, self.calcsTab.mainEnv.mercenary) + t_insert(statBoxList, { height = 10 }) t_insert(statBoxList, { height = 18, "^7Player:" }) end if self.calcsTab.mainEnv.player.mainSkill.skillFlags.disable then @@ -2165,8 +2278,11 @@ end -- Compare values of all display stats between the two output tables, and add any changed stats to the tooltip -- Adds the provided header line before the first stat line, if any are added -- Returns the number of stat lines added -function buildMode:AddStatComparesToTooltip(tooltip, baseOutput, compareOutput, header, nodeCount) +function buildMode:AddStatComparesToTooltip(tooltip, baseOutput, compareOutput, header, nodeCount, actor) local count = 0 + if actor == "MERCENARY" and self.calcsTab.mainEnv.mercenary then + return self:CompareStatList(tooltip, self.mercenaryDisplayStats, self.calcsTab.mainEnv.mercenary, baseOutput, compareOutput, header, nodeCount) + end if self.calcsTab.mainEnv.player.mainSkill.minion and baseOutput.Minion and compareOutput.Minion then count = count + self:CompareStatList(tooltip, self.minionDisplayStats, self.calcsTab.mainEnv.minion, baseOutput.Minion, compareOutput.Minion, header.."\n^7Minion:", nodeCount) if count > 0 then diff --git a/src/Modules/BuildDisplayStats.lua b/src/Modules/BuildDisplayStats.lua index 950c579f09a..d34703ea19d 100644 --- a/src/Modules/BuildDisplayStats.lua +++ b/src/Modules/BuildDisplayStats.lua @@ -277,6 +277,29 @@ local minionDisplayStats = { { stat = "EnergyShieldRegenRecovery", label = "ES Recovery", fmt = ".1f", color = colorCodes.ES }, { stat = "EnergyShieldLeechGainRate", label = "ES Leech/On Hit Rate", fmt = ".1f", color = colorCodes.ES, compPercent = true }, } +local mercenaryDisplayStats = { + { stat = "CombinedDPS", label = "Selected Skill DPS", fmt = ".1f", compactValue = true, compPercent = true }, + { stat = "FullDPS", label = "Full DPS", fmt = ".1f", compactValue = true, color = colorCodes.CURRENCY, compPercent = true }, + { stat = "FullDotDPS", label = "Full DoT DPS", fmt = ".1f", compactValue = true, color = colorCodes.CURRENCY, compPercent = true, warnFunc = function(v) return v >= data.misc.DotDpsCap and "Full DoT DPS exceeds in-game limit" end }, + { stat = "SkillDPS", label = "Skill DPS", compactValue = true, condFunc = function() return true end }, + { stat = "Speed", label = "Attack Rate", fmt = ".2f", compPercent = true, flag = "attack", condFunc = function(v,o) return v > 0 and (o.TriggerTime or 0) == 0 end }, + { stat = "PreEffectiveCritChance", label = "Crit Chance", fmt = ".2f%%", flag = "hit" }, + { stat = "CritChance", label = "Effective Crit Chance", fmt = ".2f%%", flag = "hit", condFunc = function(v,o) return v ~= o.PreEffectiveCritChance end }, + { stat = "CritMultiplier", label = "Crit Multiplier", fmt = "d%%", pc = true, condFunc = function(v,o) return (o.CritChance or 0) > 0 end }, + { stat = "HitChance", label = "Hit Chance", fmt = ".0f%%", flag = "attack" }, + { stat = "Life", label = "Life", fmt = "d", compactValue = true, color = colorCodes.LIFE }, + { stat = "EnergyShield", label = "Energy Shield", fmt = "d", compactValue = true, color = colorCodes.ES }, + { stat = "Armour", label = "Armour", fmt = "d", compactValue = true }, + { stat = "Evasion", label = "Evasion", fmt = "d", compactValue = true, color = colorCodes.EVASION }, + { stat = "FireResist", label = "Fire Resistance", fmt = "d%%", color = colorCodes.FIRE, condFunc = function() return true end, overCapStat = "FireResistOverCap" }, + { stat = "ColdResist", label = "Cold Resistance", fmt = "d%%", color = colorCodes.COLD, condFunc = function() return true end, overCapStat = "ColdResistOverCap" }, + { stat = "LightningResist", label = "Lightning Resistance", fmt = "d%%", color = colorCodes.LIGHTNING, condFunc = function() return true end, overCapStat = "LightningResistOverCap" }, + { stat = "ChaosResist", label = "Chaos Resistance", fmt = "d%%", color = colorCodes.CHAOS, condFunc = function() return true end, overCapStat = "ChaosResistOverCap" }, + { stat = "LifeRegenRecovery", label = "Life Recovery", fmt = ".1f", color = colorCodes.LIFE }, + { stat = "EnergyShieldRegenRecovery", label = "ES Recovery", fmt = ".1f", color = colorCodes.ES }, + { stat = "EffectiveMovementSpeedMod", label = "Movement Speed Modifier", fmt = "+d%%", mod = true, condFunc = function() return true end }, + { stat = "LootRarity", label = "Item Rarity", fmt = "+d%%", condFunc = function() return true end }, +} -- Extra stats saved to the xml if not already saved there, mostly for 3rd party tools ---@type string[] local extraSaveStats = { @@ -290,4 +313,9 @@ local extraSaveStats = { "ActiveMinionLimit", } -return { displayStats = displayStats, minionDisplayStats = minionDisplayStats, extraSaveStats = extraSaveStats } +return { + displayStats = displayStats, + minionDisplayStats = minionDisplayStats, + extraSaveStats = extraSaveStats, + mercenaryDisplayStats = mercenaryDisplayStats, +} diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index de16231644e..0bc001e3077 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -87,6 +87,8 @@ function calcs.createActiveSkill(activeEffect, supportList, actor, socketGroup, supportList = supportList, actor = actor, summonSkill = summonSkill, + mercenaryPossibleSupportIds = (activeEffect.srcInstance and activeEffect.srcInstance.mercenaryPossibleSupportIds) + or (summonSkill and summonSkill.mercenaryPossibleSupportIds), socketGroup = socketGroup, skillData = { }, buffList = { }, @@ -165,8 +167,8 @@ end -- Copy an Active Skill function calcs.copyActiveSkill(env, mode, skill) - local activeEffect = { - grantedEffect = skill.activeEffect.grantedEffect, + local activeEffect = { + grantedEffect = skill.activeEffect.grantedEffect, level = skill.activeEffect.level, quality = skill.activeEffect.quality } @@ -178,17 +180,26 @@ function calcs.copyActiveSkill(env, mode, skill) activeEffect.gemData = skill.activeEffect.srcInstance.gemData end - local newSkill = calcs.createActiveSkill(activeEffect, skill.supportList, skill.actor, skill.socketGroup, skill.summonSkill) - local newEnv, _, _, _ = calcs.initEnv(env.build, mode, env.override) - calcs.buildActiveSkillModList(newEnv, newSkill) + local fullEnv, _, _, _ = calcs.initEnv(env.build, mode, env.override) + local actor = fullEnv.player + local actorEnv = fullEnv + if skill.actor and skill.actor.isMercenary then + actor = fullEnv.mercenary + actorEnv = actor and actor.calcEnv + if not actorEnv then + error("copyActiveSkill: mercenary actor environment is missing") + end + end + local newSkill = calcs.createActiveSkill(activeEffect, skill.supportList, actor, skill.socketGroup, skill.summonSkill) + calcs.buildActiveSkillModList(actorEnv, newSkill) newSkill.skillModList = new("ModList"):ModList(newSkill.baseSkillModList) if newSkill.minion then newSkill.minion.modDB = new("ModDB"):ModDB() newSkill.minion.modDB.actor = newSkill.minion - calcs.createMinionSkills(env, newSkill) + calcs.createMinionSkills(actorEnv, newSkill) newSkill.skillPartName = newSkill.minion.mainSkill.activeEffect.grantedEffect.name end - return newSkill, newEnv + return newSkill, actorEnv, fullEnv end -- Get weapon flags and info for given weapon @@ -247,7 +258,9 @@ function calcs.buildActiveSkillModList(env, activeSkill) -- Handle multipart skills local activeGemParts = activeGrantedEffect.parts if activeGemParts and #activeGemParts > 1 then - if env.mode == "CALCS" and activeSkill == env.player.mainSkill then + if not activeEffect.srcInstance then + activeSkill.skillPart = 1 + elseif env.mode == "CALCS" and activeSkill == env.player.mainSkill then activeEffect.srcInstance.skillPartCalcs = m_min(#activeGemParts, activeEffect.srcInstance.skillPartCalcs or 1) activeSkill.skillPart = activeEffect.srcInstance.skillPartCalcs else @@ -574,7 +587,7 @@ function calcs.buildActiveSkillModList(env, activeSkill) end -- Add active gem modifiers - activeEffect.actorLevel = activeSkill.actor.minionData and activeSkill.actor.level + activeEffect.actorLevel = (activeSkill.actor.minionData or activeSkill.actor.isMercenary) and activeSkill.actor.level calcs.mergeSkillInstanceMods(env, skillModList, activeEffect, skillModList:List(activeSkill.skillCfg, "ExtraSkillStat")) activeEffect.grantedEffectLevel = activeGrantedEffect.levels[activeEffect.level] @@ -706,15 +719,28 @@ function calcs.buildActiveSkillModList(env, activeSkill) skillFlags.haveMinion = true minion.type = minionType minion.minionData = env.data.minions[minionType] + if not minion.minionData then + activeSkill.unsupportedReason = "Missing minion data: "..tostring(minionType) + return + end + if minion.minionData.noFallbackSkill then + -- Do not invent the generic Melee fallback for an explicitly exported Mercenary minion. + activeSkill.unsupportedReason = minion.minionData.name.." has no exported skills" + activeSkill.minion = nil + skillFlags.haveMinion = false + return + end minion.hostile = minion.minionData and minion.minionData.hostile or false if minion.hostile then minion.parent = env.enemy - minion.enemy = env.player + minion.enemy = activeSkill.actor else - minion.parent = env.player + minion.parent = activeSkill.actor minion.enemy = env.enemy end - minion.level = activeSkill.skillData.minionLevelIsEnemyLevel and env.enemyLevel or + minion.player = env.player + minion.level = activeSkill.skillData.minionLevelIsActorLevel and activeSkill.actor.level or + activeSkill.skillData.minionLevelIsEnemyLevel and env.enemyLevel or activeSkill.skillData.minionLevelIsPlayerLevel and (m_min(env.build and env.build.characterLevel or activeSkill.skillData.minionLevel or activeEffect.grantedEffectLevel.levelRequirement, activeSkill.skillData.minionLevelIsPlayerLevel)) or minionSupportLevel[minion.type] or activeSkill.skillData.minionLevel or activeEffect.grantedEffectLevel.levelRequirement -- fix minion level between 1 and 100 @@ -733,6 +759,9 @@ function calcs.buildActiveSkillModList(env, activeSkill) damage = damage * attackTime end if activeGrantedEffect.minionHasItemSet then + -- Keep the gem's assigned set. Weapon replacements for a comparison + -- targeting that set are applied here so attack data matches the preview + -- item; remaining equipment modifiers are applied later in CalcPerform. if env.mode == "CALCS" and activeSkill == env.player.mainSkill then if not env.build.itemsTab.itemSets[activeEffect.srcInstance.skillMinionItemSetCalcs] then activeEffect.srcInstance.skillMinionItemSetCalcs = env.build.itemsTab.itemSetOrderList[1] @@ -748,8 +777,8 @@ function calcs.buildActiveSkillModList(env, activeSkill) activeEffect.srcInstance.skillMinionItemSetCalcs = nil activeEffect.srcInstance.skillMinionItemSet = nil end - if (activeSkill.skillData.minionUseBowAndQuiver and env.player.weaponData1.type == "Bow") or activeSkill.skillData.minionUseMainHandWeapon then - minion.weaponData1 = env.player.weaponData1 + if (activeSkill.skillData.minionUseBowAndQuiver and activeSkill.actor.weaponData1.type == "Bow") or activeSkill.skillData.minionUseMainHandWeapon then + minion.weaponData1 = activeSkill.actor.weaponData1 elseif env.theIronMass and minionType == "RaisedSkeleton" then minion.weaponData1 = env.player.weaponData1 else @@ -763,25 +792,32 @@ function calcs.buildActiveSkillModList(env, activeSkill) } end minion.weaponData2 = { } + local function minionSetItem(itemSet, slotName) + if env.override.itemSetId == itemSet.id and env.override.repSlotName == slotName then + return env.override.repItem + end + local itemSlot = itemSet[slotName] + return itemSlot and env.build.itemsTab.items[itemSlot.selItemId] + end if minion.uses then if minion.uses["Weapon 1"] then if minion.itemSet then - local item = env.build.itemsTab.items[minion.itemSet[minion.itemSet.useSecondWeaponSet and "Weapon 1 Swap" or "Weapon 1"].selItemId] + local item = minionSetItem(minion.itemSet, minion.itemSet.useSecondWeaponSet and "Weapon 1 Swap" or "Weapon 1") if item and item.weaponData then minion.weaponData1 = item.weaponData[1] end else - minion.weaponData1 = env.player.weaponData1 + minion.weaponData1 = activeSkill.actor.weaponData1 end end if minion.uses["Weapon 2"] then if minion.itemSet then - local item = env.build.itemsTab.items[minion.itemSet[minion.itemSet.useSecondWeaponSet and "Weapon 2 Swap" or "Weapon 2"].selItemId] + local item = minionSetItem(minion.itemSet, minion.itemSet.useSecondWeaponSet and "Weapon 2 Swap" or "Weapon 2") if item and item.weaponData then minion.weaponData2 = item.weaponData[2] end else - minion.weaponData2 = env.player.weaponData2 + minion.weaponData2 = activeSkill.actor.weaponData2 end end end @@ -879,6 +915,12 @@ function calcs.createMinionSkills(env, activeSkill) local activeEffect = activeSkill.activeEffect local minion = activeSkill.minion local minionData = minion.minionData + -- Minions share the encounter, but their curses and hits are not their owner's. + if activeSkill.actor.enemySourceDB and not minion.hostile then + calcs.attachEnemySourceDB(env, minion) + else + minion.enemySourceDB = nil + end minion.activeSkillList = { } local skillIdList = { } diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index bc768a077ac..f748624fcab 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -31,6 +31,7 @@ local resistTypeList = { "Fire", "Cold", "Lightning", "Chaos" } -- Damage is shifted to external allies before Frost Shield, so this is also the order in which pools are drained. local allyLifePoolList = { + { key = "mercenary", life = "TotalMercenaryLife", mitigation = "MercenaryAllyDamageMitigation", redirect = "takenFromMercenaryBeforeYou", label = "Mercenary Life" }, { key = "minion", life = "TotalMinionLife", mitigation = "MinionAllyDamageMitigation", redirect = "takenFromMinionBeforeYou", fallback = "Multiplier:MinionLife", label = "Minion Life" }, { key = "radianceSentinel", life = "TotalRadianceSentinelLife", mitigation = "RadianceSentinelAllyDamageMitigation", redirect = "takenFromRadianceSentinelBeforeYou", label = "Total Sentinel of Radiance Life" }, { key = "spectres", life = "TotalSpectreLife", mitigation = "SpectreAllyDamageMitigation", redirect = "takenFromSpectresBeforeYou", label = "Total Spectre Life" }, @@ -670,7 +671,7 @@ function calcs.defence(env, actor) end end -- Formless Inferno - if actor == env.minion then + if actor.minionData then doActorLifeMana(actor) doActorLifeManaReservation(actor) end diff --git a/src/Modules/CalcMirages.lua b/src/Modules/CalcMirages.lua index b6826b567ea..2375f03f94b 100644 --- a/src/Modules/CalcMirages.lua +++ b/src/Modules/CalcMirages.lua @@ -37,11 +37,12 @@ local function calculateMirage(env, config) end if mirageSkill then - local newSkill, newEnv = calcs.copyActiveSkill(env, "CALCULATOR", mirageSkill) + local newSkill, newEnv, fullEnv = calcs.copyActiveSkill(env, "CALCULATOR", mirageSkill) newSkill.skillCfg.skillCond["usedByMirage"] = true newSkill.skillFlags.multiPart = nil newSkill.skillFlags.haveMinion = nil - newEnv.limitedSkills = newEnv.limitedSkills or {} + fullEnv.limitedSkills = fullEnv.limitedSkills or {} + newEnv.limitedSkills = fullEnv.limitedSkills newEnv.limitedSkills[cacheSkillUUID(newSkill, newEnv)] = true newSkill.skillData.mirageUses = env.player.mainSkill.skillData.storedUses newSkill.skillTypes[SkillType.OtherThingUsesSkill] = true @@ -49,7 +50,20 @@ local function calculateMirage(env, config) config.preCalcFunc(env, newSkill, newEnv) newEnv.player.mainSkill = newSkill - calcs.perform(newEnv) + local restoredUsedByMirage = { } + for _, actorName in ipairs({ "player", "mercenary" }) do + local otherActor = fullEnv[actorName] + if otherActor and otherActor ~= newEnv.player and otherActor.mainSkill then + local cond = otherActor.mainSkill.skillCfg.skillCond + t_insert(restoredUsedByMirage, { cond = cond, previous = cond.usedByMirage }) + cond.usedByMirage = true + end + end + calcs.perform(fullEnv) + for _, entry in ipairs(restoredUsedByMirage) do + entry.cond.usedByMirage = entry.previous + end + if newEnv.player.isMercenary then newEnv.minion = fullEnv.mercenaryMinion or false end config.postCalcFunc(env, newSkill, newEnv) else config.mirageSkillNotFoundFunc(env, config) @@ -425,4 +439,4 @@ function calcs.mirages(env) end return calculateMirage(env, config) -end \ No newline at end of file +end diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 8458c4e468f..ff5386abb4a 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -341,6 +341,62 @@ function calcs.calcTotemLife(env, activeSkill) return life, lifeMod end +-- Character-sheet main-hand attack crit chance for Destructive Link. +-- Uses the already-calculated main-hand PreEffective value when the actor +-- actually attacked; otherwise the same number from weapon local crit plus +-- global modifiers so aura/link owners still export a sheet value. +-- NeverCrit / Resolute Technique stops the linker from dealing crits; it does +-- not zero the chance stat the linked target uses. +-- Does not include lucky rolls, accuracy, or enemy SelfCrit. +function calcs.actorMainHandSheetCritChance(actor) + if not actor or not actor.modDB then + return 0 + end + local weapon = actor.weaponData1 + local info = weapon and data.weaponTypeInfo[weapon.type] + local flags = bor(ModFlag.Attack, ModFlag.Hit) + if info then + flags = bor(flags, ModFlag[info.flag] or 0) + if weapon.type ~= "None" then + flags = bor(flags, ModFlag.Weapon) + flags = bor(flags, info.oneHand and ModFlag.Weapon1H or ModFlag.Weapon2H) + flags = bor(flags, info.melee and ModFlag.WeaponMelee or ModFlag.WeaponRanged) + end + end + if weapon and weapon.countsAsAll1H then + flags = bor(flags, ModFlag.Axe, ModFlag.Claw, ModFlag.Dagger, ModFlag.Mace, ModFlag.Sword) + end + local cfg = { + flags = flags, + keywordFlags = KeywordFlag.Attack, + skillCond = { MainHandAttack = true }, + } + -- Offence zeros PreEffective when NeverCrit; that is the linker's hit + -- outcome, not the sheet chance Destructive Link copies. + local mainHand = actor.output and actor.output.MainHand + if not actor.modDB:Flag(cfg, "NeverCrit") and mainHand and mainHand.PreEffectiveCritChance then + return mainHand.PreEffectiveCritChance + end + -- Party import serializes MainHand.CritChance and does not supply weapon data. + if not weapon then + return (mainHand and mainHand.CritChance) or 0 + end + local override = actor.modDB:Override(cfg, "CritChance") + if override then + return override + end + local baseCrit = actor.modDB:Override(cfg, "WeaponBaseCritChance") or weapon.CritChance or 0 + local base = actor.modDB:Sum("BASE", cfg, "CritChance") + local inc = actor.modDB:Sum("INC", cfg, "CritChance") + local more = actor.modDB:More(cfg, "CritChance") + local chance = round((baseCrit + base) * (1 + inc / 100) * more * 100) / 100 + local cap = actor.modDB:Override(nil, "CritChanceCap") or actor.modDB:Sum("BASE", cfg, "CritChanceCap") or 100 + if (baseCrit + base) > 0 then + chance = m_max(chance, 0) + end + return m_min(chance, cap) +end + -- Performs all offensive calculations ---@param env Env ---@param actor Actor @@ -815,6 +871,8 @@ function calcs.offence(env, actor, activeSkill) return not skillModList:Flag(nil, "CannotRepeat") and ((activeSkillTypes[SkillType.Attack] or activeSkillTypes[SkillType.Spell])) end output.Repeats = 1 + (repeatSkillTypesCheck(activeSkill.skillTypes) and skillModList:Sum("BASE", skillCfg, "RepeatCount") or 0) + -- Totem attacks ignore recast cooldown; the cooldown remains for placement display. + local totemIgnoresCooldown = skillFlags.totem and skillModList:Flag(skillCfg, "TotemIgnoresCooldown") if output.Repeats > 1 then output.RepeatCount = output.Repeats -- handle all the multipliers from Repeats @@ -2424,7 +2482,9 @@ function calcs.offence(env, actor, activeSkill) end if globalOutput.Cooldown then output.Cooldown = globalOutput.Cooldown - output.Speed = m_min(output.Speed, 1 / output.Cooldown * output.Repeats) + if not totemIgnoresCooldown then + output.Speed = m_min(output.Speed, 1 / output.Cooldown * output.Repeats) + end end if output.Cooldown and skillFlags.selfCast then skillFlags.notAverage = true @@ -2448,7 +2508,7 @@ function calcs.offence(env, actor, activeSkill) { "%.2f ^8(action speed modifier)", (skillFlags.totem and output.TotemActionSpeed) or (skillFlags.selfCast and globalOutput.ActionSpeedMod) or 1 }, total = s_format("= %.2f ^8casts per second", output.CastRate) }) - if output.Cooldown and (1 / output.Cooldown) < output.CastRate then + if output.Cooldown and not totemIgnoresCooldown and (1 / output.Cooldown) < output.CastRate then t_insert(breakdown.Speed, s_format("\n")) t_insert(breakdown.Speed, s_format("1 / %.2f ^8(skill cooldown)", output.Cooldown)) if output.Repeats > 1 then @@ -2477,9 +2537,9 @@ function calcs.offence(env, actor, activeSkill) end elseif skillData.hitTimeMultiplier and output.Time and not skillData.triggeredOnDeath then output.HitTime = output.Time * skillData.hitTimeMultiplier - if output.Cooldown and skillData.triggered then + if output.Cooldown and not totemIgnoresCooldown and skillData.triggered then output.HitSpeed = 1 / (m_max(output.HitTime, output.Cooldown)) - elseif output.Cooldown then + elseif output.Cooldown and not totemIgnoresCooldown then output.HitSpeed = 1 / (output.HitTime + output.Cooldown) else output.HitSpeed = 1 / output.HitTime @@ -2558,9 +2618,9 @@ function calcs.offence(env, actor, activeSkill) output.HitSpeed = 1 / output.HitTime elseif skillData.hitTimeMultiplier and output.Time and not skillData.triggeredOnDeath then output.HitTime = output.Time * skillData.hitTimeMultiplier - if output.Cooldown and skillData.triggered then + if output.Cooldown and not totemIgnoresCooldown and skillData.triggered then output.HitSpeed = 1 / (m_max(output.HitTime, output.Cooldown)) - elseif output.Cooldown then + elseif output.Cooldown and not totemIgnoresCooldown then output.HitSpeed = 1 / (output.HitTime + output.Cooldown) else output.HitSpeed = m_min(1 / output.HitTime, data.misc.ServerTickRate) @@ -2585,9 +2645,9 @@ function calcs.offence(env, actor, activeSkill) t_insert(breakdown.HitTime, s_format("x %.2f ^8(channel time multiplier)", skillData.hitTimeMultiplier)) t_insert(breakdown.HitTime, s_format("= %.2f", output.HitTime)) breakdown.HitSpeed = { } - if output.Cooldown and skillData.triggered then + if output.Cooldown and not totemIgnoresCooldown and skillData.triggered then t_insert(breakdown.HitSpeed, s_format("1 / min(%.2f, %.2f) ^8min(hit time, cooldown)", output.HitTime, output.Cooldown)) - elseif output.Cooldown then + elseif output.Cooldown and not totemIgnoresCooldown then t_insert(breakdown.HitSpeed, s_format("1 / (%.2f + %.2f) ^8(hit time + cooldown)", output.HitTime, output.Cooldown)) else t_insert(breakdown.HitSpeed, s_format("1 / %.2f ^8(hit time)", output.HitTime)) @@ -3074,11 +3134,11 @@ function calcs.offence(env, actor, activeSkill) end else local critOverride = skillModList:Override(cfg, "CritChance") - -- destructive link + -- Destructive Link copies the linker's character-sheet main-hand crit. if skillModList:Flag(cfg, "MainHandCritIsEqualToParent") then - critOverride = actor.parent.output.MainHand and actor.parent.output.MainHand.CritChance or actor.parent.weaponData1.CritChance + critOverride = calcs.actorMainHandSheetCritChance(actor.parent) elseif skillModList:Flag(cfg, "MainHandCritIsEqualToPartyMember") then - critOverride = actor.partyMembers.output.MainHand and actor.partyMembers.output.MainHand.CritChance or (actor.partyMembers.weaponData1 and actor.partyMembers.weaponData1.CritChance or 0) + critOverride = calcs.actorMainHandSheetCritChance(actor.partyMembers) end local baseCrit = critOverride or source.CritChance or 0 @@ -3147,7 +3207,8 @@ function calcs.offence(env, actor, activeSkill) end if breakdown and output.CritChance ~= baseCrit then breakdown.CritChance = { } - local baseCritFromMainHandStr = baseCritFromMainHand and " from main weapon" or baseCritFromParentMainHand and " from parent main weapon" or "" + local fromLinkedMainHand = skillModList:Flag(cfg, "MainHandCritIsEqualToParent") or skillModList:Flag(cfg, "MainHandCritIsEqualToPartyMember") + local baseCritFromMainHandStr = baseCritFromMainHand and " from main weapon" or baseCritFromParentMainHand and " from parent main weapon" or fromLinkedMainHand and " from linked main hand" or "" if base ~= 0 then t_insert(breakdown.CritChance, s_format("(%g + %g) ^8(base%s)", baseCrit, base, baseCritFromMainHandStr)) else @@ -3691,11 +3752,15 @@ function calcs.offence(env, actor, activeSkill) output.TotalMin = totalHitMin output.TotalMax = totalHitMax - if skillModList:Flag(skillCfg, "ElementalEquilibrium") and not env.configInput.EEIgnoreHitDamage and (output.FireHitAverage + output.ColdHitAverage + output.LightningHitAverage > 0) then - -- Update enemy hit-by-damage-type conditions - enemyDB.conditions.HitByFireDamage = output.FireHitAverage > 0 - enemyDB.conditions.HitByColdDamage = output.ColdHitAverage > 0 - enemyDB.conditions.HitByLightningDamage = output.LightningHitAverage > 0 + local configInput = (actor.calcEnv and actor.calcEnv.configInput) or env.configInput + if skillModList:Flag(skillCfg, "ElementalEquilibrium") and not configInput.EEIgnoreHitDamage and (output.FireHitAverage + output.ColdHitAverage + output.LightningHitAverage > 0) then + -- Isolation overlay when a Mercenary is hired; otherwise origin writes the shared enemy. + local hitByStore = actor.enemySourceDB or (actor.enemy and actor.enemy.modDB) + if hitByStore then + hitByStore.conditions.HitByFireDamage = output.FireHitAverage > 0 + hitByStore.conditions.HitByColdDamage = output.ColdHitAverage > 0 + hitByStore.conditions.HitByLightningDamage = output.LightningHitAverage > 0 + end end local highestType = "Physical" diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index c7f75eda6c4..bbc3d4800aa 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -5,6 +5,7 @@ -- ---@class Calcs local calcs = require("Modules.CalcBase") +local MercenaryTools = require("Modules.MercenaryTools") local pairs = pairs local ipairs = ipairs @@ -34,22 +35,43 @@ local function getCachedOutputValue(env, activeSkill, ...) calcs.buildActiveSkill(env, env.mode, activeSkill, uuid, {uuid}) end + local cached = GlobalCache.cachedData[env.mode][uuid] + if not cached or not cached.Env then + error("No cached calculation for "..activeSkill.activeEffect.grantedEffect.name) + end + local cachedEnv = cached.Env + local output + if activeSkill.actor and activeSkill.actor.isMercenary then + if not (cachedEnv.mercenary and cachedEnv.mercenary.output) then + error("No cached Mercenary calculation for "..activeSkill.activeEffect.grantedEffect.name) + end + output = cachedEnv.mercenary.output + else + output = cachedEnv.player.output + end local tempValues = {} for i,v in ipairs({...}) do - tempValues[i] = GlobalCache.cachedData[env.mode][uuid].Env.player.output[v] + tempValues[i] = output[v] end return unpack(tempValues) end --- Merge an instance of a buff, taking the highest value of each modifier -local function mergeBuff(src, destTable, destKey) +local exposureStats = { FireExposure = true, ColdExposure = true, LightningExposure = true } + +-- Merge an instance of a buff, taking the highest value of each modifier. +-- Keep exposure candidates separate until their inflictor's bonuses are applied. +local function mergeBuff(src, destTable, destKey, sourceActor) if not destTable[destKey] then destTable[destKey] = new("ModList"):ModList() end local dest = destTable[destKey] for _, mod in ipairs(src) do + if exposureStats[mod.name] and sourceActor then + mod = copyTable(mod, true) + mod.sourceActor = sourceActor + end local match = false - if mod.type ~= "LIST" then + if mod.type ~= "LIST" and not exposureStats[mod.name] then for index, destMod in ipairs(dest) do if modLib.compareModParams(mod, destMod) then if type(destMod.value) == "number" and mod.value > destMod.value then @@ -66,6 +88,241 @@ local function mergeBuff(src, destTable, destKey) end end +-- Combine listed extra-effect mods with the same parameters by summing values. +local function collectMergedListedMods(modStore, skillCfg, listName) + local list = { } + for _, value in ipairs(modStore:List(skillCfg, listName)) do + local add = true + for _, mod in ipairs(list) do + if modLib.compareModParams(mod, value.mod) then + mod.value = mod.value + value.mod.value + add = false + break + end + end + if add then + t_insert(list, copyTable(value.mod, true)) + end + end + return list +end + +-- Scale a buff granted by one actor's skill onto another actor and merge it into +-- that actor's buff store. `sourceStats` are read from the source's mod store with +-- the source skill's config; `recipientStats` are read from the recipient's own +-- modDB without a config, because the source skill's config describes a skill the +-- recipient is not using. +local function mergeBuffOnRecipient(sourceStore, skillCfg, buff, recipient, destination, sourceStats, recipientStats, extraMods, scale, prepare) + local inc = sourceStore:Sum("INC", skillCfg, unpack(sourceStats)) + recipient.modDB:Sum("INC", nil, unpack(recipientStats or { })) + local more = sourceStore:More(skillCfg, unpack(sourceStats)) * recipient.modDB:More(nil, unpack(recipientStats or { })) + local mult = (1 + inc / 100) * more * (scale or 1) + local srcList = new("ModList"):ModList() + srcList:ScaleAddList(buff.modList, mult) + if extraMods then srcList:ScaleAddList(extraMods, mult) end + if prepare then prepare(srcList) end + recipient.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true + mergeBuff(srcList, destination, buff.name) + return mult +end + +local function recipientAcceptsAllyAura(recipient) + return recipient and not recipient.modDB:Flag(nil, "AlliesAurasCannotAffectSelf") +end + +local function applyExtraAuraModToActor(actor, modList) + if not actor or not recipientAcceptsAllyAura(actor) then + return + end + local inc = actor.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = actor.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + actor.modDB:ScaleAddList(modList, (1 + inc / 100) * more) +end + +-- Exported `effectMult` already includes the source's own scaling; application +-- then adds the recipient's effect-on-self modifiers. Compare against this +-- same quantity when choosing between a local aura and an imported copy. +local function allyAuraEffectOnRecipient(recipient, effectMult) + local inc = recipient.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = recipient.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + return (effectMult + inc) / 100 * more +end + +-- Party stores Vaal auras under Aura.Vaal["Vaal Grace"], not Aura["Vaal Grace"]. +local function importedAura(allyBuffs, buffName) + local auras = allyBuffs and allyBuffs["Aura"] + if not auras or not buffName then + return nil + end + if buffName:sub(1, 4) == "Vaal" then + return auras["Vaal"] and auras["Vaal"][buffName] + end + return auras[buffName] +end + +local function markAffectedByAura(recipient, buffName) + recipient.modDB.conditions.AffectedByAura = true + recipient.modDB.conditions["AffectedBy"..buffName:gsub(" ","")] = true + if buffName:sub(1, 4) == "Vaal" then + recipient.modDB.conditions["AffectedBy"..buffName:sub(6):gsub(" ","")] = true + end +end + +-- Imported ally auras that the recipient would actually take beat a weaker local copy. +local function strongerImportedAura(recipient, allyBuffs, buffName, localMult) + if not recipientAcceptsAllyAura(recipient) then + return false + end + local imported = importedAura(allyBuffs, buffName) + return imported and allyAuraEffectOnRecipient(recipient, imported.effectMult) > localMult +end + +local function mergeAuraOnRecipient(sourceStore, skillCfg, buff, recipient, destination, sourceStats, recipientStats, extraMods, allyBuffs, prepare) + if not recipient then + return false + end + local inc = sourceStore:Sum("INC", skillCfg, unpack(sourceStats)) + recipient.modDB:Sum("INC", nil, unpack(recipientStats or { })) + local more = sourceStore:More(skillCfg, unpack(sourceStats)) * recipient.modDB:More(nil, unpack(recipientStats or { })) + local mult = (1 + inc / 100) * more + if strongerImportedAura(recipient, allyBuffs, buff.name, mult) then + return false + end + markAffectedByAura(recipient, buff.name) + mergeBuffOnRecipient(sourceStore, skillCfg, buff, recipient, destination, sourceStats, recipientStats, extraMods, nil, prepare) + return true +end + +-- Apply a caster's aura to an allied recipient unless the recipient forbids +-- incoming ally auras or a stronger imported copy of the same aura exists. +local function mergeIncomingAuraOnRecipient(sourceStore, skillCfg, buff, recipient, destination, extraMods, allyBuffs, prepare) + if not recipientAcceptsAllyAura(recipient) then + return false + end + return mergeAuraOnRecipient(sourceStore, skillCfg, buff, recipient, destination, { "AuraEffect", "BuffEffect" }, { "BuffEffectOnSelf", "AuraEffectOnSelf" }, extraMods, allyBuffs, prepare) +end + +-- Merge a buff exported by another party member onto a recipient actor. The +-- exported `effectMult` already includes the source's own scaling, so only the +-- recipient's effect-on-self modifiers are applied here. +local function mergeAllyBuffOnRecipient(recipient, destination, buffName, modList, effectMult) + local srcList = new("ModList"):ModList() + srcList:ScaleAddList(modList, allyAuraEffectOnRecipient(recipient, effectMult)) + mergeBuff(srcList, destination, buffName) +end + +local function mergeImportedAuraOnRecipient(recipient, destination, auraName, aura) + local auraNameCompressed = auraName:gsub(" ", "") + if not recipientAcceptsAllyAura(recipient) or recipient.modDB.conditions["AffectedBy"..auraNameCompressed] then + return + end + markAffectedByAura(recipient, auraName) + mergeAllyBuffOnRecipient(recipient, destination, auraName, aura.modList, aura.effectMult) +end + +-- As `mergeAllyBuffOnRecipient` for a Warcry, where each modifier carries its own +-- bonus from the casting party member's Warcry Power. +local function mergeAllyWarcryOnRecipient(recipient, destination, warcryName, warcry) + local srcList = new("ModList"):ModList() + for _, warcryBuff in ipairs(warcry.modList) do + srcList:ScaleAddList({ warcryBuff }, (warcry.effectMult or 100) / 100 * (warcryBuff[1].warcryPowerBonus or 1)) + end + mergeBuff(srcList, destination, warcryName) +end + +-- As `mergeBuffOnRecipient`, but each modifier in a Warcry buff carries its own +-- bonus from the caster's Warcry Power and the whole buff is scaled by its uptime. +local function mergeWarcryOnRecipient(sourceStore, skillCfg, buff, recipient, destination, sourceStats, recipientStats, uptime, conditionName) + local inc = sourceStore:Sum("INC", skillCfg, unpack(sourceStats)) + recipient.modDB:Sum("INC", nil, unpack(recipientStats or { })) + local more = sourceStore:More(skillCfg, unpack(sourceStats)) * recipient.modDB:More(nil, unpack(recipientStats or { })) + local srcList = new("ModList"):ModList() + for _, warcryBuff in ipairs(buff.modList) do + srcList:ScaleAddList({ warcryBuff }, (1 + inc / 100) * more * (warcryBuff[1].warcryPowerBonus or 1) * uptime) + end + recipient.modDB.conditions["AffectedBy"..(conditionName or buff.name:gsub(" ",""))] = true + mergeBuff(srcList, destination, buff.name) +end + +-- Record how many attacks a Warcry exerts on its caster. The attack skill config +-- is the caster's main skill so slam/melee tags on ExertedAttacks still match. +local function applyWarcryExerts(actor, attackSkillCfg, modStore, buff, warcryList) + if not (actor and actor.modDB and attackSkillCfg) then + return + end + local warcryName = buff.name:gsub(" Cry", ""):gsub("'s",""):gsub(" ","") + local baseExerts = modStore:Sum("BASE", attackSkillCfg, warcryName.."ExertedAttacks") + if baseExerts <= 0 then + return + end + local extraExertions = modStore:Sum("BASE", nil, "ExtraExertedAttacks") or 0 + local exertMultiplier = modStore:More(nil, "ExtraExertedAttacks") + actor.modDB:NewMod("Num"..warcryName.."Exerts", "BASE", m_floor((baseExerts + extraExertions) * exertMultiplier)) + if not warcryList[buff.name] then + actor.modDB:NewMod("Multiplier:ExertingWarcryCount", "BASE", 1, buff.name) + warcryList[buff.name] = true + end +end + +local RALLYING_DAMAGE_TYPES = { "Physical", "Lightning", "Cold", "Fire", "Chaos" } + +-- Warcry buff uptime is duration/cooldown unless Max Hit treats the boost as fully active. +local function calcWarcryUptime(env, enemyDB, actorModDB, sourceStore, skillCfg, activeSkill) + if actorModDB:Flag(nil, "Condition:WarcryMaxHit") then + return 1 + end + local duration = calcSkillDuration(sourceStore, skillCfg, activeSkill.skillData, env, enemyDB) + local cooldownOverride = sourceStore:Override(skillCfg, "CooldownRecovery") + local cooldown = cooldownOverride or (activeSkill.skillData.cooldown + sourceStore:Sum("BASE", skillCfg, "CooldownRecovery")) / calcLib.mod(sourceStore, skillCfg, "CooldownRecovery") + if not cooldown or cooldown <= 0 then + return 1 + end + return m_min(duration / cooldown, 1) +end + +-- Rallying Cry grants nearby allies a portion of the caster's weapon damage. +-- Minion recipients get the additional minion-effect multiplier; other allies do not. +local function buildRallyingCryAllyMods(sourceActor, activeSkill, warcryPower) + local extraWarcryModList = new("ModList"):ModList() + if not activeSkill.activeEffect or activeSkill.activeEffect.grantedEffect.name ~= "Rallying Cry" then + return extraWarcryModList, 1 + end + local warcryPowerBonus = m_floor(m_min(warcryPower, 30) / 5) + local rallyingWeaponEffect = m_floor(activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "RallyingCryAllyDamageBonusPer5Power") * warcryPowerBonus) + local minionMultiplier = 1 + (activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "RallyingCryMinionDamageBonusMultiplier") or 0) + local weapon = sourceActor.weaponData1 + if weapon then + for _, damageType in ipairs(RALLYING_DAMAGE_TYPES) do + if weapon[damageType.."Min"] then + extraWarcryModList:NewMod(damageType.."Min", "BASE", weapon[damageType.."Min"] * rallyingWeaponEffect / 100, "Rallying Cry", 0, KeywordFlag.Attack, { type = "GlobalEffect", effectType = "Warcry", div = 5, limit = 30 }) + end + if weapon[damageType.."Max"] then + extraWarcryModList:NewMod(damageType.."Max", "BASE", weapon[damageType.."Max"] * rallyingWeaponEffect / 100, "Rallying Cry", 0, KeywordFlag.Attack, { type = "GlobalEffect", effectType = "Warcry", div = 5, limit = 30 }) + end + end + end + return extraWarcryModList, minionMultiplier +end + +local function mergeRallyingCryAllyMods(extraMods, extraScale, sourceStore, skillCfg, recipient, destination, buffName, uptime) + if not extraMods then + return + end + local inc = sourceStore:Sum("INC", skillCfg, "BuffEffect") + recipient.modDB:Sum("INC", nil, "BuffEffectOnSelf") + local srcList = new("ModList"):ModList() + srcList:ScaleAddList(extraMods, (1 + inc / 100) * extraScale * uptime) + if not srcList[1] then + return + end + mergeBuff(srcList, destination, buffName) +end + +-- Party export keeps the same-name aura with the highest effect, matching local calc and the Party tab. +local function exportStrongestAura(buffExports, name, effectMult, modList) + local existing = buffExports.Aura[name] + if existing and existing.effectMult > effectMult then + return + end + buffExports.Aura[name] = { effectMult = effectMult, modList = modList } +end + function doActorLifeMana(actor) local modDB = actor.modDB ---@class Output @@ -283,13 +540,13 @@ local function doActorAttribsConditions(env, actor) if actor.mainSkill.skillFlags.trap then condList["TriggeredTrapsRecently"] = true end - if modDB:Sum("BASE", nil, "EnemyScorchChance") > 0 or modDB:Flag(nil, "CritAlwaysAltAilments") and not modDB:Flag(env.player.mainSkill.skillCfg, "NeverCrit") or modDB:Flag(nil, "IgniteCanScorch") then + if modDB:Sum("BASE", nil, "EnemyScorchChance") > 0 or modDB:Flag(nil, "CritAlwaysAltAilments") and not modDB:Flag(actor.mainSkill.skillCfg, "NeverCrit") or modDB:Flag(nil, "IgniteCanScorch") then condList["CanInflictScorch"] = true end - if modDB:Sum("BASE", nil, "EnemyBrittleChance") > 0 or modDB:Flag(nil, "CritAlwaysAltAilments") and not modDB:Flag(env.player.mainSkill.skillCfg, "NeverCrit") then + if modDB:Sum("BASE", nil, "EnemyBrittleChance") > 0 or modDB:Flag(nil, "CritAlwaysAltAilments") and not modDB:Flag(actor.mainSkill.skillCfg, "NeverCrit") then condList["CanInflictBrittle"] = true end - if modDB:Sum("BASE", nil, "EnemySapChance") > 0 or modDB:Flag(nil, "CritAlwaysAltAilments") and not modDB:Flag(env.player.mainSkill.skillCfg, "NeverCrit") then + if modDB:Sum("BASE", nil, "EnemySapChance") > 0 or modDB:Flag(nil, "CritAlwaysAltAilments") and not modDB:Flag(actor.mainSkill.skillCfg, "NeverCrit") then condList["CanInflictSap"] = true end -- Shrine Buffs: Must be done before life pool calculated for massive shrine @@ -396,13 +653,13 @@ local function doActorAttribsConditions(env, actor) end end if env.mode_effective then - if env.player.mainSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "FireExposureChance") > 0 or modDB:Sum("BASE", nil, "FireExposureChance") > 0 then + if actor.mainSkill.skillModList:Sum("BASE", actor.mainSkill.skillCfg, "FireExposureChance") > 0 or modDB:Sum("BASE", nil, "FireExposureChance") > 0 then condList["CanApplyFireExposure"] = true end - if env.player.mainSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "ColdExposureChance") > 0 or modDB:Sum("BASE", nil, "ColdExposureChance") > 0 then + if actor.mainSkill.skillModList:Sum("BASE", actor.mainSkill.skillCfg, "ColdExposureChance") > 0 or modDB:Sum("BASE", nil, "ColdExposureChance") > 0 then condList["CanApplyColdExposure"] = true end - if env.player.mainSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "LightningExposureChance") > 0 or modDB:Sum("BASE", nil, "LightningExposureChance") > 0 then + if actor.mainSkill.skillModList:Sum("BASE", actor.mainSkill.skillCfg, "LightningExposureChance") > 0 or modDB:Sum("BASE", nil, "LightningExposureChance") > 0 then condList["CanApplyLightningExposure"] = true end end @@ -592,7 +849,7 @@ local function determineCursePriority(curseName, activeSkill) if activeSkill and activeSkill.socketGroup then source = activeSkill.socketGroup.source or "" slot = activeSkill.socketGroup.slot or "" - for k, v in ipairs(activeSkill.socketGroup.gemList) do + for k, v in ipairs(activeSkill.socketGroup.gemList or { }) do if v.gemData and v.gemData.name == curseName then -- We need to enforce a limit of 8 here to avoid collision with data.cursePriority["CurseFromEquipment"] socket = m_min(k, 8) @@ -616,6 +873,51 @@ local function determineCursePriority(curseName, activeSkill) return basePriority + socketPriority + slotPriority + sourcePriority end +local function bindSourceOwnedEnemyMod(mod, actor) + if not mod then + return nil + end + if not (actor and actor.enemySourceDB) then + return mod + end + local hasSource = false + for _, tag in ipairs(mod) do + if tag.sourceOwned == true then + hasSource = true + break + end + end + if not hasSource then + return mod + end + local bound = copyTable(mod, true) + for i, tag in ipairs(bound) do + if tag.sourceOwned == true then + bound[i] = copyTable(tag, true) + bound[i].sourceActor = actor + end + end + return bound +end + +local function actorHasChilledByHitsFlag(actor, flagName) + if not (actor and actor.modDB:Flag(nil, flagName)) then + return false + end + local sourceDB = actor.enemySourceDB or (actor.enemy and actor.enemy.modDB) + if not sourceDB then + return false + end + -- Player overlays copy shared Chilled from config; that is the same + -- back-compat as Ignited-by-you honouring the ignited checkbox. + return sourceDB:GetCondition("ChilledByYourHits") + or sourceDB:GetCondition("Chilled") +end + +local function anyActorHasChilledByHitsFlag(env, flagName) + return actorHasChilledByHitsFlag(env.player, flagName) or actorHasChilledByHitsFlag(env.mercenary, flagName) +end + local function applyEnemyModifiers(actor, clearCache) if clearCache or not actor.appliedEnemyModifiers then actor.appliedEnemyModifiers = { } @@ -625,8 +927,15 @@ local function applyEnemyModifiers(actor, clearCache) for _, value in ipairs(actor.modDB:Tabulate(nil, nil, "EnemyModifier")) do local mod = value.value and value.value.mod if mod and not cache[mod] then - local source = mod.source or value.mod.source - enemyDB:AddMod(modLib.setSource(mod, source)) + local bound = bindSourceOwnedEnemyMod(mod, actor) + if bound then + if exposureStats[bound.name] then + bound = copyTable(bound, true) + bound.sourceActor = actor + end + local source = bound.source or mod.source or value.mod.source + enemyDB:AddMod(modLib.setSource(bound, source)) + end cache[mod] = true end end @@ -640,17 +949,20 @@ local function doActorMisc(env, actor) ---@class Output local output = actor.output local condList = modDB.conditions + local configInput = (actor.calcEnv and actor.calcEnv.configInput) or env.configInput + output.LootRarity = modDB:Sum("INC", nil, "LootRarity") -- Add misc buffs/debuffs if env.mode_combat then - if env.player.mainSkill.baseSkillModList:Flag(nil, "Cruelty") then + if actor.mainSkill and actor.mainSkill.baseSkillModList:Flag(nil, "Cruelty") then modDB.multipliers["Cruelty"] = modDB:Override(nil, "Cruelty") or 40 end -- Minimum Rage if modDB:Sum("BASE", nil, "MinimumRage") > (modDB.multipliers["Rage"] or 0) then modDB.multipliers["Rage"] = modDB:Sum("BASE", nil, "MinimumRage") end - local alliedFortify = modDB:Flag(nil, "YourFortifyEqualToParent") and actor.parent.output.FortificationStacks or env.partyMembers and env.partyMembers.modDB:Flag(nil, "PartyMemberFortifyEqualToYours") and env.partyMembers.output.FortificationStacks or 0 + local alliedFortify = modDB:Flag(nil, "YourFortifyEqualToParent") and actor.parent.output.FortificationStacks + or actor == env.player and env.partyMembers and env.partyMembers.modDB:Flag(nil, "PartyMemberFortifyEqualToYours") and env.partyMembers.output.FortificationStacks or 0 -- Minimum Fortification from King Maker or Perfect Naval Officer spectres or Ally override if modDB:Sum("BASE", nil, "MinimumFortification") > 0 or alliedFortify > 0 then condList["Fortified"] = true @@ -681,12 +993,13 @@ local function doActorMisc(env, actor) end if modDB:Flag(nil, "Onslaught") then local effect - --Loop detects if a Silver flask is used to grant Onslaught. If statement adds flask effect to calculation if one is being used + -- Detect whether a Silver Flask actually applied to this actor grants Onslaught. + -- mergeFlasks() is the authority for recipient applicability (Ceinture/Link, uniques, etc). local onslaughtFromFlask --This value is set to negative and not 0 or else reduced effect would not properly apply local flaskEffectInc = -100 - for item in pairs(env.flasks) do - if item.baseName:match("Silver Flask") then + for item in pairs(actor.appliedFlasks or { }) do + if item.baseName == "Silver Flask" then onslaughtFromFlask = true local curFlaskEffectInc = item.flaskData.effectInc + modDB:Sum("INC", { actor = "player" }, "FlaskEffect") @@ -932,12 +1245,12 @@ local function doActorMisc(env, actor) output.InherentRageLossDelay = 2 + modDB:Sum("BASE", nil, "InherentRageLossDelay") output.InherentRageLoss = (not modDB:Flag(nil, "InherentRageLossIsPrevented")) and 10 * (1 + modDB:Sum("INC", nil, "InherentRageLoss") / 100) or 0 end - if (env.configInput.multiplierManaBurnStacks or 0) > 0 then + if (configInput.multiplierManaBurnStacks or 0) > 0 then local maxManaBurn = modDB:Sum("BASE", nil, "MaxManaBurnStacks") if maxManaBurn == 0 then maxManaBurn = 9999 end - local manaBurnStacks = m_min((env.configInput.multiplierManaBurnStacks or 0), maxManaBurn) + local manaBurnStacks = m_min((configInput.multiplierManaBurnStacks or 0), maxManaBurn) modDB:NewMod("Multiplier:ManaBurnStacks", "BASE", manaBurnStacks, "Config") manaBurnStacks = manaBurnStacks + modDB:Sum("BASE", { actor = "player" }, "EffectiveManaBurnStacks") if modDB:Flag(nil, "Condition:WeepingWoundsInsteadOfManaBurn") then @@ -969,6 +1282,12 @@ local function doActorMisc(env, actor) local max = modDB:Override(nil, "SoulEaterMax") or modDB:Sum("BASE", nil, "SoulEaterMax") modDB:NewMod("Speed", "INC", 5, "Base", ModFlag.Attack, { type = "Multiplier", var = "SoulEaterStack", limit = max }) modDB:NewMod("Speed", "INC", 5, "Base", ModFlag.Cast, { type = "Multiplier", var = "SoulEaterStack", limit = max }) + -- Mercenaries use monster Soul Eater: 2% less damage taken per soul, capped at 90% less. + if actor.isMercenary then + local lessPerSoul = 2 + local damageTakenLimit = m_min(max, m_floor(90 / lessPerSoul)) + modDB:NewMod("DamageTaken", "MORE", -lessPerSoul, "Soul Eater", { type = "Multiplier", var = "SoulEaterStack", limit = damageTakenLimit }) + end end end @@ -998,7 +1317,7 @@ local function doActorCharges(env, actor) modDB:ReplaceMod("EnduranceChargesMax", "OVERRIDE", output.FrenzyChargesMax, source) end output.EnduranceChargesMin = m_max(modDB:Sum("BASE", nil, "EnduranceChargesMin"), 0) - output.EnduranceChargesMax = modDB:Override(nil, "EnduranceChargesMax") or m_max(env.partyMembers.modDB:Flag(nil, "PartyMemberMaximumEnduranceChargesEqualToYours") and env.partyMembers.output.EnduranceChargesMax or (modDB:Flag(nil, "MaximumEnduranceChargesIsMaximumFrenzyCharges") and output.FrenzyChargesMax or modDB:Sum("BASE", nil, "EnduranceChargesMax")), 0) + output.EnduranceChargesMax = modDB:Override(nil, "EnduranceChargesMax") or m_max(actor == env.player and env.partyMembers.modDB:Flag(nil, "PartyMemberMaximumEnduranceChargesEqualToYours") and env.partyMembers.output.EnduranceChargesMax or (modDB:Flag(nil, "MaximumEnduranceChargesIsMaximumFrenzyCharges") and output.FrenzyChargesMax or modDB:Sum("BASE", nil, "EnduranceChargesMax")), 0) output.EnduranceChargesDuration = m_floor(modDB:Sum("BASE", nil, "ChargeDuration") * calcLib.mod(modDB, nil, "EnduranceChargesDuration", "ChargeDuration")) output.SiphoningChargesMax = m_max(modDB:Sum("BASE", nil, "SiphoningChargesMax"), 0) output.ChallengerChargesMax = m_max(modDB:Sum("BASE", nil, "ChallengerChargesMax"), 0) @@ -1152,8 +1471,16 @@ end -- Build the same modifier database for the selected minion and any minion used as a defensive Life pool. local function initMinionModDB(env, activeSkill, output) - local modDB = env.modDB + local parent = activeSkill.actor + local modDB = parent.modDB local minion = activeSkill.minion + if minion.modDB.itemModsLoaded then + if output then + minion.output = output + end + return + end + minion.modDB.itemModsLoaded = true minion.output = output or { } minion.modDB.multipliers["Level"] = minion.level calcs.initModDB(env, minion.modDB) @@ -1198,38 +1525,46 @@ local function initMinionModDB(env, activeSkill, output) for _, mod in ipairs(activeSkill.extraSkillModList) do minion.modDB:AddMod(mod) end - if env.aegisModList then + if parent == env.player and env.aegisModList then minion.itemList["Weapon 3"] = env.aegisItem minion.modDB:AddList(env.aegisModList) end - if env.theIronMass and minion.type == "RaisedSkeleton" then + if parent == env.player and env.theIronMass and minion.type == "RaisedSkeleton" then minion.modDB:AddList(env.theIronMass) end if activeSkill.skillData.minionUseBowAndQuiver then - if env.player.weaponData1.type == "Bow" then - minion.modDB:AddList(env.player.itemList["Weapon 1"].slotModList[1]) + if parent.weaponData1.type == "Bow" then + minion.modDB:AddList(parent.itemList["Weapon 1"].slotModList[1]) end - if env.player.itemList["Weapon 2"] and env.player.itemList["Weapon 2"].type == "Quiver" then - minion.modDB:ScaleAddList(env.player.itemList["Weapon 2"].modList, m_max(modDB:Sum("BASE", nil, "WidowHailMultiplier"), 1)) + if parent.itemList["Weapon 2"] and parent.itemList["Weapon 2"].type == "Quiver" then + minion.modDB:ScaleAddList(parent.itemList["Weapon 2"].modList, m_max(modDB:Sum("BASE", nil, "WidowHailMultiplier"), 1)) end - if modDB:Flag(nil, "BlinkAndMirrorUseGloves") and env.player.itemList["Gloves"] then - minion.modDB:AddList(env.player.itemList["Gloves"].modList) + if modDB:Flag(nil, "BlinkAndMirrorUseGloves") and parent.itemList["Gloves"] then + minion.modDB:AddList(parent.itemList["Gloves"].modList) end end if activeSkill.skillData.minionUseMainHandWeapon then - minion.modDB:AddList(env.player.itemList["Weapon 1"].slotModList[1]) + local weapon = parent.itemList["Weapon 1"] + if weapon then minion.modDB:AddList(weapon.slotModList[1]) end end if minion.itemSet or minion.uses then for slotName, slot in pairs(env.build.itemsTab.slots) do if minion.uses[slotName] then local item + local itemSetSlotName = slotName if minion.itemSet then if slot.weaponSet == 1 and minion.itemSet.useSecondWeaponSet then - slotName = slotName .. " Swap" + itemSetSlotName = slotName .. " Swap" + slotName = itemSetSlotName + end + local itemSlot = minion.itemSet[itemSetSlotName] + if env.override.itemSetId == minion.itemSet.id and env.override.repSlotName == itemSetSlotName then + item = env.override.repItem + elseif itemSlot then + item = env.build.itemsTab.items[itemSlot.selItemId] end - item = env.build.itemsTab.items[minion.itemSet[slotName].selItemId] else - item = env.player.itemList[slotName] + item = parent.itemList[slotName] end if item then minion.itemList[slotName] = item @@ -1241,6 +1576,13 @@ local function initMinionModDB(env, activeSkill, output) if modDB:Sum("BASE", nil, "StrengthAddedToMinions") > 0 then minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str") * modDB:Sum("BASE", nil, "StrengthAddedToMinions") / 100), "Player") end + if parent.isMercenary then + minion.modDB.multipliers.UniqueItem = parent.modDB.multipliers.UniqueItem or 0 + minion.modDB:NewMod("Damage", "MORE", MercenaryTools.permanentDamageMore(parent.level, env.data.mercenaries.permanentMercenaryDamageMore), "Permanent Mercenary") + for _, value in ipairs(env.modDB:List(nil, "MercenaryMinionModifier")) do + minion.modDB:AddMod(value.mod) + end + end end -- Add modifiers granted to the minion by its skill or an active buff. @@ -1271,6 +1613,63 @@ for _, lifePools in pairs({ minionLifePoolBySkill, totemLifePoolByStat }) do end end +local function actorHasElementalEquilibrium(actor) + return actor and (actor.modDB:Flag(nil, "ElementalEquilibrium") + or (actor.mainSkill and actor.mainSkill.skillModList:Flag(actor.mainSkill.skillCfg, "ElementalEquilibrium"))) +end + +local function copyModArray(list) + if not list then + return nil + end + local copy = { } + for index = 1, #list do + copy[index] = list[index] + end + return copy +end + +local function restoreModArray(list, cached) + if not list or not cached then + return + end + for index = #list, 1, -1 do + list[index] = nil + end + for index = 1, #cached do + list[index] = cached[index] + end +end + +local function snapshotActorForOffence(actor) + if not actor then + return nil + end + local skill = actor.mainSkill + return { + modDB = calcs.copyModDB(actor.modDB), + skillMods = skill and copyModArray(skill.skillModList), + skillData = skill and skill.skillData and copyTable(skill.skillData), + } +end + +local function restoreActorForOffence(actor, cached) + if not actor or not cached then + return + end + calcs.restoreModDB(actor.modDB, cached.modDB) + local skill = actor.mainSkill + if skill then + restoreModArray(skill.skillModList, cached.skillMods) + if cached.skillData and skill.skillData then + wipeTable(skill.skillData) + for key, value in pairs(cached.skillData) do + skill.skillData[key] = value + end + end + end +end + -- Finalises the environment and performs the stat calculations: -- 1. Merges keystone modifiers -- 2. Initialises minion skills @@ -1290,6 +1689,10 @@ function calcs.perform(env, skipEHP) -- Merge keystone modifiers env.keystonesAdded = { } modLib.mergeKeystones(env, env.modDB) + if env.mercenary then + env.mercenary.calcEnv.keystonesAdded = { } + modLib.mergeKeystones(env.mercenary.calcEnv, env.mercenary.modDB) + end -- Build minion skills for _, activeSkill in ipairs(env.player.activeSkillList) do @@ -1301,9 +1704,23 @@ function calcs.perform(env, skipEHP) activeSkill.skillPartName = activeSkill.minion.mainSkill.activeEffect.grantedEffect.name end end + if env.mercenary then + for _, activeSkill in ipairs(env.mercenary.activeSkillList) do + activeSkill.skillModList = new("ModList"):ModList(activeSkill.baseSkillModList) + if activeSkill.minion then + activeSkill.minion.modDB = new("ModDB"):ModDB() + activeSkill.minion.modDB.actor = activeSkill.minion + calcs.createMinionSkills(env.mercenary.calcEnv, activeSkill) + if activeSkill.minion.mainSkill then + activeSkill.skillPartName = activeSkill.minion.mainSkill.activeEffect.grantedEffect.name + end + end + end + end env.player.output = { } env.enemy.output = {} + if env.mercenary then env.mercenary.output = { } end ---@class Output local output = env.player.output @@ -1319,6 +1736,24 @@ function calcs.perform(env, skipEHP) output.Minion = { } initMinionModDB(env, env.player.mainSkill, output.Minion) end + -- Item-set minions such as Animate Guardian still wear their gear when they + -- are not the displayed main-skill minion, so ExtraAura / EnemyModifier from + -- that gear can reach the player and Mercenary. + for _, activeSkill in ipairs(env.player.activeSkillList) do + local minion = activeSkill.minion + if minion and minion ~= env.minion and minion.itemSet and not activeSkill.skillFlags.disable then + initMinionModDB(env, activeSkill) + end + end + env.mercenaryMinion = env.mercenary and env.mercenary.mainSkill and env.mercenary.mainSkill.minion + if env.mercenary and env.mercenary.calcEnv then + -- false (not nil) so __index does not fall through to the player's minion. + env.mercenary.calcEnv.minion = env.mercenaryMinion or false + end + if env.mercenaryMinion then + env.mercenary.output.Minion = { } + initMinionModDB(env, env.mercenary.mainSkill, env.mercenary.output.Minion) + end if env.aegisModList then env.player.itemList["Weapon 2"] = nil end @@ -1348,156 +1783,190 @@ function calcs.perform(env, skipEHP) modDB.multipliers["WarcryPower"] = output.WarcryPower applyEnemyModifiers(env.player, true) + if env.mercenary then applyEnemyModifiers(env.mercenary, true) end if env.minion then applyEnemyModifiers(env.minion, true) end + for _, activeSkill in ipairs(env.player.activeSkillList) do + local minion = activeSkill.minion + if minion and minion ~= env.minion and minion.itemSet and not activeSkill.skillFlags.disable then + applyEnemyModifiers(minion, true) + end + end + if env.mercenaryMinion then applyEnemyModifiers(env.mercenaryMinion, true) end applyEnemyModifiers(env.enemy, true) - local minionCounts = { } - for _, activeSkill in ipairs(env.player.activeSkillList) do - if activeSkill.skillTypes[SkillType.Brand] then - local attachLimit = m_min(activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "BrandsAttachedLimit"), activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "ActiveBrandLimit")) - local configured = modDB:Sum("BASE", nil, "Multiplier:ConfigBrandsAttachedToEnemy") - local attached = configured > 0 and m_min(configured, attachLimit) or attachLimit - activeSkill.skillData.attachedBrandCount = attached - local activeBrands = modDB:Sum("BASE", nil, "Multiplier:ConfigActiveBrands") - -- Cap the number of active brands by the limit, which is 3 by default - -- Also consider increase to number of active brands from other sources (e.g. Foulgrasp Support) - modDB.multipliers["ActiveBrand"] = m_max(m_min(activeBrands, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "ActiveBrandLimit")), modDB.multipliers["ActiveBrand"] or 0) - modDB.multipliers["BrandsAttachedToEnemy"] = m_max(attached, modDB.multipliers["BrandsAttachedToEnemy"] or 0) - enemyDB.multipliers["BrandsAttached"] = m_max(attached, enemyDB.multipliers["BrandsAttached"] or 0) - end - if activeSkill.skillFlags.totem then - local limit = env.player.mainSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "ActiveTotemLimit", "ActiveBallistaLimit" ) - output.ActiveTotemLimit = m_max(limit, output.ActiveTotemLimit or 0) - output.TotemsSummoned = modDB:Override(nil, "TotemsSummoned") or output.ActiveTotemLimit - enemyDB.multipliers["TotemsSummoned"] = m_max(output.TotemsSummoned or 0, enemyDB.multipliers["TotemsSummoned"] or 0) - end - -- The actual hexes as opposed to hex related skills all have the curse flag. TotemCastsWhenNotDetached is to remove blasphemy - -- Note that this doesn't work for triggers yet, insufficient support - if activeSkill.skillFlags.hex and activeSkill.skillFlags.curse and not activeSkill.skillTypes[SkillType.TotemCastsWhenNotDetached] and activeSkill.skillModList:Sum("BASE", nil, "MaxDoom") then - local hexDoom = modDB:Sum("BASE", nil, "Multiplier:HexDoomStack") - local maxDoom = activeSkill.skillModList:Sum("BASE", nil, "MaxDoom") - local doomEffect = activeSkill.skillModList:More(nil, "DoomEffect") - -- Update the max doom limit - output.HexDoomLimit = m_max(maxDoom, output.HexDoomLimit or 0) - -- Update the Hex Doom to apply - activeSkill.skillModList:NewMod("CurseEffect", "INC", m_min(hexDoom, maxDoom) * doomEffect, "Doom") - modDB.multipliers["HexDoom"] = m_min(m_max(hexDoom, modDB.multipliers["HexDoom"] or 0), output.HexDoomLimit) - end - if (activeSkill.activeEffect.grantedEffect.name == "Vaal Lightning Trap" or activeSkill.activeEffect.grantedEffect.name == "Shock Ground") then - -- Shock effect applies to shocked ground - local effect = activeSkill.skillModList:Sum("BASE", nil, "ShockedGroundEffect") * (1 + activeSkill.skillModList:Sum("INC", nil, "EnemyShockEffect") / 100) - modDB:NewMod("ShockOverride", "BASE", effect, "Shocked Ground", { type = "ActorCondition", actor = "enemy", var = "OnShockedGround" } ) + -- Skitterbot shock/chill are guaranteed enemy ailments. Magnitude is written + -- onto the inflicting actor so the shared-enemy ailment pass can cap it with + -- that actor's maximum. + local function applySkitterbotAilments(activeSkill, selfModDB) + if activeSkill.activeEffect.grantedEffect.name ~= "Summon Skitterbots" then + return false end + local skillModList = activeSkill.skillModList + local source = activeSkill.activeEffect.grantedEffect.name + local skitterbotAilmentEffect = skillModList:Sum("INC", nil, "SkitterbotAilmentEffect") + if not skillModList:Flag(nil, "SkitterbotsCannotShock") then + local effect = data.nonDamagingAilment.Shock.default * (1 + (skillModList:Sum("INC", { source = "Skill" }, "EnemyShockEffect") + skitterbotAilmentEffect) / 100) + selfModDB:NewMod("ShockOverride", "BASE", effect, source) + enemyDB:NewMod("Condition:Shocked", "FLAG", true, source) + if skillModList:Flag(nil, "SkitterbotAffectPlayer") then + selfModDB:NewMod("Shock", "FLAG", true, source) + selfModDB:NewMod("SelfShockOverride", "BASE", effect, source) + end + end + if not skillModList:Flag(nil, "SkitterbotsCannotChill") then + local effect = data.nonDamagingAilment.Chill.default * (1 + (skillModList:Sum("INC", { source = "Skill" }, "EnemyChillEffect") + skitterbotAilmentEffect) / 100) + selfModDB:NewMod("ChillOverride", "BASE", effect, source) + enemyDB:NewMod("Condition:Chilled", "FLAG", true, source) + if skillModList:Flag(nil, "SkitterbotAffectPlayer") then + selfModDB:NewMod("Chill", "FLAG", true, source) + selfModDB:NewMod("SelfChillOverride", "BASE", effect, source) + end + if activeSkill.skillData.supportBonechill then + hasGuaranteedBonechill = true + selfModDB:NewMod("SkitterbotBonechill", "FLAG", true, source) + end + end + if skillModList:Flag(nil, "ScorchingSkitterbot") then + local effect = data.nonDamagingAilment.Scorch.default * (1 + (skillModList:Sum("INC", { source = "Skill" }, "EnemyScorchEffect") + skitterbotAilmentEffect) / 100) + selfModDB:NewMod("ScorchOverride", "BASE", effect, source) + enemyDB:NewMod("Condition:Scorched", "FLAG", true, source) + if skillModList:Flag(nil, "SkitterbotAffectPlayer") then + selfModDB:NewMod("Scorch", "FLAG", true, source) + selfModDB:NewMod("SelfScorchOverride", "BASE", effect, source) + end + end + return true + end + + local function collectGuaranteedChill(activeSkill, selfModDB) if activeSkill.skillData.supportBonechill and (activeSkill.skillTypes[SkillType.ChillingArea] or activeSkill.skillTypes[SkillType.NonHitChill] or not activeSkill.skillModList:Flag(nil, "CannotChill")) then output.HasBonechill = true end - if activeSkill.activeEffect.grantedEffect.name == "Summon Skitterbots" then - local skitterbotAilmentEffect = activeSkill.skillModList:Sum("INC", nil, "SkitterbotAilmentEffect") - if not activeSkill.skillModList:Flag(nil, "SkitterbotsCannotShock") then - local effect = data.nonDamagingAilment.Shock.default * (1 + (activeSkill.skillModList:Sum("INC", { source = "Skill" }, "EnemyShockEffect") + skitterbotAilmentEffect) / 100) - modDB:NewMod("ShockOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) - enemyDB:NewMod("Condition:Shocked", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) - if activeSkill.skillModList:Flag(nil, "SkitterbotAffectPlayer") then - modDB:NewMod("Shock", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) - modDB:NewMod("SelfShockOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) - end - end - if not activeSkill.skillModList:Flag(nil, "SkitterbotsCannotChill") then - local effect = data.nonDamagingAilment.Chill.default * (1 + (activeSkill.skillModList:Sum("INC", { source = "Skill" }, "EnemyChillEffect") + skitterbotAilmentEffect) / 100) - modDB:NewMod("ChillOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) - enemyDB:NewMod("Condition:Chilled", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) - if activeSkill.skillModList:Flag(nil, "SkitterbotAffectPlayer") then - modDB:NewMod("Chill", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) - modDB:NewMod("SelfChillOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) - end - if activeSkill.skillData.supportBonechill then - hasGuaranteedBonechill = true - modDB:NewMod("SkitterbotBonechill", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) - end - end - if activeSkill.skillModList:Flag(nil, "ScorchingSkitterbot") then - local effect = data.nonDamagingAilment.Scorch.default * (1 + (activeSkill.skillModList:Sum("INC", { source = "Skill" }, "EnemyScorchEffect") + skitterbotAilmentEffect) / 100) - modDB:NewMod("ScorchOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) - enemyDB:NewMod("Condition:Scorched", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) - if activeSkill.skillModList:Flag(nil, "SkitterbotAffectPlayer") then - modDB:NewMod("Scorch", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) - modDB:NewMod("SelfScorchOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) - end - end - elseif activeSkill.skillFlags.guaranteedChill or activeSkill.skillTypes[SkillType.ChillingArea] or (activeSkill.skillTypes[SkillType.NonHitChill] and not activeSkill.skillModList:Flag(nil, "CannotChill")) then - t_insert(guaranteedChillSkills, activeSkill) + if not applySkitterbotAilments(activeSkill, selfModDB) and (activeSkill.skillFlags.guaranteedChill or activeSkill.skillTypes[SkillType.ChillingArea] or (activeSkill.skillTypes[SkillType.NonHitChill] and not activeSkill.skillModList:Flag(nil, "CannotChill"))) then + t_insert(guaranteedChillSkills, { skill = activeSkill, actorModDB = selfModDB }) enemyDB:NewMod("Condition:Chilled", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) if activeSkill.skillData.supportBonechill then hasGuaranteedBonechill = true end end - -- Count active minions. Skills without a limit contribute one minion. - local minionList = activeSkill.minionList - if not activeSkill.skillFlags.disable and minionList and minionList[1] then - local grantedEffect = activeSkill.activeEffect.grantedEffect - for _, minionType in ipairs(minionList) do - local minionData = env.data.minions[minionType] - if minionData and not minionData.hostile then - local key = minionData.limit or grantedEffect.id..":"..minionType - local count = 1 - if minionData.limit then - count = m_floor(modDB:Override(nil, minionData.limit) or (calcLib.val(activeSkill.skillModList, minionData.limit) * activeSkill.skillModList:More(activeSkill.skillCfg, "ActiveMinionLimit"))) - output[minionData.limit] = m_max(count, output[minionData.limit] or 0) - end - local counts = minionCounts[key] or { } - counts.total = m_max(count, counts.total or 0) - if not activeSkill.skillTypes[SkillType.Vaal] then - counts.nonVaal = m_max(count, counts.nonVaal or 0) - end - if activeSkill.skillFlags.permanentMinion then - counts.permanent = m_max(count, counts.permanent or 0) + end + + local function applyActorSkillSetup(actor, actorModDB, actorOutput) + local actorMinionCounts = { } + if not (actor and actor.activeSkillList) then + return 0 + end + for _, activeSkill in ipairs(actor.activeSkillList) do + if activeSkill.skillTypes[SkillType.Brand] then + local attachLimit = m_min(activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "BrandsAttachedLimit"), activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "ActiveBrandLimit")) + local configured = actorModDB:Sum("BASE", nil, "Multiplier:ConfigBrandsAttachedToEnemy") + local attached = configured > 0 and m_min(configured, attachLimit) or attachLimit + activeSkill.skillData.attachedBrandCount = attached + local activeBrands = actorModDB:Sum("BASE", nil, "Multiplier:ConfigActiveBrands") + -- Cap the number of active brands by the limit, which is 3 by default + -- Also consider increase to number of active brands from other sources (e.g. Foulgrasp Support) + actorModDB.multipliers["ActiveBrand"] = m_max(m_min(activeBrands, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "ActiveBrandLimit")), actorModDB.multipliers["ActiveBrand"] or 0) + actorModDB.multipliers["BrandsAttachedToEnemy"] = m_max(attached, actorModDB.multipliers["BrandsAttachedToEnemy"] or 0) + enemyDB.multipliers["BrandsAttached"] = m_max(attached, enemyDB.multipliers["BrandsAttached"] or 0) + end + if activeSkill.skillFlags.totem and actor.mainSkill then + local limit = actor.mainSkill.skillModList:Sum("BASE", actor.mainSkill.skillCfg, "ActiveTotemLimit", "ActiveBallistaLimit" ) + actorOutput.ActiveTotemLimit = m_max(limit, actorOutput.ActiveTotemLimit or 0) + actorOutput.TotemsSummoned = actorModDB:Override(nil, "TotemsSummoned") or actorOutput.ActiveTotemLimit + enemyDB.multipliers["TotemsSummoned"] = m_max(actorOutput.TotemsSummoned or 0, enemyDB.multipliers["TotemsSummoned"] or 0) + end + -- The actual hexes as opposed to hex related skills all have the curse flag. TotemCastsWhenNotDetached is to remove blasphemy + -- Note that this doesn't work for triggers yet, insufficient support + if activeSkill.skillFlags.hex and activeSkill.skillFlags.curse and not activeSkill.skillTypes[SkillType.TotemCastsWhenNotDetached] and activeSkill.skillModList:Sum("BASE", nil, "MaxDoom") then + local hexDoom = actorModDB:Sum("BASE", nil, "Multiplier:HexDoomStack") + local maxDoom = activeSkill.skillModList:Sum("BASE", nil, "MaxDoom") + local doomEffect = activeSkill.skillModList:More(nil, "DoomEffect") + -- Update the max doom limit + actorOutput.HexDoomLimit = m_max(maxDoom, actorOutput.HexDoomLimit or 0) + -- Update the Hex Doom to apply + activeSkill.skillModList:NewMod("CurseEffect", "INC", m_min(hexDoom, maxDoom) * doomEffect, "Doom") + actorModDB.multipliers["HexDoom"] = m_min(m_max(hexDoom, actorModDB.multipliers["HexDoom"] or 0), actorOutput.HexDoomLimit) + end + if (activeSkill.activeEffect.grantedEffect.name == "Vaal Lightning Trap" or activeSkill.activeEffect.grantedEffect.name == "Shock Ground") then + -- Shock effect applies to shocked ground + local effect = activeSkill.skillModList:Sum("BASE", nil, "ShockedGroundEffect") * (1 + activeSkill.skillModList:Sum("INC", nil, "EnemyShockEffect") / 100) + actorModDB:NewMod("ShockOverride", "BASE", effect, "Shocked Ground", { type = "ActorCondition", actor = "enemy", var = "OnShockedGround" } ) + end + collectGuaranteedChill(activeSkill, actorModDB) + -- Count active minions. Skills without a limit contribute one minion. + local minionList = activeSkill.minionList + if not activeSkill.skillFlags.disable and minionList and minionList[1] then + local grantedEffect = activeSkill.activeEffect.grantedEffect + for _, minionType in ipairs(minionList) do + local minionData = env.data.minions[minionType] + if minionData and not minionData.hostile then + local key = minionData.limit or grantedEffect.id..":"..minionType + local count = 1 + if minionData.limit then + count = m_floor(actorModDB:Override(nil, minionData.limit) or (calcLib.val(activeSkill.skillModList, minionData.limit) * activeSkill.skillModList:More(activeSkill.skillCfg, "ActiveMinionLimit"))) + actorOutput[minionData.limit] = m_max(count, actorOutput[minionData.limit] or 0) + end + local counts = actorMinionCounts[key] or { } + counts.total = m_max(count, counts.total or 0) + if not activeSkill.skillTypes[SkillType.Vaal] then + counts.nonVaal = m_max(count, counts.nonVaal or 0) + end + if activeSkill.skillFlags.permanentMinion then + counts.permanent = m_max(count, counts.permanent or 0) + end + actorMinionCounts[key] = counts end - minionCounts[key] = counts end end - end - if activeSkill.skillTypes[SkillType.CreatesMinion] and not activeSkill.skillTypes[SkillType.MinionsAreUndamagable] then - modDB:NewMod("Condition:HaveDamageableMinion", "FLAG", true) - end - if env.mode_buffs and activeSkill.skillFlags.warcry then - if activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and not activeSkill.skillModList:Flag(nil, "CannotShareWarcryBuffs") and not modDB:Flag(nil, "RallyingActive") then - env.player.modDB:NewMod("RallyingExertMoreDamagePerAlly", "BASE", activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "RallyingCryExertDamageBonus")) - modDB:NewMod("RallyingActive", "FLAG", true) -- Prevents effect from applying multiple times - elseif activeSkill.activeEffect.grantedEffect.name == "Seismic Cry" and not modDB:Flag(nil, "SeismicActive") then - env.player.modDB:NewMod("SeismicMoreAoE", "BASE", activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "SeismicAoEMoreMultiplier")) - modDB:NewMod("SeismicActive", "FLAG", true) -- Prevents effect from applying multiple times + if activeSkill.skillTypes[SkillType.CreatesMinion] and not activeSkill.skillTypes[SkillType.MinionsAreUndamagable] then + actorModDB:NewMod("Condition:HaveDamageableMinion", "FLAG", true) + end + if env.mode_buffs and activeSkill.skillFlags.warcry then + local mainCfg = actor.mainSkill and actor.mainSkill.skillCfg + if activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and not activeSkill.skillModList:Flag(nil, "CannotShareWarcryBuffs") and not actorModDB:Flag(nil, "RallyingActive") then + actorModDB:NewMod("RallyingExertMoreDamagePerAlly", "BASE", activeSkill.skillModList:Sum("BASE", mainCfg, "RallyingCryExertDamageBonus")) + actorModDB:NewMod("RallyingActive", "FLAG", true) -- Prevents effect from applying multiple times + elseif activeSkill.activeEffect.grantedEffect.name == "Seismic Cry" and not actorModDB:Flag(nil, "SeismicActive") then + actorModDB:NewMod("SeismicMoreAoE", "BASE", activeSkill.skillModList:Sum("BASE", mainCfg, "SeismicAoEMoreMultiplier")) + actorModDB:NewMod("SeismicActive", "FLAG", true) -- Prevents effect from applying multiple times + end end - end - if activeSkill.skillData.triggeredOnDeath and not activeSkill.skillFlags.minion then - activeSkill.skillData.triggered = true - for _, value in ipairs(activeSkill.skillModList:Tabulate("INC", env.player.mainSkill.skillCfg, "TriggeredDamage")) do - activeSkill.skillModList:NewMod("Damage", "INC", value.mod.value, value.mod.source, value.mod.flags, value.mod.keywordFlags, unpack(value.mod)) + if activeSkill.skillData.triggeredOnDeath and not activeSkill.skillFlags.minion and actor.mainSkill then + activeSkill.skillData.triggered = true + for _, value in ipairs(activeSkill.skillModList:Tabulate("INC", actor.mainSkill.skillCfg, "TriggeredDamage")) do + activeSkill.skillModList:NewMod("Damage", "INC", value.mod.value, value.mod.source, value.mod.flags, value.mod.keywordFlags, unpack(value.mod)) + end + for _, value in ipairs(activeSkill.skillModList:Tabulate("MORE", actor.mainSkill.skillCfg, "TriggeredDamage")) do + activeSkill.skillModList:NewMod("Damage", "MORE", value.mod.value, value.mod.source, value.mod.flags, value.mod.keywordFlags, unpack(value.mod)) + end + -- Set trigger time to 1 min in ms ( == 6000 ). Technically any large value would do. + activeSkill.skillData.triggerTime = 60 * 1000 end - for _, value in ipairs(activeSkill.skillModList:Tabulate("MORE", env.player.mainSkill.skillCfg, "TriggeredDamage")) do - activeSkill.skillModList:NewMod("Damage", "MORE", value.mod.value, value.mod.source, value.mod.flags, value.mod.keywordFlags, unpack(value.mod)) + -- The Saviour + if activeSkill.activeEffect.grantedEffect.name == "Reflection" or activeSkill.skillData.triggeredBySaviour then + activeSkill.infoMessage = "Triggered by a Crit from The Saviour" + activeSkill.infoTrigger = "Saviour" end - -- Set trigger time to 1 min in ms ( == 6000 ). Technically any large value would do. - activeSkill.skillData.triggerTime = 60 * 1000 end - -- The Saviour - if activeSkill.activeEffect.grantedEffect.name == "Reflection" or activeSkill.skillData.triggeredBySaviour then - activeSkill.infoMessage = "Triggered by a Crit from The Saviour" - activeSkill.infoTrigger = "Saviour" + local summonedMinions = 0 + for _, counts in pairs(actorMinionCounts) do + summonedMinions = summonedMinions + counts.total + actorModDB:NewMod("Multiplier:SummonedMinion", "BASE", counts.total, "Config", { type = "Condition", var = "Combat" }) + if counts.nonVaal then + actorModDB:NewMod("Multiplier:NonVaalSummonedMinion", "BASE", counts.nonVaal, "Config", { type = "Condition", var = "Combat" }) + end + if counts.permanent then + actorModDB:NewMod("Multiplier:PermanentMinion", "BASE", counts.permanent, "Config", { type = "Condition", var = "Combat" }) + end end + return summonedMinions end - local summonedMinions = 0 - for _, counts in pairs(minionCounts) do - summonedMinions = summonedMinions + counts.total - modDB:NewMod("Multiplier:SummonedMinion", "BASE", counts.total, "Config", { type = "Condition", var = "Combat" }) - if counts.nonVaal then - modDB:NewMod("Multiplier:NonVaalSummonedMinion", "BASE", counts.nonVaal, "Config", { type = "Condition", var = "Combat" }) - end - if counts.permanent then - modDB:NewMod("Multiplier:PermanentMinion", "BASE", counts.permanent, "Config", { type = "Condition", var = "Combat" }) - end + local summonedMinions = applyActorSkillSetup(env.player, modDB, output) + if env.mercenary then + applyActorSkillSetup(env.mercenary, env.mercenary.modDB, env.mercenary.output) end -- Companionship only works while exactly one Minion is summoned. @@ -1519,6 +1988,12 @@ function calcs.perform(env, skipEHP) if env.minion then env.minion.breakdown = require(calcs.breakdownModule)(env.minion.modDB, env.minion.output, env.minion) end + if env.mercenary then + env.mercenary.breakdown = require(calcs.breakdownModule)(env.mercenary.modDB, env.mercenary.output, env.mercenary) + end + if env.mercenaryMinion then + env.mercenaryMinion.breakdown = require(calcs.breakdownModule)(env.mercenaryMinion.modDB, env.mercenaryMinion.output, env.mercenaryMinion) + end end if modDB:Flag(nil, "ConvertArmourESToLife") then @@ -1580,8 +2055,10 @@ function calcs.perform(env, skipEHP) local maxRightActiveMagicUtilityCount = modDB:Sum("BASE", nil, "RightActiveMagicUtilityFlasks") if maxLeftActiveMagicUtilityCount > 0 or maxRightActiveMagicUtilityCount > 0 then local magicUtilityFlasks = {} + local activeItemSet = env.build.itemsTab.activeItemSet for _, slot in ipairs(env.build.itemsTab.orderedSlots) do - local item = env.build.itemsTab.items[slot.selItemId] + local itemSlot = activeItemSet and activeItemSet[slot.slotName] + local item = env.build.itemsTab.items[itemSlot and itemSlot.selItemId] if item and item.type == "Flask" and item.rarity == "MAGIC" and not (item.baseName:match("Life Flask") or item.baseName:match("Mana Flask") or item.baseName:match("Hybrid Flask")) then t_insert(magicUtilityFlasks, item) @@ -1604,9 +2081,27 @@ function calcs.perform(env, skipEHP) local effectIncMagicNoAdjacent = modDB:Sum("INC", {actor = "player"}, "MagicFlaskNoAdjacentEffect") local effectIncNonPlayer = modDB:Sum("INC", nil, "FlaskEffect") local effectIncMagicNonPlayer = modDB:Sum("INC", nil, "MagicUtilityFlaskEffect") - local flasksApplyToMinion = env.minion and modDB:Flag(env.player.mainSkill.skillCfg, "FlasksApplyToMinion") - local quickSilverAppliesToAllies = env.minion and modDB:Flag(env.player.mainSkill.skillCfg, "QuickSilverAppliesToAllies") + local playerSkillCfg = env.player.mainSkill and env.player.mainSkill.skillCfg + local flasksApplyToMinion = env.minion and playerSkillCfg and modDB:Flag(playerSkillCfg, "FlasksApplyToMinion") + local quickSilverAppliesToAllies = playerSkillCfg and modDB:Flag(playerSkillCfg, "QuickSilverAppliesToAllies") local nonUniqueFlasksApplyToMinion = env.minion and env.minion.modDB:Flag(nil, "ParentNonUniqueFlasksAppliedToYou") + local nonUniqueUtilityFlasksApplyToMercenary = false + if env.mercenary and env.mode_buffs then + for _, activeSkill in ipairs(env.player.activeSkillList) do + if activeSkill.skillTypes[SkillType.Link] and activeSkill.socketGroup and activeSkill.socketGroup.enabled and not activeSkill.skillFlags.disable then + for _, value in ipairs(modDB:List(activeSkill.skillCfg, "ExtraLinkEffect")) do + if value.mod.name == "ParentNonUniqueFlasksAppliedToYou" then + nonUniqueUtilityFlasksApplyToMercenary = true + break + end + end + end + if nonUniqueUtilityFlasksApplyToMercenary then break end + end + end + local mercenaryEffectInc = nonUniqueUtilityFlasksApplyToMercenary and env.mercenary.modDB:Sum("INC", { actor = "player" }, "FlaskEffect") or 0 + local mercenaryEffectIncMagic = nonUniqueUtilityFlasksApplyToMercenary and env.mercenary.modDB:Sum("INC", { actor = "player" }, "MagicUtilityFlaskEffect") or 0 + local mercenaryEffectIncMagicNoAdjacent = nonUniqueUtilityFlasksApplyToMercenary and env.mercenary.modDB:Sum("INC", { actor = "player" }, "MagicFlaskNoAdjacentEffect") or 0 local flaskTotalRateInc = modDB:Sum("INC", nil, "FlaskRecoveryRate") local flaskDurInc = modDB:Sum("INC", nil, "FlaskDuration") @@ -1697,13 +2192,40 @@ function calcs.perform(env, skipEHP) local flaskBuffsNonPlayer = {} local flaskBuffsPerBaseNonPlayer = {} local flaskBuffsNonUtility = {} + local mercenaryFlaskBuffs = {} + local mercenaryFlaskConditions = {} + local function appliesToMercenary(item) + return nonUniqueUtilityFlasksApplyToMercenary and not onlyRecovery + and item.rarity ~= "UNIQUE" and item.rarity ~= "RELIC" + and not (item.base.flask.life or item.base.flask.mana) + end + local function recordAppliedFlask(actor, item) + if actor then + actor.appliedFlasks = actor.appliedFlasks or { } + actor.appliedFlasks[item] = true + end + end + if not onlyRecovery then + env.player.appliedFlasks = { } + if env.mercenary then + env.mercenary.appliedFlasks = { } + end + if env.mercenaryMinion then + env.mercenaryMinion.appliedFlasks = { } + end + if env.minion then + env.minion.appliedFlasks = { } + end + end local function calcFlaskMods(item, baseName, buffModList, modList, onlyMinion) local flaskEffectInc = effectInc + item.flaskData.effectInc local flaskEffectIncNonPlayer = effectIncNonPlayer + item.flaskData.effectInc + local flaskEffectIncMercenary = mercenaryEffectInc + item.flaskData.effectInc if item.rarity == "MAGIC" and not (item.base.flask.life or item.base.flask.mana) then flaskEffectInc = flaskEffectInc + effectIncMagic flaskEffectIncNonPlayer = flaskEffectIncNonPlayer + effectIncMagicNonPlayer + flaskEffectIncMercenary = flaskEffectIncMercenary + mercenaryEffectIncMagic end -- Essence of Desolation belt mod: bonus for magic flasks with no flask in an adjacent slot (1-5) if item.rarity == "MAGIC" and effectIncMagicNoAdjacent ~= 0 then @@ -1712,11 +2234,13 @@ function calcs.perform(env, skipEHP) local hasAdjacent = (env.flaskSlotOccupied[flaskSlotNum - 1] or env.flaskSlotOccupied[flaskSlotNum + 1]) if not hasAdjacent then flaskEffectInc = flaskEffectInc + effectIncMagicNoAdjacent + flaskEffectIncMercenary = flaskEffectIncMercenary + mercenaryEffectIncMagicNoAdjacent end end end local effectMod = 1 + (flaskEffectInc) / 100 local effectModNonPlayer = 1 + (flaskEffectIncNonPlayer) / 100 + local effectModMercenary = 1 + flaskEffectIncMercenary / 100 -- Life and Mana flasks are not Utility flasks, so their effects are kept when Utility flasks are disabled local isUtilityFlask = not (item.base.flask.life or item.base.flask.mana) @@ -1740,6 +2264,11 @@ function calcs.perform(env, skipEHP) mergeBuff(srcList, flaskBuffsNonPlayer, baseName) mergeBuff(srcList, flaskBuffsPerBaseNonPlayer[item.baseName], baseName) end + if appliesToMercenary(item) then + local srcList = new("ModList"):ModList() + srcList:ScaleAddList(buffModList, effectModMercenary) + mergeBuff(srcList, mercenaryFlaskBuffs, baseName) + end end if modList[1] then @@ -1767,6 +2296,11 @@ function calcs.perform(env, skipEHP) mergeBuff(srcList, flaskBuffsNonPlayer, key) mergeBuff(srcList, flaskBuffsPerBaseNonPlayer[item.baseName], key) end + if appliesToMercenary(item) then + local recipientList = new("ModList"):ModList() + recipientList:ScaleAddList(modList, effectModMercenary) + mergeBuff(recipientList, mercenaryFlaskBuffs, key) + end end end @@ -1789,6 +2323,35 @@ function calcs.perform(env, skipEHP) flaskConditions["UsingManaFlask"] = true flaskConditionsNonUtility["UsingManaFlask"] = true end + if appliesToMercenary(item) then + mercenaryFlaskConditions["UsingFlask"] = true + mercenaryFlaskConditions["Using"..item.baseName:gsub("%s+", "")] = true + end + end + if not onlyRecovery then + if not modDB:Flag(nil, "FlasksDoNotApplyToPlayer") then + local isUtilityFlask = not (item.base.flask.life or item.base.flask.mana) + if not (modDB:Flag(nil, "UtilityFlasksDoNotApplyToPlayer") and isUtilityFlask) then + recordAppliedFlask(env.player, item) + end + end + if appliesToMercenary(item) then + recordAppliedFlask(env.mercenary, item) + elseif env.mercenary and not nonUniqueUtilityFlasksApplyToMercenary and quickSilverAppliesToAllies and item.baseName == "Quicksilver Flask" then + recordAppliedFlask(env.mercenary, item) + end + if env.mercenaryMinion and quickSilverAppliesToAllies and item.baseName == "Quicksilver Flask" then + recordAppliedFlask(env.mercenaryMinion, item) + end + if env.minion then + if flasksApplyToMinion then + recordAppliedFlask(env.minion, item) + elseif nonUniqueFlasksApplyToMinion and item.rarity ~= "UNIQUE" and item.rarity ~= "RELIC" then + recordAppliedFlask(env.minion, item) + elseif quickSilverAppliesToAllies and item.baseName == "Quicksilver Flask" then + recordAppliedFlask(env.minion, item) + end + end end if item.baseName == "Iron Flask" then local chargesGeneratedOnWardBreak = modDB:Sum("BASE", nil, "IronFlaskChargesGeneratedOnWardBreak") @@ -1826,6 +2389,16 @@ function calcs.perform(env, skipEHP) modDB:AddList(buffModList) end end + local function applyQuicksilverToAlly(actor) + if not (actor and quickSilverAppliesToAllies and flaskBuffsPerBaseNonPlayer["Quicksilver Flask"]) then + return + end + actor.modDB.conditions["UsingQuicksilverFlask"] = flaskConditions["UsingQuicksilverFlask"] + actor.modDB.conditions["UsingFlask"] = flaskConditions["UsingFlask"] + for _, buffModList in pairs(flaskBuffsPerBaseNonPlayer["Quicksilver Flask"]) do + actor.modDB:AddList(buffModList) + end + end if env.minion then if flasksApplyToMinion or nonUniqueFlasksApplyToMinion then -- nonUniqueAlreadyFiltered local minionModDB = env.minion.modDB @@ -1836,16 +2409,20 @@ function calcs.perform(env, skipEHP) minionModDB:AddList(buffModList) end else -- Not all flasks apply to minions. Check if some flasks need to be selectively applied - if quickSilverAppliesToAllies and flaskBuffsPerBaseNonPlayer["Quicksilver Flask"] then - local minionModDB = env.minion.modDB - minionModDB.conditions["UsingQuicksilverFlask"] = flaskConditions["UsingQuicksilverFlask"] - minionModDB.conditions["UsingFlask"] = flaskConditions["UsingFlask"] - for _, buffModList in pairs(flaskBuffsPerBaseNonPlayer["Quicksilver Flask"]) do - minionModDB:AddList(buffModList) - end - end + applyQuicksilverToAlly(env.minion) end end + if env.mercenary and nonUniqueUtilityFlasksApplyToMercenary then + for flaskCond, status in pairs(mercenaryFlaskConditions) do + env.mercenary.modDB.conditions[flaskCond] = status + end + for _, buffModList in pairs(mercenaryFlaskBuffs) do + env.mercenary.modDB:AddList(buffModList) + end + elseif env.mercenary then + applyQuicksilverToAlly(env.mercenary) + end + applyQuicksilverToAlly(env.mercenaryMinion) end local effectInc = modDB:Sum("INC", {actor = "player"}, "TinctureEffect") @@ -1938,11 +2515,25 @@ function calcs.perform(env, skipEHP) -- Merge keystones again to catch any that were added by flasks modLib.mergeKeystones(env, env.modDB) + if env.mercenary then + modLib.mergeKeystones(env.mercenary.calcEnv, env.mercenary.modDB) + end end -- Calculate attributes and life/mana pools doActorAttribsConditions(env, env.player) doActorLifeMana(env.player) + if env.mercenary then + doActorAttribsConditions(env, env.mercenary) + doActorLifeMana(env.mercenary) + env.mercenary.reserved_LifeBase = 0 + env.mercenary.reserved_LifePercent = 0 + env.mercenary.reserved_ManaBase = 0 + env.mercenary.reserved_ManaPercent = 0 + env.mercenary.uncancellable_LifeReservation = 0 + env.mercenary.uncancellable_ManaReservation = 0 + doActorLifeManaReservation(env.mercenary, true) + end if env.minion then if env.minion.hostile then for _, value in ipairs(env.modDB:Tabulate(nil, nil, "EnemyModifier")) do @@ -1963,6 +2554,15 @@ function calcs.perform(env, skipEHP) end doActorAttribsConditions(env, env.minion) end + if env.mercenaryMinion then + addMinionModifiers(env.mercenary.mainSkill.skillModList, env.mercenary.mainSkill.skillCfg, env.mercenaryMinion) + for _, name in ipairs(env.mercenaryMinion.modDB:List(nil, "Keystone")) do + if env.spec.tree.keystoneMap[name] then + env.mercenaryMinion.modDB:AddList(env.spec.tree.keystoneMap[name].modList) + end + end + doActorAttribsConditions(env, env.mercenaryMinion) + end -- Calculate skill life and mana reservations env.player.reserved_LifeBase = 0 @@ -2163,18 +2763,27 @@ function calcs.perform(env, skipEHP) -- Calculate number of active heralds and auras affecting self if env.mode_buffs then - local heraldList = { } - local auraList = { } - for _, activeSkill in ipairs(env.player.activeSkillList) do - if activeSkill.skillTypes[SkillType.Herald] and not heraldList[activeSkill.skillCfg.skillName] then - heraldList[activeSkill.skillCfg.skillName] = true - modDB.multipliers["Herald"] = (modDB.multipliers["Herald"] or 0) + 1 - modDB.conditions["AffectedByHerald"] = true - elseif activeSkill.skillTypes[SkillType.Aura] and not activeSkill.skillTypes[SkillType.AuraAffectsEnemies] and not activeSkill.skillData.auraCannotAffectSelf and not auraList[activeSkill.skillCfg.skillName] then - auraList[activeSkill.skillCfg.skillName] = true - modDB.multipliers["AuraAffectingSelf"] = (modDB.multipliers["AuraAffectingSelf"] or 0) + 1 + local function countActorAurasAndHeralds(actor, actorModDB) + if not actor then + return + end + local heraldList = { } + local auraList = { } + for _, activeSkill in ipairs(actor.activeSkillList) do + if activeSkill.skillTypes[SkillType.Herald] and not heraldList[activeSkill.skillCfg.skillName] then + heraldList[activeSkill.skillCfg.skillName] = true + actorModDB.multipliers["Herald"] = (actorModDB.multipliers["Herald"] or 0) + 1 + actorModDB.conditions["AffectedByHerald"] = true + elseif activeSkill.skillTypes[SkillType.Aura] and not activeSkill.skillTypes[SkillType.AuraAffectsEnemies] and not activeSkill.skillData.auraCannotAffectSelf and not auraList[activeSkill.skillCfg.skillName] then + auraList[activeSkill.skillCfg.skillName] = true + actorModDB.multipliers["AuraAffectingSelf"] = (actorModDB.multipliers["AuraAffectingSelf"] or 0) + 1 + end end end + countActorAurasAndHeralds(env.player, modDB) + if env.mercenary then + countActorAurasAndHeralds(env.mercenary, env.mercenary.modDB) + end end if modDB:Flag(nil, "ManaAppliesToShockEffect") then @@ -2189,6 +2798,7 @@ function calcs.perform(env, skipEHP) -- Calculate charges early to enable usage of stats that depend on charge count doActorCharges(env, env.player) + if env.mercenary then doActorCharges(env, env.mercenary) end -- Combine buffs/debuffs local buffs = { } @@ -2196,12 +2806,20 @@ function calcs.perform(env, skipEHP) local guards = { } local minionBuffs = { } env.minionBuffs = minionBuffs + local mercenaryBuffs = { } + env.mercenaryBuffs = mercenaryBuffs + local mercenaryMinionBuffs = { } + env.mercenaryMinionBuffs = mercenaryMinionBuffs local debuffs = { } env.debuffs = debuffs local curses = { } local minionCurses = { limit = 1, } + local mercenaryCurses = { + limit = env.mercenary and m_max(env.mercenary.modDB:Sum("BASE", nil, "EnemyCurseLimit"), 1) or 0, + } + local mercenaryMinionCurses = { limit = env.mercenaryMinion and 1 or 0 } local linkSkills = { } local allyBuffs = env.partyMembers["Aura"] local buffExports = { Aura = {}, Curse = {}, Warcry = {}, Link = {}, EnemyMods = {}, EnemyConditions = {}, PlayerMods = {} } @@ -2246,11 +2864,23 @@ function calcs.perform(env, skipEHP) elseif modData.name == "AllyModifier" and modData.type == "LIST" then buffs["Spectre"] = buffs["Spectre"] or new("ModList"):ModList() minionBuffs["Spectre"] = minionBuffs["Spectre"] or new("ModList"):ModList() + if env.mercenary then + mercenaryBuffs["Spectre"] = mercenaryBuffs["Spectre"] or new("ModList"):ModList() + end + if env.mercenaryMinion then + mercenaryMinionBuffs["Spectre"] = mercenaryMinionBuffs["Spectre"] or new("ModList"):ModList() + end for _, modValue in pairs(modData.value) do local copyModValue = copyTable(modValue) copyModValue.source = "Spectre:"..spectreData.name t_insert(minionBuffs["Spectre"], copyModValue) t_insert(buffs["Spectre"], copyModValue) + if env.mercenary then + t_insert(mercenaryBuffs["Spectre"], copyModValue) + end + if env.mercenaryMinion then + t_insert(mercenaryMinionBuffs["Spectre"], copyModValue) + end end elseif modData.name == "MinionModifier" and modData.type == "LIST" then minionBuffs["Spectre"] = minionBuffs["Spectre"] or new("ModList"):ModList() @@ -2275,35 +2905,59 @@ function calcs.perform(env, skipEHP) -- To support maximum sustainable stages for the following skills we need to get the data from already -- computed cached versions to satisfy the order of operations. -- See: https://github.com/PathOfBuildingCommunity/PathOfBuilding/pull/5164 + local function prepareSustainableStages(activeSkill) + if activeSkill.skillFlags.disable or (env.limitedSkills and env.limitedSkills[cacheSkillUUID(activeSkill, env)]) then + return + end + local grantedName = activeSkill.activeEffect.grantedEffect.name + if (grantedName == "Blight" or grantedName == "Blight of Contagion" or grantedName == "Blight of Atrophy") and activeSkill.skillPart == 2 then + local rate, duration = getCachedOutputValue(env, activeSkill, "Speed", "Duration") + local baseMaxStages = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "BlightBaseMaxStages") + local maximum = m_min((m_floor(rate * duration) - 1), baseMaxStages - 1) + activeSkill.skillModList:NewMod("Multiplier:"..grantedName:gsub("%s+", "").."MaxStages", "BASE", maximum, "Base") + activeSkill.skillModList:NewMod("Multiplier:"..grantedName:gsub("%s+", "").."StageAfterFirst", "BASE", maximum, "Base") + end + if grantedName == "Penance Brand of Dissipation" and activeSkill.skillPart == 2 then + local activation_frequency, duration = getCachedOutputValue(env, activeSkill, "HitSpeed", "Duration") -- HitSpeed is the brand activation frequency + local ticks = m_max(m_min((m_floor((activation_frequency or 0) * duration) - 1), 19), 0) + activeSkill.skillModList:NewMod("Multiplier:PenanceBrandofDissipationMaxStages", "BASE", ticks, "Base") + activeSkill.skillModList:NewMod("Multiplier:PenanceBrandofDissipationStageAfterFirst", "BASE", ticks, "Base") + end + if (grantedName == "Scorching Ray" or grantedName == "Scorching Ray of Immolation") and activeSkill.skillPart == 2 then + local maximum = 7 + activeSkill.skillModList:NewMod("Multiplier:"..grantedName:gsub("%s+", "").."MaxStages", "BASE", maximum, "Base") + activeSkill.skillModList:NewMod("Multiplier:"..grantedName:gsub("%s+", "").."StageAfterFirst", "BASE", maximum, "Base") + end + if grantedName == "Earthquake of Amplification" and activeSkill.skillPart == 2 then + local duration = getCachedOutputValue(env, activeSkill, "Duration") + local durationMulti = m_floor(duration * 10) + activeSkill.skillModList:NewMod("Multiplier:100msEarthquakeDuration", "BASE", durationMulti, "Skill:EarthquakeAltX") + end + end for _, activeSkill in ipairs(env.player.activeSkillList) do - if not activeSkill.skillFlags.disable and not (env.limitedSkills and env.limitedSkills[cacheSkillUUID(activeSkill, env)]) then - if (activeSkill.activeEffect.grantedEffect.name == "Blight" or activeSkill.activeEffect.grantedEffect.name == "Blight of Contagion" or activeSkill.activeEffect.grantedEffect.name == "Blight of Atrophy") and activeSkill.skillPart == 2 then - local rate, duration = getCachedOutputValue(env, activeSkill, "Speed", "Duration") - local baseMaxStages = activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "BlightBaseMaxStages") - local maximum = m_min((m_floor(rate * duration) - 1), baseMaxStages - 1) - activeSkill.skillModList:NewMod("Multiplier:"..activeSkill.activeEffect.grantedEffect.name:gsub("%s+", "").."MaxStages", "BASE", maximum, "Base") - activeSkill.skillModList:NewMod("Multiplier:"..activeSkill.activeEffect.grantedEffect.name:gsub("%s+", "").."StageAfterFirst", "BASE", maximum, "Base") - end - if activeSkill.activeEffect.grantedEffect.name == "Penance Brand of Dissipation" and activeSkill.skillPart == 2 then - local activation_frequency, duration = getCachedOutputValue(env, activeSkill, "HitSpeed", "Duration") -- HitSpeed is the brand activation frequency - local ticks = m_max(m_min((m_floor((activation_frequency or 0) * duration) - 1), 19), 0) - activeSkill.skillModList:NewMod("Multiplier:PenanceBrandofDissipationMaxStages", "BASE", ticks, "Base") - activeSkill.skillModList:NewMod("Multiplier:PenanceBrandofDissipationStageAfterFirst", "BASE", ticks, "Base") - end - if (activeSkill.activeEffect.grantedEffect.name == "Scorching Ray" or activeSkill.activeEffect.grantedEffect.name == "Scorching Ray of Immolation") and activeSkill.skillPart == 2 then - local maximum = 7 - activeSkill.skillModList:NewMod("Multiplier:"..activeSkill.activeEffect.grantedEffect.name:gsub("%s+", "").."MaxStages", "BASE", maximum, "Base") - activeSkill.skillModList:NewMod("Multiplier:"..activeSkill.activeEffect.grantedEffect.name:gsub("%s+", "").."StageAfterFirst", "BASE", maximum, "Base") - end - if (activeSkill.activeEffect.grantedEffect.name == "Earthquake of Amplification") and activeSkill.skillPart == 2 then - local duration = getCachedOutputValue(env, activeSkill, "Duration") - local durationMulti = m_floor(duration * 10) - activeSkill.skillModList:NewMod("Multiplier:100msEarthquakeDuration", "BASE", durationMulti, "Skill:EarthquakeAltX") - end + prepareSustainableStages(activeSkill) + end + if env.mercenary then + for _, activeSkill in ipairs(env.mercenary.activeSkillList) do + prepareSustainableStages(activeSkill) end end local appliedCombustion = false + local function applyCombustion(activeSkill) + if enemyDB:Flag(nil, "Condition:Ignited") and (activeSkill.skillTypes[SkillType.Damage] or activeSkill.skillTypes[SkillType.Attack]) and not appliedCombustion then + for _, support in ipairs(activeSkill.supportList) do + if support.grantedEffect.name == "Combustion" then + if not activeSkill.skillModList:Flag(activeSkill.skillCfg, "CannotIgnite") then + local value = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "CombustionFireResist") + enemyDB:NewMod("FireResist", "BASE", value, "Combustion", { type = "GlobalEffect", effectType = "Debuff", effectName = "Combustion" }, { type = "Condition", var = "Ignited" }) + appliedCombustion = true + end + break + end + end + end + end local warcryList = { } for _, activeSkill in ipairs(env.player.activeSkillList) do local skillModList = activeSkill.skillModList @@ -2340,6 +2994,13 @@ function calcs.perform(env, skipEHP) srcList:ScaleAddList(buff.modList, (1 + inc / 100) * more) mergeBuff(srcList, minionBuffs, buff.name) end + if env.mercenary and (buff.applyAllies or skillModList:Flag(nil, "BuffAppliesToAllies")) then + activeSkill.mercenaryBuffSkill = true + mergeBuffOnRecipient(modStore, skillCfg, buff, env.mercenary, mercenaryBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + end + if env.mercenaryMinion and (buff.applyMinions or buff.applyAllies or skillModList:Flag(nil, "BuffAppliesToAllies")) then + mergeBuffOnRecipient(modStore, skillCfg, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + end if partyTabEnableExportBuffs and (buff.applyAllies or skillModList:Flag(nil, "BuffAppliesToAllies") or skillModList:Flag(nil, "BuffAppliesToPartyMembers")) then local inc = modStore:Sum("INC", skillCfg, "BuffEffect") + skillModList:Sum("INC", skillCfg, buff.name:gsub(" ", "").."Effect") local more = modStore:More(skillCfg, "BuffEffect") @@ -2365,16 +3026,7 @@ function calcs.perform(env, skipEHP) local skillCfg = skillCfg local modStore = skillModList or modDB local warcryName = buff.name:gsub(" Cry", ""):gsub("'s",""):gsub(" ","") - local baseExerts = modStore:Sum("BASE", env.player.mainSkill.skillCfg, warcryName.."ExertedAttacks") - if baseExerts > 0 then - local extraExertions = modStore:Sum("BASE", nil, "ExtraExertedAttacks") or 0 - local exertMultiplier = modStore:More(nil, "ExtraExertedAttacks") - env.player.modDB:NewMod("Num"..warcryName.."Exerts", "BASE", m_floor((baseExerts + extraExertions) * exertMultiplier)) - if not warcryList[buff.name] then - env.player.modDB:NewMod("Multiplier:ExertingWarcryCount", "BASE", 1, buff.name) - warcryList[buff.name] = true - end - end + applyWarcryExerts(env.player, env.player.mainSkill.skillCfg, modStore, buff, warcryList) if not activeSkill.skillModList:Flag(nil, "CannotShareWarcryBuffs") then local warcryPower = modDB:Override(nil, "WarcryPower") or m_max((modDB:Sum("BASE", nil, "WarcryPower") or 0) * (1 + (modDB:Sum("INC", nil, "WarcryPower") or 0)/100), (modDB:Sum("BASE", nil, "MinimumWarcryPower") or 0)) for _, warcryBuff in ipairs(buff.modList) do @@ -2382,11 +3034,8 @@ function calcs.perform(env, skipEHP) warcryBuff[1].warcryPowerBonus = m_floor((warcryBuff[1].limit and m_min(warcryPower, warcryBuff[1].limit) or warcryPower) / warcryBuff[1].div) end end - local full_duration = calcSkillDuration(modStore, skillCfg, activeSkill.skillData, env, enemyDB) - local cooldownOverride = modStore:Override(skillCfg, "CooldownRecovery") - local actual_cooldown = cooldownOverride or (activeSkill.skillData.cooldown + modStore:Sum("BASE", skillCfg, "CooldownRecovery")) / calcLib.mod(modStore, skillCfg, "CooldownRecovery") - local uptime = modDB:Flag(nil, "Condition:WarcryMaxHit") and 1 or m_min(full_duration / actual_cooldown, 1) - local extraWarcryModList = activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and new("ModList"):ModList() or {} + local uptime = calcWarcryUptime(env, enemyDB, modDB, modStore, skillCfg, activeSkill) + local extraWarcryModList, rallyingMinionMultiplier = buildRallyingCryAllyMods(env.player, activeSkill, warcryPower) if not modDB:Flag(nil, "CannotGainWarcryBuffs") then if not buff.applyNotPlayer then activeSkill.buffSkill = true @@ -2411,26 +3060,21 @@ function calcs.perform(env, skipEHP) local mult = (1 + inc / 100) * more * (warcryBuff[1].warcryPowerBonus or 1) * uptime srcList:ScaleAddList({warcryBuff}, mult) end - -- Special handling for the minion side to add the flat damage bonus - if activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" then - local warcryPowerBonus = m_floor((m_min(warcryPower, 30)) / 5) - local rallyingWeaponEffect = m_floor(activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "RallyingCryAllyDamageBonusPer5Power") * warcryPowerBonus) - local inc = modStore:Sum("INC", skillCfg, "BuffEffect") + env.minion.modDB:Sum("INC", skillCfg, "BuffEffectOnSelf") - local rallyingBonusMoreMultiplier = 1 + (activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "RallyingCryMinionDamageBonusMultiplier") or 0) - -- Add all damage types - local dmgTypeList = {"Physical", "Lightning", "Cold", "Fire", "Chaos"} - for _, damageType in ipairs(dmgTypeList) do - if env.player.weaponData1[damageType.."Min"] then - extraWarcryModList:NewMod(damageType.."Min", "BASE", (env.player.weaponData1[damageType.."Min"] * rallyingWeaponEffect / 100), "Rallying Cry", 0, KeywordFlag.Attack, { type = "GlobalEffect", effectType = "Warcry", div = 5, limit = 30 }) - end - if env.player.weaponData1[damageType.."Max"] then - extraWarcryModList:NewMod(damageType.."Max", "BASE", (env.player.weaponData1[damageType.."Max"] * rallyingWeaponEffect / 100), "Rallying Cry", 0, KeywordFlag.Attack, { type = "GlobalEffect", effectType = "Warcry", div = 5, limit = 30 }) - end - end - srcList:ScaleAddList(extraWarcryModList, (1 + inc / 100) * rallyingBonusMoreMultiplier * uptime) + if extraWarcryModList[1] then + local rallyingInc = modStore:Sum("INC", skillCfg, "BuffEffect") + env.minion.modDB:Sum("INC", skillCfg, "BuffEffectOnSelf") + srcList:ScaleAddList(extraWarcryModList, (1 + rallyingInc / 100) * rallyingMinionMultiplier * uptime) end mergeBuff(srcList, minionBuffs, buff.name) end + if env.mercenary then + activeSkill.mercenaryBuffSkill = true + mergeWarcryOnRecipient(skillModList, skillCfg, buff, env.mercenary, mercenaryBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime, warcryName) + mergeRallyingCryAllyMods(extraWarcryModList, 1, skillModList, skillCfg, env.mercenary, mercenaryBuffs, buff.name, uptime) + end + if env.mercenaryMinion then + mergeWarcryOnRecipient(skillModList, skillCfg, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime, warcryName) + mergeRallyingCryAllyMods(extraWarcryModList, rallyingMinionMultiplier, skillModList, skillCfg, env.mercenaryMinion, mercenaryMinionBuffs, buff.name, uptime) + end if partyTabEnableExportBuffs then local newModList = new("ModList"):ModList() local inc = skillModList:Sum("INC", skillCfg, "BuffEffect") @@ -2444,25 +3088,12 @@ function calcs.perform(env, skipEHP) elseif buff.type == "Aura" then if env.mode_buffs then -- Check for extra modifiers to apply to aura skills - local extraAuraModList = { } - for _, value in ipairs(modDB:List(skillCfg, "ExtraAuraEffect")) do - local add = true - for _, mod in ipairs(extraAuraModList) do - if modLib.compareModParams(mod, value.mod) then - mod.value = mod.value + value.mod.value - add = false - break - end - end - if add then - t_insert(extraAuraModList, copyTable(value.mod, true)) - end - end + local extraAuraModList = collectMergedListedMods(modDB, skillCfg, "ExtraAuraEffect") if not activeSkill.skillData.auraCannotAffectSelf then local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect", "BuffEffectOnSelf", "AuraEffectOnSelf", "AuraBuffEffect", "SkillAuraEffectOnSelf") local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect", "BuffEffectOnSelf", "AuraEffectOnSelf", "AuraBuffEffect", "SkillAuraEffectOnSelf") local mult = (1 + inc / 100) * more - if modDB:Flag(nil, "AlliesAurasCannotAffectSelf") or not allyBuffs["Aura"] or not allyBuffs["Aura"][buff.name] or allyBuffs["Aura"][buff.name].effectMult / 100 <= mult then + if not strongerImportedAura(env.player, allyBuffs, buff.name, mult) then activeSkill.buffSkill = true modDB.conditions["AffectedByAura"] = true if buff.name:sub(1,4) == "Vaal" then @@ -2480,7 +3111,7 @@ function calcs.perform(env, skipEHP) local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect") + env.minion.modDB:Sum("INC", skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect") * env.minion.modDB:More(skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") local mult = (1 + inc / 100) * more - if not allyBuffs["Aura"] or not allyBuffs["Aura"][buff.name] or allyBuffs["Aura"][buff.name].effectMult / 100 <= mult then + if not strongerImportedAura(env.minion, allyBuffs, buff.name, mult) then activeSkill.minionBuffSkill = true env.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true env.minion.modDB.conditions["AffectedByAura"] = true @@ -2490,6 +3121,10 @@ function calcs.perform(env, skipEHP) mergeBuff(srcList, minionBuffs, buff.name) end end + if mergeIncomingAuraOnRecipient(skillModList, skillCfg, buff, env.mercenary, mercenaryBuffs, extraAuraModList, allyBuffs) then + activeSkill.mercenaryBuffSkill = true + end + mergeIncomingAuraOnRecipient(skillModList, skillCfg, buff, env.mercenaryMinion, mercenaryMinionBuffs, extraAuraModList, allyBuffs) local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect") local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect") local mult = (1 + inc / 100) * more @@ -2499,7 +3134,7 @@ function calcs.perform(env, skipEHP) if buffExports["Aura"][buff.name] then buffExports["Aura"][buff.name.."_Debuff"] = buffExports["Aura"][buff.name] end - buffExports["Aura"][buff.name] = { effectMult = mult, modList = newModList } + exportStrongestAura(buffExports, buff.name, mult, newModList) if modDB:Flag(nil, "AurasAffectEnemies") and not activeSkill.skillModList:Flag(skillCfg, "SelfAurasAffectYouAndLinkedTarget") then local newModList = {} local srcList = new("ModList"):ModList() @@ -2512,7 +3147,7 @@ function calcs.perform(env, skipEHP) buffExports["Aura"][buff.name..(buffExports["Aura"][buff.name] and "_Debuff" or "")] = { effectMult = mult, modList = newModList } srcList:ScaleAddList(buff.modList, mult) srcList:ScaleAddList(extraAuraModList, mult) - mergeBuff(srcList, debuffs, buff.name) + mergeBuff(srcList, debuffs, buff.name, env.player) end end if env.player.mainSkill.skillFlags.totem and not (modDB:Flag(nil, "SelfAurasCannotAffectAllies") or modDB:Flag(nil, "SelfAuraSkillsCannotAffectAllies")) then @@ -2579,7 +3214,7 @@ function calcs.perform(env, skipEHP) if allyBuffs["AuraDebuff"] and allyBuffs["AuraDebuff"][buff.name] and allyBuffs["AuraDebuff"][buff.name].effectMult / 100 > mult then mult = 0 end - mergeBuff(newModList, debuffs, buff.name) + mergeBuff(newModList, debuffs, buff.name, env.player) end end end @@ -2648,7 +3283,7 @@ function calcs.perform(env, skipEHP) if activeSkill.skillData.stackCount or buff.stackVar then srcList:NewMod("Multiplier:"..buff.name.."Stack", "BASE", stackCount, buff.name) end - mergeBuff(srcList, debuffs, buff.name) + mergeBuff(srcList, debuffs, buff.name, env.player) end elseif buff.type == "Curse" or buff.type == "CurseBuff" then local mark = activeSkill.skillTypes[SkillType.Mark] @@ -2703,12 +3338,14 @@ function calcs.perform(env, skipEHP) curse.minionBuffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore) end end + curse.sourceActor = env.player t_insert(curses, curse) end elseif buff.type == "Link" then local linksApplyToMinions = env.minion and modDB:Flag(nil, "Condition:CanLinkToMinions") and modDB:Flag(nil, "Condition:LinkedToMinion") and not env.minion.modDB:Flag(nil, "Condition:CannotBeDamaged") and not env.minion.mainSkill.summonSkill.skillTypes[SkillType.MinionsAreUndamagable] - if env.mode_buffs and (#linkSkills < 1) and (partyTabEnableExportBuffs or linksApplyToMinions) then + local linksApplyToMercenary = env.mercenary and activeSkill.socketGroup and activeSkill.socketGroup.enabled and not activeSkill.skillFlags.disable + if env.mode_buffs and (#linkSkills < 1) and (partyTabEnableExportBuffs or linksApplyToMinions or linksApplyToMercenary) then -- Check for extra modifiers to apply to link skills local extraLinkModList = { } for _, value in ipairs(modDB:List(skillCfg, "ExtraLinkEffect")) do @@ -2742,14 +3379,28 @@ function calcs.perform(env, skipEHP) env.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true env.minion.modDB.conditions["AffectedByLink"] = true local srcList = new("ModList"):ModList() - inc = inc + env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "LinkEffectOnSelf") - more = more * env.minion.modDB:More(nil, "BuffEffectOnSelf", "LinkEffectOnSelf") - mult = (1 + inc / 100) * more - srcList:ScaleAddList(buff.modList, mult) - srcList:ScaleAddList(extraLinkModList, mult) + local recipientInc = env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "LinkEffectOnSelf") + local recipientMore = env.minion.modDB:More(nil, "BuffEffectOnSelf", "LinkEffectOnSelf") + local recipientMult = (1 + (inc + recipientInc) / 100) * more * recipientMore + srcList:ScaleAddList(buff.modList, recipientMult) + srcList:ScaleAddList(extraLinkModList, recipientMult) mergeBuff(srcList, minionBuffs, buff.name) linkSkills[1] = buff.name end + if linksApplyToMercenary then + activeSkill.mercenaryBuffSkill = true + env.mercenary.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true + env.mercenary.modDB.conditions["AffectedByLink"] = true + local srcList = new("ModList"):ModList() + local recipientInc = env.mercenary.modDB:Sum("INC", nil, "BuffEffectOnSelf", "LinkEffectOnSelf") + local recipientMore = env.mercenary.modDB:More(nil, "BuffEffectOnSelf", "LinkEffectOnSelf") + local lightRadiusEffect = modDB:Flag(nil, "LightRadiusAppliesToMercenaryLinkEffect") and modDB:Sum("INC", nil, "LightRadius") or 0 + local recipientMult = (1 + (inc + recipientInc + lightRadiusEffect) / 100) * more * recipientMore + srcList:ScaleAddList(buff.modList, recipientMult) + srcList:ScaleAddList(extraLinkModList, recipientMult) + mergeBuff(srcList, mercenaryBuffs, buff.name) + linkSkills[1] = buff.name + end end end end @@ -2762,18 +3413,7 @@ function calcs.perform(env, skipEHP) modDB:NewMod("WitherEffectStack", "MAX", effect) end --Handle combustion - if enemyDB:Flag(nil, "Condition:Ignited") and (activeSkill.skillTypes[SkillType.Damage] or activeSkill.skillTypes[SkillType.Attack]) and not appliedCombustion then - for _, support in ipairs(activeSkill.supportList) do - if support.grantedEffect.name == "Combustion" then - if not activeSkill.skillModList:Flag(activeSkill.skillCfg, "CannotIgnite") then - local value = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "CombustionFireResist") - enemyDB:NewMod("FireResist", "BASE", value, "Combustion", { type = "GlobalEffect", effectType = "Debuff", effectName = "Combustion" }, { type = "Condition", var = "Ignited" }) - appliedCombustion = true - end - break - end - end - end + applyCombustion(activeSkill) if activeSkill.minion and activeSkill.minion.activeSkillList then local castingMinion = activeSkill.minion for _, activeMinionSkill in ipairs(activeSkill.minion.activeSkillList) do @@ -2816,6 +3456,12 @@ function calcs.perform(env, skipEHP) buffExports["Aura"]["otherEffects"][buff.name] = { effectMult = (1 + inc / 100) * more, modList = buff.modList } end end + if env.mercenary and buff.applyAllies then + mergeBuffOnRecipient(modStore, skillCfg, buff, env.mercenary, mercenaryBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + end + if env.mercenaryMinion and (buff.applyAllies or buff.applyMinions) then + mergeBuffOnRecipient(modStore, skillCfg, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + end local envMinionCheck = (env.minion and (env.minion == castingMinion or buff.applyAllies)) if buff.applyMinions or envMinionCheck then activeMinionSkill.minionBuffSkill = true @@ -2838,26 +3484,13 @@ function calcs.perform(env, skipEHP) elseif buff.type == "Aura" then if env.mode_buffs and activeMinionSkill.skillData.enable then -- Check for extra modifiers to apply to aura skills - local extraAuraModList = { } - for _, value in ipairs(activeSkill.minion.modDB:List(skillCfg, "ExtraAuraEffect")) do - local add = true - for _, mod in ipairs(extraAuraModList) do - if modLib.compareModParams(mod, value.mod) then - mod.value = mod.value + value.mod.value - add = false - break - end - end - if add then - t_insert(extraAuraModList, copyTable(value.mod, true)) - end - end + local extraAuraModList = collectMergedListedMods(activeSkill.minion.modDB, skillCfg, "ExtraAuraEffect") if not (activeSkill.minion.modDB:Flag(nil, "SelfAurasCannotAffectAllies") or activeSkill.minion.modDB:Flag(nil, "SelfAurasOnlyAffectYou") or activeSkill.minion.modDB:Flag(nil, "SelfAuraSkillsCannotAffectAllies") or skillModList:Flag(skillCfg, "SelfAurasAffectYouAndLinkedTarget")) then if not modDB:Flag(nil, "AlliesAurasCannotAffectSelf") and not modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] then local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect", "BuffEffectOnPlayer", "AuraBuffEffect") + modDB:Sum("INC", skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect", "AuraBuffEffect") * modDB:More(skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") local mult = (1 + inc / 100) * more - if not allyBuffs["Aura"] or not allyBuffs["Aura"][buff.name] or allyBuffs["Aura"][buff.name].effectMult / 100 <= mult then + if not strongerImportedAura(env.player, allyBuffs, buff.name, mult) then activeMinionSkill.buffSkill = true modDB.conditions["AffectedByAura"] = true if buff.name:sub(1,4) == "Vaal" then @@ -2875,7 +3508,7 @@ function calcs.perform(env, skipEHP) local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect") + env.minion.modDB:Sum("INC", skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect") * env.minion.modDB:More(skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") local mult = (1 + inc / 100) * more - if not allyBuffs["Aura"] or not allyBuffs["Aura"][buff.name] or allyBuffs["Aura"][buff.name].effectMult / 100 <= mult then + if not strongerImportedAura(env.minion, allyBuffs, buff.name, mult) then activeMinionSkill.minionBuffSkill = true env.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true env.minion.modDB.conditions["AffectedByAura"] = true @@ -2886,6 +3519,9 @@ function calcs.perform(env, skipEHP) mergeBuff(srcList, minionBuffs, buff.name) end end + local function tagSpectreSource(srcList) setSpectreSource(srcList, buff.name) end + mergeIncomingAuraOnRecipient(skillModList, skillCfg, buff, env.mercenary, mercenaryBuffs, extraAuraModList, allyBuffs, tagSpectreSource) + mergeIncomingAuraOnRecipient(skillModList, skillCfg, buff, env.mercenaryMinion, mercenaryMinionBuffs, extraAuraModList, allyBuffs, tagSpectreSource) local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect") local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect") local mult = (1 + inc / 100) * more @@ -2896,7 +3532,7 @@ function calcs.perform(env, skipEHP) if buffExports["Aura"][buff.name] then buffExports["Aura"][buff.name.."_Debuff"] = buffExports["Aura"][buff.name] end - buffExports["Aura"][buff.name] = { effectMult = mult, modList = newModList } + exportStrongestAura(buffExports, buff.name, mult, newModList) if env.player.mainSkill.skillFlags.totem and not env.player.mainSkill.skillModList.conditions["AffectedBy"..buff.name:gsub(" ","")] then activeMinionSkill.totemBuffSkill = true env.player.mainSkill.skillModList.conditions["AffectedBy"..buff.name:gsub(" ","")] = true @@ -2940,6 +3576,7 @@ function calcs.perform(env, skipEHP) local more = skillModList:More(skillCfg, "CurseEffect") * enemyDB:More(nil, "CurseEffectOnSelf") curse.modList = new("ModList"):ModList() curse.modList:ScaleAddList(buff.modList, (1 + inc / 100) * more) + curse.sourceActor = env.minion t_insert(minionCurses, curse) end elseif buff.type == "Debuff" or buff.type == "AuraDebuff" then @@ -2987,9 +3624,293 @@ function calcs.perform(env, skipEHP) if activeMinionSkill.skillData.stackCount or buff.stackVar then srcList:NewMod("Multiplier:"..buff.name.."Stack", "BASE", activeMinionSkill.skillData.stackCount, buff.name) end - mergeBuff(srcList, debuffs, buff.name) + mergeBuff(srcList, debuffs, buff.name, activeMinionSkill.actor) + end + end + end + end + end + end + + -- Permanent Mercenaries are allied actors, so their skill effects use the same + -- buff/debuff stores and curse arbitration as player and minion sources. + if env.mercenary then + local mercenary = env.mercenary + local mercenaryTauntedEnemy = false + -- Every source in this section is a Mercenary skill, so the two adapters below + -- save naming its mod store and config at each of the call sites. + local function mergeBuffFromSkill(activeSkill, buff, recipient, destination, sourceStats, recipientStats, extraMods, scale) + mergeBuffOnRecipient(activeSkill.skillModList, activeSkill.skillCfg, buff, recipient, destination, sourceStats, recipientStats, extraMods, scale) + end + local function mergeAuraFromSkill(activeSkill, buff, recipient, destination, sourceStats, recipientStats, extraMods) + return mergeAuraOnRecipient(activeSkill.skillModList, activeSkill.skillCfg, buff, recipient, destination, sourceStats, recipientStats, extraMods, allyBuffs) + end + local function mergeWarcryFromSkill(activeSkill, buff, recipient, destination, sourceStats, recipientStats, uptime) + mergeWarcryOnRecipient(activeSkill.skillModList, activeSkill.skillCfg, buff, recipient, destination, sourceStats, recipientStats, uptime) + end + local mercenaryWarcryList = { } + + for _, activeSkill in ipairs(mercenary.activeSkillList) do + local skillModList = activeSkill.skillModList + local skillCfg = activeSkill.skillCfg + if skillModList:Flag(nil, "Condition:CanWither") or (activeSkill.minion and env.mercenaryMinion and env.mercenaryMinion.modDB:Flag(nil, "Condition:CanWither")) then + local effect = activeSkill.minion and m_floor(6 * (1 + mercenary.modDB:Sum("INC", nil, "MinionWitherEffect") / 100)) or m_floor(6 * (1 + mercenary.modDB:Sum("INC", nil, "WitherEffect") / 100)) + -- Withered is one enemy debuff. Store on the player MAX so doActorMisc applies ChaosDamageTaken once. + env.modDB:NewMod("WitherEffectStack", "MAX", effect) + end + if env.modDB:Flag(nil, "MercenaryTauntsOnHit") and activeSkill.skillFlags.hit then + enemyDB.conditions.Taunted = true + enemyDB.conditions.TauntedByMercenary = true + mercenaryTauntedEnemy = true + end + applyCombustion(activeSkill) + for _, buff in ipairs(activeSkill.buffList) do + if buff.cond and not skillModList:GetCondition(buff.cond, skillCfg) then + -- Nothing! + elseif buff.enemyCond and not enemyDB:GetCondition(buff.enemyCond) then + -- Also nothing :/ + elseif buff.type == "GlobalDB" then + mercenary.modDB:AddList(buff.modList) + elseif buff.type == "Buff" and env.mode_buffs and not skillModList:Flag(skillCfg, "DisableBuff") then + if not buff.applyNotPlayer then + mergeBuffFromSkill(activeSkill, buff, mercenary, mercenaryBuffs, + { "BuffEffect", "BuffEffectOnSelf", "BuffEffectOnPlayer" }, { }) + end + local appliesToAllies = buff.applyAllies or skillModList:Flag(nil, "BuffAppliesToAllies") + if appliesToAllies then + mergeBuffFromSkill(activeSkill, buff, env.player, buffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + if partyTabEnableExportBuffs then + buffExports.Aura.otherEffects = buffExports.Aura.otherEffects or { } + buffExports.Aura.otherEffects[buff.name] = { + effectMult = calcLib.mod(skillModList, skillCfg, "BuffEffect"), + modList = buff.modList, + } + end + end + if appliesToAllies or buff.applyMinions then + if env.minion and not env.minion.hostile then + mergeBuffFromSkill(activeSkill, buff, env.minion, minionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + end + if env.mercenaryMinion then + mergeBuffFromSkill(activeSkill, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + end + end + elseif buff.type == "Aura" and env.mode_buffs then + local extraAuraModList = collectMergedListedMods(mercenary.modDB, skillCfg, "ExtraAuraEffect") + if not activeSkill.skillData.auraCannotAffectSelf then + mergeAuraFromSkill(activeSkill, buff, mercenary, mercenaryBuffs, + { "AuraEffect", "BuffEffect", "BuffEffectOnSelf", "AuraEffectOnSelf", "AuraBuffEffect", "SkillAuraEffectOnSelf" }, { }, extraAuraModList) + end + if not mercenary.modDB:Flag(nil, "SelfAurasCannotAffectAllies") and not mercenary.modDB:Flag(nil, "SelfAurasOnlyAffectYou") then + if not env.player.modDB:Flag(nil, "AlliesAurasCannotAffectSelf") then + mergeAuraFromSkill(activeSkill, buff, env.player, buffs, { "AuraEffect", "BuffEffect" }, { "BuffEffectOnSelf", "AuraEffectOnSelf" }, extraAuraModList) + end + if env.minion and not env.minion.hostile then + mergeIncomingAuraOnRecipient(skillModList, skillCfg, buff, env.minion, minionBuffs, extraAuraModList, allyBuffs) + end + mergeIncomingAuraOnRecipient(skillModList, skillCfg, buff, env.mercenaryMinion, mercenaryMinionBuffs, extraAuraModList, allyBuffs) + if partyTabEnableExportBuffs then + local exported = new("ModList"):ModList() + exported:AddList(buff.modList) + exported:AddList(extraAuraModList) + exportStrongestAura(buffExports, buff.name, calcLib.mod(skillModList, skillCfg, "AuraEffect", "BuffEffect"), exported) + end + end + elseif buff.type == "Warcry" and env.mode_buffs then + applyWarcryExerts(mercenary, mercenary.mainSkill and mercenary.mainSkill.skillCfg, skillModList, buff, mercenaryWarcryList) + if not skillModList:Flag(nil, "CannotShareWarcryBuffs") then + local warcryPower = mercenary.modDB:Override(nil, "WarcryPower") or m_max((mercenary.modDB:Sum("BASE", nil, "WarcryPower") or 0) * (1 + (mercenary.modDB:Sum("INC", nil, "WarcryPower") or 0) / 100), (mercenary.modDB:Sum("BASE", nil, "MinimumWarcryPower") or 0)) + for _, warcryBuff in ipairs(buff.modList) do + if warcryBuff[1] and warcryBuff[1].effectType == "Warcry" and warcryBuff[1].div then + warcryBuff[1].warcryPowerBonus = m_floor((warcryBuff[1].limit and m_min(warcryPower, warcryBuff[1].limit) or warcryPower) / warcryBuff[1].div) + end + end + local uptime = calcWarcryUptime(env, enemyDB, mercenary.modDB, skillModList, skillCfg, activeSkill) + local extraWarcryModList, rallyingMinionMultiplier = buildRallyingCryAllyMods(mercenary, activeSkill, warcryPower) + mergeWarcryFromSkill(activeSkill, buff, mercenary, mercenaryBuffs, { "BuffEffect", "BuffEffectOnSelf" }, { }, uptime) + mergeWarcryFromSkill(activeSkill, buff, env.player, buffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime) + mergeRallyingCryAllyMods(extraWarcryModList, 1, skillModList, skillCfg, env.player, buffs, buff.name, uptime) + if env.minion then + mergeWarcryFromSkill(activeSkill, buff, env.minion, minionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime) + mergeRallyingCryAllyMods(extraWarcryModList, rallyingMinionMultiplier, skillModList, skillCfg, env.minion, minionBuffs, buff.name, uptime) + end + if env.mercenaryMinion then + mergeWarcryFromSkill(activeSkill, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime) + mergeRallyingCryAllyMods(extraWarcryModList, rallyingMinionMultiplier, skillModList, skillCfg, env.mercenaryMinion, mercenaryMinionBuffs, buff.name, uptime) + end + if partyTabEnableExportBuffs then + local exported = new("ModList"):ModList() + exported:AddList(buff.modList) + exported:AddList(extraWarcryModList) + buffExports.Warcry[buff.name] = { effectMult = calcLib.mod(skillModList, skillCfg, "BuffEffect") * uptime, modList = exported } + end + end + elseif (buff.type == "Debuff" or buff.type == "AuraDebuff") and env.mode_effective then + local stackCount = activeSkill.skillData.stackCount or 1 + if buff.stackVar then + stackCount = skillModList:Sum("BASE", skillCfg, "Multiplier:"..buff.stackVar) + if buff.stackLimit then stackCount = m_min(stackCount, buff.stackLimit) end + end + local names = buff.type == "AuraDebuff" and { "AuraEffect", "BuffEffect", "DebuffEffect" } or { "DebuffEffect" } + local srcList = new("ModList"):ModList() + srcList:ScaleAddList(buff.modList, calcLib.mod(skillModList, skillCfg, unpack(names)) * stackCount) + mergeBuff(srcList, debuffs, buff.name, mercenary) + if partyTabEnableExportBuffs and buff.type == "AuraDebuff" then + buffExports.Aura[buff.name.."_Debuff"] = { effectMult = calcLib.mod(skillModList, skillCfg, unpack(names)), modList = buff.modList } + end + elseif (buff.type == "Curse" or buff.type == "CurseBuff") and env.mode_effective and (activeSkill.skillTypes[SkillType.Mark] or not enemyDB:Flag(nil, "Hexproof") or mercenary.modDB:Flag(nil, "CursesIgnoreHexproof")) then + local mark = activeSkill.skillTypes[SkillType.Mark] + local inc = skillModList:Sum("INC", skillCfg, "CurseEffect") + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") + if activeSkill.skillTypes[SkillType.Aura] then inc = inc + skillModList:Sum("INC", skillCfg, "AuraEffect") end + local more = skillModList:More(skillCfg, "CurseEffect") * (mark and 1 or enemyDB:More(nil, "CurseEffectOnSelf")) + local curse = { + name = buff.name, + priority = determineCursePriority(buff.name, activeSkill), + isMark = mark, + ignoreHexLimit = (mercenary.modDB:Flag(activeSkill.skillCfg, "CursesIgnoreHexLimit") or activeSkill.skillData.ignoreHexLimit) and not mark or false, + socketedCursesHexLimit = mercenary.modDB:Flag(activeSkill.skillCfg, "SocketedCursesAdditionalLimit"), + socketedCursesHexLimitValue = mercenary.modDB:Sum("BASE", nil, "SocketedCursesHexLimitValue"), + } + local curseMult = (1 + inc / 100) * more + if buff.type == "Curse" then + curse.modList = new("ModList"):ModList() + curse.modList:ScaleAddList(buff.modList, curseMult) + else + local temp = new("ModList"):ModList() + temp:ScaleAddList(buff.modList, curseMult) + curse.buffModList = new("ModList"):ModList() + curse.buffModList:ScaleAddList(temp, calcLib.mod(env.player.modDB, nil, "BuffEffectOnSelf")) + curse.mercenaryBuffModList = new("ModList"):ModList() + curse.mercenaryBuffModList:ScaleAddList(temp, calcLib.mod(mercenary.modDB, nil, "BuffEffectOnSelf")) + if env.minion then + curse.minionBuffModList = new("ModList"):ModList() + curse.minionBuffModList:ScaleAddList(temp, calcLib.mod(env.minion.modDB, nil, "BuffEffectOnSelf")) + end + if env.mercenaryMinion then + curse.mercenaryMinionBuffModList = new("ModList"):ModList() + curse.mercenaryMinionBuffModList:ScaleAddList(temp, calcLib.mod(env.mercenaryMinion.modDB, nil, "BuffEffectOnSelf")) + end + end + curse.sourceActor = mercenary + t_insert(mercenaryCurses, curse) + if partyTabEnableExportBuffs then + buffExports.Curse[buff.name] = { isMark = mark, effectMult = (1 + inc / 100) * skillModList:More(skillCfg, "CurseEffect"), modList = buff.modList } + end + end + end + end + if mercenaryTauntedEnemy then + local tauntedDamageTaken = env.data.mercenaryStatData.permanentMercenary.tauntedDamageTakenMore + env.player.modDB:NewMod("DamageTaken", "MORE", tauntedDamageTaken, "Mercenary Taunt") + if env.minion and not env.minion.hostile then env.minion.modDB:NewMod("DamageTaken", "MORE", tauntedDamageTaken, "Mercenary Taunt") end + if env.mercenaryMinion then env.mercenaryMinion.modDB:NewMod("DamageTaken", "MORE", tauntedDamageTaken, "Mercenary Taunt") end + end + + -- A Mercenary-created minion is an allied actor in its own right; route its + -- ally effects through the same shared stores as other allied sources. + for _, activeSkill in ipairs(env.mercenaryMinion and env.mercenaryMinion.activeSkillList or { }) do + local skillModList = activeSkill.skillModList + local skillCfg = activeSkill.skillCfg + for _, buff in ipairs(activeSkill.buffList) do + if buff.type == "Buff" and env.mode_buffs and activeSkill.skillData.enable then + if not buff.applyNotPlayer or buff.applyMinions then + mergeBuffFromSkill(activeSkill, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "BuffEffect", "BuffEffectOnSelf" }, { }) + end + if buff.applyAllies then + mergeBuffFromSkill(activeSkill, buff, env.player, buffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + mergeBuffFromSkill(activeSkill, buff, mercenary, mercenaryBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + if partyTabEnableExportBuffs then + buffExports.Aura.otherEffects = buffExports.Aura.otherEffects or { } + buffExports.Aura.otherEffects[buff.name] = { effectMult = calcLib.mod(skillModList, skillCfg, "BuffEffect"), modList = buff.modList } + end + end + if env.minion and (buff.applyAllies or buff.applyMinions) then + mergeBuffFromSkill(activeSkill, buff, env.minion, minionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }) + end + elseif buff.type == "Aura" and env.mode_buffs and activeSkill.skillData.enable then + local extraAuraModList = collectMergedListedMods(env.mercenaryMinion.modDB, skillCfg, "ExtraAuraEffect") + if not activeSkill.skillData.auraCannotAffectSelf then + mergeAuraFromSkill(activeSkill, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "AuraEffect", "BuffEffect" }, { "AuraEffectOnSelf", "BuffEffectOnSelf" }, extraAuraModList) + end + if not env.mercenaryMinion.modDB:Flag(nil, "SelfAurasCannotAffectAllies") and not env.mercenaryMinion.modDB:Flag(nil, "SelfAurasOnlyAffectYou") then + if not env.player.modDB:Flag(nil, "AlliesAurasCannotAffectSelf") then + mergeAuraFromSkill(activeSkill, buff, env.player, buffs, { "AuraEffect", "BuffEffect" }, { "AuraEffectOnSelf", "BuffEffectOnSelf" }, extraAuraModList) + end + mergeAuraFromSkill(activeSkill, buff, mercenary, mercenaryBuffs, { "AuraEffect", "BuffEffect" }, { "AuraEffectOnSelf", "BuffEffectOnSelf" }, extraAuraModList) + if env.minion then mergeAuraFromSkill(activeSkill, buff, env.minion, minionBuffs, { "AuraEffect", "BuffEffect" }, { "AuraEffectOnSelf", "BuffEffectOnSelf" }, extraAuraModList) end + if partyTabEnableExportBuffs then + local exported = new("ModList"):ModList() + exported:AddList(buff.modList) + exported:AddList(extraAuraModList) + exportStrongestAura(buffExports, buff.name, calcLib.mod(skillModList, skillCfg, "AuraEffect", "BuffEffect"), exported) + end + end + elseif buff.type == "Warcry" and env.mode_buffs then + local warcryPower = env.mercenaryMinion.modDB:Override(nil, "WarcryPower") or m_max((env.mercenaryMinion.modDB:Sum("BASE", nil, "WarcryPower") or 0) * (1 + (env.mercenaryMinion.modDB:Sum("INC", nil, "WarcryPower") or 0) / 100), (env.mercenaryMinion.modDB:Sum("BASE", nil, "MinimumWarcryPower") or 0)) + for _, warcryBuff in ipairs(buff.modList) do + if warcryBuff[1] and warcryBuff[1].effectType == "Warcry" and warcryBuff[1].div then + warcryBuff[1].warcryPowerBonus = m_floor((warcryBuff[1].limit and m_min(warcryPower, warcryBuff[1].limit) or warcryPower) / warcryBuff[1].div) end end + local uptime = calcWarcryUptime(env, enemyDB, env.mercenaryMinion.modDB, skillModList, skillCfg, activeSkill) + local extraWarcryModList, rallyingMinionMultiplier = buildRallyingCryAllyMods(env.mercenaryMinion, activeSkill, warcryPower) + mergeWarcryFromSkill(activeSkill, buff, env.mercenaryMinion, mercenaryMinionBuffs, { "BuffEffect", "BuffEffectOnSelf" }, { }, uptime) + mergeWarcryFromSkill(activeSkill, buff, env.player, buffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime) + mergeRallyingCryAllyMods(extraWarcryModList, 1, skillModList, skillCfg, env.player, buffs, buff.name, uptime) + mergeWarcryFromSkill(activeSkill, buff, mercenary, mercenaryBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime) + mergeRallyingCryAllyMods(extraWarcryModList, 1, skillModList, skillCfg, mercenary, mercenaryBuffs, buff.name, uptime) + if env.minion then + mergeWarcryFromSkill(activeSkill, buff, env.minion, minionBuffs, { "BuffEffect" }, { "BuffEffectOnSelf" }, uptime) + mergeRallyingCryAllyMods(extraWarcryModList, rallyingMinionMultiplier, skillModList, skillCfg, env.minion, minionBuffs, buff.name, uptime) + end + if partyTabEnableExportBuffs then + local exported = new("ModList"):ModList() + exported:AddList(buff.modList) + exported:AddList(extraWarcryModList) + buffExports.Warcry[buff.name] = { effectMult = calcLib.mod(skillModList, skillCfg, "BuffEffect") * uptime, modList = exported } + end + elseif (buff.type == "Debuff" or buff.type == "AuraDebuff") and env.mode_effective then + local stackCount = activeSkill.skillData.stackCount or 1 + local effectStats = buff.type == "AuraDebuff" and { "AuraEffect", "BuffEffect", "DebuffEffect" } or { "DebuffEffect" } + local srcList = new("ModList"):ModList() + srcList:ScaleAddList(buff.modList, calcLib.mod(skillModList, skillCfg, unpack(effectStats)) * stackCount) + mergeBuff(srcList, debuffs, buff.name, env.mercenaryMinion) + if partyTabEnableExportBuffs and buff.type == "AuraDebuff" then + buffExports.Aura[buff.name.."_Debuff"] = { effectMult = calcLib.mod(skillModList, skillCfg, unpack(effectStats)), modList = buff.modList } + end + elseif (buff.type == "Curse" or buff.type == "CurseBuff") and env.mode_effective and (activeSkill.skillTypes[SkillType.Mark] or not enemyDB:Flag(nil, "Hexproof") or env.mercenaryMinion.modDB:Flag(nil, "CursesIgnoreHexproof")) then + local mark = activeSkill.skillTypes[SkillType.Mark] + local inc = skillModList:Sum("INC", skillCfg, "CurseEffect") + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") + local more = skillModList:More(skillCfg, "CurseEffect") * (mark and 1 or enemyDB:More(nil, "CurseEffectOnSelf")) + local curse = { + name = buff.name, + priority = determineCursePriority(buff.name, activeSkill), + isMark = mark, + ignoreHexLimit = (env.mercenaryMinion.modDB:Flag(activeSkill.skillCfg, "CursesIgnoreHexLimit") or activeSkill.skillData.ignoreHexLimit) and not mark or false, + socketedCursesHexLimit = env.mercenaryMinion.modDB:Flag(activeSkill.skillCfg, "SocketedCursesAdditionalLimit"), + socketedCursesHexLimitValue = env.mercenaryMinion.modDB:Sum("BASE", nil, "SocketedCursesHexLimitValue"), + } + local temp = new("ModList"):ModList() + temp:ScaleAddList(buff.modList, (1 + inc / 100) * more) + if buff.type == "Curse" then + curse.modList = temp + else + curse.buffModList = new("ModList"):ModList() + curse.buffModList:ScaleAddList(temp, calcLib.mod(env.player.modDB, nil, "BuffEffectOnSelf")) + curse.mercenaryBuffModList = new("ModList"):ModList() + curse.mercenaryBuffModList:ScaleAddList(temp, calcLib.mod(mercenary.modDB, nil, "BuffEffectOnSelf")) + if env.minion then + curse.minionBuffModList = new("ModList"):ModList() + curse.minionBuffModList:ScaleAddList(temp, calcLib.mod(env.minion.modDB, nil, "BuffEffectOnSelf")) + end + curse.mercenaryMinionBuffModList = new("ModList"):ModList() + curse.mercenaryMinionBuffModList:ScaleAddList(temp, calcLib.mod(env.mercenaryMinion.modDB, nil, "BuffEffectOnSelf")) + end + curse.sourceActor = env.mercenaryMinion + t_insert(mercenaryMinionCurses, curse) + if partyTabEnableExportBuffs then + buffExports.Curse[buff.name] = { isMark = mark, effectMult = (1 + inc / 100) * skillModList:More(skillCfg, "CurseEffect"), modList = buff.modList } + end end end end @@ -3010,46 +3931,31 @@ function calcs.perform(env, skipEHP) srcList:ScaleAddList(buff.modList, (buff.effectMult + inc) / 100 * more) mergeBuff(srcList, minionBuffs, buffName) end + if env.mercenary then + env.mercenary.modDB.conditions["AffectedBy"..buffName:gsub(" ","")] = true + mergeAllyBuffOnRecipient(env.mercenary, mercenaryBuffs, buffName, buff.modList, buff.effectMult) + end + if env.mercenaryMinion then + env.mercenaryMinion.modDB.conditions["AffectedBy"..buffName:gsub(" ","")] = true + mergeAllyBuffOnRecipient(env.mercenaryMinion, mercenaryMinionBuffs, buffName, buff.modList, buff.effectMult) + end end end if allyBuffs["Aura"] then for auraName, aura in pairs(allyBuffs["Aura"]) do if auraName ~= "Vaal" then - local auraNameCompressed = auraName:gsub(" ","") - if not modDB:Flag(nil, "AlliesAurasCannotAffectSelf") and not modDB.conditions["AffectedBy"..auraNameCompressed] then - modDB.conditions["AffectedByAura"] = true - modDB.conditions["AffectedBy"..auraNameCompressed] = true - local srcList = new("ModList"):ModList() - srcList:ScaleAddList(aura.modList, aura.effectMult / 100) - mergeBuff(srcList, buffs, auraName) - end - if env.minion and not env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] then - env.minion.modDB.conditions["AffectedByAura"] = true - env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] = true - local srcList = new("ModList"):ModList() - srcList:ScaleAddList(aura.modList, aura.effectMult / 100) - mergeBuff(srcList, minionBuffs, auraName) - end + mergeImportedAuraOnRecipient(env.player, buffs, auraName, aura) + mergeImportedAuraOnRecipient(env.minion, minionBuffs, auraName, aura) + mergeImportedAuraOnRecipient(env.mercenary, mercenaryBuffs, auraName, aura) + mergeImportedAuraOnRecipient(env.mercenaryMinion, mercenaryMinionBuffs, auraName, aura) end end if allyBuffs["Aura"]["Vaal"] then for auraName, aura in pairs(allyBuffs["Aura"]["Vaal"]) do - local auraNameCompressed = auraName:gsub(" ","") - if not modDB:Flag(nil, "AlliesAurasCannotAffectSelf") and not modDB.conditions["AffectedBy"..auraNameCompressed] then - modDB.conditions["AffectedByAura"] = true - modDB.conditions["AffectedBy"..auraName:sub(6):gsub(" ","")] = true - modDB.conditions["AffectedBy"..auraNameCompressed] = true - local srcList = new("ModList"):ModList() - srcList:ScaleAddList(aura.modList, aura.effectMult / 100) - mergeBuff(srcList, buffs, auraName) - end - if env.minion and not env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] then - env.minion.modDB.conditions["AffectedByAura"] = true - env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] = true - local srcList = new("ModList"):ModList() - srcList:ScaleAddList(aura.modList, aura.effectMult / 100) - mergeBuff(srcList, minionBuffs, auraName) - end + mergeImportedAuraOnRecipient(env.player, buffs, auraName, aura) + mergeImportedAuraOnRecipient(env.minion, minionBuffs, auraName, aura) + mergeImportedAuraOnRecipient(env.mercenary, mercenaryBuffs, auraName, aura) + mergeImportedAuraOnRecipient(env.mercenaryMinion, mercenaryMinionBuffs, auraName, aura) end end end @@ -3100,6 +4006,16 @@ function calcs.perform(env, skipEHP) end mergeBuff(srcList, minionBuffs, warcryName) end + if env.mercenary and not env.mercenary.modDB.conditions["AffectedBy"..warcryNameCompressed] then + env.mercenary.modDB.conditions.AffectedByWarcry = true + env.mercenary.modDB.conditions["AffectedBy"..warcryNameCompressed] = true + mergeAllyWarcryOnRecipient(env.mercenary, mercenaryBuffs, warcryName, warcry) + end + if env.mercenaryMinion and not env.mercenaryMinion.modDB.conditions["AffectedBy"..warcryNameCompressed] then + env.mercenaryMinion.modDB.conditions.AffectedByWarcry = true + env.mercenaryMinion.modDB.conditions["AffectedBy"..warcryNameCompressed] = true + mergeAllyWarcryOnRecipient(env.mercenaryMinion, mercenaryMinionBuffs, warcryName, warcry) + end end end if env.partyMembers["Link"] and env.partyMembers["Link"]["Link"] then @@ -3141,7 +4057,7 @@ function calcs.perform(env, skipEHP) end -- Check for extra curses - for dest, modDB in pairs({[curses] = modDB, [minionCurses] = env.minion and env.minion.modDB}) do + for dest, modDB in pairs({ [curses] = modDB, [minionCurses] = env.minion and env.minion.modDB, [mercenaryCurses] = env.mercenary and env.mercenary.modDB, [mercenaryMinionCurses] = env.mercenaryMinion and env.mercenaryMinion.modDB }) do if env.mode_combat and modDB:Flag(nil, "Condition:OnConsecratedGround") then local effect = 1 + modDB:Sum("INC", nil, "ConsecratedGroundEffect") / 100 modDB:NewMod("CurseEffectOnSelf", "INC", -50 * effect, "Consecrated Ground") @@ -3180,6 +4096,10 @@ function calcs.perform(env, skipEHP) name = grantedEffect.name, fromPlayer = (dest == curses), priority = determineCursePriority(grantedEffect.name), + sourceActor = dest == curses and env.player + or dest == minionCurses and env.minion + or dest == mercenaryCurses and env.mercenary + or dest == mercenaryMinionCurses and env.mercenaryMinion, } curse.modList = new("ModList"):ModList() curse.modList:ScaleAddList(curseModList, (1 + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") / 100) * enemyDB:More(nil, "CurseEffectOnSelf")) @@ -3221,7 +4141,21 @@ function calcs.perform(env, skipEHP) env.curseSlots = curseSlots -- Currently assume only 1 mark is possible local markSlotted = false - for _, source in ipairs({curses, minionCurses, allyCurses}) do + local curseSources = { curses, minionCurses, mercenaryCurses, mercenaryMinionCurses, allyCurses } + local curseSlotLimit = 0 + for _, source in ipairs(curseSources) do + curseSlotLimit = m_max(curseSlotLimit, source.limit or 0) + end + local function slotsUsedBy(sourceActor) + local used = 0 + for i = 1, curseSlotLimit do + if curseSlots[i] and curseSlots[i].sourceActor == sourceActor then + used = used + 1 + end + end + return used + end + for _, source in ipairs(curseSources) do for _, curse in ipairs(source) do -- Calculate curses that ignore hex limit after if not curse.ignoreHexLimit and not curse.socketedCursesHexLimit then @@ -3236,7 +4170,8 @@ function calcs.perform(env, skipEHP) break end end - for i = 1, source.limit do + local used = slotsUsedBy(curse.sourceActor) + for i = 1, curseSlotLimit do -- Prevent multiple marks from being considered if curse.isMark then if markSlotted then @@ -3244,18 +4179,24 @@ function calcs.perform(env, skipEHP) break end end - if not curseSlots[i] then - slot = i - break - elseif curseSlots[i].name == curse.name then - if curseSlots[i].priority < curse.priority then + local existing = curseSlots[i] + if not existing then + if used < source.limit then + slot = i + break + end + elseif existing.name == curse.name then + if existing.priority < curse.priority + and (existing.sourceActor == curse.sourceActor or used < source.limit) then slot = i else slot = nil end break - elseif curseSlots[i].priority < curse.priority then - slot = i + elseif existing.priority < curse.priority then + if existing.sourceActor == curse.sourceActor or used < source.limit then + slot = i + end end end if slot then @@ -3273,7 +4214,7 @@ function calcs.perform(env, skipEHP) end end - for _, source in ipairs({curses, minionCurses}) do + for _, source in ipairs({ curses, minionCurses, mercenaryCurses, mercenaryMinionCurses }) do for _, curse in ipairs(source) do if curse.ignoreHexLimit then local skipAddingCurse = false @@ -3292,7 +4233,7 @@ function calcs.perform(env, skipEHP) end end if curse.socketedCursesHexLimit then - local socketedCursesHexLimitValue = modDB:Sum("BASE", nil, "SocketedCursesHexLimitValue") + local socketedCursesHexLimitValue = curse.socketedCursesHexLimitValue or modDB:Sum("BASE", nil, "SocketedCursesHexLimitValue") local skipAddingCurse = false for i = 1, #curseSlots do if curseSlots[i].name == curse.name then @@ -3355,12 +4296,29 @@ function calcs.perform(env, skipEHP) env.minion.modDB:AddList(modList) end end + if env.mercenary then + for _, modList in pairs(mercenaryBuffs) do + env.mercenary.modDB:AddList(modList) + if env.mercenaryMinion then + addMinionModifiers(modList, env.mercenary.mainSkill.skillCfg, env.mercenaryMinion) + end + end + end + if env.mercenaryMinion then + for _, modList in pairs(mercenaryMinionBuffs) do + env.mercenaryMinion.modDB:AddList(modList) + end + end for _, modList in pairs(debuffs) do enemyDB:AddList(modList) end modDB.multipliers["CurseOnEnemy"] = #curseSlots + if env.mercenary then env.mercenary.modDB.multipliers.CurseOnEnemy = #curseSlots end for _, slot in ipairs(curseSlots) do enemyDB.conditions["Cursed"] = true + if slot.sourceActor and slot.sourceActor.enemySourceDB then + slot.sourceActor.enemySourceDB.conditions.Cursed = true + end if slot.isMark then enemyDB.conditions["Marked"] = true end @@ -3370,15 +4328,22 @@ function calcs.perform(env, skipEHP) if slot.buffModList then modDB:AddList(slot.buffModList) end - if slot.minionBuffModList then + if slot.minionBuffModList and env.minion then env.minion.modDB:AddList(slot.minionBuffModList) end + if slot.mercenaryBuffModList and env.mercenary then + env.mercenary.modDB:AddList(slot.mercenaryBuffModList) + end + if slot.mercenaryMinionBuffModList and env.mercenaryMinion then + env.mercenaryMinion.modDB:AddList(slot.mercenaryMinionBuffModList) + end end -- Calculate guaranteed chills after buffs so chilling areas benefit from active buff modifiers. - for _, activeSkill in ipairs(guaranteedChillSkills) do + for _, entry in ipairs(guaranteedChillSkills) do + local activeSkill = entry.skill local effect = data.nonDamagingAilment.Chill.default * calcLib.mod(activeSkill.skillModList, activeSkill.skillCfg, "EnemyChillEffect") - modDB:NewMod("ChillOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) + entry.actorModDB:NewMod("ChillOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) end -- Fix the configured impale stacks on the enemy @@ -3432,6 +4397,16 @@ function calcs.perform(env, skipEHP) local more = env.minion.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") env.minion.modDB:ScaleAddList(modList, (1 + inc / 100) * more) end + if env.mercenary and recipientAcceptsAllyAura(env.mercenary) then + local inc = env.mercenary.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = env.mercenary.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + env.mercenary.modDB:ScaleAddList(modList, (1 + inc / 100) * more) + end + if env.mercenaryMinion and recipientAcceptsAllyAura(env.mercenaryMinion) then + local inc = env.mercenaryMinion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = env.mercenaryMinion.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + env.mercenaryMinion.modDB:ScaleAddList(modList, (1 + inc / 100) * more) + end buffExports["Aura"]["extraAura"].modList:AddMod(value.mod) local totemModBlacklist = value.mod.name and (value.mod.name == "Speed" or value.mod.name == "CritMultiplier" or value.mod.name == "CritChance") if env.player.mainSkill.skillFlags.totem and not totemModBlacklist then @@ -3445,6 +4420,44 @@ function calcs.perform(env, skipEHP) end end end + if env.mercenary then + for _, value in ipairs(env.mercenary.modDB:List(nil, "ExtraAura")) do + local modList = { value.mod } + if not value.onlyAllies then + local inc = env.mercenary.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = env.mercenary.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + env.mercenary.modDB:ScaleAddList(modList, (1 + inc / 100) * more) + end + if not env.mercenary.modDB:Flag(nil, "SelfAurasCannotAffectAllies") then + applyExtraAuraModToActor(env.player, modList) + applyExtraAuraModToActor(env.minion, modList) + applyExtraAuraModToActor(env.mercenaryMinion, modList) + if partyTabEnableExportBuffs then buffExports.Aura.extraAura.modList:AddMod(value.mod) end + end + end + end + for _, activeSkill in ipairs(env.player.activeSkillList) do + local minion = activeSkill.minion + if minion and minion.itemSet and not activeSkill.skillFlags.disable then + for _, value in ipairs(minion.modDB:List(nil, "ExtraAura")) do + local extraAuraModList = { value.mod } + if not value.onlyAllies then + local inc = minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = minion.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + minion.modDB:ScaleAddList(extraAuraModList, (1 + inc / 100) * more) + end + if not minion.modDB:Flag(nil, "SelfAurasCannotAffectAllies") then + applyExtraAuraModToActor(env.player, extraAuraModList) + if env.minion ~= minion then + applyExtraAuraModToActor(env.minion, extraAuraModList) + end + applyExtraAuraModToActor(env.mercenary, extraAuraModList) + applyExtraAuraModToActor(env.mercenaryMinion, extraAuraModList) + buffExports["Aura"]["extraAura"].modList:AddMod(value.mod) + end + end + end + end if allyBuffs["extraAura"] then for _, buff in pairs(allyBuffs["extraAura"]) do local modList = buff.modList @@ -3456,6 +4469,16 @@ function calcs.perform(env, skipEHP) local more = env.minion.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") env.minion.modDB:ScaleAddList(modList, (1 + inc / 100) * more) end + if env.mercenary and recipientAcceptsAllyAura(env.mercenary) then + local inc = env.mercenary.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = env.mercenary.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + env.mercenary.modDB:ScaleAddList(modList, (1 + inc / 100) * more) + end + if env.mercenaryMinion and recipientAcceptsAllyAura(env.mercenaryMinion) then + local inc = env.mercenaryMinion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + local more = env.mercenaryMinion.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + env.mercenaryMinion.modDB:ScaleAddList(modList, (1 + inc / 100) * more) + end end end @@ -3468,6 +4491,9 @@ function calcs.perform(env, skipEHP) -- Merge keystones again to catch any that were added by buffs modLib.mergeKeystones(env, env.modDB) + if env.mercenary then + modLib.mergeKeystones(env.mercenary.calcEnv, env.mercenary.modDB) + end -- Special handling for Dancing Dervish if modDB:Flag(nil, "DisableWeapons") then @@ -3482,17 +4508,29 @@ function calcs.perform(env, skipEHP) -- Process prerequisites for conditionals calcs.defenceForConditionals(env, env.player) + if env.mercenary then + calcs.defenceForConditionals(env, env.mercenary) + end if env.minion then calcs.defenceForConditionals(env, env.minion) end + if env.mercenaryMinion then calcs.defenceForConditionals(env, env.mercenaryMinion) end -- Process misc buffs/modifiers doActorCharges(env, env.player) doActorMisc(env, env.player) + if env.mercenary then + doActorCharges(env, env.mercenary) + doActorMisc(env, env.mercenary) + end if env.minion then doActorCharges(env, env.minion) doActorMisc(env, env.minion) end + if env.mercenaryMinion then + doActorCharges(env, env.mercenaryMinion) + doActorMisc(env, env.mercenaryMinion) + end -- Calculate maximum and apply the strongest non-damaging ailments local ailmentData = data.nonDamagingAilment @@ -3501,16 +4539,16 @@ function calcs.perform(env, skipEHP) condition = "Chilled", mods = function(num) local mods = { modLib.createMod("ActionSpeed", "INC", -num, "Chill", { type = "Condition", var = "Chilled" }) } - if modDB:Flag(nil, "ChillEffectIncDamageTaken") then + if anyActorHasChilledByHitsFlag(env, "ChillEffectIncDamageTaken") then t_insert(mods, modLib.createMod("DamageTaken", "INC", num, "Ahuana's Bite", { type = "Condition", var = "Chilled" })) - elseif modDB:Flag(nil, "ChillEffectIncColdDamageTaken") then + elseif anyActorHasChilledByHitsFlag(env, "ChillEffectIncColdDamageTaken") then t_insert(mods, modLib.createMod("ColdDamageTaken", "INC", num, "Chilled by Hits", { type = "Condition", var = "Chilled" })) elseif modDB:Flag(nil, "ChillingAreaIncColdDamageTaken") then t_insert(mods, modLib.createMod("ColdDamageTaken", "INC", num, "Chilling Area", { type = "Condition", var = "Chilled" })) elseif output.HasBonechill and (hasGuaranteedBonechill or enemyDB:Sum("BASE", nil, "ChillVal") > 0) then t_insert(mods, modLib.createMod("ColdDamageTaken", "INC", num, "Bonechill", { type = "Condition", var = "Chilled" })) end - if modDB:Flag(nil, "ChillEffectLessDamageDealt") then + if anyActorHasChilledByHitsFlag(env, "ChillEffectLessDamageDealt") then t_insert(mods, modLib.createMod("Damage", "MORE", -num / 2, "Shaper of Winter", { type = "Condition", var = "Chilled" })) end return mods @@ -3562,52 +4600,110 @@ function calcs.perform(env, skipEHP) }, } - for ailment, val in pairs(ailments) do - if (enemyDB:Sum("BASE", nil, ailment.."Val") > 0 - or modDB:Sum("BASE", nil, ailment.."Base", ailment.."Override", ailment.."Minimum")) - and not (enemyDB:Flag(nil, "Condition:Already"..val.condition) or enemyDB:Flag(nil, ailment.."Immune", "ElementalAilmentImmune") or enemyDB:Sum("BASE", nil, "Avoid"..ailment, "AvoidAilments", "AvoidElementalAilments") >= 100) then - local override = 0 - local minimum = 0 - for _, value in ipairs(modDB:Tabulate("BASE", nil, ailment.."Base", ailment.."Override", ailment.."Minimum")) do - local mod = value.mod - local effect = mod.value - local scalesWithSource = mod.name == ailment.."Base" or mod.name == ailment.."Minimum" - if mod.name == ailment.."Override" then - enemyDB:NewMod("Condition:"..val.condition, "FLAG", true, mod.source) - end - if scalesWithSource then - -- If the main skill can inflict the ailment, the ailment is inflicted with a hit, and we have a node allocated that checks what our highest damage is, then - -- use the skill's ailment modifiers - -- if not, use the generic modifiers - -- Scorch/Sap/Brittle do not have guaranteed sources from hits, and therefore will only end up in this bit of code if it's not supposed to apply the skillModList, which is bad - if ailment ~= "Scorch" and ailment ~= "Sap" and ailment ~= "Brittle" and not env.player.mainSkill.skillModList:Flag(nil, "Cannot"..ailment) and env.player.mainSkill.skillFlags.hit and modDB:Flag(nil, "ChecksHighestDamage") then - effect = effect * calcLib.mod(env.player.mainSkill.skillModList, nil, "Enemy"..ailment.."Effect") - else - effect = effect * calcLib.mod(modDB, nil, "Enemy"..ailment.."Effect") - end + -- Always write each actor's ailment cap. The Calcs tab shows Maximum Chill/Shock whenever + -- the skill can inflict that ailment, not only when a guaranteed or configured ailment is + -- currently applied, and Mercenary/minion views read their own output tables. + local function actorAilmentMaximum(actor, ailment) + local actorModDB = actor.modDB + local override = actorModDB:Override(nil, ailment.."Max") + if override then + return override + end + local maxAilment = ailmentData[ailment].max + for _, skill in ipairs(actor.activeSkillList or { }) do + if skill.baseSkillModList then + local skillMax = ailmentData[ailment].max + skill.baseSkillModList:Sum("BASE", nil, ailment.."Max") + if skillMax > maxAilment then + maxAilment = skillMax end - effect = effect * calcLib.mod(enemyDB, nil, "Self"..ailment.."Effect") - if scalesWithSource then - modDB:NewMod(ailment.."Override", "BASE", effect, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) - if mod.name == ailment.."Minimum" then - minimum = minimum + effect - end + end + end + return maxAilment + end + local function setActorAilmentMaximums(actor) + if not (actor and actor.output and actor.modDB) then + return + end + for ailment in pairs(ailments) do + actor.output["Maximum"..ailment] = actorAilmentMaximum(actor, ailment) + end + end + setActorAilmentMaximums(env.player) + setActorAilmentMaximums(env.minion) + setActorAilmentMaximums(env.mercenary) + setActorAilmentMaximums(env.mercenaryMinion) + + -- Each inflictor keeps its own guaranteed sources and cap. Configured enemy + -- magnitude is unattributed encounter state, so it is legal up to the highest + -- cap among those actors. The strongest candidate is applied once to the shared enemy. + local function eachAilmentActor(fn) + fn(env.player) + if env.minion then fn(env.minion) end + if env.mercenary then fn(env.mercenary) end + if env.mercenaryMinion then fn(env.mercenaryMinion) end + end + local function actorGuaranteedAilment(actor, ailment, condition) + if not (actor.modDB and actor.output) then + return 0 + end + local actorModDB = actor.modDB + local override, minimum = 0, 0 + for _, value in ipairs(actorModDB:Tabulate("BASE", nil, ailment.."Base", ailment.."Override", ailment.."Minimum")) do + local mod = value.mod + local effect = mod.value + local scalesWithSource = mod.name == ailment.."Base" or mod.name == ailment.."Minimum" + if mod.name == ailment.."Override" then + enemyDB:NewMod("Condition:"..condition, "FLAG", true, mod.source) + end + if scalesWithSource then + -- If the main skill can inflict the ailment, the ailment is inflicted with a hit, and we have a node allocated that checks what our highest damage is, then + -- use the skill's ailment modifiers + -- if not, use the generic modifiers + -- Scorch/Sap/Brittle do not have guaranteed sources from hits, and therefore will only end up in this bit of code if it's not supposed to apply the skillModList, which is bad + local mainSkill = actor.mainSkill + if ailment ~= "Scorch" and ailment ~= "Sap" and ailment ~= "Brittle" and mainSkill and mainSkill.skillModList and mainSkill.skillFlags and not mainSkill.skillModList:Flag(nil, "Cannot"..ailment) and mainSkill.skillFlags.hit and actorModDB:Flag(nil, "ChecksHighestDamage") then + effect = effect * calcLib.mod(mainSkill.skillModList, nil, "Enemy"..ailment.."Effect") + else + effect = effect * calcLib.mod(actorModDB, nil, "Enemy"..ailment.."Effect") end - override = m_max(m_max(override, effect or 0), minimum) end - local maxAilment = modDB:Override(nil, ailment.."Max") or 0 - if not modDB:Override(nil, ailment.."Max") then - for _, skill in ipairs(env.player.activeSkillList) do - local skillMax = modDB:Override(nil, ailment.."Max") or (ailmentData[ailment].max + skill.baseSkillModList:Sum("BASE", nil, ailment.."Max")) - maxAilment = skillMax > maxAilment and skillMax or maxAilment + effect = effect * calcLib.mod(enemyDB, nil, "Self"..ailment.."Effect") + if scalesWithSource then + actorModDB:NewMod(ailment.."Override", "BASE", effect, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + if mod.name == ailment.."Minimum" then + minimum = minimum + effect end end - output["Maximum"..ailment] = maxAilment - output["Current"..ailment] = m_floor(m_min(m_max(override, enemyDB:Sum("BASE", nil, ailment.."Val")), output["Maximum"..ailment]) * (10 ^ ailmentData[ailment].precision)) / (10 ^ ailmentData[ailment].precision) - for _, mod in ipairs(val.mods(output["Current"..ailment])) do - enemyDB:AddMod(mod) + override = m_max(m_max(override, effect or 0), minimum) + end + return m_min(override, actor.output["Maximum"..ailment] or ailmentData[ailment].max) + end + + for ailment, val in pairs(ailments) do + if not (enemyDB:Flag(nil, "Condition:Already"..val.condition) or enemyDB:Flag(nil, ailment.."Immune", "ElementalAilmentImmune") or enemyDB:Sum("BASE", nil, "Avoid"..ailment, "AvoidAilments", "AvoidElementalAilments") >= 100) then + local highestMax, guaranteed = 0, 0 + eachAilmentActor(function(actor) + if actor.output then + highestMax = m_max(highestMax, actor.output["Maximum"..ailment] or 0) + guaranteed = m_max(guaranteed, actorGuaranteedAilment(actor, ailment, val.condition)) + end + end) + if highestMax == 0 then + highestMax = ailmentData[ailment].max + end + local current = m_max(guaranteed, m_min(enemyDB:Sum("BASE", nil, ailment.."Val"), highestMax)) + if current > 0 then + current = m_floor(current * (10 ^ ailmentData[ailment].precision)) / (10 ^ ailmentData[ailment].precision) + eachAilmentActor(function(actor) + if actor.output then + actor.output["Current"..ailment] = current + end + end) + for _, mod in ipairs(val.mods(current)) do + enemyDB:AddMod(mod) + end + enemyDB:NewMod("Condition:Already"..val.condition, "FLAG", true, { type = "Condition", var = val.condition } ) -- Prevents ailment from applying doubly for minions end - enemyDB:NewMod("Condition:Already"..val.condition, "FLAG", true, { type = "Condition", var = val.condition } ) -- Prevents ailment from applying doubly for minions end end @@ -3625,38 +4721,77 @@ function calcs.perform(env, skipEHP) doActorMisc(env, env.enemy) local major, minor = env.spec.treeVersion:match("(%d+)_(%d+)") - - -- Apply exposures - for _, element in ipairs({"Fire", "Cold", "Lightning"}) do - if tonumber(major) <= 3 and tonumber(minor) <= 15 -- Elemental Equilibrium pre-3.16 does not remove Exposure effects - or not modDB:Flag(nil, "ElementalEquilibrium") -- if Elemental Equilibrium isn't active we just process Exposure normally - or element == "Fire" and not enemyDB:Flag(nil, "Condition:HitByFireDamage") - or element == "Cold" and not enemyDB:Flag(nil, "Condition:HitByColdDamage") - or element == "Lightning" and not enemyDB:Flag(nil, "Condition:HitByLightningDamage") then + local function actorHidesExposure(actor, cond) + if not (actor and actor.modDB:Flag(nil, "ElementalEquilibrium")) then + return false + end + local sourceDB = actor.enemySourceDB or (actor == env.player and enemyDB) + return sourceDB and sourceDB:GetCondition(cond) + end + -- HitBy from offence is unknown on the first pass. Replacing the converted + -- resist lets a later, stronger EE exposure win instead of stacking. + -- The matching HasExposure FLAG is mutated with that resist so + -- EE hiding an already-converted element also clears the condition. + local convertedExposureResist = { } + local convertedExposureCondition = { } + local function applyElementalExposures() + for _, element in ipairs({"Fire", "Cold", "Lightning"}) do + local hidden = tonumber(major) > 3 or tonumber(minor) > 15 + hidden = hidden and (actorHidesExposure(env.player, "HitBy"..element.."Damage") + or (env.mercenary and actorHidesExposure(env.mercenary, "HitBy"..element.."Damage"))) local min = math.huge local source = "" - for _, mod in ipairs(enemyDB:Tabulate("BASE", nil, element.."Exposure")) do - if mod.value < min then - min = mod.value - source = mod.mod.source + if not hidden then + local function considerExposure(mod, actor) + local value = mod.value + -- Unattributed encounter/party effects have no local inflictor to scale them. + if actor then + local sourceDB = actor.modDB + value = value + sourceDB:Sum("BASE", nil, "ExtraExposure", "Extra"..element.."Exposure") + value = value * (1 + sourceDB:Sum("INC", nil, "ExposureEffect", element.."ExposureEffect") / 100) + value = m_min(value, sourceDB:Override(nil, "ExposureMin")) + sourceDB:NewMod("Condition:AppliedExposureRecently", "FLAG", true, "") + end + if value < min then + min = value + source = mod.mod.source + end + end + for _, mod in ipairs(enemyDB:Tabulate("BASE", nil, element.."Exposure")) do + if mod.mod.source == "Config" and not mod.mod.sourceActor then + -- The encounter checkbox applies to every actor capable of inflicting it. + for _, actor in ipairs({ env.player, env.mercenary or false, env.minion or false, env.mercenaryMinion or false }) do + if actor and actor.modDB:GetCondition("CanApply"..element.."Exposure") then + considerExposure(mod, actor) + end + end + else + considerExposure(mod, mod.mod.sourceActor) + end end end + local resistMod = convertedExposureResist[element] + local conditionMod = convertedExposureCondition[element] if min ~= math.huge then - -- Modify the magnitude of all exposures - for _, mod in ipairs(modDB:Tabulate("BASE", nil, "ExtraExposure", "Extra"..element.."Exposure")) do - min = min + mod.value - end - -- Scale the resulting magnitude by increased effect of Exposure you inflict - local exposureEffectInc = modDB:Sum("INC", nil, "ExposureEffect", element.."ExposureEffect") - if exposureEffectInc ~= 0 then - min = min * (1 + exposureEffectInc / 100) + if resistMod then + resistMod.value = min + resistMod.source = source + conditionMod.value = true + else + resistMod = modLib.createMod(element.."Resist", "BASE", min, source) + conditionMod = modLib.createMod("Condition:Has"..element.."Exposure", "FLAG", true, "") + enemyDB:AddMod(resistMod) + enemyDB:AddMod(conditionMod) + convertedExposureResist[element] = resistMod + convertedExposureCondition[element] = conditionMod end - enemyDB:NewMod("Condition:Has"..element.."Exposure", "FLAG", true, "") - enemyDB:NewMod(element.."Resist", "BASE", m_min(min, modDB:Override(nil, "ExposureMin")), source) - modDB:NewMod("Condition:AppliedExposureRecently", "FLAG", true, "") + elseif resistMod then + resistMod.value = 0 + conditionMod.value = false end end end + applyElementalExposures() -- Handle consecrated ground effects on enemies if enemyDB:Flag(nil, "Condition:OnConsecratedGround") then @@ -3788,6 +4923,25 @@ function calcs.perform(env, skipEHP) end end + if env.mercenary then + doActorLifeMana(env.mercenary) + local comparison = env.mercenary.profile.lifeComparison or "AUTO" + local mercenaryHigher = comparison == "MERCENARY" or comparison == "AUTO" and env.mercenary.output.Life > output.Life + local playerHigher = comparison == "PLAYER" or comparison == "AUTO" and output.Life > env.mercenary.output.Life + if mercenaryHigher then + local redirect = modDB:Sum("BASE", nil, "LoyalBodyguardRedirect") + if redirect > 0 then + modDB:NewMod("takenFromMercenaryBeforeYou", "BASE", redirect, "Loyal Bodyguard") + modDB:NewMod("TotalMercenaryLife", "BASE", env.mercenary.output.Life, "Mercenary") + env.player.allyLifeList = env.player.allyLifeList or { } + env.player.allyLifeList.TotalMercenaryLife = { { name = "Mercenary", life = env.mercenary.output.Life, count = 1 } } + end + elseif playerHigher then + local recoup = modDB:Sum("BASE", nil, "MercenaryLifeRecoup") + if recoup > 0 then env.mercenary.modDB:NewMod("LifeRecoup", "BASE", recoup, "Loyal Bodyguard") end + end + end + -- Defence/offence calculations calcs.defence(env, env.player) if not skipEHP then @@ -3795,13 +4949,83 @@ function calcs.perform(env, skipEHP) end calcs.triggers(env, env.player) - if not calcs.mirages(env) then - calcs.offence(env, env.player, env.player.mainSkill) + + local mercEnv + if env.mercenary and (env.mercenary.mainSkill or (env.mercenaryMinion and env.mercenaryMinion.mainSkill)) then + mercEnv = assert(env.mercenary.calcEnv, "Mercenary calculation requires Mercenary calculation environment") + if env.mercenary.mainSkill then + calcs.defence(mercEnv, env.mercenary) + if not skipEHP then + calcs.buildDefenceEstimations(mercEnv, env.mercenary) + end + calcs.triggers(mercEnv, env.mercenary) + end + if env.mercenaryMinion and env.mercenaryMinion.mainSkill then + -- Mercenary-created minions must run in the Mercenary actor environment so + -- env.modDB / env.player / env.configInput (physMode, ailmentMode, distances, + -- ...) match the summoner instead of the root character. + doActorLifeMana(env.mercenaryMinion) + calcs.defence(mercEnv, env.mercenaryMinion) + if not skipEHP then + calcs.buildDefenceEstimations(mercEnv, env.mercenaryMinion) + end + calcs.triggers(mercEnv, env.mercenaryMinion) + end + end + + local function calculatePlayerOffence() + if not calcs.mirages(env) then + calcs.offence(env, env.player, env.player.mainSkill) + end + end + local function calculateMercenaryOffence() + if env.mercenary.mainSkill then + if not calcs.mirages(mercEnv) then + calcs.offence(mercEnv, env.mercenary, env.mercenary.mainSkill) + end + end + if env.mercenaryMinion and env.mercenaryMinion.mainSkill then + calcs.offence(mercEnv, env.mercenaryMinion, env.mercenaryMinion.mainSkill) + end + end + + -- HitBy* is written during offence onto each actor's overlay. Shared exposure + -- is applied from the EE actor's flags; the other actor then sees that exposure. + -- Single-EE therefore runs the EE actor first. Both-EE double-pass writes both, + -- applies exposure, restores, and recalculates. + local playerHasEE = actorHasElementalEquilibrium(env.player) + local mercHasEE = actorHasElementalEquilibrium(env.mercenary) + if env.mercenary then + if playerHasEE and mercHasEE then + local playerSnap = snapshotActorForOffence(env.player) + local minionSnap = snapshotActorForOffence(env.minion) + local mercSnap = snapshotActorForOffence(env.mercenary) + local mercMinionSnap = snapshotActorForOffence(env.mercenaryMinion) + calculatePlayerOffence() + calculateMercenaryOffence() + applyElementalExposures() + restoreActorForOffence(env.player, playerSnap) + restoreActorForOffence(env.minion, minionSnap) + restoreActorForOffence(env.mercenary, mercSnap) + restoreActorForOffence(env.mercenaryMinion, mercMinionSnap) + calculatePlayerOffence() + calculateMercenaryOffence() + elseif playerHasEE then + calculatePlayerOffence() + applyElementalExposures() + calculateMercenaryOffence() + else + calculateMercenaryOffence() + applyElementalExposures() + calculatePlayerOffence() + end + else + calculatePlayerOffence() end if env.minion then calcs.defence(env, env.minion) - if not skipEHP then -- main.build.calcsTab.input.showMinion and -- should be disabled unless "calcsTab.input.showMinion" is true + if not skipEHP then calcs.buildDefenceEstimations(env, env.minion) end calcs.triggers(env, env.minion) @@ -3919,11 +5143,7 @@ function calcs.perform(env, skipEHP) elseif mod.name == "TakenFromParentESBeforeYou" then buffExports.PlayerMods["EnergyShieldRecoveryCap="..tostring(output["EnergyShieldRecoveryCap"])] = true elseif mod.name == "MainHandCritIsEqualToParent" then - if output.MainHand then - buffExports.PlayerMods["MainHand.CritChance="..tostring(output["MainHand"]["CritChance"])] = true - elseif env.player.weaponData1 then - buffExports.PlayerMods["MainHand.CritChance="..tostring(env.player.weaponData1.CritChance)] = true - end + buffExports.PlayerMods["MainHand.CritChance="..tostring(calcs.actorMainHandSheetCritChance(env.player))] = true end end end @@ -3987,4 +5207,7 @@ function calcs.perform(env, skipEHP) end cacheData(cacheSkillUUID(env.player.mainSkill, env), env) + if env.mercenary and env.mercenary.mainSkill then + cacheData(cacheSkillUUID(env.mercenary.mainSkill, env), env, env.mercenary) + end end diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 70301168360..649224e9169 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -5,16 +5,749 @@ -- ---@class Calcs local calcs = require("Modules.CalcBase") +local MercenaryTools = require("Modules.MercenaryTools") +local ConfigScope = require("Modules.ConfigScope") local pairs = pairs local ipairs = ipairs local t_insert = table.insert local t_remove = table.remove +local t_sort = table.sort local m_min = math.min local m_max = math.max +local m_floor = math.floor local tempTable1 = { } +local function mercenarySupportEffect(env, support, supportedEffect, errors) + if not support then + t_insert(errors, "Missing exported Mercenary support data") + return + end + local grantedEffect = env.data.mercenarySupportGrantedEffect(support.id, supportedEffect and supportedEffect.id) + if not grantedEffect then + t_insert(errors, "Missing Mercenary support grantedEffect: "..support.id) + return + end + if grantedEffect.missingSupportTemplate then + t_insert(errors, "Missing Mercenary support template: "..grantedEffect.missingSupportTemplate) + end + for _, statId in ipairs(grantedEffect.unsupportedMercenaryStats or { }) do + t_insert(errors, "Unsupported Mercenary support stat: "..statId) + end + return { + grantedEffect = grantedEffect, + level = 1, + quality = 0, + enabled = true, + isSupporting = { }, + } +end + +local function validateMercenarySkillStats(env, grantedEffect, errors) + local function validate(statId) + if not grantedEffect.statMap[statId] and not env.data.knownUncalculatedSkillStats[statId] then + t_insert(errors, "Unsupported Mercenary skill stat: "..statId.." ("..grantedEffect.id..")") + end + end + for _, statId in ipairs(grantedEffect.stats or { }) do validate(statId) end + for _, stat in ipairs(grantedEffect.constantStats or { }) do validate(stat[1]) end + local baseEffect = grantedEffect.inheritedFrom and env.data.skills[grantedEffect.inheritedFrom] + for _, message in ipairs(MercenaryTools.preDamageFuncErrors(grantedEffect, baseEffect, env.data.mercenaryStatData) or { }) do + t_insert(errors, message) + end +end + +local function recordMercenaryAuxiliarySkill(env, auxiliarySkills, statId, selectedSkill) + local auxiliarySkillId = env.data.mercenaryStatData.auxiliarySkills[statId] + if auxiliarySkillId and not auxiliarySkills[auxiliarySkillId] then auxiliarySkills[auxiliarySkillId] = selectedSkill end +end + +-- Hired Mercenaries treat Eldritch "while a Unique / Pinnacle Atlas Boss is in +-- your Presence" implicits as always active. That is a mercenary-item exception, +-- not a second encounter: shared RareOrUnique / PinnacleBoss on the enemy is +-- left alone, and "against unique enemies" mods still follow that encounter. +-- https://www.poewiki.net/wiki/Mercenary +local function addEquippedItemPropertyCounts(modDB, item) + if (item.rarity == "UNIQUE" or item.rarity == "RELIC") and item.foulborn then + modDB.multipliers["FoulbornUniqueItem"] = (modDB.multipliers["FoulbornUniqueItem"] or 0) + 1 + end + for mult, property in pairs({["CorruptedItem"] = "corrupted", ["ShaperItem"] = "shaper", ["ElderItem"] = "elder", ["WarlordItem"] = "adjudicator", ["HunterItem"] = "basilisk", ["CrusaderItem"] = "crusader", ["RedeemerItem"] = "eyrie"}) do + if item[property] then + modDB.multipliers[mult] = (modDB.multipliers[mult] or 0) + 1 + else + modDB.multipliers["Non"..mult] = (modDB.multipliers["Non"..mult] or 0) + 1 + end + end + if item.shaper or item.elder then + modDB.multipliers.ShaperOrElderItem = (modDB.multipliers.ShaperOrElderItem or 0) + 1 + end + modDB.multipliers[item.type:gsub(" ", ""):gsub(".+Handed", "").."Item"] = (modDB.multipliers[item.type:gsub(" ", ""):gsub(".+Handed", "").."Item"] or 0) + 1 + if item.type == "Ring" then + local key = item.baseName:gsub(" ", "").."Equipped" + modDB.multipliers[key] = (modDB.multipliers[key] or 0) + 1 + end +end + +local function mercenaryItemMod(mod, presenceImplicit) + if mod.name == "ExtraSkill" or mod.name == "ExtraSupport" or mod.name == "GemProperty" then + return + end + local copy = copyTable(mod, true) + local keepSocketedIn = copy.name == "SocketProperty" or copy.name == "GroupProperty" + local index = 1 + while copy[index] do + local tag = copy[index] + if tag.type == "SocketedIn" and not keepSocketedIn then + return + elseif presenceImplicit and tag.type == "ActorCondition" and tag.actor == "enemy" and (tag.var == "RareOrUnique" or tag.var == "PinnacleBoss") then + t_remove(copy, index) + else + index = index + 1 + end + end + return copy +end + +local function applySocketMods(env, gem, groupCfg, socketNum, modSource) + local socketCfg = copyTable(groupCfg, true) + socketCfg.skillGem = gem + socketCfg.socketNum = socketNum + for _, value in ipairs(env.modDB:List(socketCfg, "SocketProperty")) do + env.player.modDB:AddMod(modLib.setSource(value.value, modSource or groupCfg.slotName or "")) + end +end + +local function mercenarySocketedGemData(env, occupancy) + if not occupancy then + return + end + if occupancy.gemData then + return occupancy.gemData + end + local gemId = occupancy.gemId or occupancy.nameSpec and env.data.gemForBaseName[occupancy.nameSpec:lower()] + return gemId and env.data.gems[gemId] +end + +local function addMercenaryItem(env, mercenary, item, slotName, slotNum, scale) + mercenary.itemList[slotName] = item + scale = scale or 1 + if item.type == "Quiver" then + local quiverEffect = mercenary.modDB:Sum("INC", nil, "EffectOfBonusesFromQuiver") + if quiverEffect ~= 0 then + local widowHailMod = 1 + quiverEffect / 100 + scale = scale * widowHailMod + mercenary.modDB:NewMod("WidowHailMultiplier", "BASE", widowHailMod, "Widowhail") + end + end + local presenceImplicitCounts = { } + for _, modLine in ipairs(item.implicitModLines or { }) do + if modLine.line and modLine.line:lower():match("^while .+ in your presence") then + for _, implicitMod in ipairs(modLine.modList or { }) do + local key = modLib.formatMod(implicitMod) + presenceImplicitCounts[key] = (presenceImplicitCounts[key] or 0) + 1 + end + end + end + local srcList = item.modList or item.slotModList[slotNum] + if item.type == "Quiver" and scale ~= 1 then + local combinedList = new("ModList"):ModList() + for _, itemMod in ipairs(srcList) do + local key = modLib.formatMod(itemMod) + local presenceImplicit = (presenceImplicitCounts[key] or 0) > 0 + if presenceImplicit then presenceImplicitCounts[key] = presenceImplicitCounts[key] - 1 end + local mod = mercenaryItemMod(itemMod, presenceImplicit) + if mod then combinedList:MergeMod(mod) end + end + mercenary.modDB:ScaleAddList(combinedList, scale) + else + for _, itemMod in ipairs(srcList) do + local key = modLib.formatMod(itemMod) + local presenceImplicit = (presenceImplicitCounts[key] or 0) > 0 + if presenceImplicit then presenceImplicitCounts[key] = presenceImplicitCounts[key] - 1 end + local mod = mercenaryItemMod(itemMod, presenceImplicit) + if mod then mercenary.modDB:ScaleAddMod(mod, scale) end + end + end + if slotName == "Weapon 1" and item.name == "The Iron Mass, Gladius" then + -- Special handling for The Iron Mass + local ironMass = new("ModList"):ModList() + for _, itemMod in ipairs(srcList) do + -- Filter out mods that apply to socketed gems, or which add supports + local add = true + for _, tag in ipairs(itemMod) do + if tag.type == "SocketedIn" then + add = false + break + end + end + if add then + local mod = mercenaryItemMod(itemMod, false) + if mod then ironMass:ScaleAddMod(mod, scale) end + end + end + mercenary.theIronMass = ironMass + end + local emptySockets = { R = 0, G = 0, B = 0, W = 0 } + local socketedColours = { R = 0, G = 0, B = 0 } + local socketedCount = 0 + local groupCfg = { slotName = slotName, strengthGems = 0, dexterityGems = 0, intelligenceGems = 0 } + for i, socket in ipairs(item.sockets or { }) do + if socket.color == "R" or socket.color == "G" or socket.color == "B" or socket.color == "W" then + local gemData = mercenarySocketedGemData(env, item.socketedGems and item.socketedGems[i]) + if gemData then + socketedCount = socketedCount + 1 + if gemData.tags.strength then + socketedColours.R = socketedColours.R + 1 + groupCfg.strengthGems = groupCfg.strengthGems + 1 + end + if gemData.tags.dexterity then + socketedColours.G = socketedColours.G + 1 + groupCfg.dexterityGems = groupCfg.dexterityGems + 1 + end + if gemData.tags.intelligence then + socketedColours.B = socketedColours.B + 1 + groupCfg.intelligenceGems = groupCfg.intelligenceGems + 1 + end + applySocketMods({ modDB = mercenary.modDB, player = mercenary }, gemData, groupCfg, i, item.name) + else + emptySockets[socket.color] = emptySockets[socket.color] + 1 + end + end + end + mercenary.modDB.multipliers["EmptySocketIn"..slotName] = emptySockets.R + emptySockets.G + emptySockets.B + emptySockets.W + mercenary.modDB.multipliers["SocketedGemsIn"..slotName] = socketedCount + mercenary.modDB.multipliers["SocketedRedGemsIn"..slotName] = socketedColours.R + mercenary.modDB.multipliers["SocketedGreenGemsIn"..slotName] = socketedColours.G + mercenary.modDB.multipliers["SocketedBlueGemsIn"..slotName] = socketedColours.B + for color, name in pairs({ R = "Red", G = "Green", B = "Blue", W = "White" }) do + local multiplier = "Empty"..name.."SocketsInAnySlot" + mercenary.modDB.multipliers[multiplier] = (mercenary.modDB.multipliers[multiplier] or 0) + emptySockets[color] + end + for _, value in ipairs(mercenary.modDB:List(groupCfg, "GroupProperty")) do + mercenary.modDB:AddMod(modLib.setSource(value.value, slotName)) + end + local rarity = (item.rarity == "UNIQUE" or item.rarity == "RELIC") and "UniqueItem" or item.rarity == "RARE" and "RareItem" or item.rarity == "MAGIC" and "MagicItem" or "NormalItem" + mercenary.modDB.multipliers[rarity] = (mercenary.modDB.multipliers[rarity] or 0) + 1 + mercenary.modDB.conditions[rarity.."In"..slotName] = true + if item.type ~= "Jewel" and item.type ~= "Flask" and item.type ~= "Tincture" and item.type ~= "Graft" then + addEquippedItemPropertyCounts(mercenary.modDB, item) + end +end + +local function addMercenaryMonsterStats(env, mercenary, monster, errors) + local rawStats = { } + for _, stat in ipairs(monster.stats or { }) do + if not env.data.mercenaryStatData.knownMonsterStats[stat.id] then + t_insert(errors, "Unsupported Mercenary monster stat: "..stat.id) + end + rawStats[stat.id] = (rawStats[stat.id] or 0) + stat.value + end + mercenary.modDB:NewMod("MaximumRage", "BASE", rawStats.maximum_rage or env.data.characterConstants["maximum_rage"], "Mercenary") + mercenary.modDB:NewMod("ActiveTrapLimit", "BASE", rawStats.base_number_of_traps_allowed or env.data.characterConstants["base_number_of_traps_allowed"], "Mercenary") + mercenary.modDB:NewMod("ActiveMineLimit", "BASE", rawStats.base_number_of_remote_mines_allowed or env.data.characterConstants["base_number_of_remote_mines_allowed"], "Mercenary") + mercenary.modDB:NewMod("ActiveTotemLimit", "BASE", env.data.characterConstants["base_number_of_totems_allowed"] + (rawStats.number_of_additional_totems_allowed or 0), "Mercenary") + mercenary.modDB:NewMod("LifeRegenPercent", "BASE", (rawStats["life_regeneration_per_minute_%_for_hired_mercenary_out_of_combat_window"] or 0) / 60, "Mercenary") + mercenary.modDB:NewMod("ManaCost", "INC", -(rawStats["set_base_mana_cost_-%"] or 0), "Mercenary") + mercenary.modDB:NewMod("ManaRegen", "BASE", (rawStats.base_mana_regeneration_rate_per_minute or 0) / 60, "Mercenary") + mercenary.modDB:NewMod("TotemLife", "MORE", rawStats["set_totem_life_+%_final"] or 0, "Mercenary") + mercenary.modDB:NewMod("DamageTaken", "INC", rawStats["set_minion_damage_taken_+%"] or 0, "Mercenary") + mercenary.modDB:NewMod("DamageTaken", "MORE", env.data.mercenaryStatData.permanentMercenary.damageOverTimeTakenMore, "Mercenary", ModFlag.Dot) + -- Rarity stats correct engine rarity bonuses; this normalized actor applies neither side. + if monster.damageFixup then + mercenary.modDB:NewMod("Damage", "MORE", -100 * monster.damageFixup, "Damage Fixup", ModFlag.Attack) + mercenary.modDB:NewMod("Speed", "MORE", 100 * monster.damageFixup, "Damage Fixup", ModFlag.Attack) + end + if rawStats.keystone_minion_instability == 1 then + mercenary.modDB:NewMod("Keystone", "LIST", "Minion Instability", "Mercenary") + end +end + +-- parseMod is not cheap; mercenary passives are rebuilt on every real initEnv. +local mercenaryPassiveModCache = { } + +local function addMercenaryPassiveStats(mercenary, mercenaryBuild, errors) + mercenary.passiveStats = { } + for _, passive in ipairs(mercenaryBuild.passiveStats or { }) do + local value = MercenaryTools.passiveStatValue(passive.values, mercenary.level) + local scaledValue = value / (passive.divisor or 1) + local valueText = scaledValue == m_floor(scaledValue) and tostring(m_floor(scaledValue)) or tostring(scaledValue) + local line = passive.line or string.format(passive.format, valueText) + if not passive.line or value ~= 0 then + local cached = mercenaryPassiveModCache[line] + if cached == nil then + local parsed, extra = modLib.parseMod(line) + if not parsed or extra then + mercenaryPassiveModCache[line] = false + cached = false + else + mercenaryPassiveModCache[line] = parsed + cached = parsed + end + end + if not cached then + t_insert(errors, "Unsupported Mercenary passive stat "..passive.id..": "..line) + else + local source = "Mercenary Passive: "..passive.id + for _, mod in ipairs(cached) do + mercenary.modDB:AddMod(modLib.setSource(copyTable(mod), source)) + end + end + end + t_insert(mercenary.passiveStats, { id = passive.id, statId = passive.statId, value = scaledValue }) + end +end + +function calcs.attachEnemySourceDB(env, actor, sourceModList) + if not actor then + return + end + local hasSource = sourceModList and sourceModList[1] ~= nil + local encounterList = actor == env.player and env.build.configTab.enemyModList + local sourceDB = actor.enemySourceDB + if sourceDB then + wipeTable(sourceDB.mods) + wipeTable(sourceDB.conditions) + wipeTable(sourceDB.multipliers) + else + sourceDB = new("ModDB"):ModDB() + actor.enemySourceDB = sourceDB + end + sourceDB.actor = actor + sourceDB.conditions.Combat = env.mode_combat + sourceDB.conditions.Effective = env.mode_effective + if hasSource then + sourceDB:AddList(sourceModList) + end + -- Player "by you" mods that reuse encounter names (Ignited, WitheredStack, ...) + -- still honour the shared config checkboxes. Mercenary overlays do not copy + -- those predicates, so they cannot claim the player's ailments as their own. + if actor == env.player then + for _, mod in ipairs(encounterList or { }) do + if ConfigScope.shouldCopyEncounterOntoPlayerOverlay(mod) then + sourceDB:AddMod(mod) + end + end + end +end + +local function copyModDB(db) + if not db then + return nil + end + local copy = new("ModDB"):ModDB() + copy:AddDB(db) + copy.conditions = copyTable(db.conditions) + copy.multipliers = copyTable(db.multipliers) + return copy +end + +-- Copy cached mods into the live database. Parenting would round MORE in each +-- store and then multiply, which disagrees with a reconstructed actor. +local function restoreModDB(db, cached, actor) + if not db then + return + end + wipeTable(db.mods) + wipeTable(db.conditions) + wipeTable(db.multipliers) + if actor then + db.parent = nil + db.actor = actor + end + if cached then + db:AddDB(cached) + for key, value in pairs(cached.conditions) do + db.conditions[key] = value + end + for key, value in pairs(cached.multipliers) do + db.multipliers[key] = value + end + end +end +calcs.copyModDB = copyModDB +calcs.restoreModDB = restoreModDB + +-- Mercenary actors are reconstructed each initEnv. Do not park ModDBs or +-- snapshot a pre-perform baseline for Full DPS reuse; that cache has to +-- round-trip every field perform() mutates. Reconstruct instead. +local function dropCurrentMercenary(env) + env.mercenary = nil + env.mercenaryMinion = nil + env.mercenaryCalculationErrors = nil + if env.player then + env.player.enemySourceDB = nil + end +end + +-- Mercenary calculations reuse upstream functions that still read env.player. +-- This proxy is a Mercenary compatibility adapter: actor-local values are substituted, +-- encounter-wide state is shared, and unclassified root fields error on access. +-- It is not a general actor framework. Add a key to mercenaryLocalEnvKeys when +-- Mercenary calculation reads it and the value is actor-owned. +-- createMercenaryCalcEnv refuses to construct a proxy that omits them, and errors +-- if they are read unset. +local mercenaryLocalEnvKeys = { + "player", + "modDB", + "configInput", + "configPlaceholder", + "keystonesAdded", + "minion", + "itemModDB", + "auxSkillList", + "theIronMass", +} + +-- Encounter/build state that Mercenary calculation actually reads through the proxy +-- and that is semantically shared. Unclassified root fields error on access. +local mercenarySharedEnvKeys = { + "build", + "data", + "enemy", + "enemyLevel", + "limitedSkills", + "mode", + "mode_buffs", + "mode_combat", + "mode_effective", + "override", + "partyMembers", + "spec", +} + +local mercenaryLocalEnvKeySet = { } +for _, key in ipairs(mercenaryLocalEnvKeys) do + mercenaryLocalEnvKeySet[key] = true +end + +local mercenarySharedEnvKeySet = { } +for _, key in ipairs(mercenarySharedEnvKeys) do + if mercenaryLocalEnvKeySet[key] then + error("Calc env field '"..key.."' cannot be both mercenary-local and shared") + end + mercenarySharedEnvKeySet[key] = true +end + +-- Build a Mercenary-scoped calculation environment over `rootEnv`. +-- Inheritable encounter/build state is read from the root; mercenary-local +-- fields must be supplied on `actorFields` (use `false` rather than nil +-- when the Mercenary has no value, so __index cannot leak the player actor). +function calcs.createMercenaryCalcEnv(rootEnv, actorFields) + if not rootEnv then + error("createMercenaryCalcEnv requires a root environment") + end + actorFields = actorFields or { } + for _, key in ipairs(mercenaryLocalEnvKeys) do + if actorFields[key] == nil then + error("createMercenaryCalcEnv: missing mercenary-local field '"..key.."'") + end + end + for _, key in ipairs(mercenarySharedEnvKeys) do + if actorFields[key] == nil then + local value = rootEnv[key] + if value ~= nil then + actorFields[key] = value + end + end + end + return setmetatable(actorFields, { + __index = function(_, key) + if mercenaryLocalEnvKeySet[key] then + error("createMercenaryCalcEnv: mercenary-local field '"..key.."' is unset") + end + if mercenarySharedEnvKeySet[key] then + return rootEnv[key] + end + if rawget(rootEnv, key) ~= nil then + error("createMercenaryCalcEnv: unclassified env field '"..key.."'") + end + end, + }) +end + +function calcs.initMercenary(env) + local tab = env.build.mercenaryTab + dropCurrentMercenary(env) + if not tab or not tab.profile or not tab.profile.buildId then + return + end + env.data.ensureMercenaries() + + local function abortInit(errors) + env.mercenaryCalculationErrors = errors + end + + -- Profile and current-loadout equipment errors belong to MercenaryTab:GetErrors(). + -- mercenaryCalculationErrors is only for failures this environment discovered + -- while constructing the actor, including equipment that exists only on this override. + local function overrideChangesMercenaryEquipment(override, mercenaryItemSetId) + if not override then + return false + end + if override.itemSetId and override.itemSetId == mercenaryItemSetId then + return true + end + local slotName = MercenaryTools.baseItemSlotName(override.repSlotName) or override.repSlotName + return MercenaryTools.overrideReplacesMercenarySlot(override, slotName, mercenaryItemSetId) + end + + local profile = tab.profile + local profileErrors = MercenaryTools.validateProfile(profile, env.data.mercenaries) + if #profileErrors > 0 then + return + end + local mercenaryBuild = env.data.mercenaries.builds[profile.buildId] + local mercenaryClass = mercenaryBuild and env.data.mercenaries.classes[mercenaryBuild.classId] + local monster = mercenaryClass and mercenaryClass.monster + local calculationErrors = { } + if not monster then + abortInit({ "Selected Mercenary has no allied MonsterVariety data" }) + return + end + local itemsTab = env.build.itemsTab + local itemSet = itemsTab:GetActorItemSet("MERCENARY") + local mercenaryItemSetId = itemsTab:GetActorItemSetId("MERCENARY") + local selectedItemSet = env.override.itemSetId and itemsTab.itemSets[env.override.itemSetId] + if selectedItemSet and mercenaryItemSetId == selectedItemSet.id then + itemSet = selectedItemSet + end + local equipmentErrors = MercenaryTools.equipmentErrors({ + profile = profile, + mercenaryData = env.data.mercenaries, + itemSet = itemSet, + playerItemSet = itemsTab.activeItemSet, + items = itemsTab.items, + override = env.override, + mercenaryItemSetId = mercenaryItemSetId, + playerHasFlag = function(flagName) return env.modDB:Flag(nil, flagName) and true or false end, + isItemValidForSlot = function(item, slotName, set, equippedLookup) + return itemsTab:IsItemValidForSlot(item, slotName, set, equippedLookup) + end, + }) + if #equipmentErrors > 0 then + if overrideChangesMercenaryEquipment(env.override, mercenaryItemSetId) then + abortInit(equipmentErrors) + end + return + end + -- Permanent hiring is a Luminary/Noble Blood capability. Keep the + -- configured profile for editing, but do not construct an actor that + -- would enter the player calculation graph. + if not env.modDB:Flag(nil, "CanHirePermanentMercenary") then + return + end + local mercenary = { + type = "Mercenary", + isMercenary = true, + player = env.player, + parent = env.player, + enemy = env.enemy, + level = MercenaryTools.effectiveLevel(profile.foundAreaLevel, env.enemyLevel), + foundAreaLevel = profile.foundAreaLevel, + itemList = { }, + activeSkillList = { }, + profile = profile, + monster = monster, + } + mercenary.modDB = new("ModDB"):ModDB() + mercenary.modDB.actor = mercenary + mercenary.modDB.multipliers.Level = mercenary.level + calcs.initModDB(env, mercenary.modDB) + if env.build.configTab.mercenaryModList then + mercenary.modDB:AddList(env.build.configTab.mercenaryModList) + end + calcs.attachEnemySourceDB(env, env.player, env.build.configTab.playerEnemyModList) + calcs.attachEnemySourceDB(env, mercenary, env.build.configTab.mercenaryEnemyModList) + local baseStats = env.data.mercenaries.baseStats + mercenary.modDB:NewMod("Life", "BASE", baseStats.lifePerLevel * mercenary.level, "Base") + mercenary.modDB:NewMod("Mana", "BASE", env.data.monsterConstants.base_maximum_mana + baseStats.manaPerLevel * mercenary.level, "Base") + mercenary.modDB:NewMod("Accuracy", "BASE", baseStats.accuracyPerLevel * mercenary.level, "Base") + if not baseStats.disableDefaultMonsterStats then + mercenary.modDB:NewMod("Armour", "BASE", round(env.data.monsterArmourTable[mercenary.level] * monster.armour), "Base") + mercenary.modDB:NewMod("Evasion", "BASE", round(env.data.monsterEvasionTable[mercenary.level] * monster.evasion), "Base") + end + mercenary.modDB:NewMod("CritMultiplier", "BASE", env.data.monsterConstants["base_critical_strike_multiplier"] - 100, "Base") + mercenary.modDB:NewMod("DotMultiplier", "BASE", env.data.monsterConstants["critical_ailment_dot_multiplier_+"], "Base", { type = "Condition", var = "CriticalStrike" }) + mercenary.modDB:NewMod("FireResist", "BASE", monster.fireResist, "Base") + mercenary.modDB:NewMod("ColdResist", "BASE", monster.coldResist, "Base") + mercenary.modDB:NewMod("LightningResist", "BASE", monster.lightningResist, "Base") + mercenary.modDB:NewMod("ChaosResist", "BASE", monster.chaosResist, "Base") + mercenary.modDB:NewMod("CritChance", "INC", env.data.characterConstants["critical_strike_chance_+%_per_power_charge"], "Base", { type = "Multiplier", var = "PowerCharge" }) + mercenary.modDB:NewMod("Speed", "INC", env.data.characterConstants["base_attack_speed_+%_per_frenzy_charge"], "Base", ModFlag.Attack, { type = "Multiplier", var = "FrenzyCharge" }) + mercenary.modDB:NewMod("Speed", "INC", env.data.characterConstants["base_cast_speed_+%_per_frenzy_charge"], "Base", ModFlag.Cast, { type = "Multiplier", var = "FrenzyCharge" }) + mercenary.modDB:NewMod("Damage", "MORE", env.data.characterConstants["object_inherent_damage_+%_final_per_frenzy_charge"], "Base", { type = "Multiplier", var = "FrenzyCharge" }) + mercenary.modDB:NewMod("PhysicalDamageReduction", "BASE", env.data.characterConstants["physical_damage_reduction_%_per_endurance_charge"], "Base", { type = "Multiplier", var = "EnduranceCharge" }) + mercenary.modDB:NewMod("ElementalDamageReduction", "BASE", env.data.characterConstants["elemental_damage_reduction_%_per_endurance_charge"], "Base", { type = "Multiplier", var = "EnduranceCharge" }) + mercenary.modDB:NewMod("ProjectileCount", "BASE", 1, "Base") + mercenary.modDB:NewMod("MineThrowCount", "BASE", 1, "Base") + mercenary.modDB:NewMod("TrapThrowCount", "BASE", 1, "Base") + mercenary.modDB:NewMod("MaximumFortification", "BASE", env.data.characterConstants["base_max_fortification"], "Base") + calcs.addActorInherentCombatMods(mercenary.modDB) + mercenary.modDB:NewMod("Damage", "MORE", MercenaryTools.permanentDamageMore(mercenary.level, env.data.mercenaries.permanentMercenaryDamageMore), "Permanent Mercenary") + addMercenaryMonsterStats(env, mercenary, monster, calculationErrors) + addMercenaryPassiveStats(mercenary, mercenaryBuild, calculationErrors) + for _, value in ipairs(env.modDB:List(nil, "MercenaryModifier")) do + mercenary.modDB:AddMod(value.mod) + end + + for _, slotName in ipairs(MercenaryTools.equipmentSlots) do + local slot = env.build.itemsTab.slots[slotName] + local item = MercenaryTools.equippedItem(itemSet, itemsTab.items, slotName, env.override, mercenaryItemSetId) + if item then addMercenaryItem(env, mercenary, item, slotName, slot and slot.slotNum or 1) end + for abyssalSocketIndex = 1, 6 do + local abyssalSlotName = slotName.." Abyssal Socket "..abyssalSocketIndex + local abyssalJewel = MercenaryTools.equippedItem(itemSet, itemsTab.items, abyssalSlotName, env.override, mercenaryItemSetId) + if abyssalJewel then + local parentItem = mercenary.itemList[slotName] + addMercenaryItem(env, mercenary, abyssalJewel, abyssalSlotName, abyssalSocketIndex, parentItem and parentItem.socketedJewelEffectModifier) + end + end + end + for _, passiveName in ipairs(mercenary.modDB:List(nil, "GrantedPassive")) do + local node = env.spec.tree.notableMap[passiveName] or env.spec.tree.ascendancyMap[passiveName] + or env.build.latestTree.notableMap[passiveName] or env.build.latestTree.ascendancyMap[passiveName] + if node then + mercenary.modDB:AddList((env.spec.nodes[node.id] or node).modList) + else + t_insert(calculationErrors, "Unsupported Mercenary anoint: "..tostring(passiveName)) + end + end + for _, keystoneName in ipairs(mercenary.modDB:List(nil, "Keystone")) do + if not env.spec.tree.keystoneMap[keystoneName] and not env.build.latestTree.keystoneMap[keystoneName] then + t_insert(calculationErrors, "Unsupported Mercenary keystone: "..tostring(keystoneName)) + end + end + + local attackTime = monster.attackTime + -- Only reached while a weapon slot is empty. `disable_default_monster_stats` has + -- no per-level replacement for damage, so an unarmed Mercenary keeps the same + -- allied-monster damage model PoB uses for minions. + mercenary.averageDamage = env.data.monsterAllyDamageTable[mercenary.level] * monster.damage + local damage = mercenary.averageDamage + if not monster.baseDamageIgnoresAttackSpeed then damage = damage * attackTime end + mercenary.weaponData1 = mercenary.itemList["Weapon 1"] and mercenary.itemList["Weapon 1"].weaponData and mercenary.itemList["Weapon 1"].weaponData[1] or { + type = "None", + AttackRate = 1 / attackTime, + CritChance = 5, + PhysicalMin = round(damage * (1 - monster.damageSpread)), + PhysicalMax = round(damage * (1 + monster.damageSpread)), + range = monster.attackRange, + } + if mercenary.weaponData1.countsAsDualWielding then + mercenary.weaponData2 = mercenary.itemList["Weapon 1"].weaponData[2] or { } + else + mercenary.weaponData2 = mercenary.itemList["Weapon 2"] and mercenary.itemList["Weapon 2"].weaponData and mercenary.itemList["Weapon 2"].weaponData[2] or { } + end + + -- Skill building reads `env.player` and `env.modDB` for the actor that owns the + -- skill. This proxy environment presents the Mercenary as that actor while + -- inheritable encounter/build state still falls through to the real environment. + -- Invariant: `mercenaryEnv.player` is the Mercenary; `env.player` is always + -- the character. `mercenaryEnv.minion` is the Mercenary minion or false. + -- false (not nil) prevents __index from returning the player's minion. + local mercInput, mercPlaceholder = { }, { } + if env.build.configTab.GetActorConfigInput then + -- GetActorConfigInput reuses its merge buffers; snapshot before the next call. + mercInput, mercPlaceholder = env.build.configTab:GetActorConfigInput("mercenary") + mercInput = copyTable(mercInput) + mercPlaceholder = copyTable(mercPlaceholder) + end + local mercenaryEnv = calcs.createMercenaryCalcEnv(env, { + modDB = mercenary.modDB, + player = mercenary, + keystonesAdded = { }, + minion = false, + configInput = mercInput, + configPlaceholder = mercPlaceholder, + itemModDB = new("ModDB"):ModDB(), + auxSkillList = { }, + theIronMass = mercenary.theIronMass or false, + }) + mercenary.calcEnv = mercenaryEnv + local function addActiveSkill(selectedSkill, grantedEffect, supports, isPrimary) + local skillPart = isPrimary and selectedSkill.skillPart or env.data.mercenaryStatData.defaultSkillParts[grantedEffect.id] or 1 + if grantedEffect.parts and (skillPart < 1 or skillPart > #grantedEffect.parts) then + t_insert(calculationErrors, "Invalid Mercenary skill part for "..grantedEffect.id..": "..tostring(skillPart)) + return + end + local instance = { + skillId = grantedEffect.id, + level = MercenaryTools.skillLevel(grantedEffect, mercenary.level), + quality = 0, + enabled = true, + mercenarySkill = selectedSkill, + skillPart = skillPart, + skillStageCount = isPrimary and selectedSkill.skillStageCount or nil, + skillStageCountCalcs = isPrimary and (selectedSkill.skillStageCountCalcs or selectedSkill.skillStageCount) or nil, + skillMineCount = isPrimary and selectedSkill.skillMineCount or nil, + skillMineCountCalcs = isPrimary and (selectedSkill.skillMineCountCalcs or selectedSkill.skillMineCount) or nil, + skillMinionSkill = isPrimary and selectedSkill.skillMinionSkill or nil, + skillMinionSkillCalcs = isPrimary and (selectedSkill.skillMinionSkillCalcs or selectedSkill.skillMinionSkill) or nil, + mercenaryPossibleSupportIds = env.data.mercenaries.skills[grantedEffect.id] and env.data.mercenaries.skills[grantedEffect.id].possibleSupportIds, + } + local activeSkill = calcs.createActiveSkill({ grantedEffect = grantedEffect, level = instance.level, quality = 0, srcInstance = instance }, supports or { }, mercenary, selectedSkill) + activeSkill.mercenarySkill = selectedSkill + activeSkill.isMercenaryPrimary = isPrimary + activeSkill.isMercenaryAuxiliary = not isPrimary + calcs.buildActiveSkillModList(mercenaryEnv, activeSkill) + if activeSkill.unsupportedReason then + t_insert(calculationErrors, activeSkill.unsupportedReason) + else + t_insert(mercenary.activeSkillList, activeSkill) + end + return activeSkill + end + local auxiliarySkills = { } + for _, selectedSkill in ipairs(profile.skills) do + if selectedSkill.enabled ~= false then + local grantedEffect = env.data.skills[selectedSkill.id] + if not grantedEffect then + t_insert(calculationErrors, "Missing generated Mercenary skill: "..tostring(selectedSkill.id)) + else + validateMercenarySkillStats(env, grantedEffect, calculationErrors) + for _, statId in ipairs(grantedEffect.stats or { }) do + recordMercenaryAuxiliarySkill(env, auxiliarySkills, statId, selectedSkill) + end + for _, stat in ipairs(grantedEffect.constantStats or { }) do + recordMercenaryAuxiliarySkill(env, auxiliarySkills, stat[1], selectedSkill) + end + local supports = { } + for _, selectedSupport in ipairs(selectedSkill.supports or { }) do + local support = env.data.mercenaries.supports[selectedSupport.id] + local supportEffect = mercenarySupportEffect(env, support, grantedEffect, calculationErrors) + if supportEffect then t_insert(supports, supportEffect) end + for _, stat in ipairs(support and support.stats or { }) do + recordMercenaryAuxiliarySkill(env, auxiliarySkills, stat.id, selectedSkill) + end + end + local activeSkill = addActiveSkill(selectedSkill, grantedEffect, supports, true) + if selectedSkill.id == profile.mainSkillId then mercenary.mainSkill = activeSkill end + end + end + end + local auxiliarySkillIds = { } + for auxiliarySkillId in pairs(auxiliarySkills) do t_insert(auxiliarySkillIds, auxiliarySkillId) end + t_sort(auxiliarySkillIds) + for _, auxiliarySkillId in ipairs(auxiliarySkillIds) do + local auxiliaryEffect = env.data.skills[auxiliarySkillId] + if auxiliaryEffect then + validateMercenarySkillStats(env, auxiliaryEffect, calculationErrors) + addActiveSkill(auxiliarySkills[auxiliarySkillId], auxiliaryEffect, nil, false) + else + t_insert(calculationErrors, "Missing Mercenary auxiliary skill: "..auxiliarySkillId) + end + end + if not mercenary.mainSkill then + t_insert(calculationErrors, "Configured Mercenary main skill could not be constructed: "..tostring(profile.mainSkillId)) + end + if #calculationErrors > 0 then + env.mercenaryCalculationErrors = calculationErrors + return + end + env.mercenary = mercenary +end + -- Initialise modifier database with stats and conditions common to all actors function calcs.initModDB(env, modDB) modDB:NewMod("FireResistMax", "BASE", data.characterConstants["base_maximum_all_resistances_%"], "Base") @@ -119,6 +852,25 @@ function calcs.initModDB(env, modDB) modDB.conditions["Effective"] = env.mode_effective end +-- Character combat inherent mods shared by the player and a hired Mercenary. +function calcs.addActorInherentCombatMods(modDB) + modDB:NewMod("ActiveBrandLimit", "BASE", 3, "Base") + modDB:NewMod("EnemyCurseLimit", "BASE", 1, "Base") + modDB:NewMod("SocketedCursesHexLimitValue", "BASE", 1, "Base") + modDB:NewMod("Speed", "MORE", data.characterConstants["dual_wield_inherent_attack_speed_+%_final"], "Base", ModFlag.Attack, { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "DoubledInherentDualWieldingSpeed", neg = true }) + modDB:NewMod("Speed", "MORE", 2 * data.characterConstants["dual_wield_inherent_attack_speed_+%_final"], "Base", ModFlag.Attack, { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "DoubledInherentDualWieldingSpeed"}) + modDB:NewMod("BlockChance", "BASE", data.characterConstants["inherent_block_while_dual_wielding_%"], "Base", { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "NoInherentBlock", neg = true}, { type = "Condition", var = "DoubledInherentDualWieldingBlock", neg = true}) + modDB:NewMod("BlockChance", "BASE", 2 * data.characterConstants["inherent_block_while_dual_wielding_%"], "Base", { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "NoInherentBlock", neg = true}, { type = "Condition", var = "DoubledInherentDualWieldingBlock"}) + modDB:NewMod("Damage", "MORE", 200, "Base", 0, KeywordFlag.Bleed, { type = "ActorCondition", actor = "enemy", var = "Moving" }, { type = "Condition", var = "NoExtraBleedDamageToMovingEnemy", neg = true }) + modDB:NewMod("Condition:BloodStance", "FLAG", true, "Base", { type = "Condition", var = "SandStance", neg = true }) + modDB:NewMod("Condition:PrideMinEffect", "FLAG", true, "Base", { type = "Condition", var = "PrideMaxEffect", neg = true }) + modDB:NewMod("PerBrutalTripleDamageChance", "BASE", data.characterConstants["chance_to_deal_triple_damage_%_per_brutal_charge"], "Base") + modDB:NewMod("PerAfflictionAilmentDamage", "BASE", data.characterConstants["ailment_damage_+%_final_per_affliction_charge"], "Base") + modDB:NewMod("PerAfflictionNonDamageEffect", "BASE", data.characterConstants["non_damaging_ailment_effect_+%_final_per_affliction_charge"], "Base") + modDB:NewMod("PerAbsorptionElementalEnergyShieldRecoup", "BASE", data.characterConstants["elemental_damage_taken_goes_to_energy_shield_over_4_seconds_%_per_absorption_charge"], "Base") + modDB:NewMod("PresenceRadius", "BASE", data.characterConstants["base_presence_radius"], "Base") +end + ---@param reuse table|nil A ModList to recycle instead of allocating. Only safe when the caller discards the result. function calcs.buildModListForNode(env, node, reuse) local modList @@ -321,6 +1073,10 @@ function wipeEnv(env, accelerate) end if accelerate.everything then + -- Player DBs are restored via parent snapshots. Mercenary is + -- reconstructed at the end of initEnv rather than restored from a + -- pre-perform cache. + dropCurrentMercenary(env) return end @@ -377,6 +1133,7 @@ function wipeEnv(env, accelerate) -- and modifiers that affect skill scaling (e.g., global buffs/effects) wipeTable(env.auxSkillList) end + dropCurrentMercenary(env) end local function applyGemMods(effect, modList) @@ -416,15 +1173,6 @@ local function applyGemMods(effect, modList) end end -local function applySocketMods(env, gem, groupCfg, socketNum, modSource) - local socketCfg = copyTable(groupCfg, true) - socketCfg.skillGem = gem - socketCfg.socketNum = socketNum - for _, value in ipairs(env.modDB:List(socketCfg, "SocketProperty")) do - env.player.modDB:AddMod(modLib.setSource(value.value, modSource or groupCfg.slotName or "")) - end -end - local function addBestSupport(supportEffect, appliedSupportList, mode) local add = true for index, otherSupport in ipairs(appliedSupportList) do @@ -483,6 +1231,10 @@ function calcs.initEnv(build, mode, override, specEnv) -- environment variables local override = override or { } + if override.itemSetId ~= nil and not build.itemsTab.itemSets[override.itemSetId] then + error("Unknown item set id: "..tostring(override.itemSetId)) + end + local replacesPlayerItem = MercenaryTools.overrideReplacesPlayerItem(override, build.itemsTab.activeItemSetId) local modDB = nil local enemyDB = nil local classStats = nil @@ -628,25 +1380,11 @@ function calcs.initEnv(build, mode, override, specEnv) modDB:NewMod("ActiveMineLimit", "BASE", data.characterConstants["base_number_of_remote_mines_allowed"], "Base") modDB:NewMod("MineThrowCount", "BASE", 1, "Base") modDB:NewMod("TrapThrowCount", "BASE", 1, "Base") - modDB:NewMod("ActiveBrandLimit", "BASE", 3, "Base") - modDB:NewMod("EnemyCurseLimit", "BASE", 1, "Base") - modDB:NewMod("SocketedCursesHexLimitValue", "BASE", 1, "Base") modDB:NewMod("ProjectileCount", "BASE", 1, "Base") - modDB:NewMod("Speed", "MORE", data.characterConstants["dual_wield_inherent_attack_speed_+%_final"], "Base", ModFlag.Attack, { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "DoubledInherentDualWieldingSpeed", neg = true }) - modDB:NewMod("Speed", "MORE", 2 * data.characterConstants["dual_wield_inherent_attack_speed_+%_final"], "Base", ModFlag.Attack, { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "DoubledInherentDualWieldingSpeed"}) - modDB:NewMod("BlockChance", "BASE", data.characterConstants["inherent_block_while_dual_wielding_%"], "Base", { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "NoInherentBlock", neg = true}, { type = "Condition", var = "DoubledInherentDualWieldingBlock", neg = true}) - modDB:NewMod("BlockChance", "BASE", 2 * data.characterConstants["inherent_block_while_dual_wielding_%"], "Base", { type = "Condition", var = "DualWielding" }, { type = "Condition", var = "NoInherentBlock", neg = true}, { type = "Condition", var = "DoubledInherentDualWieldingBlock"}) - modDB:NewMod("Damage", "MORE", 200, "Base", 0, KeywordFlag.Bleed, { type = "ActorCondition", actor = "enemy", var = "Moving" }, { type = "Condition", var = "NoExtraBleedDamageToMovingEnemy", neg = true }) - modDB:NewMod("Condition:BloodStance", "FLAG", true, "Base", { type = "Condition", var = "SandStance", neg = true }) - modDB:NewMod("Condition:PrideMinEffect", "FLAG", true, "Base", { type = "Condition", var = "PrideMaxEffect", neg = true }) - modDB:NewMod("PerBrutalTripleDamageChance", "BASE", data.characterConstants["chance_to_deal_triple_damage_%_per_brutal_charge"], "Base") - modDB:NewMod("PerAfflictionAilmentDamage", "BASE", data.characterConstants["ailment_damage_+%_final_per_affliction_charge"], "Base") - modDB:NewMod("PerAfflictionNonDamageEffect", "BASE", data.characterConstants["non_damaging_ailment_effect_+%_final_per_affliction_charge"], "Base") - modDB:NewMod("PerAbsorptionElementalEnergyShieldRecoup", "BASE", data.characterConstants["elemental_damage_taken_goes_to_energy_shield_over_4_seconds_%_per_absorption_charge"], "Base") + calcs.addActorInherentCombatMods(modDB) modDB:NewMod("TinctureLimit", "BASE", 1, "Base") modDB:NewMod("ManaDegenPercentTincture", "BASE", 1, "Base", { type = "Multiplier", var = "EffectiveManaBurnStacks" }) modDB:NewMod("LifeDegenPercentTincture", "BASE", 1, "Base", { type = "Multiplier", var = "WeepingWoundsStacks" }) - modDB:NewMod("PresenceRadius", "BASE", data.characterConstants["base_presence_radius"], "Base") -- Add bandit mods if env.configInput.bandit == "Alira" then @@ -678,6 +1416,7 @@ function calcs.initEnv(build, mode, override, specEnv) enemyDB:NewMod("Condition:AgainstDamageOverTime", "FLAG", true, "Base", ModFlag.Dot, { type = "ActorCondition", actor = "player", var = "Combat" }) -- Add mods from the config tab + build.configTab:EnsureHiredMercenaryModList() env.modDB:AddList(build.configTab.modList) env.enemyDB:AddList(build.configTab.enemyModList) @@ -812,16 +1551,17 @@ function calcs.initEnv(build, mode, override, specEnv) goto continue end local item - if slotName == override.repSlotName then + if replacesPlayerItem and slotName == override.repSlotName then item = override.repItem - elseif override.repItem and override.repSlotName:match("^Weapon 1") and slotName:match("^Weapon 2") and + elseif replacesPlayerItem and override.repItem and override.repSlotName:match("^Weapon 1") and slotName:match("^Weapon 2") and (override.repItem.base.type == "Staff" or override.repItem.base.type == "Two Handed Sword" or override.repItem.base.type == "Two Handed Axe" or override.repItem.base.type == "Two Handed Mace" or (override.repItem.base.type == "Bow" and item and item.base.type ~= "Quiver")) then goto continue - elseif slot.nodeId and override.spec then + elseif slot.nodeId then item = build.itemsTab.items[env.spec.jewels[slot.nodeId]] else - item = build.itemsTab.items[slot.selItemId] + local itemSlot = build.itemsTab.activeItemSet[slotName] + item = build.itemsTab.items[itemSlot and itemSlot.selItemId] end if item and item.grantedSkills then -- Find skills granted by this item @@ -1027,7 +1767,7 @@ function calcs.initEnv(build, mode, override, specEnv) local item = items[slotName] if item and item.type == "Flask" then env.itemModDB.conditions["Have"..item.baseName:gsub("%s+", "")] = true - if slot.active then + if build.itemsTab.activeItemSet[slotName].active then env.flasks[item] = true end local flaskNum = tonumber(slotName:match("Flask (%d+)")) @@ -1043,7 +1783,7 @@ function calcs.initEnv(build, mode, override, specEnv) end item = nil elseif item and item.type == "Tincture" then - if slot.active then + if build.itemsTab.activeItemSet[slotName].active then env.tinctures[item] = true end item = nil @@ -1276,9 +2016,6 @@ function calcs.initEnv(build, mode, override, specEnv) -- Update item counts local key if item.rarity == "UNIQUE" or item.rarity == "RELIC" then - if item.foulborn then - env.itemModDB.multipliers["FoulbornUniqueItem"] = (env.itemModDB.multipliers["FoulbornUniqueItem"] or 0) + 1 - end key = "UniqueItem" elseif item.rarity == "RARE" then key = "RareItem" @@ -1289,22 +2026,7 @@ function calcs.initEnv(build, mode, override, specEnv) end env.itemModDB.multipliers[key] = (env.itemModDB.multipliers[key] or 0) + 1 env.itemModDB.conditions[key .. "In" .. slotName] = true - for mult, property in pairs({["CorruptedItem"] = "corrupted", ["ShaperItem"] = "shaper", ["ElderItem"] = "elder", ["WarlordItem"] = "adjudicator", ["HunterItem"] = "basilisk", ["CrusaderItem"] = "crusader", ["RedeemerItem"] = "eyrie"}) do - if item[property] then - env.itemModDB.multipliers[mult] = (env.itemModDB.multipliers[mult] or 0) + 1 - else - env.itemModDB.multipliers["Non"..mult] = (env.itemModDB.multipliers["Non"..mult] or 0) + 1 - end - end - if item.shaper or item.elder then - env.itemModDB.multipliers.ShaperOrElderItem = (env.itemModDB.multipliers.ShaperOrElderItem or 0) + 1 - end - env.itemModDB.multipliers[item.type:gsub(" ", ""):gsub(".+Handed", "").."Item"] = (env.itemModDB.multipliers[item.type:gsub(" ", ""):gsub(".+Handed", "").."Item"] or 0) + 1 - -- base ring count, e.g. Cryonic, Synaptic for Breachlord Esh of the Storm, Tul of the Blizzard - if item.type == "Ring" then - local key = item.baseName:gsub(" ", "").."Equipped" - env.itemModDB.multipliers[key] = (env.itemModDB.multipliers[key] or 0) + 1 - end + addEquippedItemPropertyCounts(env.itemModDB, item) -- Calculate socket counts local slotEmptySocketsCount = { R = 0, G = 0, B = 0, W = 0} local slotGemSocketsCount = 0 @@ -1970,6 +2692,7 @@ function calcs.initEnv(build, mode, override, specEnv) -- Merge Requirements Tables env.requirementsTable = tableConcat(env.requirementsTableItems, env.requirementsTableGems) + calcs.initMercenary(env) return env, cachedPlayerDB, cachedEnemyDB, cachedMinionDB end diff --git a/src/Modules/CalcTools.lua b/src/Modules/CalcTools.lua index aafc74e523e..89274eb7fa2 100644 --- a/src/Modules/CalcTools.lua +++ b/src/Modules/CalcTools.lua @@ -12,6 +12,14 @@ local m_max = math.max calcLib = { } +-- The actors a build can display calculations for, in the order they are offered. +calcLib.calculationActorList = { + { label = "Player", actorId = "PLAYER" }, + { label = "Player Minion", actorId = "PLAYER_MINION" }, + { label = "Mercenary", actorId = "MERCENARY" }, + { label = "Mercenary Minion", actorId = "MERCENARY_MINION" }, +} + -- Calculate and combine INC/MORE modifiers for the given modifier names function calcLib.mod(modStore, cfg, ...) return (1 + (modStore:Sum("INC", cfg, ...)) / 100) * modStore:More(cfg, ...) @@ -95,6 +103,10 @@ function calcLib.canGrantedEffectSupportActiveSkill(grantedEffect, activeSkill, if not appliesToGrantedSkills and grantedEffect.fromItem and grantedEffect.support and (activeSkill.activeEffect.grantedEffect.fromItem or activeSkill.activeEffect.grantedEffect.modSource:sub(1, #"Item") == "Item" or (activeSkill.activeEffect.srcInstance and activeSkill.activeEffect.srcInstance.fromItem)) then return false end + if grantedEffect.mercenarySupportId then + -- MercenarySkills.PossibleSupports is the game's explicit compatibility list. + return activeSkill.mercenaryPossibleSupportIds and isValueInArray(activeSkill.mercenaryPossibleSupportIds, grantedEffect.mercenarySupportId) ~= nil + end local effectiveSkillTypes local effectiveMinionTypes diff --git a/src/Modules/Calcs.lua b/src/Modules/Calcs.lua index dc12041374f..2c4c51e1d24 100644 --- a/src/Modules/Calcs.lua +++ b/src/Modules/Calcs.lua @@ -8,7 +8,10 @@ local ipairs = ipairs local t_insert = table.insert local s_format = string.format local m_min = math.min +local m_max = math.max local m_ceil = math.ceil +local MercenaryTools = require("Modules.MercenaryTools") +local ConfigScope = require("Modules.ConfigScope") ---@class Calcs local calcs = require("Modules.CalcBase") @@ -70,6 +73,16 @@ local function infoDump(env) prettyPrintTable(env.player.output) end +local function applyFullDPSOutput(env, fullDPS) + env.player.output.SkillDPS = fullDPS.skills + env.player.output.FullDPS = fullDPS.combinedDPS + env.player.output.FullDotDPS = fullDPS.TotalDotDPS + if env.mercenary then + env.mercenary.output.SkillDPS = fullDPS.mercenarySkills + env.mercenary.output.FullDPS = fullDPS.mercenaryDPS + env.mercenary.output.FullDotDPS = fullDPS.mercenaryDotDPS + end +end ---@class CalcOverride ---@field spec PassiveSpec? @@ -81,11 +94,14 @@ end ---@field toggleTincture Item? Item object used as a table key. ---@field conditions string[]? ---@field extraJewelFuncs ModList? +---@field comparisonActor string? +---@field itemSetId integer? -- Get calculator for other changes (adding/removing nodes, items, gems, etc) ---@param build Build ---@return fun(override?: CalcOverride, useFullDPS?: boolean): Output calcFunc ---@return Output output +---@return table baseOutputs function calcs.getMiscCalculator(build) -- Run base calculation pass local env, cachedPlayerDB, cachedEnemyDB, cachedMinionDB = calcs.initEnv(build, "CALCULATOR") @@ -93,10 +109,30 @@ function calcs.getMiscCalculator(build) local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", {}, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = nil}) local usedFullDPS = #fullDPS.skills > 0 if usedFullDPS then - env.player.output.SkillDPS = fullDPS.skills - env.player.output.FullDPS = fullDPS.combinedDPS - env.player.output.FullDotDPS = fullDPS.TotalDotDPS + applyFullDPSOutput(env, fullDPS) + end + local function comparisonOutput(calculationEnv, override) + if override and (override.comparisonActor == "MERCENARY" or MercenaryTools.baseItemSlotName(override.repSlotName)) then + if calculationEnv.mercenary then + return MercenaryTools.buildComparisonOutput(calculationEnv.mercenary.output, calculationEnv.player.output) + end + local message = "The selected mercenary is unavailable for this build." + if calculationEnv.mercenaryCalculationErrors and calculationEnv.mercenaryCalculationErrors[1] then + message = table.concat(calculationEnv.mercenaryCalculationErrors, "\n") + else + local tabErrors = build.mercenaryTab and build.mercenaryTab:GetErrors() + if tabErrors and tabErrors[1] then + message = table.concat(tabErrors, "\n") + end + end + return { ActorUnavailableMessage = message } + end + return calculationEnv.player.output end + local baseOutputs = { + PLAYER = comparisonOutput(env), + MERCENARY = comparisonOutput(env, { comparisonActor = "MERCENARY" }), + } return function(override, useFullDPS) local env, cachedPlayerDB, cachedEnemyDB, cachedMinionDB = calcs.initEnv(build, "CALCULATOR", override) calcs.perform(env) @@ -105,12 +141,10 @@ function calcs.getMiscCalculator(build) -- without this, FullDPS increase/decrease when for node/item/gem comparison would be all 0 as it would be comparing -- A with A (due to cache reuse) instead of A with B local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", override, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = nil}) - env.player.output.SkillDPS = fullDPS.skills - env.player.output.FullDPS = fullDPS.combinedDPS - env.player.output.FullDotDPS = fullDPS.TotalDotDPS + applyFullDPSOutput(env, fullDPS) end - return env.player.output - end, env.player.output + return comparisonOutput(env, override) + end, baseOutputs.PLAYER, baseOutputs end local function getActiveSkillCount(activeSkill) @@ -139,14 +173,146 @@ local function getActiveSkillCount(activeSkill) return 1, true end -function calcs.calcFullDPS(build, mode, override, specEnv) - local fullEnv, cachedPlayerDB, cachedEnemyDB, cachedMinionDB = calcs.initEnv(build, mode, override, specEnv) - local usedEnv = nil +local function countSkillDamageOnce(activeSkill, modDB) + local skillName = activeSkill.activeEffect.grantedEffect.name + return (skillName:match("Absolution") and modDB:Flag(false, "Condition:AbsolutionSkillDamageCountedOnce")) + or (skillName:match("Dominating Blow") and modDB:Flag(false, "Condition:DominatingBlowSkillDamageCountedOnce")) + or (skillName:match("Holy Strike") and modDB:Flag(false, "Condition:HolyStrikeSkillDamageCountedOnce")) +end + +-- Generic skill DoT for Full DPS. Non-stacking DoTs of the same identity +-- keep the strongest instance; stackable DoTs sum, multiplied by count. +function calcs.genericDotIdentity(grantedEffect) + local identity = grantedEffect and (grantedEffect.inheritedFrom or grantedEffect.id) + if not identity then + error("Full DPS generic DoT is missing an identity") + end + return identity +end + +function calcs.genericDotContribution(output, skillFlags, count) + if not (output.TotalDot and output.TotalDot > 0) then + return 0 + end + return output.TotalDot * (skillFlags.DotCanStack and count or 1) +end + +function calcs.contributeGenericDot(totals, identity, output, skillFlags, count) + local contribution = calcs.genericDotContribution(output, skillFlags, count) + if contribution <= 0 then + return + end + if skillFlags.DotCanStack then + totals[identity] = (totals[identity] or 0) + contribution + elseif contribution > (totals[identity] or 0) then + totals[identity] = contribution + end +end + +-- Minion actors carry their own mainSkill. Full DPS must key generic DoT from +-- that skill, not from the summoning skill that created the actor. +function calcs.contributeSkillGenericDot(totals, skill, output, count) + if not (output and output.TotalDot and output.TotalDot > 0) then + return + end + if not (skill and skill.activeEffect and skill.activeEffect.grantedEffect) then + error("Full DPS generic DoT is missing a skill identity") + end + calcs.contributeGenericDot(totals, calcs.genericDotIdentity(skill.activeEffect.grantedEffect), output, skill.skillFlags or { }, count) +end +-- Shared Full DPS contribution for one actor output. Direct, poison, and impale +-- scale by count; ailment/ground/decay maxima keep the strongest instance. +-- extra.skills / extra.totals / extra.genericDots receive the same contribution +-- for Mercenary subtotals without a second pass. +local FULL_DPS_MAXIMUMS = { + { output = "BleedDPS", full = "bleedDPS", source = "bleed", totals = "bleed" }, + { output = "CorruptingBloodDPS", full = "corruptingBloodDPS", source = "corruptingBlood", totals = "corruptingBlood" }, + { output = "IgniteDPS", full = "igniteDPS", source = "ignite", totals = "ignite" }, + { output = "BurningGroundDPS", full = "burningGroundDPS", source = "burningGround", totals = "burningGround" }, + { output = "CausticGroundDPS", full = "causticGroundDPS", source = "causticGround", totals = "causticGround" }, + { output = "DecayDPS", full = "decayDPS", source = "decay", totals = "decay" }, +} + +function calcs.contributeActorFullDPS(fullDPS, sources, genericDots, output, count, info, extra) + if not output then + return + end + info = info or { } + local name = info.name + local sourceName = info.sourceName or name + if output.TotalDPS and output.TotalDPS > 0 then + local skillDPS = { + name = name, + dps = output.TotalDPS, + count = count, + trigger = info.trigger, + source = info.source, + skillPart = info.skillPart, + } + t_insert(fullDPS.skills, skillDPS) + if extra and extra.skills then + t_insert(extra.skills, skillDPS) + end + local direct = output.TotalDPS * count + fullDPS.combinedDPS = fullDPS.combinedDPS + direct + if extra and extra.totals then + extra.totals.direct = extra.totals.direct + direct + end + end + for _, spec in ipairs(FULL_DPS_MAXIMUMS) do + local value = output[spec.output] or 0 + if value > fullDPS[spec.full] then + fullDPS[spec.full] = value + sources[spec.source] = sourceName + end + if extra and extra.totals and value > extra.totals[spec.totals] then + extra.totals[spec.totals] = value + extra.totals[spec.totals.."Source"] = sourceName + end + end + if output.PoisonDPS and output.PoisonDPS > 0 then + local poison = output.TotalPoisonDPS * count + fullDPS.TotalPoisonDPS = fullDPS.TotalPoisonDPS + poison + if extra and extra.totals then + extra.totals.poison = extra.totals.poison + poison + end + end + if output.ImpaleDPS and output.ImpaleDPS > 0 then + local impale = output.ImpaleDPS * count + fullDPS.impaleDPS = fullDPS.impaleDPS + impale + if extra and extra.totals then + extra.totals.impale = extra.totals.impale + impale + end + end + calcs.contributeSkillGenericDot(genericDots, info.skill, output, count) + if extra and extra.genericDots then + calcs.contributeSkillGenericDot(extra.genericDots, info.skill, output, count) + end + if output.CullMultiplier and output.CullMultiplier > 1 and output.CullMultiplier > fullDPS.cullingMulti then + fullDPS.cullingMulti = output.CullMultiplier + end + if extra and extra.totals then + extra.totals.culling = m_max(extra.totals.culling, output.CullMultiplier or 0) + end +end + +function calcs.sumDotTotals(totals) + local sum = 0 + for _, value in pairs(totals) do + sum = sum + value + end + return sum +end + +function calcs.calcFullDPS(build, mode, override, specEnv) local fullDPS = { combinedDPS = 0, TotalDotDPS = 0, skills = { }, + mercenarySkills = { }, + mercenaryDPS = 0, + mercenaryDotDPS = 0, TotalPoisonDPS = 0, causticGroundDPS = 0, impaleDPS = 0, @@ -158,13 +324,38 @@ function calcs.calcFullDPS(build, mode, override, specEnv) dotDPS = 0, cullingMulti = 0 } + local hasFullDPSSkill = false + for _, socketGroup in ipairs(build.skillsTab.socketGroupList) do + if socketGroup.includeInFullDPS then hasFullDPSSkill = true break end + end + if not hasFullDPSSkill then + local mercenarySkills = build.mercenaryTab and build.mercenaryTab.profile and build.mercenaryTab.profile.skills + for _, selected in ipairs(mercenarySkills or { }) do + if selected.enabled ~= false and selected.includeInFullDPS then hasFullDPSSkill = true break end + end + end + if not hasFullDPSSkill then return fullDPS end - local bleedSource = "" - local corruptingBloodSource = "" - local igniteSource = "" - local burningGroundSource = "" - local causticGroundSource = "" - + local fullEnv, cachedPlayerDB, cachedEnemyDB, cachedMinionDB = calcs.initEnv(build, mode, override, specEnv) + local usedEnv = nil + + local sources = { bleed = "", corruptingBlood = "", ignite = "", burningGround = "", causticGround = "", decay = "" } + local genericDots = { } + local remainingPlayerFullDPS = 0 + for _, activeSkill in ipairs(fullEnv.player.activeSkillList) do + if activeSkill.socketGroup and activeSkill.socketGroup.includeInFullDPS then + local _, enabled = getActiveSkillCount(activeSkill) + if enabled then + remainingPlayerFullDPS = remainingPlayerFullDPS + 1 + end + end + end + local mercenaryFullDPSSkills = { } + for _, activeSkill in ipairs(fullEnv.mercenary and fullEnv.mercenary.activeSkillList or { }) do + if activeSkill.isMercenaryPrimary and activeSkill.mercenarySkill and activeSkill.mercenarySkill.includeInFullDPS then + t_insert(mercenaryFullDPSSkills, activeSkill.mercenarySkill) + end + end for _, activeSkill in ipairs(fullEnv.player.activeSkillList) do if activeSkill.socketGroup and activeSkill.socketGroup.includeInFullDPS then local activeSkillCount, enabled = getActiveSkillCount(activeSkill) @@ -181,11 +372,11 @@ function calcs.calcFullDPS(build, mode, override, specEnv) end if usedEnv.minion.output.BleedDPS and usedEnv.minion.output.BleedDPS > fullDPS.bleedDPS then fullDPS.bleedDPS = usedEnv.minion.output.BleedDPS - bleedSource = activeSkill.activeEffect.grantedEffect.name + sources.bleed = activeSkill.activeEffect.grantedEffect.name end if usedEnv.minion.output.IgniteDPS and usedEnv.minion.output.IgniteDPS > fullDPS.igniteDPS then fullDPS.igniteDPS = usedEnv.minion.output.IgniteDPS - igniteSource = activeSkill.activeEffect.grantedEffect.name + sources.ignite = activeSkill.activeEffect.grantedEffect.name end if usedEnv.minion.output.PoisonDPS and usedEnv.minion.output.PoisonDPS > 0 then fullDPS.TotalPoisonDPS = fullDPS.TotalPoisonDPS + usedEnv.minion.output.TotalPoisonDPS * activeSkillCount @@ -193,19 +384,16 @@ function calcs.calcFullDPS(build, mode, override, specEnv) if usedEnv.minion.output.ImpaleDPS and usedEnv.minion.output.ImpaleDPS > 0 then fullDPS.impaleDPS = fullDPS.impaleDPS + usedEnv.minion.output.ImpaleDPS * activeSkillCount end - if usedEnv.minion.output.DecayDPS and usedEnv.minion.output.DecayDPS > 0 then - fullDPS.decayDPS = fullDPS.decayDPS + usedEnv.minion.output.DecayDPS - end - if usedEnv.minion.output.TotalDot and usedEnv.minion.output.TotalDot > 0 then - fullDPS.dotDPS = fullDPS.dotDPS + usedEnv.minion.output.TotalDot + if usedEnv.minion.output.DecayDPS and usedEnv.minion.output.DecayDPS > fullDPS.decayDPS then + fullDPS.decayDPS = usedEnv.minion.output.DecayDPS + sources.decay = activeSkill.activeEffect.grantedEffect.name end + calcs.contributeSkillGenericDot(genericDots, usedEnv.minion.mainSkill, usedEnv.minion.output, activeSkillCount) if usedEnv.minion.output.CullMultiplier and usedEnv.minion.output.CullMultiplier > 1 and usedEnv.minion.output.CullMultiplier > fullDPS.cullingMulti then fullDPS.cullingMulti = usedEnv.minion.output.CullMultiplier end -- This is a fix to prevent skills such as Absolution or Dominating Blow from being counted multiple times when increasing minions count - if (activeSkill.activeEffect.grantedEffect.name:match("Absolution") and fullEnv.modDB:Flag(false, "Condition:AbsolutionSkillDamageCountedOnce")) - or (activeSkill.activeEffect.grantedEffect.name:match("Dominating Blow") and fullEnv.modDB:Flag(false, "Condition:DominatingBlowSkillDamageCountedOnce")) - or (activeSkill.activeEffect.grantedEffect.name:match("Holy Strike") and fullEnv.modDB:Flag(false, "Condition:HolyStrikeSkillDamageCountedOnce"))then + if countSkillDamageOnce(activeSkill, fullEnv.modDB) then activeSkillCount = 1 activeSkill.infoMessage2 = "Skill Damage" end @@ -219,11 +407,11 @@ function calcs.calcFullDPS(build, mode, override, specEnv) end if activeSkill.mirage.output.BleedDPS and activeSkill.mirage.output.BleedDPS > fullDPS.bleedDPS then fullDPS.bleedDPS = activeSkill.mirage.output.BleedDPS - bleedSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" + sources.bleed = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" end if activeSkill.mirage.output.IgniteDPS and activeSkill.mirage.output.IgniteDPS > fullDPS.igniteDPS then fullDPS.igniteDPS = activeSkill.mirage.output.IgniteDPS - igniteSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" + sources.ignite = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" end if activeSkill.mirage.output.PoisonDPS and activeSkill.mirage.output.PoisonDPS > 0 then fullDPS.TotalPoisonDPS = fullDPS.TotalPoisonDPS + activeSkill.mirage.output.TotalPoisonDPS * mirageCount @@ -231,22 +419,21 @@ function calcs.calcFullDPS(build, mode, override, specEnv) if activeSkill.mirage.output.ImpaleDPS and activeSkill.mirage.output.ImpaleDPS > 0 then fullDPS.impaleDPS = fullDPS.impaleDPS + activeSkill.mirage.output.ImpaleDPS * mirageCount end - if activeSkill.mirage.output.DecayDPS and activeSkill.mirage.output.DecayDPS > 0 then - fullDPS.decayDPS = fullDPS.decayDPS + activeSkill.mirage.output.DecayDPS - end - if activeSkill.mirage.output.TotalDot and activeSkill.mirage.output.TotalDot > 0 and (activeSkill.skillFlags.DotCanStack or (usedEnv.player.output.TotalDot and usedEnv.player.output.TotalDot == 0)) then - fullDPS.dotDPS = fullDPS.dotDPS + activeSkill.mirage.output.TotalDot * (activeSkill.skillFlags.DotCanStack and mirageCount or 1) + if activeSkill.mirage.output.DecayDPS and activeSkill.mirage.output.DecayDPS > fullDPS.decayDPS then + fullDPS.decayDPS = activeSkill.mirage.output.DecayDPS + sources.decay = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" end + calcs.contributeSkillGenericDot(genericDots, activeSkill, activeSkill.mirage.output, mirageCount) if activeSkill.mirage.output.CullMultiplier and activeSkill.mirage.output.CullMultiplier > 1 and activeSkill.mirage.output.CullMultiplier > fullDPS.cullingMulti then fullDPS.cullingMulti = activeSkill.mirage.output.CullMultiplier end if activeSkill.mirage.output.BurningGroundDPS and activeSkill.mirage.output.BurningGroundDPS > fullDPS.burningGroundDPS then fullDPS.burningGroundDPS = activeSkill.mirage.output.BurningGroundDPS - burningGroundSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" + sources.burningGround = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" end if activeSkill.mirage.output.CausticGroundDPS and activeSkill.mirage.output.CausticGroundDPS > fullDPS.causticGroundDPS then fullDPS.causticGroundDPS = activeSkill.mirage.output.CausticGroundDPS - causticGroundSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" + sources.causticGround = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" end end @@ -256,49 +443,121 @@ function calcs.calcFullDPS(build, mode, override, specEnv) end if usedEnv.player.output.BleedDPS and usedEnv.player.output.BleedDPS > fullDPS.bleedDPS then fullDPS.bleedDPS = usedEnv.player.output.BleedDPS - bleedSource = activeSkill.activeEffect.grantedEffect.name + sources.bleed = activeSkill.activeEffect.grantedEffect.name end if usedEnv.player.output.CorruptingBloodDPS and usedEnv.player.output.CorruptingBloodDPS > fullDPS.corruptingBloodDPS then fullDPS.corruptingBloodDPS = usedEnv.player.output.CorruptingBloodDPS - corruptingBloodSource = activeSkill.activeEffect.grantedEffect.name + sources.corruptingBlood = activeSkill.activeEffect.grantedEffect.name end if usedEnv.player.output.IgniteDPS and usedEnv.player.output.IgniteDPS > fullDPS.igniteDPS then fullDPS.igniteDPS = usedEnv.player.output.IgniteDPS - igniteSource = activeSkill.activeEffect.grantedEffect.name + sources.ignite = activeSkill.activeEffect.grantedEffect.name end if usedEnv.player.output.BurningGroundDPS and usedEnv.player.output.BurningGroundDPS > fullDPS.burningGroundDPS then fullDPS.burningGroundDPS = usedEnv.player.output.BurningGroundDPS - burningGroundSource = activeSkill.activeEffect.grantedEffect.name + sources.burningGround = activeSkill.activeEffect.grantedEffect.name end if usedEnv.player.output.PoisonDPS and usedEnv.player.output.PoisonDPS > 0 then fullDPS.TotalPoisonDPS = fullDPS.TotalPoisonDPS + usedEnv.player.output.TotalPoisonDPS * activeSkillCount end if usedEnv.player.output.CausticGroundDPS and usedEnv.player.output.CausticGroundDPS > fullDPS.causticGroundDPS then fullDPS.causticGroundDPS = usedEnv.player.output.CausticGroundDPS - causticGroundSource = activeSkill.activeEffect.grantedEffect.name + sources.causticGround = activeSkill.activeEffect.grantedEffect.name end if usedEnv.player.output.ImpaleDPS and usedEnv.player.output.ImpaleDPS > 0 then fullDPS.impaleDPS = fullDPS.impaleDPS + usedEnv.player.output.ImpaleDPS * activeSkillCount end - if usedEnv.player.output.DecayDPS and usedEnv.player.output.DecayDPS > 0 then - fullDPS.decayDPS = fullDPS.decayDPS + usedEnv.player.output.DecayDPS - end - if usedEnv.player.output.TotalDot and usedEnv.player.output.TotalDot > 0 then - fullDPS.dotDPS = fullDPS.dotDPS + usedEnv.player.output.TotalDot * (activeSkill.skillFlags.DotCanStack and activeSkillCount or 1) + if usedEnv.player.output.DecayDPS and usedEnv.player.output.DecayDPS > fullDPS.decayDPS then + fullDPS.decayDPS = usedEnv.player.output.DecayDPS + sources.decay = activeSkill.activeEffect.grantedEffect.name end + calcs.contributeSkillGenericDot(genericDots, activeSkill, usedEnv.player.output, activeSkillCount) if usedEnv.player.output.CullMultiplier and usedEnv.player.output.CullMultiplier > 1 and usedEnv.player.output.CullMultiplier > fullDPS.cullingMulti then fullDPS.cullingMulti = usedEnv.player.output.CullMultiplier end - -- Re-Build env calculator for new run - local accelerationTbl = { - nodeAlloc = true, - requirementsItems = true, - requirementsGems = true, - skills = true, - everything = true, - } - fullEnv, _, _, _ = calcs.initEnv(build, mode, override, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = fullEnv, accelerate = accelerationTbl }) + remainingPlayerFullDPS = remainingPlayerFullDPS - 1 + -- Rebuild after the last player skill too when a Mercenary Full DPS + -- loop follows, so that loop does not inherit the last perform(). + if remainingPlayerFullDPS > 0 or #mercenaryFullDPSSkills > 0 then + local accelerationTbl = { + nodeAlloc = true, + requirementsItems = true, + requirementsGems = true, + skills = true, + everything = true, + } + fullEnv, _, _, _ = calcs.initEnv(build, mode, override, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = fullEnv, accelerate = accelerationTbl }) + end + end + end + end + + local mercenaryGenericDots, mercenaryTotals + if fullEnv.mercenary then + mercenaryGenericDots = { } + mercenaryTotals = { + direct = 0, poison = 0, impale = 0, decay = 0, dot = 0, + bleed = 0, corruptingBlood = 0, ignite = 0, burningGround = 0, causticGround = 0, culling = 0, + bleedSource = "", corruptingBloodSource = "", igniteSource = "", burningGroundSource = "", causticGroundSource = "", decaySource = "", + } + for selectedIndex, selected in ipairs(mercenaryFullDPSSkills) do + local activeSkill + for _, candidate in ipairs(fullEnv.mercenary.activeSkillList or { }) do + if candidate.mercenarySkill and candidate.mercenarySkill.id == selected.id then activeSkill = candidate break end + end + if activeSkill then + fullEnv.mercenary.mainSkill = activeSkill + calcs.perform(fullEnv, true) + usedEnv = fullEnv + local count = selected.count or 1 + local directCount = count + if activeSkill.minion and countSkillDamageOnce(activeSkill, fullEnv.mercenary.modDB) then + directCount = 1 + activeSkill.infoMessage2 = "Skill Damage" + end + local actorOutputs = { { + output = usedEnv.mercenary.output, + name = activeSkill.activeEffect.grantedEffect.name, + source = "Mercenary", + count = directCount, + skill = activeSkill, + skillPart = activeSkill.minion and activeSkill.infoMessage2 or activeSkill.skillPartName, + } } + if activeSkill.minion and usedEnv.mercenaryMinion then + t_insert(actorOutputs, 1, { + output = usedEnv.mercenaryMinion.output, + name = usedEnv.mercenaryMinion.minionData.name..": "..activeSkill.activeEffect.grantedEffect.name, + source = "Mercenary Minion", + count = count, + skill = usedEnv.mercenaryMinion.mainSkill, + skillPart = activeSkill.skillPartName, + }) + end + if activeSkill.mirage then + t_insert(actorOutputs, { + output = activeSkill.mirage.output, + name = activeSkill.mirage.name.." (Mirage)", + source = "Mercenary Mirage", + count = (activeSkill.mirage.count or 1) * directCount, + skill = activeSkill, + skillPart = activeSkill.mirage.skillPartName, + }) + end + local extra = { skills = fullDPS.mercenarySkills, totals = mercenaryTotals, genericDots = mercenaryGenericDots } + for _, actorData in ipairs(actorOutputs) do + calcs.contributeActorFullDPS(fullDPS, sources, genericDots, actorData.output, actorData.count, { + name = actorData.name, + source = actorData.source, + skillPart = actorData.skillPart, + skill = actorData.skill, + }, extra) + end + + if selectedIndex < #mercenaryFullDPSSkills then + local accelerationTbl = { nodeAlloc = true, requirementsItems = true, requirementsGems = true, skills = true, everything = true } + fullEnv, _, _, _ = calcs.initEnv(build, mode, override, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = fullEnv, accelerate = accelerationTbl }) + end end end end @@ -306,19 +565,19 @@ function calcs.calcFullDPS(build, mode, override, specEnv) -- Re-Add ailment DPS components fullDPS.TotalDotDPS = 0 if fullDPS.bleedDPS > 0 then - t_insert(fullDPS.skills, { name = "Best Bleed DPS", dps = fullDPS.bleedDPS, count = 1, source = bleedSource }) + t_insert(fullDPS.skills, { name = "Best Bleed DPS", dps = fullDPS.bleedDPS, count = 1, source = sources.bleed }) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.bleedDPS end if fullDPS.corruptingBloodDPS > 0 then - t_insert(fullDPS.skills, { name = "Corrupting Blood DPS", dps = fullDPS.corruptingBloodDPS, count = 1, source = corruptingBloodSource }) + t_insert(fullDPS.skills, { name = "Corrupting Blood DPS", dps = fullDPS.corruptingBloodDPS, count = 1, source = sources.corruptingBlood }) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.corruptingBloodDPS end if fullDPS.igniteDPS > 0 then - t_insert(fullDPS.skills, { name = "Best Ignite DPS", dps = fullDPS.igniteDPS, count = 1, source = igniteSource }) + t_insert(fullDPS.skills, { name = "Best Ignite DPS", dps = fullDPS.igniteDPS, count = 1, source = sources.ignite }) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.igniteDPS end if fullDPS.burningGroundDPS > 0 then - t_insert(fullDPS.skills, { name = "Best Burning Ground DPS", dps = fullDPS.burningGroundDPS, count = 1, source = burningGroundSource }) + t_insert(fullDPS.skills, { name = "Best Burning Ground DPS", dps = fullDPS.burningGroundDPS, count = 1, source = sources.burningGround }) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.burningGroundDPS end if fullDPS.TotalPoisonDPS > 0 then @@ -327,7 +586,7 @@ function calcs.calcFullDPS(build, mode, override, specEnv) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.TotalPoisonDPS end if fullDPS.causticGroundDPS > 0 then - t_insert(fullDPS.skills, { name = "Best Caustic Ground DPS", dps = fullDPS.causticGroundDPS, count = 1, source = causticGroundSource }) + t_insert(fullDPS.skills, { name = "Best Caustic Ground DPS", dps = fullDPS.causticGroundDPS, count = 1, source = sources.causticGround }) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.causticGroundDPS end if fullDPS.impaleDPS > 0 then @@ -335,9 +594,10 @@ function calcs.calcFullDPS(build, mode, override, specEnv) fullDPS.combinedDPS = fullDPS.combinedDPS + fullDPS.impaleDPS end if fullDPS.decayDPS > 0 then - t_insert(fullDPS.skills, { name = "Full Decay DPS", dps = fullDPS.decayDPS, count = 1 }) + t_insert(fullDPS.skills, { name = "Best Decay DPS", dps = fullDPS.decayDPS, count = 1, source = sources.decay }) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.decayDPS end + fullDPS.dotDPS = calcs.sumDotTotals(genericDots) if fullDPS.dotDPS > 0 then t_insert(fullDPS.skills, { name = "Full DoT DPS", dps = fullDPS.dotDPS, count = 1 }) fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.dotDPS @@ -349,6 +609,32 @@ function calcs.calcFullDPS(build, mode, override, specEnv) t_insert(fullDPS.skills, { name = "Full Culling DPS", dps = fullDPS.cullingDPS, count = 1 }) fullDPS.combinedDPS = fullDPS.combinedDPS + fullDPS.cullingDPS end + if mercenaryTotals then + mercenaryTotals.dot = calcs.sumDotTotals(mercenaryGenericDots) + local function addMercenaryDPS(name, dps, source) + if dps > 0 then + t_insert(fullDPS.mercenarySkills, { name = name, dps = dps, count = 1, source = source }) + end + end + local mercenaryPoison = m_min(mercenaryTotals.poison, data.misc.DotDpsCap) + addMercenaryDPS("Best Bleed DPS", mercenaryTotals.bleed, mercenaryTotals.bleedSource) + addMercenaryDPS("Corrupting Blood DPS", mercenaryTotals.corruptingBlood, mercenaryTotals.corruptingBloodSource) + addMercenaryDPS("Best Ignite DPS", mercenaryTotals.ignite, mercenaryTotals.igniteSource) + addMercenaryDPS("Best Burning Ground DPS", mercenaryTotals.burningGround, mercenaryTotals.burningGroundSource) + addMercenaryDPS("Full Poison DPS", mercenaryPoison) + addMercenaryDPS("Best Caustic Ground DPS", mercenaryTotals.causticGround, mercenaryTotals.causticGroundSource) + addMercenaryDPS("Full Impale DPS", mercenaryTotals.impale) + addMercenaryDPS("Best Decay DPS", mercenaryTotals.decay, mercenaryTotals.decaySource) + addMercenaryDPS("Full DoT DPS", mercenaryTotals.dot) + fullDPS.mercenaryDotDPS = m_min(mercenaryTotals.bleed + mercenaryTotals.corruptingBlood + mercenaryTotals.ignite + + mercenaryTotals.burningGround + mercenaryTotals.causticGround + mercenaryPoison + mercenaryTotals.decay + mercenaryTotals.dot, data.misc.DotDpsCap) + fullDPS.mercenaryDPS = mercenaryTotals.direct + mercenaryTotals.impale + fullDPS.mercenaryDotDPS + if mercenaryTotals.culling > 1 then + local cullingDPS = fullDPS.mercenaryDPS * (mercenaryTotals.culling - 1) + addMercenaryDPS("Full Culling DPS", cullingDPS) + fullDPS.mercenaryDPS = fullDPS.mercenaryDPS + cullingDPS + end + end return fullDPS end @@ -369,12 +655,21 @@ function calcs.buildActiveSkill(env, mode, skill, targetUUID, limitedProcessingF end targetUUID = targetUUID or cacheSkillUUID(skill, env) - for _, activeSkill in ipairs(fullEnv.player.activeSkillList) do - local activeSkillUUID = cacheSkillUUID(activeSkill, fullEnv) - if activeSkillUUID == targetUUID then - fullEnv.player.mainSkill = activeSkill - calcs.perform(fullEnv, true) - return + local skillLists = { fullEnv.player.activeSkillList } + if fullEnv.mercenary then + t_insert(skillLists, fullEnv.mercenary.activeSkillList) + end + for _, skillList in ipairs(skillLists) do + for _, activeSkill in ipairs(skillList) do + if cacheSkillUUID(activeSkill, fullEnv) == targetUUID then + if activeSkill.actor and activeSkill.actor.isMercenary then + fullEnv.mercenary.mainSkill = activeSkill + else + fullEnv.player.mainSkill = activeSkill + end + calcs.perform(fullEnv, true) + return + end end end ConPrintf("[calcs.buildActiveSkill] Failed to process skill: " .. skill.activeEffect.grantedEffect.name) @@ -392,9 +687,7 @@ function calcs.buildOutput(build, mode) local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", {}, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = nil }) -- Add Full DPS data to main `env` - env.player.output.SkillDPS = fullDPS.skills - env.player.output.FullDPS = fullDPS.combinedDPS - env.player.output.FullDotDPS = fullDPS.TotalDotDPS + applyFullDPSOutput(env, fullDPS) if mode == "MAIN" then for _, skill in ipairs(env.player.activeSkillList) do @@ -446,16 +739,20 @@ function calcs.buildOutput(build, mode) output["Spec:EnergyShieldInc"] = env.modDB:Sum("INC", specCfg, "EnergyShield") env.skillsUsed = { } - for _, activeSkill in ipairs(env.player.activeSkillList) do - for _, skillEffect in ipairs(activeSkill.effectList) do - env.skillsUsed[skillEffect.grantedEffect.name] = true - end - if activeSkill.minion then - for _, activeSkill in ipairs(activeSkill.minion.activeSkillList) do - env.skillsUsed[activeSkill.activeEffect.grantedEffect.id] = true + local function recordActorSkills(actor) + for _, activeSkill in ipairs(actor and actor.activeSkillList or { }) do + for _, skillEffect in ipairs(activeSkill.effectList) do + env.skillsUsed[skillEffect.grantedEffect.name] = true + end + if activeSkill.minion then + for _, minionSkill in ipairs(activeSkill.minion.activeSkillList) do + env.skillsUsed[minionSkill.activeEffect.grantedEffect.id] = true + end end end end + local primaryActorKeys = { "player", "mercenary" } + for _, actorKey in ipairs(primaryActorKeys) do recordActorSkills(env[actorKey]) end env.conditionsUsed = { } env.enemyConditionsUsed = { } @@ -466,6 +763,28 @@ function calcs.buildOutput(build, mode) env.enemyPerStatsUsed = { } env.tagTypesUsed = { } env.modsUsed = { } + env.actorUsage = { + player = { conditions = { }, multipliers = { }, mods = { }, perStats = { }, minionConditions = { }, enemyConditions = { }, enemyMultipliers = { }, enemyPerStats = { } }, + } + if env.mercenary then + env.actorUsage.mercenary = { conditions = { }, multipliers = { }, mods = { }, perStats = { }, minionConditions = { }, enemyConditions = { }, enemyMultipliers = { }, enemyPerStats = { } } + end + local function actorUsageFor(actor) + if actor == env.mercenary then + return env.actorUsage.mercenary + end + if actor == env.player then + return env.actorUsage.player + end + end + local function ownerUsageForMinion(actor) + if actor == env.minion or (actor and actor.parent == env.player) then + return env.actorUsage.player + end + if actor == env.mercenaryMinion or (actor and actor.parent == env.mercenary) then + return env.actorUsage.mercenary + end + end local function addTo(out, var, mod) -- Do not count Base mods as mods being actually used as they are only used as descriptors for mods if mod.source == "Base" then @@ -496,6 +815,10 @@ function calcs.buildOutput(build, mode) end local function addModTags(actor, mod) addTo(env.modsUsed, mod.name, mod) + local usage = actorUsageFor(actor) + if usage then + addTo(usage.mods, mod.name, mod) + end -- Imply enemy conditionals based on damage type -- Needed to preemptively show config options for elemental ailments @@ -506,63 +829,123 @@ function calcs.buildOutput(build, mode) end end end + if ConfigScope.impliesChilledByYourHits(mod.name) then + addTo(env.enemyConditionsUsed, "ChilledByYourHits", mod) + if usage then + addTo(usage.enemyConditions, "ChilledByYourHits", mod) + end + end for _, tag in ipairs(mod) do addTo(env.tagTypesUsed, tag.type, mod) if tag.type == "IgnoreCond" then break elseif tag.type == "Condition" then - if actor == env.player then + if actor == env.player or actor == env.mercenary then addVarTag(env.conditionsUsed, tag, mod) + if usage then + addVarTag(usage.conditions, tag, mod) + end else addVarTag(env.minionConditionsUsed, tag, mod) + local ownerUsage = ownerUsageForMinion(actor) + if ownerUsage then + addVarTag(ownerUsage.minionConditions, tag, mod) + end end elseif tag.type == "ActorCondition" and tag.var then if tag.actor == "enemy" then addTo(env.enemyConditionsUsed, tag.var, mod) + if usage then + addTo(usage.enemyConditions, tag.var, mod) + end else addTo(env.conditionsUsed, tag.var, mod) + if usage then + addTo(usage.conditions, tag.var, mod) + end end elseif tag.type == "Multiplier" or tag.type == "MultiplierThreshold" then if not tag.actor then - if actor == env.player then + if actor == env.player or actor == env.mercenary then addVarTag(env.multipliersUsed, tag, mod) + if usage then + addVarTag(usage.multipliers, tag, mod) + end end elseif tag.actor == "enemy" then addVarTag(env.enemyMultipliersUsed, tag, mod) + if usage then + addVarTag(usage.enemyMultipliers, tag, mod) + end end elseif tag.type == "PerStat" or tag.type == "StatThreshold" then if not tag.actor then - if actor == env.player then + if actor == env.player or actor == env.mercenary then addStatTag(env.perStatsUsed, tag, mod) + if usage then + addStatTag(usage.perStats, tag, mod) + end end elseif tag.actor == "enemy" then addStatTag(env.enemyPerStatsUsed, tag, mod) + if usage then + addStatTag(usage.enemyPerStats, tag, mod) + end end end end - end - for _, actor in ipairs({env.player, env.minion}) do - for modName, modList in pairs(actor.modDB.mods) do - for _, mod in ipairs(modList) do - addModTags(actor, mod) + if mod.name == "EnemyModifier" and mod.value and mod.value.mod then + for _, innerTag in ipairs(mod.value.mod) do + if innerTag.type == "IgnoreCond" then + break + elseif innerTag.type == "Condition" then + addVarTag(env.enemyConditionsUsed, innerTag, mod.value.mod) + if usage then + addVarTag(usage.enemyConditions, innerTag, mod.value.mod) + end + elseif innerTag.type == "Multiplier" or innerTag.type == "MultiplierThreshold" then + if not innerTag.actor then + addVarTag(env.enemyMultipliersUsed, innerTag, mod.value.mod) + if usage then + addVarTag(usage.enemyMultipliers, innerTag, mod.value.mod) + end + end + end end end end - for _, activeSkill in pairs(env.player.activeSkillList) do - for _, mod in ipairs(activeSkill.baseSkillModList) do - addModTags(env.player, mod) - end - for _, mod in ipairs(activeSkill.skillModList) do - addTo(env.modsUsed, mod.name, mod) - for _, tag in ipairs(mod) do - addTo(env.tagTypesUsed, tag.type, mod) + for _, actorKey in ipairs({ "player", "mercenary", "minion", "mercenaryMinion" }) do + local actor = env[actorKey] + if actor then + for modName, modList in pairs(actor.modDB.mods) do + for _, mod in ipairs(modList) do + addModTags(actor, mod) + end end end - if activeSkill.minion then - for _, activeSkill in pairs(activeSkill.minion.activeSkillList) do - for _, mod in ipairs(activeSkill.baseSkillModList) do - addModTags(env.minion, mod) + end + for _, actorKey in ipairs(primaryActorKeys) do + local actor = env[actorKey] + for _, activeSkill in pairs(actor and actor.activeSkillList or { }) do + for _, mod in ipairs(activeSkill.baseSkillModList) do + addModTags(actor, mod) + end + for _, mod in ipairs(activeSkill.skillModList) do + addTo(env.modsUsed, mod.name, mod) + local usage = actorUsageFor(actor) + if usage then + addTo(usage.mods, mod.name, mod) + end + for _, tag in ipairs(mod) do + addTo(env.tagTypesUsed, tag.type, mod) + end + end + if activeSkill.minion then + for _, minionSkill in pairs(activeSkill.minion.activeSkillList) do + for _, mod in ipairs(minionSkill.baseSkillModList) do + addModTags(activeSkill.minion, mod) + end end end end diff --git a/src/Modules/Common.lua b/src/Modules/Common.lua index b71053f5f24..1c7febe7d38 100644 --- a/src/Modules/Common.lua +++ b/src/Modules/Common.lua @@ -543,7 +543,7 @@ function specCopy(env) end -- Wipe all keys from the table and return it, or return a new table if no table --- provided. This is useful to avoid alllocations in hot paths if a table can be reused. Using LuaJIT's `table.clear()` is another alternative to this, but this performs similarly on small tables, or tables which are often already empty. +-- provided. This is useful to avoid allocations in hot paths if a table can be reused. Using LuaJIT's `table.clear()` is another alternative to this, but this performs similarly on small tables, or tables which are often already empty. ---@param tbl table? ---@return table tbl function wipeTable(tbl) @@ -917,25 +917,35 @@ function cacheSkillUUID(skill, env) end end - return strName.."_"..strSlotName.."_"..tostring(slotIndx) .. "_" .. tostring(groupIdx) + local uuid = strName.."_"..strSlotName.."_"..tostring(slotIndx) .. "_" .. tostring(groupIdx) + if skill.actor and skill.actor.isMercenary then + local grantedId = skill.activeEffect.grantedEffect.id + if not grantedId then + error("Mercenary skill cache UUID requires grantedEffect.id") + end + uuid = uuid .. "_MERCENARY_" .. grantedId + end + return uuid end -- Global Cache related -function cacheData(uuid, env) +function cacheData(uuid, env, actor) + actor = actor or env.player + local output = actor.output GlobalCache.cachedData[env.mode][uuid] = { - Name = env.player.mainSkill.activeEffect.grantedEffect.name, - Speed = env.player.output.Speed, - HitSpeed = env.player.output.HitSpeed, - ManaCost = env.player.output.ManaCost, - LifeCost = env.player.output.LifeCost, - ESCost = env.player.output.ESCost, - RageCost = env.player.output.RageCost, - HitChance = env.player.output.HitChance, - AccuracyHitChance = env.player.output.AccuracyHitChance, - PreEffectiveCritChance = env.player.output.PreEffectiveCritChance, - CritChance = env.player.output.CritChance, - TotalDPS = env.player.output.TotalDPS, - ActiveSkill = env.player.mainSkill, + Name = actor.mainSkill.activeEffect.grantedEffect.name, + Speed = output.Speed, + HitSpeed = output.HitSpeed, + ManaCost = output.ManaCost, + LifeCost = output.LifeCost, + ESCost = output.ESCost, + RageCost = output.RageCost, + HitChance = output.HitChance, + AccuracyHitChance = output.AccuracyHitChance, + PreEffectiveCritChance = output.PreEffectiveCritChance, + CritChance = output.CritChance, + TotalDPS = output.TotalDPS, + ActiveSkill = actor.mainSkill, Env = env, } end diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 8ff3e6f8c79..6482ecc40f3 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -7,6 +7,7 @@ local m_min = math.min local m_max = math.max local s_format = string.format +local ConfigScope = require("Modules.ConfigScope") local function applyPantheonDescription(tooltip, mode, index, value) tooltip:Clear() @@ -131,17 +132,17 @@ end return { -- Section: General options - { section = "General", col = 1 }, - { var = "resistancePenalty", type = "list", label = "Resistance penalty:", list = {{val=0,label="None"},{val=-30,label="Act 5 (-30%)"},{val=-60,label="Act 10 (-60%)"}}, defaultIndex = 3 }, - { var = "bandit", type = "list", defaultIndex = 1, label = "Bandit quest:", tooltipFunc = banditTooltip, list = {{val="None",label="Kill all"},{val="Oak",label="Help Oak"},{val="Kraityn",label="Help Kraityn"},{val="Alira",label="Help Alira"}} }, - { var = "pantheonMajorGod", type = "list", defaultIndex = 1, label = "Major God:", tooltipFunc = applyPantheonDescription, list = { + { section = "General", col = 1, scope = "actor" }, + { var = "resistancePenalty", scope = "player", type = "list", label = "Resistance penalty:", list = {{val=0,label="None"},{val=-30,label="Act 5 (-30%)"},{val=-60,label="Act 10 (-60%)"}}, defaultIndex = 3 }, + { var = "bandit", scope = "player", type = "list", defaultIndex = 1, label = "Bandit quest:", tooltipFunc = banditTooltip, list = {{val="None",label="Kill all"},{val="Oak",label="Help Oak"},{val="Kraityn",label="Help Kraityn"},{val="Alira",label="Help Alira"}} }, + { var = "pantheonMajorGod", scope = "player", type = "list", defaultIndex = 1, label = "Major God:", tooltipFunc = applyPantheonDescription, list = { { label = "Nothing", val = "None" }, { label = "Soul of the Brine King", val = "TheBrineKing" }, { label = "Soul of Lunaris", val = "Lunaris" }, { label = "Soul of Solaris", val = "Solaris" }, { label = "Soul of Arakaali", val = "Arakaali" }, } }, - { var = "pantheonMinorGod", type = "list", defaultIndex = 1, label = "Minor God:", tooltipFunc = applyPantheonDescription, list = { + { var = "pantheonMinorGod", scope = "player", type = "list", defaultIndex = 1, label = "Minor God:", tooltipFunc = applyPantheonDescription, list = { { label = "Nothing", val = "None" }, { label = "Soul of Gruthkul", val = "Gruthkul" }, { label = "Soul of Yugul", val = "Yugul" }, @@ -245,15 +246,15 @@ return { { var = "EVBypass", type = "check", label = "Disable Emperor's Vigilance Bypass", ifCond = "EVBypass", apply = function(val, modList, enemyModList) modList:NewMod("Condition:EVBypass", "FLAG", true, "Config") end }, - { var = "ignoreItemDisablers", type = "check", label = "Don't disable items", ifTagType = "DisablesItem", tooltip = "Ignore the effects of things which disable items, like Bringer of Rain" }, - { var = "ignoreJewelLimits", type = "check", label = "Ignore Jewel Limits", tooltip = "Ignore the limits on jewels" }, - { var = "overrideEmptyRedSockets", type = "count", label = "# of Empty ^xE05030Red^7 Sockets", ifMult = "EmptyRedSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^xE05030Red^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, - { var = "overrideEmptyGreenSockets", type = "count", label = "# of Empty ^x70FF70Green^7 Sockets", ifMult = "EmptyGreenSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x70FF70Green^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, - { var = "overrideEmptyBlueSockets", type = "count", label = "# of Empty ^x7070FFBlue^7 Sockets", ifMult = "EmptyBlueSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x7070FFBlue^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, - { var = "overrideEmptyWhiteSockets", type = "count", label = "# of Empty White Sockets", ifMult = "EmptyWhiteSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty White Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "ignoreItemDisablers", scope = "player", type = "check", label = "Don't disable items", ifTagType = "DisablesItem", tooltip = "Ignore the effects of things which disable items, like Bringer of Rain" }, + { var = "ignoreJewelLimits", scope = "player", type = "check", label = "Ignore Jewel Limits", tooltip = "Ignore the limits on jewels" }, + { var = "overrideEmptyRedSockets", scope = "player", type = "count", label = "# of Empty ^xE05030Red^7 Sockets", ifMult = "EmptyRedSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^xE05030Red^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "overrideEmptyGreenSockets", scope = "player", type = "count", label = "# of Empty ^x70FF70Green^7 Sockets", ifMult = "EmptyGreenSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x70FF70Green^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "overrideEmptyBlueSockets", scope = "player", type = "count", label = "# of Empty ^x7070FFBlue^7 Sockets", ifMult = "EmptyBlueSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x7070FFBlue^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "overrideEmptyWhiteSockets", scope = "player", type = "count", label = "# of Empty White Sockets", ifMult = "EmptyWhiteSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty White Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, -- Section: Skill-specific options - { section = "Skill Options", col = 2 }, + { section = "Skill Options", col = 2, scope = "actor" }, { label = "Arcane Cloak:", ifSkill = "Arcane Cloak"}, { var = "arcaneCloakUsedRecentlyCheck", type = "check", label = "Include in ^x7070FFMana ^7spent Recently?", ifSkill = "Arcane Cloak", tooltip = "When enabled, the mana spent by Arcane Cloak used at full mana \nwill be added to the value provided in # of ^x7070FFMana ^7spent Recently.", apply = function(val, modList, enemyModList) modList:NewMod("Condition:ArcaneCloakUsedRecently", "FLAG", true, "Config") @@ -536,7 +537,7 @@ return { modList:NewMod("Multiplier:MinionLife", "BASE", val, "Config") end }, { label = "Eldritch Blasphemy:", ifSkill = "Eldritch Blasphemy" }, - { var = "conditionEnemyMalignantMadness", type = "check", label = "Enemy has Malignant Madness?", ifSkill = "Eldritch Blasphemy", tooltip = "A debuff that applies:\n\tDeal 10% less Damage\n\t10% reduced Action Speed", apply = function(val, modList, enemyModList) + { var = "conditionEnemyMalignantMadness", scope = "shared", type = "check", label = "Enemy has Malignant Madness?", ifSkill = "Eldritch Blasphemy", tooltip = "A debuff that applies:\n\tDeal 10% less Damage\n\t10% reduced Action Speed", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:MalignantMadness", "FLAG", true, "Config") end }, { label = "Meat Shield:", ifSkill = "Meat Shield" }, @@ -544,7 +545,7 @@ return { modList:NewMod("Condition:MeatShieldEnemyNearYou", "FLAG", true, "Config") end }, { label = "Misty Reflection:", ifSkill = "Misty Reflection" }, - { var = "enemyHitMistyReflection", type = "check", label = "Enemy hit by Misty Reflection?", ifSkill = "Misty Reflection", tooltip = "Misty Reflection debuff lasts 4 seconds and makes enemies have:\n\t30% increased Damage Taken\n\tDeal 30% less Damage", apply = function(val, modList, enemyModList) + { var = "enemyHitMistyReflection", scope = "shared", type = "check", label = "Enemy hit by Misty Reflection?", ifSkill = "Misty Reflection", tooltip = "Misty Reflection debuff lasts 4 seconds and makes enemies have:\n\t30% increased Damage Taken\n\tDeal 30% less Damage", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:MistyReflection", "FLAG", true, "Config") end }, { label = "Momentum:", ifSkill = "Momentum" }, @@ -774,7 +775,7 @@ return { modList:NewMod("SkillData", "LIST", { key = "VaalMoltenShellDamageMitigated", value = val }, "Config", { type = "SkillName", skillName = "Molten Shell" }) end }, { label = "Multi-part area skills:", ifSkill = { "Seismic Trap", "Lightning Spire Trap", "Explosive Trap", "Molten Strike", "Ball Lightning" }, includeTransfigured = true }, - { var = "enemySizePreset", type = "list", label = "Enemy size preset:", ifSkill = { "Seismic Trap", "Lightning Spire Trap", "Explosive Trap", "Molten Strike", "Ball Lightning" }, includeTransfigured = true, defaultIndex = 2, tooltip = [[ + { var = "enemySizePreset", scope = "shared", type = "list", label = "Enemy size preset:", ifSkill = { "Seismic Trap", "Lightning Spire Trap", "Explosive Trap", "Molten Strike", "Ball Lightning" }, includeTransfigured = true, defaultIndex = 2, tooltip = [[ Configure the radius of an enemy hitbox which is used in calculating some area multi-hitting (shotgunning) effects. Small sets the radius to 2. @@ -799,7 +800,7 @@ Huge sets the radius to 11. modList:NewMod("EnemyRadius", "BASE", 11, "Config") end end }, - { var = "enemyRadius", type = "integer", label = "Enemy radius:", ifSkill = { "Seismic Trap", "Lightning Spire Trap", "Explosive Trap", "Molten Strike", "Ball Lightning" }, includeTransfigured = true, tooltip = "Configure the radius of an enemy hitbox to calculate some area overlapping (shotgunning) effects.", apply = function(val, modList, enemyModList) + { var = "enemyRadius", scope = "shared", type = "integer", label = "Enemy radius:", ifSkill = { "Seismic Trap", "Lightning Spire Trap", "Explosive Trap", "Molten Strike", "Ball Lightning" }, includeTransfigured = true, tooltip = "Configure the radius of an enemy hitbox to calculate some area overlapping (shotgunning) effects.", apply = function(val, modList, enemyModList) modList:NewMod("EnemyRadius", "OVERRIDE", m_max(val, 1), "Config") end }, { var = "TotalMinionLife", type = "integer", label = "Minion Life override:", ifMod = "takenFromMinionBeforeYou", tooltip = "Overrides the automatically calculated Life of the minion supported by Companionship.", apply = function(val, modList, enemyModList) @@ -834,7 +835,7 @@ Huge sets the radius to 11. { var = "balanceOfTerrorSelfCastTemporalChains", type = "check", label = "Temporal Chains self-only", ifSkill = "Temporal Chains", ifCond = "SelfCastTemporalChains", tooltip = "Counts Temporal Chains as self-cast for Balance of Terror without applying it to enemies." }, { var = "balanceOfTerrorSelfCastVulnerability", type = "check", label = "Vulnerability self-only", ifSkill = "Vulnerability", ifCond = "SelfCastVulnerability", tooltip = "Counts Vulnerability as self-cast for Balance of Terror without applying it to enemies." }, -- Section: Map modifiers/curses - { section = "Map Modifiers and Player Debuffs", col = 2 }, + { section = "Map Modifiers and Player Debuffs", col = 2, scope = "shared" }, { var = "multiplierSextant", type = "count", label = "# of Sextants affecting the area", ifMult = "Sextant", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:Sextant", "BASE", m_min(val, 5), "Config") end }, @@ -855,48 +856,48 @@ Huge sets the radius to 11. modList:NewMod("HasPvpScaling", "FLAG", true, "Config") end }, { label = "Player is cursed by:" }, - { var = "playerCursedWithAssassinsMark", type = "count", label = "Assassin's Mark:", tooltip = "Sets the level of Assassin's Mark to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithAssassinsMark", scope = "actor", type = "count", label = "Assassin's Mark:", tooltip = "Sets the level of Assassin's Mark to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "AssassinsMark", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithConductivity", type = "count", label = "Conductivity:", tooltip = "Sets the level of Conductivity to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithConductivity", scope = "actor", type = "count", label = "Conductivity:", tooltip = "Sets the level of Conductivity to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "Conductivity", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithDespair", type = "count", label = "Despair:", tooltip = "Sets the level of Despair to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithDespair", scope = "actor", type = "count", label = "Despair:", tooltip = "Sets the level of Despair to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "Despair", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithElementalWeakness", type = "count", label = "Elemental Weakness:", tooltip = "Sets the level of Elemental Weakness to apply to the player.\nIn mid tier maps, 'of Elemental Weakness' applies level 10.\nIn high tier maps, 'of Elemental Weakness' applies level 15.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithElementalWeakness", scope = "actor", type = "count", label = "Elemental Weakness:", tooltip = "Sets the level of Elemental Weakness to apply to the player.\nIn mid tier maps, 'of Elemental Weakness' applies level 10.\nIn high tier maps, 'of Elemental Weakness' applies level 15.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "ElementalWeakness", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithEnfeeble", type = "count", label = "Enfeeble:", tooltip = "Sets the level of Enfeeble to apply to the player.\nIn mid tier maps, 'of Enfeeblement' applies level 10.\nIn high tier maps, 'of Enfeeblement' applies level 15.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithEnfeeble", scope = "actor", type = "count", label = "Enfeeble:", tooltip = "Sets the level of Enfeeble to apply to the player.\nIn mid tier maps, 'of Enfeeblement' applies level 10.\nIn high tier maps, 'of Enfeeblement' applies level 15.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "Enfeeble", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithFlammability", type = "count", label = "Flammability:", tooltip = "Sets the level of Flammability to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithFlammability", scope = "actor", type = "count", label = "Flammability:", tooltip = "Sets the level of Flammability to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "Flammability", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithFrostbite", type = "count", label = "Frostbite:", tooltip = "Sets the level of Frostbite to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithFrostbite", scope = "actor", type = "count", label = "Frostbite:", tooltip = "Sets the level of Frostbite to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "Frostbite", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithPoachersMark", type = "count", label = "Poacher's Mark:", tooltip = "Sets the level of Poacher's Mark to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithPoachersMark", scope = "actor", type = "count", label = "Poacher's Mark:", tooltip = "Sets the level of Poacher's Mark to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "PoachersMark", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithProjectileWeakness", type = "count", label = "Projectile Weakness:", tooltip = "Sets the level of Projectile Weakness to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithProjectileWeakness", scope = "actor", type = "count", label = "Projectile Weakness:", tooltip = "Sets the level of Projectile Weakness to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "ProjectileWeakness", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithPunishment", type = "count", label = "Punishment:", tooltip = "Sets the level of Punishment to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithPunishment", scope = "actor", type = "count", label = "Punishment:", tooltip = "Sets the level of Punishment to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "Punishment", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithTemporalChains", type = "count", label = "Temporal Chains:", tooltip = "Sets the level of Temporal Chains to apply to the player.\nIn mid tier maps, 'of Temporal Chains' applies level 10.\nIn high tier maps, 'of Temporal Chains' applies level 15.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithTemporalChains", scope = "actor", type = "count", label = "Temporal Chains:", tooltip = "Sets the level of Temporal Chains to apply to the player.\nIn mid tier maps, 'of Temporal Chains' applies level 10.\nIn high tier maps, 'of Temporal Chains' applies level 15.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "TemporalChains", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithVulnerability", type = "count", label = "Vulnerability:", tooltip = "Sets the level of Vulnerability to apply to the player.\nIn mid tier maps, 'of Vulnerability' applies level 10.\nIn high tier maps, 'of Vulnerability' applies level 15.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithVulnerability", scope = "actor", type = "count", label = "Vulnerability:", tooltip = "Sets the level of Vulnerability to apply to the player.\nIn mid tier maps, 'of Vulnerability' applies level 10.\nIn high tier maps, 'of Vulnerability' applies level 15.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "Vulnerability", level = val, applyToPlayer = true }) end }, - { var = "playerCursedWithWarlordsMark", type = "count", label = "Warlord's Mark:", tooltip = "Sets the level of Warlord's Mark to apply to the player.", apply = function(val, modList, enemyModList) + { var = "playerCursedWithWarlordsMark", scope = "actor", type = "count", label = "Warlord's Mark:", tooltip = "Sets the level of Warlord's Mark to apply to the player.", apply = function(val, modList, enemyModList) modList:NewMod("ExtraCurse", "LIST", { skillId = "WarlordsMark", level = val, applyToPlayer = true }) end }, -- Section: Combat options - { section = "When In Combat", col = 1 }, + { section = "When In Combat", col = 1, scope = "actor" }, { var = "usePowerCharges", type = "check", label = "Do you use Power Charges?", apply = function(val, modList, enemyModList) modList:NewMod("UsePowerCharges", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, @@ -1235,7 +1236,7 @@ Huge sets the radius to 11. modList:NewMod("Multiplier:NearbyEnemies", "BASE", val, "Config", { type = "Condition", var = "Combat" }) modList:NewMod("Condition:OnlyOneNearbyEnemy", "FLAG", val == 1, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierNearbyRareOrUniqueEnemies", type = "countAllowZero", label = "# of nearby Rare or Unique Enemies:", ifMult = "NearbyRareOrUniqueEnemies", apply = function(val, modList, enemyModList) + { var = "multiplierNearbyRareOrUniqueEnemies", type = "countAllowZero", label = "# of nearby Rare or Unique Enemies:", ifMult = "NearbyRareOrUniqueEnemies", scope = "shared", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:NearbyRareOrUniqueEnemies", "BASE", val, "Config", { type = "Condition", var = "Combat" }) modList:NewMod("Multiplier:NearbyEnemies", "BASE", val, "Config", { type = "Condition", var = "Combat" }) modList:NewMod("Condition:AtMostOneNearbyRareOrUniqueEnemy", "FLAG", val <= 1, "Config", { type = "Condition", var = "Combat" }) @@ -1483,7 +1484,7 @@ Huge sets the radius to 11. { var = "buffHerEmbrace", type = "check", label = "Are you in Her Embrace?", ifCond = "HerEmbrace", tooltip = "This option is specific to Oni-Goroshi.", apply = function(val, modList, enemyModList) modList:NewMod("HerEmbrace", "FLAG", true, "Config", { type = "Condition", var = "Combat" }, { type = "Condition", var = "CanGainHerEmbrace" }) end }, - { var = "conditionChampionIntimidate", type = "check", label = "Is Champion's Intimidate active?", ifEnemyCond = "ChampionIntimidate", defaultState = true, apply = function(val, modList, enemyModList) + { var = "conditionChampionIntimidate", type = "check", label = "Is Champion's Intimidate active?", ifEnemyCond = "ChampionIntimidate", enemyState = "source", defaultState = true, apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:ChampionIntimidate", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, { var = "conditionUsedSkillRecently", type = "check", label = "Have you used a Skill Recently?", ifCond = "UsedSkillRecently", apply = function(val, modList, enemyModList) @@ -1648,13 +1649,13 @@ Huge sets the radius to 11. { var = "conditionImpaledRecently", type = "check", ifCond = "ImpaledRecently", label = "Impaled an enemy recently?", apply = function(val, modList, enemyModLIst) modList:NewMod("Condition:ImpaledRecently", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierImpalesOnEnemy", type = "countAllowZero", label = "# of Impales on enemy (if not maximum):", ifFlag = "impale", apply = function(val, modList, enemyModList) + { var = "multiplierImpalesOnEnemy", scope = "shared", type = "countAllowZero", label = "# of Impales on enemy (if not maximum):", ifFlag = "impale", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:ImpaleStacks", "BASE", val, "Config", { type = "Condition", var = "Combat" }) end }, { var = "conditionCausedBleedingRecently", type = "check", label = "Have you caused ^xE05030Bleeding ^7Recently?", ifCond = "CausedBleedingRecently", apply = function(val, modList, enemyModList) modList:NewMod("Condition:CausedBleedingRecently", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierBleedsOnEnemy", type = "count", label = "# of Bleeds on enemy (if not maximum):", ifFlag = "Condition:HaveCrimsonDance", tooltip = "Sets current number of Bleeds on the enemy if using the Crimson Dance keystone.\nThis also implies that the enemy is Bleeding.", apply = function(val, modList, enemyModList) + { var = "multiplierBleedsOnEnemy", scope = "shared", type = "count", label = "# of Bleeds on enemy (if not maximum):", ifFlag = "Condition:HaveCrimsonDance", tooltip = "Sets current number of Bleeds on the enemy if using the Crimson Dance keystone.\nThis also implies that the enemy is Bleeding.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:BleedStacks", "BASE", val, "Config", { type = "Condition", var = "Combat" }) enemyModList:NewMod("Condition:Bleeding", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, @@ -1776,7 +1777,7 @@ Huge sets the radius to 11. modList:NewMod("Condition:BloodShrineOfBats", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, -- Section: Effective DPS options - { section = "For Effective DPS", col = 1 }, + { section = "For Effective DPS", col = 1, scope = "actor" }, { var = "skillForkCount", type = "count", label = "# of times Skill has Forked:", ifFlag = "forking", apply = function(val, modList, enemyModList) modList:NewMod("ForkedCount", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, @@ -1791,25 +1792,25 @@ Huge sets the radius to 11. { var = "conditionAtCloseRange", type = "check", label = "Is the enemy at Close Range?", ifCond = "AtCloseRange", apply = function(val, modList, enemyModList) modList:NewMod("Condition:AtCloseRange", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "enemyMultiplierEnemyPresenceSeconds", type = "count", label = "Enemy in Your Presence Duration", tooltip = "Number of seconds the enemy has been in your presence.", ifEnemyMult = "EnemyPresenceSeconds", apply = function(val, modList, enemyModList) + { var = "enemyMultiplierEnemyPresenceSeconds", scope = "shared", type = "count", label = "Enemy in Your Presence Duration", tooltip = "Number of seconds the enemy has been in your presence.", ifEnemyMult = "EnemyPresenceSeconds", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:EnemyPresenceSeconds", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyMoving", type = "check", label = "Is the enemy Moving?", ifMod = "BleedChance", apply = function(val, modList, enemyModList) + { var = "conditionEnemyMoving", scope = "shared", type = "check", label = "Is the enemy Moving?", ifMod = "BleedChance", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Moving", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyFullLife", type = "check", label = "Is the enemy on Full ^xE05030Life?", ifEnemyCond = "FullLife", apply = function(val, modList, enemyModList) + { var = "conditionEnemyFullLife", scope = "shared", type = "check", label = "Is the enemy on Full ^xE05030Life?", ifEnemyCond = "FullLife", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:FullLife", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyLowLife", type = "check", label = "Is the enemy on Low ^xE05030Life?", ifEnemyCond = "LowLife", apply = function(val, modList, enemyModList) + { var = "conditionEnemyLowLife", scope = "shared", type = "check", label = "Is the enemy on Low ^xE05030Life?", ifEnemyCond = "LowLife", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:LowLife", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyCursed", type = "check", label = "Is the enemy Cursed?", ifEnemyCond = "Cursed", tooltip = "The enemy will automatically be considered to be Cursed if you have at least one curse enabled,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyCursed", scope = "shared", type = "check", label = "Is the enemy Cursed?", ifEnemyCond = "Cursed", enemyState = "encounter", tooltip = "The enemy will automatically be considered to be Cursed if you have at least one curse enabled,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Cursed", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyStunned", type = "check", label = "Is the enemy Stunned?", ifEnemyCond = "Stunned", apply = function(val, modList, enemyModList) + { var = "conditionEnemyStunned", scope = "shared", type = "check", label = "Is the enemy Stunned?", ifEnemyCond = "Stunned", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Stunned", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyBleeding", type = "check", label = "Is the enemy Bleeding?", ifEnemyCond = "Bleeding", apply = function(val, modList, enemyModList) + { var = "conditionEnemyBleeding", scope = "shared", type = "check", label = "Is the enemy Bleeding?", ifEnemyCond = "Bleeding", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Bleeding", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, { var = "overrideBleedStackPotential", type = "count", label = "Bleed Stack Potential override:", ifOption = "conditionEnemyBleeding", tooltip = "Allows you to manually set the Stack Potential value for a skill.\nStack Potential equates to the number of times you are able to inflict a Bleed on an enemy before the duration of your first Bleed expires", apply = function(val, modList, enemyModList) @@ -1818,177 +1819,179 @@ Huge sets the radius to 11. { var = "conditionSingleBleed", type = "check", label = "Cap to Single Bleed on enemy?", ifCond = "SingleBleed", tooltip = "This is for Blood Sap Tincture, but will limit you to only applying a single Bleed on the enemy", apply = function(val, modList, enemyModList) modList:NewMod("Condition:SingleBleed", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierRuptureStacks", type = "count", label = "# of Rupture stacks?", ifFlag = "Condition:CanInflictRupture", tooltip = "Rupture applies more bleed damage and faster bleeds for 3 seconds, up to 4 stacks", apply = function(val, modList, enemyModList) + { var = "multiplierRuptureStacks", type = "count", label = "# of Rupture stacks?", ifFlag = "Condition:CanInflictRupture", scope = "shared", tooltip = "Rupture applies more bleed damage and faster bleeds for 3 seconds, up to 4 stacks", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:RuptureStack", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyPoisoned", type = "check", label = "Is the enemy Poisoned?", ifEnemyCond = "Poisoned", apply = function(val, modList, enemyModList) + { var = "conditionEnemyPoisoned", scope = "shared", type = "check", label = "Is the enemy Poisoned?", ifEnemyCond = "Poisoned", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Poisoned", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierPoisonOnEnemy", type = "count", label = "# of Poison on enemy:", ifEnemyMult = "PoisonStack", implyCond = "Poisoned", apply = function(val, modList, enemyModList) + { var = "multiplierPoisonOnEnemy", scope = "shared", type = "count", label = "# of Poison on enemy:", ifEnemyMult = "PoisonStack", enemyState = "encounter", implyCond = "Poisoned", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:PoisonStack", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, { var = "conditionNonPoisonedOnly", type = "check", label = "Is the enemy non-Poisoned?", ifCond = "NonPoisonedOnly", tooltip = "This is for low tolerance, but will limit you to only applying poison a single time\n^8(Note that you can still apply multiple stacks via 'inflict additional poison' mods)^7", apply = function(val, modList, enemyModList) modList:NewMod("Condition:NonPoisonedOnly", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierCurseExpiredOnEnemy", type = "count", label = "#% of Curse Expired on enemy:", ifEnemyMult = "CurseExpired", apply = function(val, modList, enemyModList) + { var = "multiplierCurseExpiredOnEnemy", scope = "shared", type = "count", label = "#% of Curse Expired on enemy:", ifEnemyMult = "CurseExpired", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:CurseExpired", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierCurseDurationExpiredOnEnemy", type = "count", label = "Curse Duration Expired on enemy:", ifEnemyMult = "CurseDurationExpired", apply = function(val, modList, enemyModList) + { var = "multiplierCurseDurationExpiredOnEnemy", scope = "shared", type = "count", label = "Curse Duration Expired on enemy:", ifEnemyMult = "CurseDurationExpired", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:CurseDurationExpired", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierWitheredStackCount", type = "count", label = "# of Withered Stacks:", ifFlag = "Condition:CanWither", tooltip = "Withered applies 6% increased ^xD02090Chaos ^7Damage Taken to the enemy, up to 15 stacks.", apply = function(val, modList, enemyModList) + { var = "multiplierWitheredStackCount", type = "count", label = "# of Withered Stacks:", ifFlag = "Condition:CanWither", scope = "shared", tooltip = "Withered applies 6% increased ^xD02090Chaos ^7Damage Taken to the enemy, up to 15 stacks.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:WitheredStack", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierCorrosionStackCount", type = "count", label = "# of Corrosion Stacks:", ifFlag = "Condition:CanCorrode", tooltip = "Each stack of Corrosion applies -5000 to total Armour and -1000 to total ^x33FF77Evasion Rating ^7to the enemy.\nCorrosion lasts 4 seconds and refreshes the duration of existing Corrosion stacks\nCorrosion has no stack limit", apply = function(val, modList, enemyModList) + { var = "multiplierCorrosionStackCount", type = "count", label = "# of Corrosion Stacks:", ifFlag = "Condition:CanCorrode", scope = "shared", tooltip = "Each stack of Corrosion applies -5000 to total Armour and -1000 to total ^x33FF77Evasion Rating ^7to the enemy.\nCorrosion lasts 4 seconds and refreshes the duration of existing Corrosion stacks\nCorrosion has no stack limit", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:CorrosionStack", "BASE", val, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Armour", "BASE", -5000, "Corrosion", { type = "Multiplier", var = "CorrosionStack" }, { type = "ActorCondition", actor = "enemy", var = "CanCorrode" }) enemyModList:NewMod("Evasion", "BASE", -1000, "Corrosion", { type = "Multiplier", var = "CorrosionStack" }, { type = "ActorCondition", actor = "enemy", var = "CanCorrode" }) end }, - { var = "multiplierEnsnaredStackCount", type = "count", label = "# of Ensnare Stacks:", ifSkill = "Ensnaring Arrow", tooltip = "While ensnared, enemies take increased Projectile Damage from Attack Hits\nEnsnared enemies always count as moving, and have less movement speed while trying to break the snare.", apply = function(val, modList, enemyModList) + { var = "multiplierEnsnaredStackCount", type = "count", label = "# of Ensnare Stacks:", ifSkill = "Ensnaring Arrow", scope = "shared", tooltip = "While ensnared, enemies take increased Projectile Damage from Attack Hits\nEnsnared enemies always count as moving, and have less movement speed while trying to break the snare.", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:EnsnareStackCount", "BASE", val, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:Moving", "FLAG", true, "Config", { type = "MultiplierThreshold", actor = "enemy", var = "EnsnareStackCount", threshold = 1 }) end }, - { var = "conditionEnemyMaimed", type = "check", label = "Is the enemy Maimed?", ifEnemyCond = "Maimed", apply = function(val, modList, enemyModList) + { var = "conditionEnemyMaimed", scope = "shared", type = "check", label = "Is the enemy Maimed?", ifEnemyCond = "Maimed", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Maimed", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyHindered", type = "check", label = "Is the enemy Hindered?", ifEnemyCond = "Hindered", apply = function(val, modList, enemyModList) + { var = "conditionEnemyHindered", scope = "shared", type = "check", label = "Is the enemy Hindered?", ifEnemyCond = "Hindered", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Hindered", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyExcommunicated", type = "check", label = "Is the enemy Excommunicated?", ifFlag = "Condition:CanExcommunicate", tooltip = "Excommunicated Enemies cannot deal ^xD02090Chaos ^7Damage.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyExcommunicated", scope = "shared", type = "check", label = "Is the enemy Excommunicated?", ifFlag = "Condition:CanExcommunicate", tooltip = "Excommunicated Enemies cannot deal ^xD02090Chaos ^7Damage.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Excommunicated", "FLAG", true, "Config", { type = "ActorCondition", actor = "enemy", var = "CanExcommunicate" }) end }, - { var = "conditionEnemyBlinded", type = "check", label = "Is the enemy Blinded?", tooltip = "In addition to allowing 'against Blinded Enemies' modifiers to apply,\n Blind applies the following effects.\n -20% Accuracy \n -20% ^x33FF77Evasion", apply = function(val, modList, enemyModList) + { var = "conditionEnemyBlinded", scope = "shared", type = "check", label = "Is the enemy Blinded?", tooltip = "In addition to allowing 'against Blinded Enemies' modifiers to apply,\n Blind applies the following effects.\n -20% Accuracy \n -20% ^x33FF77Evasion", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Blinded", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "overrideBuffBlinded", type = "count", label = "Effect of Blind (if not maximum):", ifOption = "conditionEnemyBlinded", tooltip = "If you have a guaranteed source of Blind, the strongest one will apply.", apply = function(val, modList, enemyModList) + { var = "overrideBuffBlinded", type = "count", label = "Effect of Blind (if not maximum):", ifOption = "conditionEnemyBlinded", scope = "shared", tooltip = "If you have a guaranteed source of Blind, the strongest one will apply.", apply = function(val, modList, enemyModList) enemyModList:NewMod("BlindEffect", "OVERRIDE", val, "Config", {type = "GlobalEffect", effectType = "Buff" }) end }, - { var = "conditionEnemyTaunted", type = "check", label = "Is the enemy Taunted?", ifEnemyCond = "Taunted", apply = function(val, modList, enemyModList) + { var = "conditionEnemyTaunted", scope = "shared", type = "check", label = "Is the enemy Taunted?", ifEnemyCond = "Taunted", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Taunted", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyDebilitated", type = "check", label = "Is the enemy Debilitated?", ifMod = "DebilitateChance", tooltip = "Debilitated enemies deal 10% less damage.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyDebilitated", scope = "shared", type = "check", label = "Is the enemy Debilitated?", ifMod = "DebilitateChance", tooltip = "Debilitated enemies deal 10% less damage.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Debilitated", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyPacified", type = "check", label = "Is the enemy Pacified?", ifSkill = "Pacify", tooltip = "Enemies are Pacified after 60% of Pacify's duration has expired", apply = function(val, modList, enemyModList) + { var = "conditionEnemyPacified", scope = "shared", type = "check", label = "Is the enemy Pacified?", ifSkill = "Pacify", tooltip = "Enemies are Pacified after 60% of Pacify's duration has expired", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Pacified", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyBurning", type = "check", label = "Is the enemy ^xB97123Burning?", ifEnemyCond = "Burning", apply = function(val, modList, enemyModList) + { var = "conditionEnemyBurning", scope = "shared", type = "check", label = "Is the enemy ^xB97123Burning?", ifEnemyCond = "Burning", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Burning", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyIgnited", type = "check", label = "Is the enemy ^xB97123Ignited?", ifEnemyCond = "Ignited", implyCond = "Burning", tooltip = "This also implies that the enemy is ^xB97123Burning.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyIgnited", scope = "shared", type = "check", label = "Is the enemy ^xB97123Ignited?", ifEnemyCond = "Ignited", enemyState = "encounter", implyCond = "Burning", tooltip = "This also implies that the enemy is ^xB97123Burning.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Ignited", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, { var = "overrideIgniteStackPotential", type = "count", label = "^xB97123Ignite^7 Stack Potential override:", ifOption = "conditionEnemyIgnited", tooltip = "Allows you to manually set the Stack Potential value for a skill.\nStack Potential equates to the number of times you are able to inflict an Ignite on an enemy before the duration of your first Ignite expires", apply = function(val, modList, enemyModList) modList:NewMod("IgniteStackPotentialOverride", "OVERRIDE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyScorched", type = "check", ifFlag = "inflictScorch", label = "Is the enemy ^xB97123Scorched?", tooltip = "^xB97123Scorched ^7enemies have lowered elemental resistances, up to -30%.\nThis option will also allow you to input the effect of ^xB97123Scorched.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyScorched", scope = "shared", type = "check", ifFlag = "inflictScorch", label = "Is the enemy ^xB97123Scorched?", tooltip = "^xB97123Scorched ^7enemies have lowered elemental resistances, up to -30%.\nThis option will also allow you to input the effect of ^xB97123Scorched.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Scorched", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:ScorchedConfig", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionScorchedEffect", type = "count", label = "Effect of ^xB97123Scorched:", ifOption = "conditionEnemyScorched", tooltip = "This effect will only be applied while you can inflict ^xB97123Scorched.", apply = function(val, modList, enemyModList) + { var = "conditionScorchedEffect", type = "count", label = "Effect of ^xB97123Scorched:", ifOption = "conditionEnemyScorched", scope = "shared", tooltip = "This effect will only be applied while you can inflict ^xB97123Scorched.", apply = function(val, modList, enemyModList) enemyModList:NewMod("ScorchVal", "BASE", val, "Config", { type = "Condition", var = "ScorchedConfig" }) enemyModList:NewMod("DesiredScorchVal", "BASE", val, "Scorch", { type = "Condition", var = "ScorchedConfig", neg = true }) end }, - { var = "ScorchStacks", type = "integer", label = "^xB97123Scorch ^7Stacks", ifFlag = "ScorchCanStack", ifOption = "conditionEnemyScorched", defaultPlaceholderState = 1, tooltip = "Amount of stacks of ^xB97123Scorch ^7applied to the enemy.", apply = function(val, modList, enemyModList) + { var = "ScorchStacks", scope = "shared", type = "integer", label = "^xB97123Scorch ^7Stacks", ifFlag = "ScorchCanStack", ifOption = "conditionEnemyScorched", defaultPlaceholderState = 1, tooltip = "Amount of stacks of ^xB97123Scorch ^7applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:ScorchStacks", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyOnScorchedGround", type = "check", label = "Is the enemy on ^xB97123Scorched ^7Ground?", tooltip = "This also implies that the enemy is ^xB97123Scorched.", ifEnemyCond = "OnScorchedGround", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnScorchedGround", scope = "shared", type = "check", label = "Is the enemy on ^xB97123Scorched ^7Ground?", tooltip = "This also implies that the enemy is ^xB97123Scorched.", ifEnemyCond = "OnScorchedGround", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Scorched", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:OnScorchedGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyChilled", type = "check", label = "Is the enemy ^x3F6DB3Chilled?", apply = function(val, modList, enemyModList) + { var = "conditionEnemyChilled", scope = "shared", type = "check", label = "Is the enemy ^x3F6DB3Chilled?", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Chilled", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:ChilledConfig", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierChilledByYouSeconds", type = "count", label = "Seconds of chill on enemy?", ifEnemyCond = "ChilledByYou", apply = function(val, modList, enemyModList) + { var = "multiplierChilledByYouSeconds", type = "count", label = "Seconds of chill on enemy?", ifEnemyCond = "ChilledByYou", enemyState = "source", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:ChilledByYouSeconds", "BASE", val, "Config", { type = "Condition", var = "Combat" }) enemyModList:NewMod("Condition:ChilledByYou", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) + ConfigScope.addSourceEncounterFact(enemyModList, "Chilled") end }, - { var = "conditionEnemyChilledEffect", type = "count", label = "Effect of ^x3F6DB3Chill:", ifOption = "conditionEnemyChilled", apply = function(val, modList, enemyModList) + { var = "conditionEnemyChilledEffect", scope = "shared", type = "count", label = "Effect of ^x3F6DB3Chill:", ifOption = "conditionEnemyChilled", apply = function(val, modList, enemyModList) enemyModList:NewMod("ChillVal", "BASE", val, "Chill", { type = "Condition", var = "ChilledConfig" }) enemyModList:NewMod("DesiredChillVal", "BASE", val, "Chill", { type = "Condition", var = "ChilledConfig", neg = true }) end }, - { var = "conditionEnemyChilledByYourHits", type = "check", ifEnemyCond = "ChilledByYourHits", label = "Is the enemy ^x3F6DB3Chilled ^7by your Hits?", apply = function(val, modList, enemyModList) - enemyModList:NewMod("Condition:Chilled", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) + { var = "conditionEnemyChilledByYourHits", type = "check", ifEnemyCond = "ChilledByYourHits", enemyState = "source", label = "Is the enemy ^x3F6DB3Chilled ^7by your Hits?", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:ChilledByYourHits", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) + ConfigScope.addSourceEncounterFact(enemyModList, "Chilled") end }, - { var = "HoarfrostStacks", type = "count", label = "^x3F6DB3Hoarfrost ^7Stacks", ifFlag = "HitsCanInflictHoarfrost", tooltip = "Amount of stacks of ^x3F6DB3Hoarfrost ^7applied to the enemy.", apply = function(val, modList, enemyModList) + { var = "HoarfrostStacks", type = "count", label = "^x3F6DB3Hoarfrost ^7Stacks", ifFlag = "HitsCanInflictHoarfrost", scope = "shared", tooltip = "Amount of stacks of ^x3F6DB3Hoarfrost ^7applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("HoarfrostFreezeDuration", "INC", val * 20, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierBarnacleStacks", type = "count", label = "^x3F6DB3Barnacle ^7Stacks", ifFlag = "CanInflictBarnacles", tooltip = "Amount of stacks of ^x3F6DB3Barnacle ^7applied to the enemy.\n\n^8(Enemies affected by Barnacles Convert 5% of Physical Damage to Cold and have 5% increased duration of Chill and Freeze on them.\nEach instance of Barnacles lasts 30 seconds and can be inflicted up to 10 times)", apply = function(val, modList, enemyModList) + { var = "multiplierBarnacleStacks", type = "count", label = "^x3F6DB3Barnacle ^7Stacks", ifFlag = "CanInflictBarnacles", scope = "shared", tooltip = "Amount of stacks of ^x3F6DB3Barnacle ^7applied to the enemy.\n\n^8(Enemies affected by Barnacles Convert 5% of Physical Damage to Cold and have 5% increased duration of Chill and Freeze on them.\nEach instance of Barnacles lasts 30 seconds and can be inflicted up to 10 times)", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:BarnacleStack", "BASE", m_min(val, 10), "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("SelfFreezeDuration", "INC", 5, "Config", { type = "Multiplier", var = "BarnacleStack" }, { type = "Condition", var = "Effective" } ) enemyModList:NewMod("SelfChillDuration", "INC", 5, "Config", { type = "Multiplier", var = "BarnacleStack" }, { type = "Condition", var = "Effective" } ) enemyModList:NewMod("PhysicalDamageConvertToCold", "BASE", 5, "Config", { type = "Multiplier", var = "BarnacleStack" }, { type = "Condition", var = "Effective" } ) end }, - { var = "conditionEnemyFrozen", type = "check", label = "Is the enemy ^x3F6DB3Frozen?", ifEnemyCond = "Frozen", apply = function(val, modList, enemyModList) + { var = "conditionEnemyFrozen", scope = "shared", type = "check", label = "Is the enemy ^x3F6DB3Frozen?", ifEnemyCond = "Frozen", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Frozen", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierFrozenByYouSeconds", type = "count", label = "Seconds of freeze on enemy?", ifEnemyCond = "FrozenByYou", apply = function(val, modList, enemyModList) + { var = "multiplierFrozenByYouSeconds", type = "count", label = "Seconds of freeze on enemy?", ifEnemyCond = "FrozenByYou", enemyState = "source", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:FrozenByYouSeconds", "BASE", val, "Config", { type = "Condition", var = "Combat" }) enemyModList:NewMod("Condition:FrozenByYou", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) + ConfigScope.addSourceEncounterFact(enemyModList, "Frozen") end }, - { var = "conditionEnemyBrittle", type = "check", ifFlag = "inflictBrittle", label = "Is the enemy ^x3F6DB3Brittle?", tooltip = "Hits against ^x3F6DB3Brittle ^7enemies have up to +6% Critical Strike Chance.\nThis option will also allow you to input the effect of ^x3F6DB3Brittle.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyBrittle", scope = "shared", type = "check", ifFlag = "inflictBrittle", label = "Is the enemy ^x3F6DB3Brittle?", tooltip = "Hits against ^x3F6DB3Brittle ^7enemies have up to +6% Critical Strike Chance.\nThis option will also allow you to input the effect of ^x3F6DB3Brittle.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Brittle", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:BrittleConfig", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionBrittleEffect", type = "count", label = "Effect of ^x3F6DB3Brittle:", ifOption = "conditionEnemyBrittle", tooltip = "This effect will only be applied while you can inflict ^x3F6DB3Brittle.", apply = function(val, modList, enemyModList) + { var = "conditionBrittleEffect", type = "count", label = "Effect of ^x3F6DB3Brittle:", ifOption = "conditionEnemyBrittle", scope = "shared", tooltip = "This effect will only be applied while you can inflict ^x3F6DB3Brittle.", apply = function(val, modList, enemyModList) enemyModList:NewMod("BrittleVal", "BASE", val, "Config", { type = "Condition", var = "BrittleConfig" }) enemyModList:NewMod("DesiredBrittleVal", "BASE", val, "Brittle", { type = "Condition", var = "BrittleConfig", neg = true }) end }, - { var = "conditionEnemyOnBrittleGround", type = "check", label = "Is the enemy on ^xADAA47Brittle ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Brittle.", ifEnemyCond = "OnBrittleGround", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnBrittleGround", scope = "shared", type = "check", label = "Is the enemy on ^xADAA47Brittle ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Brittle.", ifEnemyCond = "OnBrittleGround", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Brittle", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:OnBrittleGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyShocked", type = "check", label = "Is the enemy ^xADAA47Shocked?", tooltip = "In addition to allowing any 'against ^xADAA47Shocked ^7Enemies' modifiers to apply,\nthis will allow you to input the effect of the ^xADAA47Shock ^7applied to the enemy.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyShocked", scope = "shared", type = "check", label = "Is the enemy ^xADAA47Shocked?", tooltip = "In addition to allowing any 'against ^xADAA47Shocked ^7Enemies' modifiers to apply,\nthis will allow you to input the effect of the ^xADAA47Shock ^7applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Shocked", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:ShockedConfig", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionShockEffect", type = "count", label = "Effect of ^xADAA47Shock:", ifOption = "conditionEnemyShocked", tooltip = "If you have a guaranteed source of ^xADAA47Shock^7,\nthe strongest one will apply instead unless this option would apply a stronger ^xADAA47Shock.", apply = function(val, modList, enemyModList) + { var = "conditionShockEffect", type = "count", label = "Effect of ^xADAA47Shock:", ifOption = "conditionEnemyShocked", scope = "shared", tooltip = "If you have a guaranteed source of ^xADAA47Shock^7,\nthe strongest one will apply instead unless this option would apply a stronger ^xADAA47Shock.", apply = function(val, modList, enemyModList) enemyModList:NewMod("ShockVal", "BASE", val, "Shock", { type = "Condition", var = "ShockedConfig" }) enemyModList:NewMod("DesiredShockVal", "BASE", val, "Shock", { type = "Condition", var = "ShockedConfig", neg = true }) end }, - { var = "ShockStacks", type = "count", label = "^xADAA47Shock ^7Stacks", ifFlag = "ShockCanStack", ifOption = "conditionEnemyShocked", defaultPlaceholderState = 1, tooltip = "Amount of stacks of ^xADAA47Shock ^7applied to the enemy.", apply = function(val, modList, enemyModList) + { var = "ShockStacks", scope = "shared", type = "count", label = "^xADAA47Shock ^7Stacks", ifFlag = "ShockCanStack", ifOption = "conditionEnemyShocked", defaultPlaceholderState = 1, tooltip = "Amount of stacks of ^xADAA47Shock ^7applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:ShockStacks", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyOnShockedGround", type = "check", label = "Is the enemy on ^xADAA47Shocked ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Shocked.", ifEnemyCond = "OnShockedGround", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnShockedGround", scope = "shared", type = "check", label = "Is the enemy on ^xADAA47Shocked ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Shocked.", ifEnemyCond = "OnShockedGround", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Shocked", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:OnShockedGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemySapped", type = "check", ifFlag = "inflictSap", label = "Is the enemy ^xADAA47Sapped?", tooltip = "^xADAA47Sapped ^7enemies deal less damage, up to 20%.", apply = function(val, modList, enemyModList) + { var = "conditionEnemySapped", scope = "shared", type = "check", ifFlag = "inflictSap", label = "Is the enemy ^xADAA47Sapped?", tooltip = "^xADAA47Sapped ^7enemies deal less damage, up to 20%.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Sapped", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:SappedConfig", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionSapEffect", type = "count", label = "Effect of ^xADAA47Sap:", ifOption = "conditionEnemySapped", tooltip = "If you have a guaranteed source of ^xADAA47Sap^7,\nthe strongest one will apply instead unless this option would apply a stronger ^xADAA47Sap.", apply = function(val, modList, enemyModList) + { var = "conditionSapEffect", type = "count", label = "Effect of ^xADAA47Sap:", ifOption = "conditionEnemySapped", scope = "shared", tooltip = "If you have a guaranteed source of ^xADAA47Sap^7,\nthe strongest one will apply instead unless this option would apply a stronger ^xADAA47Sap.", apply = function(val, modList, enemyModList) enemyModList:NewMod("SapVal", "BASE", val, "Sap", { type = "Condition", var = "SappedConfig" }) enemyModList:NewMod("DesiredSapVal", "BASE", val, "Sap", { type = "Condition", var = "SappedConfig", neg = true }) end }, - { var = "conditionEnemyOnSappedGround", type = "check", label = "Is the enemy on ^xADAA47Sapped ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Sapped.", ifEnemyCond = "OnSappedGround", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnSappedGround", scope = "shared", type = "check", label = "Is the enemy on ^xADAA47Sapped ^7Ground?", tooltip = "This also implies that the enemy is ^xADAA47Sapped.", ifEnemyCond = "OnSappedGround", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Sapped", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("Condition:OnSappedGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierFreezeShockIgniteOnEnemy", type = "count", label = "# of ^x3F6DB3Freeze ^7/ ^xADAA47Shock ^7/ ^xB97123Ignite ^7on enemy:", ifMult = "FreezeShockIgniteOnEnemy", apply = function(val, modList, enemyModList) + { var = "multiplierFreezeShockIgniteOnEnemy", scope = "shared", type = "count", label = "# of ^x3F6DB3Freeze ^7/ ^xADAA47Shock ^7/ ^xB97123Ignite ^7on enemy:", ifMult = "FreezeShockIgniteOnEnemy", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:FreezeShockIgniteOnEnemy", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyFireExposure", type = "check", label = "Is the enemy Exposed to ^xB97123Fire?", ifFlag = "applyFireExposure", tooltip = "This applies -10% ^xB97123Fire Resistance ^7to the enemy.", apply = function(val, modList, enemyModList) - enemyModList:NewMod("FireExposure", "BASE", -10, "Config", { type = "Condition", var = "Effective" }, { type = "ActorCondition", actor = "enemy", var = "CanApplyFireExposure" }) + { var = "conditionEnemyFireExposure", scope = "shared", type = "check", label = "Is the enemy Exposed to ^xB97123Fire?", ifFlag = "applyFireExposure", tooltip = "This applies -10% ^xB97123Fire Resistance ^7to the enemy.", apply = function(val, modList, enemyModList) + enemyModList:NewMod("FireExposure", "BASE", -10, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyColdExposure", type = "check", label = "Is the enemy Exposed to ^x3F6DB3Cold?", ifFlag = "applyColdExposure", tooltip = "This applies -10% ^x3F6DB3Cold Resistance ^7to the enemy.", apply = function(val, modList, enemyModList) - enemyModList:NewMod("ColdExposure", "BASE", -10, "Config", { type = "Condition", var = "Effective" }, { type = "ActorCondition", actor = "enemy", var = "CanApplyColdExposure" }) + { var = "conditionEnemyColdExposure", scope = "shared", type = "check", label = "Is the enemy Exposed to ^x3F6DB3Cold?", ifFlag = "applyColdExposure", tooltip = "This applies -10% ^x3F6DB3Cold Resistance ^7to the enemy.", apply = function(val, modList, enemyModList) + enemyModList:NewMod("ColdExposure", "BASE", -10, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyLightningExposure", type = "check", label = "Is the enemy Exposed to ^xADAA47Lightning?", ifFlag = "applyLightningExposure", tooltip = "This applies -10% ^xADAA47Lightning Resistance ^7to the enemy.", apply = function(val, modList, enemyModList) - enemyModList:NewMod("LightningExposure", "BASE", -10, "Config", { type = "Condition", var = "Effective" }, { type = "ActorCondition", actor = "enemy", var = "CanApplyLightningExposure" }) + { var = "conditionEnemyLightningExposure", scope = "shared", type = "check", label = "Is the enemy Exposed to ^xADAA47Lightning?", ifFlag = "applyLightningExposure", tooltip = "This applies -10% ^xADAA47Lightning Resistance ^7to the enemy.", apply = function(val, modList, enemyModList) + enemyModList:NewMod("LightningExposure", "BASE", -10, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyIntimidated", type = "check", label = "Is the enemy Intimidated?", tooltip = "Intimidated enemies take 10% increased Attack Damage.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyIntimidated", scope = "shared", type = "check", label = "Is the enemy Intimidated?", tooltip = "Intimidated enemies take 10% increased Attack Damage.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Intimidated", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyCrushed", type = "check", label = "Is the enemy Crushed?", tooltip = "Crushed enemies have 15% reduced Physical Damage Reduction.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyCrushed", scope = "shared", type = "check", label = "Is the enemy Crushed?", tooltip = "Crushed enemies have 15% reduced Physical Damage Reduction.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Crushed", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyHallowingFlame", type = "check", label = "Is enemy affected by Hallowing Flame?", ifFlag = "Condition:CanInflictHallowingFlame", apply = function(val, modList, enemyModList, build) + { var = "conditionEnemyHallowingFlame", scope = "shared", type = "check", label = "Is enemy affected by Hallowing Flame?", ifFlag = "Condition:CanInflictHallowingFlame", apply = function(val, modList, enemyModList, build) enemyModList:NewMod("Condition:HallowingFlame", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "multiplierEnemyHallowingFlame", type = "count", label = "Hallowing Flame stacks", ifOption = "conditionEnemyHallowingFlame", defaultPlaceholderState = 1, tooltip = "Amount of Hallowing Flame stacks applied to the enemy.", apply = function(val, modList, enemyModList) + { var = "multiplierEnemyHallowingFlame", type = "count", label = "Hallowing Flame stacks", ifOption = "conditionEnemyHallowingFlame", scope = "shared", defaultPlaceholderState = 1, tooltip = "Amount of Hallowing Flame stacks applied to the enemy.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Multiplier:HallowingFlame", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, { var = "multiplierHallowingFlameStacksRemovedByAlly", type = "countAllowZero", label = "Hallowing Flames removed by an ally recently", ifOption = "conditionEnemyHallowingFlame", ifMult = "HallowingFlameStacksRemovedByAlly", defaultPlaceholderState = 1, tooltip = "Amount of Hallowing Flame stacks removed from enemies by allies recently.", apply = function(val, modList, enemyModList) @@ -1997,25 +2000,25 @@ Huge sets the radius to 11. { var = "conditionHallowingFlameMagnitude", type = "countAllowZero", label = "Inc. magnitude of Hallowing Flame stacks", ifOption = "conditionEnemyHallowingFlame", tooltip = "The magnitude of Hallowing Flame stacks applied to the enemy", apply = function(val, modList, enemyModList) modList:NewMod("HallowingFlameMagnitude", "OVERRIDE", val, "Config") end }, - { var = "conditionNearLinkedTarget", type = "check", label = "Is the enemy near you Linked target?", ifEnemyCond = "NearLinkedTarget", apply = function(val, modList, enemyModList) + { var = "conditionNearLinkedTarget", type = "check", label = "Is the enemy near you Linked target?", ifEnemyCond = "NearLinkedTarget", enemyState = "source", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:NearLinkedTarget", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyUnnerved", type = "check", label = "Is the enemy Unnerved?", tooltip = "Unnerved enemies take 10% increased Spell Damage.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyUnnerved", scope = "shared", type = "check", label = "Is the enemy Unnerved?", tooltip = "Unnerved enemies take 10% increased Spell Damage.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Unnerved", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyCoveredInAsh", type = "check", label = "Is the enemy covered in Ash?", tooltip = "Covered in Ash applies the following to the enemy:\n\t20% increased ^xB97123Fire ^7Damage taken\n\t20% less Movement Speed", apply = function(val, modList, enemyModList) + { var = "conditionEnemyCoveredInAsh", scope = "shared", type = "check", label = "Is the enemy covered in Ash?", tooltip = "Covered in Ash applies the following to the enemy:\n\t20% increased ^xB97123Fire ^7Damage taken\n\t20% less Movement Speed", apply = function(val, modList, enemyModList) modList:NewMod("CoveredInAshEffect", "BASE", 20, "Covered in Ash") end }, - { var = "conditionEnemyCoveredInFrost", type = "check", label = "Is the enemy covered in Frost?", tooltip = "Covered in Frost applies the following to the enemy:\n\t20% increased ^x3F6DB3Cold ^7Damage taken\n\t50% less Critical Strike Chance", apply = function(val, modList, enemyModList) + { var = "conditionEnemyCoveredInFrost", scope = "shared", type = "check", label = "Is the enemy covered in Frost?", tooltip = "Covered in Frost applies the following to the enemy:\n\t20% increased ^x3F6DB3Cold ^7Damage taken\n\t50% less Critical Strike Chance", apply = function(val, modList, enemyModList) modList:NewMod("CoveredInFrostEffect", "BASE", 20, "Covered in Frost") end }, - { var = "conditionEnemyOnConsecratedGround", type = "check", label = "Is the enemy on Consecrated Ground?", ifEnemyCond = "OnConsecratedGround", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnConsecratedGround", scope = "shared", type = "check", label = "Is the enemy on Consecrated Ground?", ifEnemyCond = "OnConsecratedGround", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:OnConsecratedGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyHaveEnergyShield", type = "check", label = "Does the enemy have ^x88FFFFEnergy Shield^7?", ifEnemyCond = "HaveEnergyShield", apply = function(val, modList, enemyModList) + { var = "conditionEnemyHaveEnergyShield", scope = "shared", type = "check", label = "Does the enemy have ^x88FFFFEnergy Shield^7?", ifEnemyCond = "HaveEnergyShield", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:HaveEnergyShield", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyOnProfaneGround", type = "check", label = "Is the enemy on Profane Ground?", ifFlag = "Condition:CreateProfaneGround", tooltip = "Enemies on Profane Ground receive the following modifiers:\n\t10% increased Effect of Curses\n\t100% increased chance to be Critically Hit", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnProfaneGround", scope = "shared", type = "check", label = "Is the enemy on Profane Ground?", ifFlag = "Condition:CreateProfaneGround", tooltip = "Enemies on Profane Ground receive the following modifiers:\n\t10% increased Effect of Curses\n\t100% increased chance to be Critically Hit", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:OnProfaneGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("CurseEffectOnSelf", "INC", 10, "Config", { type = "Condition", var = "OnProfaneGround" }) enemyModList:NewMod("SelfCritChance", "INC", 100, "Config", { type = "Condition", var = "OnProfaneGround" }) @@ -2023,10 +2026,10 @@ Huge sets the radius to 11. { var = "multiplierEnemyAffectedByGraspingVines", type = "count", label = "# of Grasping Vines affecting enemy:", ifMult = "GraspingVinesAffectingEnemy", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:GraspingVinesAffectingEnemy", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyOnFungalGround", type = "check", label = "Is the enemy on Fungal Ground?", ifCond = { "OnFungalGround", "CreateFungalGround" }, tooltip = "Enemies on your Fungal Ground have -10% to all Resistances", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnFungalGround", scope = "shared", type = "check", label = "Is the enemy on Fungal Ground?", ifCond = { "OnFungalGround", "CreateFungalGround" }, tooltip = "Enemies on your Fungal Ground have -10% to all Resistances", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:OnFungalGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyOnBrineGround", type = "check", label = "Is the enemy on Brine Ground?", ifFlag = "CanCreateBrineGround", tooltip = "Enemies on your Brine Ground have \n30% increased effect of Lightning and Cold Ailments on them and \nhave 25% reduced Armour and Evasion Rating.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyOnBrineGround", scope = "shared", type = "check", label = "Is the enemy on Brine Ground?", ifFlag = "CanCreateBrineGround", tooltip = "Enemies on your Brine Ground have \n30% increased effect of Lightning and Cold Ailments on them and \nhave 25% reduced Armour and Evasion Rating.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:OnBrineGround", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) enemyModList:NewMod("SelfChillEffect", "INC", 30, "Config", { type = "Condition", var = "OnBrineGround" }) enemyModList:NewMod("SelfBrittleEffect", "INC", 30, "Config", { type = "Condition", var = "OnBrineGround" }) @@ -2036,41 +2039,41 @@ Huge sets the radius to 11. enemyModList:NewMod("Evasion", "INC", -25, "Config", { type = "Condition", var = "OnBrineGround" }) end }, - { var = "conditionEnemyInChillingArea", type = "check", label = "Is the enemy in a ^x3F6DB3Chilling ^7area?", ifEnemyCond = "InChillingArea", apply = function(val, modList, enemyModList) + { var = "conditionEnemyInChillingArea", scope = "shared", type = "check", label = "Is the enemy in a ^x3F6DB3Chilling ^7area?", ifEnemyCond = "InChillingArea", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:InChillingArea", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyInFrostGlobe", type = "check", label = "Is the enemy in the Frost Shield area?", ifEnemyCond = "EnemyInFrostGlobe", apply = function(val, modList, enemyModList) + { var = "conditionEnemyInFrostGlobe", scope = "shared", type = "check", label = "Is the enemy in the Frost Shield area?", ifEnemyCond = "EnemyInFrostGlobe", enemyState = "encounter", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:EnemyInFrostGlobe", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyLifeHigherThanPlayer", type = "check", label = "Is the enemy ^xE05030Life^7% higher than yours?", ifEnemyCond = "HigherLifePercentThanPlayer", apply = function(val, modList, enemyModList) + { var = "conditionEnemyLifeHigherThanPlayer", type = "check", label = "Is the enemy ^xE05030Life^7% higher than yours?", ifEnemyCond = "HigherLifePercentThanPlayer", enemyState = "source", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:HigherLifePercentThanPlayer", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "enemyConditionHitByFireDamage", type = "check", label = "Enemy was Hit by ^xB97123Fire ^7Damage?", ifFlag = "ElementalEquilibrium", apply = function(val, modList, enemyModList) + { var = "enemyConditionHitByFireDamage", type = "check", label = "Enemy was Hit by ^xB97123Fire ^7Damage?", ifFlag = "ElementalEquilibrium", enemyState = "source", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:HitByFireDamage", "FLAG", true, "Config") end }, - { var = "enemyConditionHitByColdDamage", type = "check", label = "Enemy was Hit by ^x3F6DB3Cold ^7Damage?", ifFlag = "ElementalEquilibrium", apply = function(val, modList, enemyModList) + { var = "enemyConditionHitByColdDamage", type = "check", label = "Enemy was Hit by ^x3F6DB3Cold ^7Damage?", ifFlag = "ElementalEquilibrium", enemyState = "source", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:HitByColdDamage", "FLAG", true, "Config") end }, - { var = "enemyConditionHitByLightningDamage", type = "check", label = "Enemy was Hit by ^xADAA47Light. ^7Damage?", ifFlag = "ElementalEquilibrium", apply = function(val, modList, enemyModList) + { var = "enemyConditionHitByLightningDamage", type = "check", label = "Enemy was Hit by ^xADAA47Light. ^7Damage?", ifFlag = "ElementalEquilibrium", enemyState = "source", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:HitByLightningDamage", "FLAG", true, "Config") end }, - { var = "enemyInRFOrScorchingRay", type = "check", label = "Is the enemy in RF or Scorching Ray:", ifCond = "InRFOrScorchingRay", ifSkill = { "Righteous Fire", "Scorching Ray" }, includeTransfigured = true, apply = function(val, modList, enemyModList) + { var = "enemyInRFOrScorchingRay", scope = "shared", type = "check", label = "Is the enemy in RF or Scorching Ray:", ifCond = "InRFOrScorchingRay", ifSkill = { "Righteous Fire", "Scorching Ray" }, includeTransfigured = true, apply = function(val, modList, enemyModList) modList:NewMod("Condition:InRFOrScorchingRay", "FLAG", true, "Config") end }, { var = "EEIgnoreHitDamage", type = "check", label = "Ignore Skill Hit Damage?", ifFlag = "ElementalEquilibrium", tooltip = "This option prevents EE from being reset by the hit damage of your main skill." }, - { var = "conditionBetweenYouAndLinkedTarget", type = "check", label = "Is the enemy in your Link beams?", ifEnemyCond = "BetweenYouAndLinkedTarget", tooltip = "This option sets whether an enemy is between you and your linked target.", apply = function(val, modList, enemyModList) + { var = "conditionBetweenYouAndLinkedTarget", type = "check", label = "Is the enemy in your Link beams?", ifEnemyCond = "BetweenYouAndLinkedTarget", enemyState = "source", tooltip = "This option sets whether an enemy is between you and your linked target.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:BetweenYouAndLinkedTarget", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "conditionEnemyFireResZero", type = "check", label = "Enemy hit you with ^xB97123Fire Damage^7?", ifFlag = "Condition:HaveTrickstersSmile", tooltip = "This option sets whether or not the enemy has hit you with ^xB97123Fire Damage^7 in the last 4 seconds.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyFireResZero", scope = "shared", type = "check", label = "Enemy hit you with ^xB97123Fire Damage^7?", ifFlag = "Condition:HaveTrickstersSmile", tooltip = "This option sets whether or not the enemy has hit you with ^xB97123Fire Damage^7 in the last 4 seconds.", apply = function(val, modList, enemyModList) enemyModList:NewMod("FireResist", "OVERRIDE", 0, "Config", { type = "Condition", var = "Effective"}, { type = "ActorCondition", actor = "enemy", var = "HaveTrickstersSmile" }) end }, - { var = "conditionEnemyColdResZero", type = "check", label = "Enemy hit you with ^x3F6DB3Cold Damage^7?", ifFlag = "Condition:HaveTrickstersSmile", tooltip = "This option sets whether or not the enemy has hit you with ^x3F6DB3Cold Damage^7 in the last 4 seconds.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyColdResZero", scope = "shared", type = "check", label = "Enemy hit you with ^x3F6DB3Cold Damage^7?", ifFlag = "Condition:HaveTrickstersSmile", tooltip = "This option sets whether or not the enemy has hit you with ^x3F6DB3Cold Damage^7 in the last 4 seconds.", apply = function(val, modList, enemyModList) enemyModList:NewMod("ColdResist", "OVERRIDE", 0, "Config", { type = "Condition", var = "Effective"}, { type = "ActorCondition", actor = "enemy", var = "HaveTrickstersSmile" }) end }, - { var = "conditionEnemyLightningResZero", type = "check", label = "Enemy hit you with ^xADAA47Light. Damage^7?", ifFlag = "Condition:HaveTrickstersSmile", tooltip = "This option sets whether or not the enemy has hit you with ^xADAA47Lightning Damage^7 in the last 4 seconds.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyLightningResZero", scope = "shared", type = "check", label = "Enemy hit you with ^xADAA47Light. Damage^7?", ifFlag = "Condition:HaveTrickstersSmile", tooltip = "This option sets whether or not the enemy has hit you with ^xADAA47Lightning Damage^7 in the last 4 seconds.", apply = function(val, modList, enemyModList) enemyModList:NewMod("LightningResist", "OVERRIDE", 0, "Config", { type = "Condition", var = "Effective"}, { type = "ActorCondition", actor = "enemy", var = "HaveTrickstersSmile" }) end }, - { var = "maniaDebuffsCount", type = "countAllowZero", label = "# of Mania Stacks", ifFlag = "Condition:CanInflictMania", defaultState = 15, tooltip = "Mania Stacks apply:\n\t4% inc Damage Taken per stack\n\t2% reduced Action Speed per stack\n\t10% reduced ^xE05030Life ^7and ^x88FFFFEnergy Shield ^7Recovery Rate per stack", apply = function(val, modList, enemyModList) + { var = "maniaDebuffsCount", type = "countAllowZero", label = "# of Mania Stacks", ifFlag = "Condition:CanInflictMania", scope = "shared", defaultState = 15, tooltip = "Mania Stacks apply:\n\t4% inc Damage Taken per stack\n\t2% reduced Action Speed per stack\n\t10% reduced ^xE05030Life ^7and ^x88FFFFEnergy Shield ^7Recovery Rate per stack", apply = function(val, modList, enemyModList) val = m_min(val, 15) enemyModList:NewMod("DamageTaken", "INC", val * 4, val.." Mania Stacks", { type = "GlobalEffect", effectType = "Debuff" }, { type = "Condition", var = "AfflictedByMania" }) enemyModList:NewMod("ActionSpeed", "INC", -val * 2, val.." Mania Stacks", { type = "GlobalEffect", effectType = "Debuff" }, { type = "Condition", var = "AfflictedByMania" }) @@ -2078,9 +2081,9 @@ Huge sets the radius to 11. enemyModList:NewMod("EnergyShieldRecoveryRate", "INC", -val * 10, val.." Mania Stacks", { type = "GlobalEffect", effectType = "Debuff" }, { type = "Condition", var = "AfflictedByMania" }) end }, -- Section: Enemy Stats - { section = "Enemy Stats", col = 3 }, + { section = "Enemy Stats", col = 3, scope = "shared" }, { var = "enemyLevel", type = "count", label = "Enemy Level:", tooltip = "This overrides the default enemy level used to estimate your hit and ^x33FF77evade ^7chance.\n\nThe default level for normal enemies and standard bosses is 83.\nTheir default level is capped by your character level.\n\nThe default level for pinnacle bosses is 84, and the default level for uber pinnacle bosses is 85.\nTheir default level is not capped by your character level." }, - { var = "conditionEnemyRareOrUnique", type = "check", label = "Is the enemy Rare or Unique?", ifEnemyCond = "EnemyRareOrUnique", tooltip = "The enemy will automatically be considered to be Unique if they are a Boss,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList) + { var = "conditionEnemyRareOrUnique", type = "check", label = "Is the enemy Rare or Unique?", ifEnemyCond = "EnemyRareOrUnique", enemyState = "encounter", tooltip = "The enemy will automatically be considered to be Unique if they are a Boss,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:RareOrUnique", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, { var = "enemyIsBoss", type = "list", label = "Is the enemy a Boss?", defaultIndex = 3, tooltip = data.enemyIsBossTooltip, list = {{val="None",label="No"},{val="Boss",label="Standard Boss"},{val="Pinnacle",label="Guardian/Pinnacle Boss"},{val="Uber",label="Uber Pinnacle Boss"}}, apply = function(val, modList, enemyModList, build) @@ -2376,5 +2379,5 @@ Huge sets the radius to 11. { var = "enemyChaosDamage", type = "countAllowZero", label = "Enemy Skill ^xD02090Chaos Damage:"}, -- Section: Custom mods - { section = "Custom Modifiers", col = 1 }, + { section = "Custom Modifiers", col = 1, scope = "actor" }, } diff --git a/src/Modules/ConfigScope.lua b/src/Modules/ConfigScope.lua new file mode 100644 index 00000000000..8ed08b87985 --- /dev/null +++ b/src/Modules/ConfigScope.lua @@ -0,0 +1,419 @@ +-- Path of Building +-- +-- Module: Config Scope +-- Classifies Configuration options as shared (encounter), actor, or player-only. +-- Enemy/encounter state is shared. Source attribution exists only for mechanics +-- whose wording depends on the originating actor ("by you", "you have inflicted", +-- source-specific hit conditions, and equivalent actor-sensitive semantics). +-- +-- Runtime bootstrap: Classes/ConfigTab.lua calls ConfigScope.index(ConfigOptions). +-- Querying before a successful index(), or looking up a name that was not indexed, +-- is an error. Legacy XML keys that are no longer in ConfigOptions should use tryForVar(). +-- +-- Options inherit their section's scope unless they set `scope` explicitly. Naming +-- heuristics still detect likely section overrides so a new option cannot silently +-- change actor vs encounter ownership; those cases require explicit metadata. +-- Enemy predicates (ifEnemyCond / ifEnemyMult / ifEnemyStat) and ByYou/ByYour +-- names likewise require explicit enemyState so a game update cannot silently +-- share a new source-owned condition. +-- +-- "ByYou" name matching is an index-time assertion only. Calculation reads +-- tag.sourceOwned, which parse/config stamping must set. ModStore does not +-- consult this module. +-- +local ConfigScope = { } + +local PLAYER_VARS = { + resistancePenalty = true, + bandit = true, + pantheonMajorGod = true, + pantheonMinorGod = true, + ignoreItemDisablers = true, + ignoreJewelLimits = true, +} + +-- Enemy conditions/multipliers whose wording establishes source ownership. +-- Each actor evaluates these against its own overlay; resulting encounter effects +-- (Shock, Exposure, increased damage taken, ...) are published to shared enemy state. +local SOURCE_OWNED_ENEMY_VARS = { + ChilledByYou = true, + ChilledByYourHits = true, + FrozenByYou = true, + ChilledByYouSeconds = true, + FrozenByYouSeconds = true, + BetweenYouAndLinkedTarget = true, + NearLinkedTarget = true, + ChampionIntimidate = true, + HigherLifePercentThanPlayer = true, + HitByFireDamage = true, + HitByColdDamage = true, + HitByLightningDamage = true, +} + +-- Actor flags that only apply while that actor's hits have chilled the enemy. +-- These mods do not tag ChilledByYourHits themselves, so usage must be implied +-- for Config visibility and overlay gating. +local CHILL_BY_HITS_EFFECT_FLAGS = { + ChillEffectIncDamageTaken = true, + ChillEffectIncColdDamageTaken = true, + ChillEffectLessDamageDealt = true, +} + +local scopeByVar = { } +local enemyStateByVar = { } +local indexedSourceOwned = { } +local indexed = false + +local SOURCE_OWNED_TAG_TYPES = { + Condition = true, + Multiplier = true, + MultiplierThreshold = true, + ActorCondition = true, +} + +local sourceOwnedNameCache = { } + +-- Runtime classification: explicit config metadata and the inherent source-owned +-- vocabulary. Does not match "ByYou" in names. +local function isExplicitSourceOwnedName(name) + return name and (SOURCE_OWNED_ENEMY_VARS[name] or indexedSourceOwned[name]) or false +end + +-- Index-time assertion: explicit names plus ByYou wording that still needs enemyState. +local function looksSourceOwnedName(name) + if not name then + return false + end + local cached = sourceOwnedNameCache[name] + if cached ~= nil then + return cached + end + -- "ByYou" is also a prefix of "ByYour". + local owned = isExplicitSourceOwnedName(name) or name:find("ByYou", 1, true) ~= nil + sourceOwnedNameCache[name] = owned + return owned +end + +local function anyLooksSourceOwned(value) + if type(value) == "table" then + for _, name in ipairs(value) do + if looksSourceOwnedName(name) then + return true + end + end + return false + end + return looksSourceOwnedName(value) +end + +local function anyExplicitSourceOwned(value) + if type(value) == "table" then + for _, name in ipairs(value) do + if isExplicitSourceOwnedName(name) then + return true + end + end + return false + end + return isExplicitSourceOwnedName(value) +end + +function ConfigScope.isSourceOwnedEnemyVar(var) + return isExplicitSourceOwnedName(var) +end + +function ConfigScope.isSourceOwnedEnemyMod(mod) + if not mod or not mod.name then + return false + end + if mod.sourceOwned == true then + return true + end + local var = mod.name:match("^Condition:(.+)$") or mod.name:match("^Multiplier:(.+)$") + return var and isExplicitSourceOwnedName(var) +end + +-- Stamp tag.sourceOwned on inherently source-owned predicates. Parser patterns +-- that wrap encounter names ("Ignited by you") already set the flag themselves. +function ConfigScope.stampSourceOwnedOnMod(mod) + if type(mod) ~= "table" then + return + end + for _, tag in ipairs(mod) do + if type(tag) == "table" and SOURCE_OWNED_TAG_TYPES[tag.type] and tag.sourceOwned == nil then + if anyExplicitSourceOwned(tag.var or tag.varList) then + tag.sourceOwned = true + end + end + end + local value = mod.value + if type(value) == "table" and value.mod then + ConfigScope.stampSourceOwnedOnMod(value.mod) + end +end + +function ConfigScope.stampSourceOwnedOnMods(mods) + if type(mods) ~= "table" then + return + end + for _, mod in ipairs(mods) do + ConfigScope.stampSourceOwnedOnMod(mod) + end +end + +-- Encounter statuses that "by you" mods query by the shared ailment name. +-- ModCache stamps sourceOwned on Condition:Ignited (etc.); the player overlay +-- must still see the config checkbox. Mercenary overlays do not copy these. +local ENCOUNTER_OVERLAY_VARS = { + Blinded = true, + Bleeding = true, + Burning = true, + Brittle = true, + Chilled = true, + ChillEffect = true, + Cursed = true, + CurseDurationExpired = true, + CurseExpired = true, + Debilitated = true, + Frozen = true, + Hindered = true, + Ignited = true, + ImpaleStacks = true, + Intimidated = true, + Maimed = true, + Marked = true, + Poisoned = true, + PoisonStack = true, + Sapped = true, + Scorched = true, + Shocked = true, + ShockEffect = true, + ["Spider's WebStack"] = true, + Taunted = true, + Unnerved = true, + Withered = true, + WitheredStack = true, +} + +function ConfigScope.shouldCopyEncounterOntoPlayerOverlay(mod) + if not mod or not mod.name or mod.skipEncounterOverlayCopy then + return false + end + local var = mod.name:match("^Condition:(.+)$") or mod.name:match("^Multiplier:(.+)$") + if not var then + return false + end + return isExplicitSourceOwnedName(var) or ENCOUNTER_OVERLAY_VARS[var] +end + +-- Source-owned options imply an encounter fact (one shared enemy is chilled/frozen) +-- and a source-owned copy for "by you" predicates. The shared half must not be +-- copied onto the player overlay or the other actor's "by you" mods would fire. +function ConfigScope.addSourceEncounterFact(enemyModList, conditionName) + local shared = modLib.createMod("Condition:"..conditionName, "FLAG", true, "Config", { type = "Condition", var = "Effective" }) + shared.skipEncounterOverlayCopy = true + enemyModList:AddMod(shared) + local owned = modLib.createMod("Condition:"..conditionName, "FLAG", true, "Config", { type = "Condition", var = "Effective" }) + owned.sourceOwned = true + enemyModList:AddMod(owned) +end + +function ConfigScope.impliesChilledByYourHits(modName) + return modName and CHILL_BY_HITS_EFFECT_FLAGS[modName] or false +end + +local VALID_ENEMY_STATE = { + source = true, + encounter = true, +} + +local VALID_SCOPE = { + shared = true, + actor = true, + player = true, +} + +local function requireIndexed() + if not indexed then + error("ConfigScope queried before index()") + end +end + +local function hasEnemyPredicate(varData) + return varData.ifEnemyCond or varData.ifEnemyMult or varData.ifEnemyStat +end + +local function looksSourceOwned(varData) + if anyLooksSourceOwned(varData.ifEnemyCond) or anyLooksSourceOwned(varData.ifEnemyMult) then + return true + end + local var = varData.var or "" + return var:find("ByYou", 1, true) ~= nil +end + +local function registerSourceOwned(value) + if type(value) == "table" then + for _, name in ipairs(value) do + if name then + indexedSourceOwned[name] = true + end + end + elseif value then + indexedSourceOwned[value] = true + end +end + +local function inferEnemyState(varData) + local sourceOwned = looksSourceOwned(varData) + if varData.enemyState then + if not VALID_ENEMY_STATE[varData.enemyState] then + error("ConfigScope: invalid enemyState '"..tostring(varData.enemyState).."' for "..tostring(varData.var)) + end + if sourceOwned and varData.enemyState ~= "source" then + error("ConfigScope: '"..tostring(varData.var).."' looks source-owned and cannot have enemyState '"..varData.enemyState.."'") + end + return varData.enemyState + end + if sourceOwned or hasEnemyPredicate(varData) then + error("ConfigScope: '"..tostring(varData.var).."' needs explicit enemyState") + end + return "encounter" +end + +-- Name/predicate hints that would pull an option off its section default. +-- Returning nil means "use the section scope". +local function heuristicScope(varData) + local var = varData.var or "" + if var:match("^playerCursed") then + return "actor" + end + if PLAYER_VARS[var] or var:match("^overrideEmpty") then + return "player" + end + if varData.ifEnemyCond or varData.ifEnemyMult or varData.ifEnemyStat + or var:match("^enemy") or var:match("^conditionEnemy") + or var:match("^MapPrefix") or var:match("^MapSuffix") + or var:match("^multiplierMap") or var == "multiplierSextant" or var == "PvpScaling" + or var:match("OnEnemy") or var == "ShockStacks" or var == "ScorchStacks" + then + return "shared" + end + return nil +end + +local function inferScope(varData, sectionScope) + if varData.scope and not VALID_SCOPE[varData.scope] then + error("ConfigScope: invalid scope '"..tostring(varData.scope).."' for "..tostring(varData.var)) + end + -- Source-owned enemy predicates are per-actor even if a section default is shared. + if inferEnemyState(varData) == "source" then + if varData.scope and varData.scope ~= "actor" then + error("ConfigScope: '"..tostring(varData.var).."' is source-owned and cannot have scope '"..varData.scope.."'") + end + return "actor" + end + if varData.scope then + return varData.scope + end + local guessed = heuristicScope(varData) + if guessed and guessed ~= sectionScope then + error("ConfigScope: '"..tostring(varData.var).."' needs explicit scope (heuristic '"..guessed.."' vs section '"..tostring(sectionScope).."')") + end + return sectionScope or "actor" +end + +function ConfigScope.index(varList) + indexed = false + scopeByVar = { } + enemyStateByVar = { } + indexedSourceOwned = { } + sourceOwnedNameCache = { } + if varList == nil then + error("ConfigScope.index requires a config option list") + end + local sectionScope = "actor" + for _, varData in ipairs(varList) do + if varData.section then + if not varData.scope then + error("ConfigScope: section '"..tostring(varData.section).."' needs explicit scope") + elseif not VALID_SCOPE[varData.scope] then + error("ConfigScope: invalid scope '"..tostring(varData.scope).."' for section "..tostring(varData.section)) + end + sectionScope = varData.scope + end + if varData.var then + local enemyState = inferEnemyState(varData) + local scope = inferScope(varData, sectionScope) + scopeByVar[varData.var] = scope + enemyStateByVar[varData.var] = enemyState + varData.resolvedScope = scope + varData.resolvedEnemyState = enemyState + if enemyState == "source" then + registerSourceOwned(varData.ifEnemyCond) + registerSourceOwned(varData.ifEnemyMult) + end + end + end + indexed = true + -- Names registered as source-owned during this pass must not keep + -- a false negative from an earlier option's lookup. + sourceOwnedNameCache = { } +end + +function ConfigScope.tryForVar(var) + requireIndexed() + if not var then + return nil + end + return scopeByVar[var] +end + +function ConfigScope.tryEnemyStateForVar(var) + requireIndexed() + if not var then + return nil + end + return enemyStateByVar[var] +end + +function ConfigScope.forVar(var) + local scope = ConfigScope.tryForVar(var) + if not scope then + error("ConfigScope: unknown config var '"..tostring(var).."'") + end + return scope +end + +function ConfigScope.forVarData(varData) + if varData and varData.resolvedScope then + return varData.resolvedScope + end + if varData and varData.var then + return ConfigScope.forVar(varData.var) + end + return nil +end + +function ConfigScope.enemyStateForVar(var) + local enemyState = ConfigScope.tryEnemyStateForVar(var) + if not enemyState then + error("ConfigScope: unknown config var '"..tostring(var).."'") + end + return enemyState +end + +function ConfigScope.enemyStateForVarData(varData) + if varData and varData.resolvedEnemyState then + return varData.resolvedEnemyState + end + if varData and varData.var then + return ConfigScope.enemyStateForVar(varData.var) + end + return nil +end + +function ConfigScope.isIndexed() + return indexed +end + +return ConfigScope diff --git a/src/Modules/ConfigVisibility.lua b/src/Modules/ConfigVisibility.lua index 94692f953aa..9ff5eca7fb0 100644 --- a/src/Modules/ConfigVisibility.lua +++ b/src/Modules/ConfigVisibility.lua @@ -32,43 +32,189 @@ local function anyIfValue(ifOption, predicate) return predicate(ifOption) and true or false end +local ConfigScope = require("Modules.ConfigScope") + +local ACTOR_USED_FIELD = { + conditionsUsed = "conditions", + multipliersUsed = "multipliers", + modsUsed = "mods", + perStatsUsed = "perStats", + minionConditionsUsed = "minionConditions", + enemyConditionsUsed = "enemyConditions", + enemyMultipliersUsed = "enemyMultipliers", + enemyPerStatsUsed = "enemyPerStats", +} + +local function usedForVar(mainEnv, envKey, varData, viewActor) + if not mainEnv then + return { } + end + local field = ACTOR_USED_FIELD[envKey] + if field then + local scope = ConfigScope.forVarData(varData) + if scope == "actor" or scope == "player" then + local actorKey = (scope == "actor" and viewActor == "mercenary") and "mercenary" or "player" + local usage = mainEnv.actorUsage and mainEnv.actorUsage[actorKey] + return (usage and usage[field]) or { } + end + end + return mainEnv[envKey] or { } +end + +local PRIMARY_ACTOR_KEYS = { "player", "mercenary" } + +local function actorKeysForVar(varData, viewActor) + local scope = ConfigScope.forVarData(varData) + if scope == "shared" then + return PRIMARY_ACTOR_KEYS + end + if scope == "player" or viewActor ~= "mercenary" then + return { "player" } + end + return { "mercenary" } +end + +local function formatUsedMods(mainEnv, envKey, varData, viewActor, ifOption) + local mods = usedForVar(mainEnv, envKey, varData, viewActor)[ifOption] + if not mods then + return + end + local out + for _, mod in ipairs(mods) do + out = (out and out.."\n" or "") .. modLib.formatMod(mod) .. "|" .. mod.source + end + return out +end + +local function formatCondTrue(mainEnv, varData, viewActor, ifOption) + local keys = actorKeysForVar(varData, viewActor) + if #keys == 1 then + local actor = mainEnv and mainEnv[keys[1]] + return "Condition state: " .. ifOption .. "=" .. tostring(actor and actor.modDB and actor.modDB.conditions[ifOption]) + end + local out + for _, actorKey in ipairs(keys) do + local actor = mainEnv and mainEnv[actorKey] + local value = actor and actor.modDB and actor.modDB.conditions[ifOption] + local line = actorKey .. " " .. ifOption .. "=" .. tostring(value) + out = (out and out.."\n" or "") .. line + end + return out and ("Condition state:\n" .. out) or ("Condition state: " .. ifOption .. "=nil") +end + +local function anyPrimaryActor(mainEnv, predicate, actorKeys) + for _, actorKey in ipairs(actorKeys or PRIMARY_ACTOR_KEYS) do + local actor = mainEnv and mainEnv[actorKey] + if actor and predicate(actor) then return true end + end + return false +end + +local function anyMainSkill(mainEnv, predicate, actorKeys) + return anyPrimaryActor(mainEnv, function(actor) + return actor.mainSkill and predicate(actor.mainSkill) + end, actorKeys) +end + +local function anyActiveSkill(mainEnv, predicate, actorKeys) + return anyPrimaryActor(mainEnv, function(actor) + for _, activeSkill in ipairs(actor.activeSkillList or { }) do + if predicate(activeSkill) then return true end + end + return false + end, actorKeys) +end + +local function grantedEffectMatches(grantedEffect, ifOption, includeTransfigured) + if not grantedEffect then + return false + end + if grantedEffect.id == ifOption or grantedEffect.name == ifOption then + return true + end + local name = grantedEffect.name + if includeTransfigured and name and calcLib.getGameIdFromGemName(ifOption, true) then + return calcLib.isGemIdSame(name, ifOption, true) + end + return false +end + +-- Per-actor equivalent of the skillsUsed walk in Calcs.lua: the actor's own effects +-- and that actor's minion skills. Do not consult env.skillsUsed; it is global. +local function actorUsesSkill(actor, ifOption, includeTransfigured) + for _, activeSkill in ipairs(actor and actor.activeSkillList or { }) do + for _, skillEffect in ipairs(activeSkill.effectList or { }) do + if grantedEffectMatches(skillEffect.grantedEffect, ifOption, includeTransfigured) then + return true + end + end + if activeSkill.minion then + for _, minionSkill in ipairs(activeSkill.minion.activeSkillList or { }) do + local grantedEffect = minionSkill.activeEffect and minionSkill.activeEffect.grantedEffect + if grantedEffectMatches(grantedEffect, ifOption, includeTransfigured) then + return true + end + end + end + end + return false +end + -- When the option has an input value and one of its implied conditions is currently used, treat gated predicates as passing. -local function implyCondActive(varData, build) +local function optionValue(configTab, var, viewActor, input) + if input then + return input[var] + end + if viewActor and configTab and configTab.GetActorConfigInput then + input = configTab:GetActorConfigInput(viewActor) + return input and input[var] + end + if configTab and configTab.GetConfigValue then + return configTab:GetConfigValue(var) + end + local activeSet = configTab and configTab.configSets and configTab.configSets[configTab.activeConfigSetId] + return activeSet and activeSet.input and activeSet.input[var] +end + +local function implyCondActive(varData, build, viewActor, input) local configTab = build and build.configTab if not configTab then return false end - local activeSet = configTab.configSets and configTab.configSets[configTab.activeConfigSetId] - if not activeSet or not activeSet.input[varData.var] then return false end + viewActor = viewActor or (configTab.GetViewActor and configTab:GetViewActor()) or "player" + if not optionValue(configTab, varData.var, viewActor, input) then return false end local mainEnv = build.calcsTab and build.calcsTab.mainEnv if not mainEnv then return false end + local conditionsUsed = usedForVar(mainEnv, "conditionsUsed", varData, viewActor) + local minionConditionsUsed = usedForVar(mainEnv, "minionConditionsUsed", varData, viewActor) if varData.implyCondList then for _, implyCond in ipairs(varData.implyCondList) do - if implyCond and mainEnv.conditionsUsed[implyCond] then return true end + if implyCond and conditionsUsed[implyCond] then return true end end end - return (varData.implyCond and mainEnv.conditionsUsed[varData.implyCond]) - or (varData.implyMinionCond and mainEnv.minionConditionsUsed[varData.implyMinionCond]) + return (varData.implyCond and conditionsUsed[varData.implyCond]) + or (varData.implyMinionCond and minionConditionsUsed[varData.implyMinionCond]) or (varData.implyEnemyCond and mainEnv.enemyConditionsUsed[varData.implyEnemyCond]) or false end --- True if every `ifX` predicate on `varData` currently passes for `build` -local function isRelevantForBuild(varData, build) +-- True if every `ifX` predicate on `varData` currently passes for `build`. +-- Actor-scoped options are evaluated for `viewActor`; shared options scan every primary actor. +local function isRelevantForBuild(varData, build, viewActor) if not build then return false end local mainEnv = build.calcsTab and build.calcsTab.mainEnv if not mainEnv then return false end - local player = mainEnv.player - local mainSkill = player and player.mainSkill local spec = build.spec local configTab = build.configTab - local activeInput = configTab and configTab.configSets - and configTab.configSets[configTab.activeConfigSetId] - and configTab.configSets[configTab.activeConfigSetId].input - or {} + viewActor = viewActor or "player" + local actorInput + if configTab and configTab.GetActorConfigInput then + actorInput = configTab:GetActorConfigInput(viewActor) + end + local actorKeys = actorKeysForVar(varData, viewActor) local impliedCache local function implied() if impliedCache == nil then - impliedCache = implyCondActive(varData, build) or false + impliedCache = implyCondActive(varData, build, viewActor, actorInput) or false end return impliedCache end @@ -76,7 +222,7 @@ local function isRelevantForBuild(varData, build) for _, p in ipairs(SIMPLE_PREDICATES) do local ifVal = varData[p.key] if ifVal then - local envTable = mainEnv[p.env] or {} + local envTable = usedForVar(mainEnv, p.env, varData, viewActor) if not anyIfValue(ifVal, function(opt) return envTable[opt] or (p.canImply and implied()) end) then return false end @@ -94,45 +240,39 @@ local function isRelevantForBuild(varData, build) end) then return false end end if varData.ifOption then - if not anyIfValue(varData.ifOption, function(opt) return activeInput[opt] end) then return false end + if not anyIfValue(varData.ifOption, function(opt) return optionValue(configTab, opt, viewActor, actorInput) end) then return false end end if varData.ifCondTrue then - if not anyIfValue(varData.ifCondTrue, function(opt) return player and player.modDB.conditions[opt] end) then return false end + if not anyIfValue(varData.ifCondTrue, function(opt) + return anyPrimaryActor(mainEnv, function(actor) return actor.modDB.conditions[opt] end, actorKeys) + end) then return false end end if varData.ifStat then if not anyIfValue(varData.ifStat, function(opt) - return mainEnv.perStatsUsed[opt] or mainEnv.enemyMultipliersUsed[opt] or implied() + return usedForVar(mainEnv, "perStatsUsed", varData, viewActor or "player")[opt] or usedForVar(mainEnv, "enemyMultipliersUsed", varData, viewActor or "player")[opt] or implied() end) then return false end end if varData.ifFlag then - if not mainSkill then return false end - local skillFlags = mainSkill.skillFlags or {} - local skillModList = mainSkill.skillModList if not anyIfValue(varData.ifFlag, function(opt) - return skillFlags[opt] or (skillModList and skillModList:Flag(nil, opt)) + return anyMainSkill(mainEnv, function(mainSkill) + local skillFlags = mainSkill.skillFlags or { } + return skillFlags[opt] or (mainSkill.skillModList and mainSkill.skillModList:Flag(nil, opt)) + end, actorKeys) end) then return false end end if varData.ifSkill then - local skillsUsed = mainEnv.skillsUsed or {} - if varData.includeTransfigured then - if not anyIfValue(varData.ifSkill, function(opt) - if not calcLib.getGameIdFromGemName(opt, true) then return false end - for skill, _ in pairs(skillsUsed) do - if calcLib.isGemIdSame(skill, opt, true) then return true end - end - return false - end) then return false end - else - if not anyIfValue(varData.ifSkill, function(opt) return skillsUsed[opt] end) then return false end - end + if not anyIfValue(varData.ifSkill, function(opt) + return anyPrimaryActor(mainEnv, function(actor) + return actorUsesSkill(actor, opt, varData.includeTransfigured) + end, actorKeys) + end) then return false end end if varData.ifSkillFlag or varData.ifSkillData then - local skillList = (player and player.activeSkillList) or {} local function anySkillHas(field, opt) - for _, s in ipairs(skillList) do - if s[field][opt] then return true end - end - return false + return anyActiveSkill(mainEnv, function(activeSkill) + local values = activeSkill[field] + return values and values[opt] + end, actorKeys) end if varData.ifSkillFlag and not anyIfValue(varData.ifSkillFlag, function(opt) return anySkillHas("skillFlags", opt) end) then return false end if varData.ifSkillData and not anyIfValue(varData.ifSkillData, function(opt) return anySkillHas("skillData", opt) end) then return false end @@ -155,6 +295,15 @@ local function isShowAllExcluded(varData) end return { + actorKeysForVar = actorKeysForVar, + anyPrimaryActor = anyPrimaryActor, + anyMainSkill = anyMainSkill, + anyActiveSkill = anyActiveSkill, + actorUsesSkill = actorUsesSkill, + implyCondActive = implyCondActive, isRelevantForBuild = isRelevantForBuild, isShowAllExcluded = isShowAllExcluded, + usedForVar = usedForVar, + formatUsedMods = formatUsedMods, + formatCondTrue = formatCondTrue, } diff --git a/src/Modules/Data.lua b/src/Modules/Data.lua index 26afb5f4dfb..099bbbf0015 100644 --- a/src/Modules/Data.lua +++ b/src/Modules/Data.lua @@ -102,10 +102,10 @@ end -- Boss data, skills and minions -- Remaining Item Data and uniques ---------------------------------------- - ---@diagnostic disable-next-line: lowercase-global ---@class Data : MiscDataExport ---@field bosses BossData + data = { } -- Misc data tables @@ -684,7 +684,9 @@ data.enchantments = { -- combined table of many mod categories data.itemMods.Item = {} -for _, key in ipairs({ "Explicit", "ItemExclusive", "Corrupted", "Delve", "Synthesis", "Scourge", "Eldritch", "Mercenary" }) do +-- Infamous Mercenary explicits stay on data.itemMods.Mercenary so player +-- craft/parse cannot match them. ParseRaw still applies pasted text via parseMod. +for _, key in ipairs({ "Explicit", "ItemExclusive", "Corrupted", "Delve", "Synthesis", "Scourge", "Eldritch" }) do local itemData = data.itemMods[key] for k, v in pairs(itemData) do data.itemMods.Item[k] = v @@ -1027,7 +1029,8 @@ Uber Pinnacle Boss adds the following modifiers: ]]..tostring(data.misc.uberBossPen)..[[% penetration]] end --- Load skills +-- Load skills. Mercenary granted effects stay off the player/startup path; +-- data.ensureMercenaries() loads Data/Skills/mercenary.lua and MercenaryStatMap. data.skills = { } data.skillStatMap = LoadModule("Data/SkillStatMap")(makeSkillMod, makeFlagMod, makeSkillDataMod) data.skillStatMapMeta = { @@ -1046,18 +1049,24 @@ data.skillStatMapMeta = { for _, type in pairs(skillTypes) do LoadModule("Data/Skills/" .. type)(data.skills, makeSkillMod, makeFlagMod, makeSkillDataMod) end -for skillId, grantedEffect in pairs(data.skills) do +local orderedSkillIds = { } +for skillId in pairs(data.skills) do t_insert(orderedSkillIds, skillId) end +table.sort(orderedSkillIds) + +local function finishGrantedEffect(skillId, grantedEffect) grantedEffect.name = sanitiseText(grantedEffect.name) grantedEffect.id = skillId grantedEffect.modSource = "Skill:"..skillId -- Add sources for skill mods, and check for global effects for _, list in pairs({grantedEffect.baseMods, grantedEffect.qualityMods, grantedEffect.levelMods}) do - for _, mod in pairs(list) do - if mod.name then - processMod(grantedEffect, mod) - else - for _, mod in ipairs(mod) do + if list then + for _, mod in pairs(list) do + if mod.name then processMod(grantedEffect, mod) + else + for _, nestedMod in ipairs(mod) do + processMod(grantedEffect, nestedMod) + end end end end @@ -1072,12 +1081,227 @@ for skillId, grantedEffect in pairs(data.skills) do if modOrGroup.name then processMod(grantedEffect, modOrGroup, name) else - for _, mod in ipairs(modOrGroup) do - processMod(grantedEffect, mod, name) + for _, nestedMod in ipairs(modOrGroup) do + processMod(grantedEffect, nestedMod, name) + end + end + end + end +end + +-- Some mechanics are mapped on a specific player skill instead of the global +-- stat map. Reuse those mappings only when every existing implementation is +-- identical; conflicting meanings must receive an explicit Mercenary override. +local sharedSkillStatMap, ambiguousSkillStats = { }, { } +for _, skillId in ipairs(orderedSkillIds) do + local grantedEffect = data.skills[skillId] + for statId, map in pairs(grantedEffect.statMap or { }) do + if type(statId) == "string" and statId ~= "_grantedEffect" and not ambiguousSkillStats[statId] then + if sharedSkillStatMap[statId] and not tableDeepEquals(sharedSkillStatMap[statId], map) then + sharedSkillStatMap[statId] = nil + ambiguousSkillStats[statId] = true + else + sharedSkillStatMap[statId] = map + end + end + end +end +for _, skillId in ipairs(orderedSkillIds) do + finishGrantedEffect(skillId, data.skills[skillId]) +end + +data.knownUncalculatedSkillStats = { } +data.knownUncalculatedMinionStats = { } + +-- processMod mutates the mods it is given (source, notMinionStat tags), so a stat +-- map borrowed from another skill or from a shared stat map must be a private copy. +local function copyBorrowedStatMap(statMap) + local copy = { } + for statId, map in pairs(statMap or { }) do + if statId ~= "_grantedEffect" then + copy[statId] = copyTable(map) + end + end + return copy +end + +local function borrowStatMapEntry(sharedMaps, statId) + for _, maps in ipairs(sharedMaps) do + if maps[statId] then + return copyTable(maps[statId]) + end + end +end + +local function ensureMercenarySkills() + if data.mercenaryStatData then + return + end + data.mercenaryStatData = LoadModule("Data/MercenaryStatMap")(makeSkillMod, makeFlagMod, makeSkillDataMod) + data.mercenaryStatMap = data.mercenaryStatData.statMap + LoadModule("Data/Skills/mercenary")(data.skills, makeSkillMod, makeFlagMod, makeSkillDataMod) + local mercenarySkillIds = { } + for skillId, grantedEffect in pairs(data.skills) do + if grantedEffect.mercenary then + t_insert(mercenarySkillIds, skillId) + end + end + table.sort(mercenarySkillIds) + -- Mercenary Granted Effects are exported as data only. Each one records the + -- player skill it was derived from, and reuses that skill's implementation for + -- anything GGG's data does not state directly. Inheriting from exactly the one + -- recorded skill is what keeps a display-name rename or a new transfigured + -- variant from silently changing Mercenary behaviour. + for _, skillId in ipairs(mercenarySkillIds) do + local grantedEffect = data.skills[skillId] + for _, statId in ipairs(grantedEffect.stats or { }) do + if statId == "base_is_projectile" then grantedEffect.baseFlags.projectile = true end + if statId == "is_area_damage" then grantedEffect.baseFlags.area = true end + if statId:match("^spell_minimum_base_.*_damage$") then grantedEffect.baseFlags.hit = true end + end + local base = grantedEffect.inheritedFrom and data.skills[grantedEffect.inheritedFrom] + if grantedEffect.inheritedFrom and not base then + error("Missing base skill mapping: "..grantedEffect.inheritedFrom.." for "..skillId) + end + for key, value in pairs(base or { }) do + if grantedEffect[key] == nil then + if key == "statMap" then + grantedEffect.statMap = copyBorrowedStatMap(value) + else + grantedEffect[key] = type(value) == "table" and copyTable(value) or value + end + elseif key == "baseFlags" then + for flagName, enabled in pairs(value) do + if grantedEffect.baseFlags[flagName] == nil then grantedEffect.baseFlags[flagName] = enabled end + end + end + end + if data.mercenaryStatData.droppedPreDamageFuncs[skillId] then + grantedEffect.preDamageFunc = nil + end + grantedEffect.statMap = grantedEffect.statMap or { } + local sharedMaps = { data.mercenaryStatMap, data.skillStatMap, sharedSkillStatMap } + for _, statId in ipairs(grantedEffect.stats or { }) do + if not grantedEffect.statMap[statId] then + grantedEffect.statMap[statId] = borrowStatMapEntry(sharedMaps, statId) + end + end + for _, stat in ipairs(grantedEffect.constantStats or { }) do + if not grantedEffect.statMap[stat[1]] then + grantedEffect.statMap[stat[1]] = borrowStatMapEntry(sharedMaps, stat[1]) + end + end + local override = data.mercenaryStatData.skillOverrides[skillId] + if override then + for statId, map in pairs(override.statMap or { }) do grantedEffect.statMap[statId] = copyTable(map) end + if override.parts then grantedEffect.parts = copyTable(override.parts, true) end + grantedEffect.baseMods = grantedEffect.baseMods or { } + for _, baseMod in ipairs(override.baseMods or { }) do t_insert(grantedEffect.baseMods, copyTable(baseMod)) end + if override.preDamageFunc then grantedEffect.preDamageFunc = override.preDamageFunc end + end + finishGrantedEffect(skillId, grantedEffect) + end + data.knownUncalculatedSkillStats = data.mercenaryStatData.knownUncalculatedStats + data.knownUncalculatedMinionStats = data.mercenaryStatData.knownUncalculatedMinionStats + -- Mercenary supports store raw stats instead of GrantedEffect references. Reuse + -- the deterministic stat implementations already exported for skills/supports. + data.mercenarySupportStatMap = { } + for statId, map in pairs(data.skillStatMap) do data.mercenarySupportStatMap[statId] = copyTable(map) end + for statId, map in pairs(data.mercenaryStatMap) do data.mercenarySupportStatMap[statId] = copyTable(map) end + -- Per-skill implementations are only borrowed where they are unambiguous, to the + -- same standard as the Mercenary skill fallback above. + for statId, map in pairs(sharedSkillStatMap) do + if not data.mercenarySupportStatMap[statId] then + data.mercenarySupportStatMap[statId] = copyTable(map) + end + end +end + +-- Turn extracted Mercenary support rows into ordinary grantedEffect objects. +-- Skill-specific stat maps are applied here so CalcSetup only looks them up. +local function buildMercenarySupportGrantedEffect(support, supportedEffect) + local source = "Mercenary Support:"..support.id + local constantStats = { } + local statMap = { } + local unsupported = { } + for _, stat in ipairs(support.stats or { }) do + local implementation = (supportedEffect and supportedEffect.statMap[stat.id]) or data.mercenarySupportStatMap[stat.id] + if not implementation then + t_insert(unsupported, stat.id) + else + t_insert(constantStats, { stat.id, stat.value }) + statMap[stat.id] = copyTable(implementation) + for _, modOrGroup in ipairs(statMap[stat.id]) do + if modOrGroup.name then + modOrGroup.source = source + else + for _, mod in ipairs(modOrGroup) do + mod.source = source + end end end end end + local templateId = data.mercenaryStatData.supportTemplates[support.id] + local template = templateId and data.skills[templateId] + local grantedEffect = { + name = support.name, + support = true, + mercenary = true, + mercenarySupportId = support.id, + requireSkillTypes = copyTable(template and template.requireSkillTypes or { }, true), + excludeSkillTypes = copyTable(template and template.excludeSkillTypes or { }, true), + addSkillTypes = copyTable(template and template.addSkillTypes or { }, true), + addFlags = copyTable(template and template.addFlags or { }, true), + weaponTypes = template and template.weaponTypes and copyTable(template.weaponTypes, true), + ignoreMinionTypes = template and template.ignoreMinionTypes, + isTrigger = template and template.isTrigger, + statDescriptionScope = template and template.statDescriptionScope or "gem_stat_descriptions", + baseFlags = { }, + skillTypes = { }, + constantStats = constantStats, + stats = { }, + levels = { { levelRequirement = 1 } }, + statMap = statMap, + unsupportedMercenaryStats = unsupported[1] and unsupported or nil, + missingSupportTemplate = (templateId and not template) and templateId or nil, + } + grantedEffect.name = sanitiseText(grantedEffect.name) + grantedEffect.id = "MercenarySupport:"..support.id + grantedEffect.modSource = source + setmetatable(grantedEffect.statMap, data.skillStatMapMeta) + grantedEffect.statMap._grantedEffect = grantedEffect + return grantedEffect +end + +local function installMercenarySupportGrantedEffects(mercenaries) + data.mercenarySupportGrantedEffects = { } + data.mercenarySupportGrantedEffectsBySkill = { } + for supportId, support in pairs(mercenaries.supports) do + data.mercenarySupportGrantedEffects[supportId] = buildMercenarySupportGrantedEffect(support) + end + for skillId, skill in pairs(mercenaries.skills) do + local skillEffect = data.skills[skillId] + local bySkill = { } + for _, supportId in ipairs(skill.possibleSupportIds or { }) do + local support = mercenaries.supports[supportId] + if support then + bySkill[supportId] = buildMercenarySupportGrantedEffect(support, skillEffect) + end + end + data.mercenarySupportGrantedEffectsBySkill[skillId] = bySkill + end +end + +function data.mercenarySupportGrantedEffect(supportId, skillId) + if not data.mercenarySupportGrantedEffects then + data.ensureMercenaries() + end + local bySkill = skillId and data.mercenarySupportGrantedEffectsBySkill[skillId] + if bySkill and bySkill[supportId] then + return bySkill[supportId] + end + return data.mercenarySupportGrantedEffects[supportId] end -- Load gems @@ -1153,6 +1377,63 @@ end -- Load minions data.minions = LoadModule("Data/Minions")(makeSkillMod, makeFlagMod) +local function addMercenaryMinionStatMods(minion, stat) + local map = data.mercenarySupportStatMap[stat.id] + if not map then return end + for _, modOrGroup in ipairs(map) do + local templates = modOrGroup.name and { modOrGroup } or modOrGroup + local value = modOrGroup.value or stat.value * (modOrGroup.mult or map.mult or 1) / (modOrGroup.div or map.div or 1) + (modOrGroup.base or map.base or 0) + for _, template in ipairs(templates) do + local newMod = copyTable(template) + if type(newMod.value) == "table" then + if newMod.value.mod then + newMod.value.mod.value = value + else + newMod.value.value = value + end + else + newMod.value = value + end + t_insert(minion.modList, newMod) + end + end +end +-- Builds, classes, and allied-monster tables are only needed once a Mercenary +-- tab or actor exists. Keep them off the HeadlessWrapper / app-start path. +function data.ensureMercenaries() + if data.mercenaries then + return data.mercenaries + end + ensureMercenarySkills() + local mercenaries = LoadModule("Data/Mercenaries") + mercenaries.supportCounts = data.mercenaryStatData.supportCounts + for minionId, minion in pairs(mercenaries.minions or { }) do + minion.skillList = minion.skillIds + minion.noFallbackSkill = not minion.skillList[1] + minion.modList = { } + for _, stat in ipairs(minion.stats or { }) do addMercenaryMinionStatMods(minion, stat) end + for _, mod in ipairs(minion.modList) do + mod.source = "Minion:"..minion.name + end + if not data.minions[minionId] then + data.minions[minionId] = minion + end + end + for skillId, minionId in pairs(mercenaries.summonedMinions or { }) do + local grantedEffect = data.skills[skillId] + if grantedEffect then + grantedEffect.minionList = { minionId } + grantedEffect.baseFlags.minion = true + grantedEffect.skillTypes[SkillType.Minion] = true + grantedEffect.skillTypes[SkillType.CreatesMinion] = true + grantedEffect.baseMods = grantedEffect.baseMods or { } + t_insert(grantedEffect.baseMods, makeSkillDataMod("minionLevelIsActorLevel", true)) + end + end + data.mercenaries = mercenaries + installMercenarySupportGrantedEffects(mercenaries) + return mercenaries +end data.spectres = LoadModule("Data/Spectres")(makeSkillMod, makeFlagMod) for name, spectre in pairs(data.spectres) do spectre.limit = "ActiveSpectreLimit" diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index 294fb64c24b..66facc1dade 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -566,6 +566,7 @@ function main:LoadSettings(ignoreBuild) self.lastToken = node.attrib.lastToken self.lastRefreshToken = node.attrib.lastRefreshToken self.tokenExpiry = tonumber(node.attrib.tokenExpiry) + self.grantedScopes = node.attrib.grantedScopes for _, child in ipairs(node) do if child.elem == "Account" then self.gameAccounts[child.attrib.accountName] = { @@ -759,7 +760,7 @@ function main:SaveSettings() return true end t_insert(setXML, mode) - local accounts = { elem = "Accounts", attrib = { lastAccountName = self.lastAccountName, lastRealm = self.lastRealm, lastLeague = self.lastLeague, lastToken = self.lastToken, lastRefreshToken = self.lastRefreshToken, tokenExpiry = tostring(self.tokenExpiry) } } + local accounts = { elem = "Accounts", attrib = { lastAccountName = self.lastAccountName, lastRealm = self.lastRealm, lastLeague = self.lastLeague, lastToken = self.lastToken, lastRefreshToken = self.lastRefreshToken, tokenExpiry = tostring(self.tokenExpiry), grantedScopes = self.grantedScopes } } for accountName, account in pairs(self.gameAccounts) do t_insert(accounts, { elem = "Account", attrib = { accountName = accountName, sessionID = account.sessionID } }) end diff --git a/src/Modules/MercenaryImport.lua b/src/Modules/MercenaryImport.lua new file mode 100644 index 00000000000..fe768e73047 --- /dev/null +++ b/src/Modules/MercenaryImport.lua @@ -0,0 +1,139 @@ +-- Path of Building +-- +-- Module: Mercenary Import +-- Convert LeagueAccount Mercenary snapshots into Mercenary profiles. +-- Skill/support/build IDs are optional; hashes are required and win on conflict. +-- +local t_insert = table.insert +local sha = require("sha2") +local MercenaryTools = require("Modules.MercenaryTools") +local MercenaryImport = { } + +local function resolve(records, id, hash, kind) + if type(hash) ~= "number" then + return nil, "Missing " .. kind .. " hash" + end + local record = id and records[id] + if id then + if not record then + return nil, "Unsupported " .. kind .. " ID: " .. tostring(id) + end + if record.hash ~= hash then + return nil, "Conflicting " .. kind .. " ID and hash: " .. tostring(id) + end + else + for _, candidate in pairs(records) do + if candidate.hash == hash then + if record then + return nil, "Ambiguous " .. kind .. " hash: " .. hash + end + record = candidate + end + end + end + if not record then + return nil, "Unsupported " .. kind .. " hash: " .. hash + end + return record +end + +function MercenaryImport.profile(hire, mercenaryData) + if type(hire) ~= "table" or type(hire.name) ~= "string" or hire.name == "" or type(hire.skills) ~= "table" then + return nil, "Missing Mercenary name or skills" + end + local mercBuild, err = resolve(mercenaryData.builds, hire.build, hire.build_hash, "build") + if not mercBuild then + return nil, err + end + local profile = { + title = hire.name, + buildId = mercBuild.id, + classId = mercBuild.classId, + foundAreaLevel = hire.level, + lifeComparison = "AUTO", + skills = { }, + } + for _, sourceSkill in ipairs(hire.skills) do + local skill, err = resolve(mercenaryData.skills, sourceSkill.id, sourceSkill.hash, "skill") + if not skill then + return nil, err + end + if sourceSkill.supports ~= nil and type(sourceSkill.supports) ~= "table" then + return nil, "Missing supports for " .. skill.id + end + local selected = { id = skill.id, enabled = true, includeInFullDPS = false, count = 1, supports = { } } + for _, sourceSupport in ipairs(sourceSkill.supports or { }) do + local support, err = resolve(mercenaryData.supports, sourceSupport.id, sourceSupport.hash, "support") + if not support then + return nil, err + end + t_insert(selected.supports, { id = support.id, tier = sourceSupport.tier }) + end + t_insert(profile.skills, selected) + end + profile.mainSkillId = MercenaryTools.firstEnabledSkillId(profile) + local errors = MercenaryTools.validateProfile(profile, mercenaryData) + if #errors > 0 then + return nil, table.concat(errors, "; ") + end + return profile +end + +function MercenaryImport.activeIndex(account) + local index = account.active_mercenary_index + if type(index) == "number" and index % 1 == 0 and index > 0 and index <= #(account.mercenaries or { }) then + return index + end +end + +-- LeagueAccount mercenaries have no unique id. Identity is account/realm/league +-- plus name, build hash, and a canonical skill/support-hash fingerprint. +-- Equipment is excluded because it is mutable in game and in PoB. +-- Names are not assumed unique within a roster; skill hashes disambiguate. +-- The association is stored hashed so shareable XML never carries the account UUID. +local function lengthPrefixed(parts) + for index, value in ipairs(parts) do + parts[index] = #value .. ":" .. value + end + return table.concat(parts) +end + +local function skillFingerprint(hire) + local fingerprints = { } + for _, skill in ipairs(hire.skills or { }) do + local supports = { } + for _, support in ipairs(skill.supports or { }) do + t_insert(supports, tostring(support.hash) .. ":" .. tostring(support.tier)) + end + table.sort(supports) + t_insert(fingerprints, tostring(skill.hash) .. ":" .. table.concat(supports, ",")) + end + table.sort(fingerprints) + return table.concat(fingerprints, ";") +end + +function MercenaryImport.association(account, realm, league, hire) + return sha.sha256(lengthPrefixed({ + account, realm, league, hire.name, tostring(hire.build_hash), skillFingerprint(hire), + })) +end + +function MercenaryImport.matchesAssociation(stored, account, realm, league, hire) + return type(stored) == "string" and stored == MercenaryImport.association(account, realm, league, hire) +end + +function MercenaryImport.unusedEmptyId(sets, order) + local unused + for _, id in ipairs(order or { }) do + local profile = sets[id] + if profile and not profile.buildId and not profile.importAssociation then + if unused then + return + end + unused = id + end + end + return unused +end + +return MercenaryImport diff --git a/src/Modules/MercenaryTools.lua b/src/Modules/MercenaryTools.lua new file mode 100644 index 00000000000..c1ec067f9e7 --- /dev/null +++ b/src/Modules/MercenaryTools.lua @@ -0,0 +1,928 @@ +local t_insert = table.insert +local t_remove = table.remove +local t_sort = table.sort +local t_concat = table.concat +local m_floor = math.floor +local m_min = math.min +local m_max = math.max + +local MercenaryTools = { } + +MercenaryTools.equipmentSlots = { "Weapon 1", "Weapon 2", "Helmet", "Body Armour", "Gloves", "Boots", "Amulet", "Ring 1", "Ring 2", "Belt" } + +function MercenaryTools.baseItemSlotName(slotName) + return type(slotName) == "string" and slotName:match("^Mercenary (.+)$") or nil +end + +function MercenaryTools.overrideReplacesMercenarySlot(override, slotName, mercenaryItemSetId) + if not override or not override.repSlotName then + return false + end + local overrideBase = MercenaryTools.baseItemSlotName(override.repSlotName) or override.repSlotName + if overrideBase ~= slotName then + return false + end + if override.comparisonActor == "PLAYER" then + return false + end + if override.comparisonActor == "MERCENARY" or MercenaryTools.baseItemSlotName(override.repSlotName) then + return true + end + return override.itemSetId ~= nil and override.itemSetId == mercenaryItemSetId +end + +-- Effective item in a slot after replacement, removal, and parent sockets. +-- Does not mutate the saved item set. +function MercenaryTools.equippedItem(itemSet, items, slotName, override, mercenaryItemSetId) + if MercenaryTools.overrideReplacesMercenarySlot(override, slotName, mercenaryItemSetId) then + return override.repItem + end + local parentSlot, abyssalIndex = slotName:match("^(.-) Abyssal Socket (%d+)$") + if parentSlot then + local parentItem = MercenaryTools.equippedItem(itemSet, items, parentSlot, override, mercenaryItemSetId) + if not parentItem or (parentItem.abyssalSocketCount or 0) < tonumber(abyssalIndex) then + return nil + end + end + local setSlot = itemSet and itemSet[slotName] + return items and items[setSlot and setSlot.selItemId] +end + +local function withRestored(restore, fn) + local ok, result = pcall(fn) + restore() + if not ok then + error(result) + end + return result +end + +function MercenaryTools.withMainSkill(profile, skillId, fn) + local previous = profile.mainSkillId + profile.mainSkillId = skillId + return withRestored(function() + profile.mainSkillId = previous + end, fn) +end + +function MercenaryTools.withReplacedSkill(profile, index, replacement, fn) + local original = profile.skills[index] + profile.skills[index] = replacement + return withRestored(function() + profile.skills[index] = original + end, fn) +end + +function MercenaryTools.overrideReplacesPlayerItem(override, activeItemSetId) + if not override then + return true + end + if override.comparisonActor == "MERCENARY" or MercenaryTools.baseItemSlotName(override.repSlotName) then + return false + end + return override.itemSetId == nil or override.itemSetId == activeItemSetId +end + +-- Mercenary Life/ES/selected-skill DPS stay on the mercenary output. +-- Full DPS is a build-wide rollup (player skills + mercenary skills), so +-- support auras that only buff the player must use the player's Full DPS +-- or item tooltips and trade weights score them as zero. +function MercenaryTools.buildComparisonOutput(mercenaryOutput, playerOutput) + if not MercenaryTools.mercenaryOutputAvailable(mercenaryOutput) or not playerOutput then + return mercenaryOutput + end + local output = { } + for key, value in pairs(mercenaryOutput) do + output[key] = value + end + output.FullDPS = playerOutput.FullDPS + output.FullDotDPS = playerOutput.FullDotDPS + return output +end + +function MercenaryTools.comparisonBaseOutput(playerOutput, actorOutputs, comparisonActor) + if comparisonActor == "MERCENARY" then + return MercenaryTools.buildComparisonOutput(actorOutputs and actorOutputs.MERCENARY, playerOutput) + end + return playerOutput +end + +function MercenaryTools.mercenaryOutputAvailable(output) + return output ~= nil and not output.ActorUnavailableMessage +end + +-- Hire is a Scion/Luminary mechanic. Every Scion sees the tab so a Mercenary +-- can be configured before Noble Blood is allocated. +function MercenaryTools.tabVisible(build) + return build and build.spec and build.spec.curClassName == "Scion" +end + +function MercenaryTools.isMercenaryCalculationActor(actorId) + return actorId == "MERCENARY" or actorId == "MERCENARY_MINION" +end + +function MercenaryTools.configActorList(build) + if MercenaryTools.tabVisible(build) then + return { + { id = "player", label = "Player" }, + { id = "mercenary", label = "Mercenary" }, + } + end + return { + { id = "player", label = "Player" }, + } +end + +-- Always copies. DropDownControl:SetList wipes the control's previous list, so the +-- source table must never be installed as a dropdown's current list. +function MercenaryTools.filterCalculationActors(actors, build) + local list = { } + for _, actor in ipairs(actors) do + if MercenaryTools.tabVisible(build) or not MercenaryTools.isMercenaryCalculationActor(actor.actorId) then + t_insert(list, actor) + end + end + return list +end + +function MercenaryTools.hasProfile(build) + return build.mercenaryTab ~= nil and build.mercenaryTab.profile ~= nil and build.mercenaryTab.profile.buildId ~= nil +end + +-- Overlay isolation is only valid while a Mercenary actor is in the graph. +-- A configured-but-unhired profile must keep origin's shared enemy HitBy* writes. +function MercenaryTools.playerCanHire(build) + for _, node in pairs(build and build.spec and build.spec.allocNodes or { }) do + for _, mod in ipairs(node.modList or { }) do + if mod.name == "CanHirePermanentMercenary" then + return true + end + end + end + return false +end + +function MercenaryTools.isHired(build) + return MercenaryTools.hasProfile(build) and MercenaryTools.playerCanHire(build) +end + +function MercenaryTools.firstEnabledSkillId(profile) + for _, skill in ipairs(profile and profile.skills or { }) do + if skill.enabled ~= false then + return skill.id + end + end +end + +function MercenaryTools.includeInBuildWarnings(build) + if not MercenaryTools.tabVisible(build) then + return false + end + if build.viewMode == "MERCENARY" then + return true + end + return MercenaryTools.hasProfile(build) +end + +function MercenaryTools.applyHiddenState(build) + if MercenaryTools.tabVisible(build) then + return + end + if build.viewMode == "MERCENARY" then + build.viewMode = "TREE" + end + if build.calcsTab and MercenaryTools.isMercenaryCalculationActor(build.calcsTab.input.actor) then + build.calcsTab.input.actor = "PLAYER" + end + if build.configTab and build.configTab:GetViewActor() == "mercenary" then + build.configTab.viewActor = "player" + end + if build.itemsTab and build.itemsTab.viewComparisonActor == "MERCENARY" then + build.itemsTab:SetViewItemSet(build.itemsTab.activeItemSetId, "PLAYER") + end +end + +local MAX_WARRANT_BYTES = 256 * 1024 +local MAX_SKILLS = 6 + +local function contains(values, wanted) + return values ~= nil and isValueInArray(values, wanted) ~= nil +end + +function MercenaryTools.classGroups(mercenaryData) + local groups = { } + local groupsByClassId = { } + local groupsByLabel = { } + for _, classId in ipairs(mercenaryData.classOrder or { }) do + local class = mercenaryData.classes[classId] + local name = class.name:gsub("^%[DNT%]%s*", "") + name = name:gsub("^Merc ", ""):gsub(" Merc ", " "):gsub("%s+%d+$", "") + local label = name.." ("..class.attributeName..")" + local group = groupsByLabel[label] + if not group then + group = { id = label, label = label, classIds = { }, buildIds = { } } + groupsByLabel[label] = group + t_insert(groups, group) + end + t_insert(group.classIds, classId) + groupsByClassId[classId] = group + for _, buildId in ipairs(class.buildIds or { }) do + t_insert(group.buildIds, buildId) + end + end + return groups, groupsByClassId +end + +-- How many supports a skill accepts, and the largest limit any skill accepts. Both +-- come from the hand-authored `supportCounts` policy attached to the Mercenary data. +-- A missing policy record is nil, not 0: 0 is a valid gameplay capacity. +function MercenaryTools.supportLimit(mercenaryData, skill) + if not skill then + return nil + end + local count = mercenaryData and mercenaryData.supportCounts and mercenaryData.supportCounts[skill.supportCountId] + if not count then + return nil + end + return count.maximum +end + +function MercenaryTools.missingSupportPolicyError(skill) + if not skill then + return nil + end + return "Missing support-count policy for "..tostring(skill.supportCountId).." on skill "..tostring(skill.id) +end + +function MercenaryTools.skillCandidateError(profile, mercenaryData, index, skillId) + if not skillId then + return nil + end + local build = profile and mercenaryData and mercenaryData.builds[profile.buildId] + if not build then + return "Select a Mercenary class and build" + end + local skill = mercenaryData.skills[skillId] + if not skill or not contains(build.skillIds, skillId) then + return "Invalid skill for selected build: "..tostring(skillId) + end + local skills = profile.skills or { } + local replacing = skills[index] ~= nil + if not replacing and #skills >= MAX_SKILLS then + return "A Mercenary cannot have more than 6 inherent skills" + end + for skillIndex, selected in ipairs(skills) do + if skillIndex ~= index and selected.id == skillId then + return "Duplicate skill: "..skillId + end + end + local poolCounts = { } + for skillIndex, selected in ipairs(skills) do + local id = skillIndex == index and skillId or selected.id + for poolIndex, pool in ipairs(build.skillPools or { }) do + if contains(pool.skillIds, id) then + poolCounts[poolIndex] = (poolCounts[poolIndex] or 0) + 1 + break + end + end + end + if not replacing then + for poolIndex, pool in ipairs(build.skillPools or { }) do + if contains(pool.skillIds, skillId) then + poolCounts[poolIndex] = (poolCounts[poolIndex] or 0) + 1 + break + end + end + end + for poolIndex, pool in ipairs(build.skillPools or { }) do + if pool.countMax and (poolCounts[poolIndex] or 0) > pool.countMax then + return "Skill pool "..poolIndex.." allows at most "..pool.countMax.." skills" + end + end +end + +function MercenaryTools.firstLegalSkillId(profile, mercenaryData) + local build = profile and mercenaryData and mercenaryData.builds[profile.buildId] + if not build then + return nil + end + local index = #(profile.skills or { }) + 1 + for _, skillId in ipairs(build.skillIds) do + if not MercenaryTools.skillCandidateError(profile, mercenaryData, index, skillId) then + return skillId + end + end +end + +-- Dense support-list edit used by committed selection and DPS-sort previews. +-- Writing by raw index creates holes that ipairs ignores during calculation. +function MercenaryTools.setSkillSupport(supports, index, support) + if support then + supports[m_min(index, #supports + 1)] = support + elseif supports[index] then + t_remove(supports, index) + end +end + +function MercenaryTools.withEditedSupports(skill, index, support, fn) + local original = skill.supports + skill.supports = copyTable(original or { }, true) + MercenaryTools.setSkillSupport(skill.supports, index, support) + return withRestored(function() + skill.supports = original + end, fn) +end + +function MercenaryTools.supportCandidateError(profile, mercenaryData, skillIndex, supportIndex, supportId) + if not supportId then + return nil + end + local selected = profile and profile.skills and profile.skills[skillIndex] + if not selected then + return "No selected Mercenary skill" + end + local skill = mercenaryData.skills[selected.id] + local maxSupports = MercenaryTools.supportLimit(mercenaryData, skill) + if maxSupports == nil then + return MercenaryTools.missingSupportPolicyError(skill) or "Missing support-count policy" + end + if supportIndex > maxSupports then + return "Skill "..tostring(selected.id).." allows at most "..maxSupports.." supports" + end + local supports = selected.supports or { } + if not supports[supportIndex] and #supports >= maxSupports then + return "Skill "..tostring(selected.id).." has more than "..maxSupports.." supports" + end + local support = mercenaryData.supports[supportId] + if not support or not skill or not contains(skill.possibleSupportIds, supportId) then + return "Invalid support for skill "..tostring(selected.id)..": "..tostring(supportId) + end + for index, selectedSupport in ipairs(supports) do + if index ~= supportIndex then + if selectedSupport.id == supportId then + return "Duplicate support "..supportId.." on skill "..tostring(selected.id) + end + local existing = mercenaryData.supports[selectedSupport.id] + if support.familyId and existing and existing.familyId == support.familyId then + return "Duplicate support family "..support.familyId.." on skill "..tostring(selected.id) + end + end + end +end + +function MercenaryTools.maxSupportLimit(mercenaryData) + local maximum = 0 + for _, count in pairs(mercenaryData.supportCounts) do + maximum = m_max(maximum, count.maximum) + end + return maximum +end +local supportLimit = MercenaryTools.supportLimit + +function MercenaryTools.skillLevel(grantedEffect, actorLevel) + local bestLevel, bestRequirement = 1, -1 + for level, levelData in pairs(grantedEffect and grantedEffect.levels or { }) do + local requirement = levelData.levelRequirement or 1 + if type(level) == "number" and requirement <= actorLevel and (requirement > bestRequirement or requirement == bestRequirement and level > bestLevel) then + bestLevel, bestRequirement = level, requirement + end + end + return bestLevel +end + +local function listProducesSkillData(mods, key) + for _, modOrGroup in ipairs(mods or { }) do + for _, mod in ipairs(modOrGroup.name and { modOrGroup } or modOrGroup) do + if mod.name == "SkillData" and type(mod.value) == "table" and mod.value.key == key then + return true + end + end + end + return false +end + +local function producesSkillData(grantedEffect, key) + if listProducesSkillData(grantedEffect.baseMods, key) then + return true + end + local function statProduces(statId) + local map = grantedEffect.statMap[statId] + return map ~= nil and listProducesSkillData(map, key) + end + for _, statId in ipairs(grantedEffect.stats or { }) do + if statProduces(statId) then return true end + end + for _, stat in ipairs(grantedEffect.constantStats or { }) do + if statProduces(stat[1]) then return true end + end + -- Quality stats are deliberately not consulted: a Mercenary skill is not a gem and + -- always has quality 0, so anything only a quality stat produces stays nil. + return false +end + +-- Which declared inputs of the base skill's `preDamageFunc` this Mercenary skill cannot +-- populate from its own stats, or nil when the base declares no inputs at all. +function MercenaryTools.missingPreDamageFuncInputs(grantedEffect, baseSkillId, mercenaryStatData) + local declared = mercenaryStatData.preDamageFuncInputs[baseSkillId] + if not declared then + return nil + end + local missing = { } + for _, key in ipairs(declared) do + if not producesSkillData(grantedEffect, key) then t_insert(missing, key) end + end + return missing +end + +-- Report every declared input of an inherited `preDamageFunc` that the Mercenary +-- skill's own stats cannot populate. Without this the function reads nil, which +-- either errors or reports the missing damage component as zero. +-- A Mercenary skill that overrides `preDamageFunc` itself is not checked, because that +-- function was written against the stats the Mercenary version actually has. +function MercenaryTools.preDamageFuncErrors(grantedEffect, baseEffect, mercenaryStatData) + if not grantedEffect.preDamageFunc or not grantedEffect.inheritedFrom + or grantedEffect.preDamageFunc ~= (baseEffect and baseEffect.preDamageFunc) then + return nil + end + local missing = MercenaryTools.missingPreDamageFuncInputs(grantedEffect, grantedEffect.inheritedFrom, mercenaryStatData) + if not missing then + return { "Undeclared preDamageFunc inputs for "..grantedEffect.inheritedFrom.." (inherited by "..grantedEffect.id..")" } + end + local errors + for _, key in ipairs(missing) do + errors = errors or { } + t_insert(errors, "Mercenary skill "..grantedEffect.id.." has no stat for "..key..", required by the "..grantedEffect.inheritedFrom.." preDamageFunc") + end + return errors +end + +-- A Mercenary is as strong as the area it was found in, and levels up with the areas +-- it is taken to, but stops gaining levels past the level of the highest-level +-- non-endgame area (GGG patch notes: "up to a maximum of level 68"). Found-area +-- level itself is not limited by that ceiling: map Mercenaries keep their high +-- found-area level, but monster damage/armour/evasion tables only exist for 1-100. +local MERCENARY_AREA_SCALING_CAP = 68 +local MERCENARY_LEVEL_MAX = 100 +-- A Mercenary can equip an item requiring up to this fraction more than the level +-- of the area it was found in. +local FOUND_AREA_LEVEL_REQUIREMENT_RATIO = 0.7 + +function MercenaryTools.effectiveLevel(foundAreaLevel, currentAreaLevel) + local found = m_max(1, m_min(tonumber(foundAreaLevel) or 1, MERCENARY_LEVEL_MAX)) + local current = m_max(1, m_min(tonumber(currentAreaLevel) or 1, MERCENARY_AREA_SCALING_CAP)) + return m_max(found, current) +end + +function MercenaryTools.requiredFoundAreaLevel(requiredLevel) + return math.ceil((tonumber(requiredLevel) or 0) * FOUND_AREA_LEVEL_REQUIREMENT_RATIO) +end + +-- MercenaryBuildExtraStats exports the three values but not their tier boundaries. +-- Keep the validated runtime tier policy here until those boundaries are exposed. +-- Values are truncated because passive mods are integer values. +MercenaryTools.PASSIVE_STAT_LEVELS = { 24, 68, 84 } + +-- Noble Blood's PassiveSkills row exports only the maximum MORE penalty. +-- 3.29.1 tapers that penalty in; those breakpoints are not a DAT table. +-- Patch notes: no penalty before level 45, maximum at level 83. +-- Round-to-nearest integer MORE so the cap is reached at 83, not 82. +MercenaryTools.PERMANENT_DAMAGE_MORE_START_LEVEL = 45 +MercenaryTools.PERMANENT_DAMAGE_MORE_END_LEVEL = 83 + +function MercenaryTools.permanentDamageMore(level, maxMore) + maxMore = tonumber(maxMore) + if maxMore == nil then + error("permanent Mercenary damage max is required") + end + local startLevel = MercenaryTools.PERMANENT_DAMAGE_MORE_START_LEVEL + local endLevel = MercenaryTools.PERMANENT_DAMAGE_MORE_END_LEVEL + local actorLevel = m_max(1, tonumber(level) or 1) + if actorLevel <= startLevel then + return 0 + end + if actorLevel >= endLevel then + return maxMore + end + return m_floor(maxMore * (actorLevel - startLevel) / (endLevel - startLevel) + 0.5) +end + +function MercenaryTools.passiveStatValue(values, level) + local levels = MercenaryTools.PASSIVE_STAT_LEVELS + local clampedLevel = m_max(levels[1], m_min(tonumber(level) or levels[1], levels[3])) + local first, second, third = tonumber(values and values[1]) or 0, tonumber(values and values[2]) or 0, tonumber(values and values[3]) or 0 + if clampedLevel <= levels[2] then + return m_floor(first + (second - first) * (clampedLevel - levels[1]) / (levels[2] - levels[1])) + end + return m_floor(second + (third - second) * (clampedLevel - levels[2]) / (levels[3] - levels[2])) +end + +local function splitWarrantBlocks(text) + local blocks, block = { }, { } + for line in (text.."\n"):gmatch("(.-)\n") do + line = line:match("^%s*(.-)%s*$") + if line:match("^%-+$") then + if #block > 0 then t_insert(blocks, block) end + block = { } + elseif line ~= "" then + t_insert(block, line) + end + end + if #block > 0 then t_insert(blocks, block) end + return blocks +end + +local function namedRecords(records, ids, name) + local matches = { } + if ids then + for _, id in ipairs(ids) do + local record = records[id] + if record and record.name == name then t_insert(matches, id) end + end + else + for id, record in pairs(records or { }) do + if record.name == name then t_insert(matches, id) end + end + t_sort(matches) + end + return matches +end + +function MercenaryTools.importWarrant(text, mercenaryData) + if type(text) ~= "string" or text:match("^%s*$") then + return nil, "Paste a Mercenary Warrant item text" + elseif #text > MAX_WARRANT_BYTES then + return nil, "Mercenary Warrant text exceeds 256 KiB" + elseif not mercenaryData or not mercenaryData.builds or not mercenaryData.skills or not mercenaryData.supports then + return nil, "Mercenary data is unavailable" + end + + text = text:gsub("\r\n", "\n"):gsub("\r", "\n") + local blocks = splitWarrantBlocks(text) + local hasWarrant, buildName, foundAreaLevel = false, nil, nil + for _, block in ipairs(blocks) do + for _, line in ipairs(block) do + hasWarrant = hasWarrant or line == "Mercenary Warrant" + local value = line:match("^Build:%s*(.-)%s*$") + if value then + buildName = value + end + value = line:match("^Mercenary Level:%s*(%d+)%s*$") + if value then + foundAreaLevel = tonumber(value) + end + end + end + if not hasWarrant then return nil, "Text is not a Mercenary Warrant" end + if not buildName then return nil, "Mercenary Warrant is missing its Build line" end + if not foundAreaLevel then return nil, "Mercenary Warrant is missing its Mercenary Level line" end + if foundAreaLevel < 1 or foundAreaLevel > 100 then + return nil, "Mercenary Level must be an integer between 1 and 100" + end + + local buildIds = namedRecords(mercenaryData.builds, mercenaryData.buildOrder, buildName) + if #buildIds == 0 then + return nil, "Unknown Mercenary build: "..buildName + elseif #buildIds > 1 then + return nil, "Ambiguous Mercenary build: "..buildName + end + local build = mercenaryData.builds[buildIds[1]] + local importedSkills, startedSkills = { }, false + local sawBuildLine, sawLevelLine = false, false + for _, block in ipairs(blocks) do + local firstLine = block[1] + if firstLine and firstLine:match("^Right click this item") then break end + + local hasMetadataLine = false + for _, line in ipairs(block) do + if line:match("^Build:") then + sawBuildLine = true + hasMetadataLine = true + end + if line:match("^Mercenary Level:") then + sawLevelLine = true + hasMetadataLine = true + end + end + local metadataReady = sawBuildLine and sawLevelLine + if metadataReady and not hasMetadataLine then + local skillIds = namedRecords(mercenaryData.skills, build.skillIds, firstLine) + if #skillIds == 0 then + return nil, "Unknown Mercenary skill for "..buildName..": "..tostring(firstLine) + elseif #skillIds > 1 then + return nil, "Ambiguous Mercenary skill for "..buildName..": "..firstLine + elseif #importedSkills >= MAX_SKILLS then + return nil, "A Mercenary Warrant cannot contain more than 6 skills" + end + + local skillId = skillIds[1] + local skill = mercenaryData.skills[skillId] + local importedSkill = { + id = skillId, + enabled = true, + includeInFullDPS = false, + count = 1, + supports = { }, + } + local seenSupports, seenFamilies = { }, { } + for lineIndex = 2, #block do + local supportName, tierText = block[lineIndex]:match("^(.+)%s+%(%s*Tier:%s*(%d+)%s*%)$") + if not supportName then + return nil, "Invalid support line for "..skill.name..": "..block[lineIndex] + end + local tier = tonumber(tierText) + local supportIds = { } + for _, supportId in ipairs(skill.possibleSupportIds or { }) do + local support = mercenaryData.supports[supportId] + if support and support.name == supportName and support.variant == tier then + t_insert(supportIds, supportId) + end + end + if #supportIds == 0 then + return nil, "Support "..supportName.." (Tier: "..tier..") is not valid for "..skill.name + elseif #supportIds > 1 then + return nil, "Ambiguous support "..supportName.." (Tier: "..tier..") for "..skill.name + end + local supportId = supportIds[1] + local support = mercenaryData.supports[supportId] + if seenSupports[supportId] then + return nil, "Duplicate support "..supportName.." on "..skill.name + elseif support.familyId and seenFamilies[support.familyId] then + return nil, "Duplicate support family "..support.familyId.." on "..skill.name + end + seenSupports[supportId] = true + if support.familyId then seenFamilies[support.familyId] = true end + t_insert(importedSkill.supports, { id = supportId, tier = tier }) + end + t_insert(importedSkills, importedSkill) + startedSkills = true + elseif startedSkills and firstLine then + return nil, "Unexpected text after Mercenary skills: "..firstLine + end + end + if #importedSkills == 0 then return nil, "Mercenary Warrant contains no recognized skills" end + + local profile = { + classId = build.classId, + buildId = build.id, + foundAreaLevel = foundAreaLevel, + importedWarrant = true, + mainSkillId = importedSkills[1].id, + skills = importedSkills, + } + local errors = MercenaryTools.validateProfile(profile, mercenaryData) + if #errors > 0 then return nil, t_concat(errors, "; ") end + return profile +end + +function MercenaryTools.validateProfile(profile, mercenaryData) + local errors = { } + local build = profile and mercenaryData and mercenaryData.builds[profile.buildId] + if not build then + t_insert(errors, "Select a Mercenary class and build") + return errors + end + local foundAreaLevel = tonumber(profile.foundAreaLevel) + if not foundAreaLevel or foundAreaLevel % 1 ~= 0 or foundAreaLevel < 1 or foundAreaLevel > 100 then + t_insert(errors, "Mercenary level must be an integer between 1 and 100") + end + if #(profile.skills or { }) > MAX_SKILLS then + t_insert(errors, "A Mercenary cannot have more than 6 inherent skills") + end + local seenSkills, enabledSkillsById = { }, { } + local poolCounts = { } + local enabledSkills = 0 + for _, selected in ipairs(profile.skills or { }) do + if selected.count ~= nil and (type(selected.count) ~= "number" or selected.count % 1 ~= 0 or selected.count < 1 or selected.count > 99) then + t_insert(errors, "Full DPS count for "..tostring(selected.id).." must be an integer from 1 to 99") + end + if selected.enabled ~= false and selected.id then + enabledSkills = enabledSkills + 1 + enabledSkillsById[selected.id] = true + end + local skill = mercenaryData.skills[selected.id] + if not skill or not contains(build.skillIds, selected.id) then + t_insert(errors, "Invalid skill for selected build: "..tostring(selected.id)) + elseif seenSkills[selected.id] then + t_insert(errors, "Duplicate skill: "..selected.id) + else + seenSkills[selected.id] = true + end + for poolIndex, pool in ipairs(build.skillPools or { }) do + if contains(pool.skillIds, selected.id) then + poolCounts[poolIndex] = (poolCounts[poolIndex] or 0) + 1 + break + end + end + if skill then + local maxSupports = supportLimit(mercenaryData, skill) + if maxSupports == nil then + t_insert(errors, MercenaryTools.missingSupportPolicyError(skill)) + elseif #(selected.supports or { }) > maxSupports then + t_insert(errors, "Skill "..tostring(selected.id).." has more than "..maxSupports.." supports") + end + end + local seenSupports, seenFamilies = { }, { } + for _, selectedSupport in ipairs(selected.supports or { }) do + local supportId = selectedSupport and selectedSupport.id + local support = mercenaryData.supports[supportId] + if not support or not skill or not contains(skill.possibleSupportIds, supportId) then + t_insert(errors, "Invalid support for skill "..tostring(selected.id)..": "..tostring(supportId)) + elseif selectedSupport.tier ~= support.variant then + t_insert(errors, "Invalid tier for support "..selectedSupport.id) + elseif seenSupports[supportId] then + t_insert(errors, "Duplicate support "..selectedSupport.id.." on skill "..tostring(selected.id)) + elseif support.familyId and seenFamilies[support.familyId] then + t_insert(errors, "Duplicate support family "..support.familyId.." on skill "..tostring(selected.id)) + end + if supportId then seenSupports[supportId] = true end + if support and support.familyId then seenFamilies[support.familyId] = true end + end + end + -- Warrant text contains the authoritative complete roster. The exported pool + -- maximums describe spawn selection, so they do not constrain an imported Warrant. + if not profile.importedWarrant then + for poolIndex, pool in ipairs(build.skillPools or { }) do + if pool.countMax and (poolCounts[poolIndex] or 0) > pool.countMax then + t_insert(errors, "Skill pool "..poolIndex.." allows at most "..pool.countMax.." skills") + end + end + end + if #(profile.skills or { }) == 0 then + t_insert(errors, "Select at least one Mercenary skill") + elseif enabledSkills == 0 then + t_insert(errors, "Enable at least one Mercenary skill") + elseif not profile.mainSkillId then + t_insert(errors, "Select a Mercenary skill for Calcs") + elseif not seenSkills[profile.mainSkillId] then + t_insert(errors, "Selected Calcs skill is not configured") + elseif not enabledSkillsById[profile.mainSkillId] then + t_insert(errors, "Selected Calcs skill is disabled") + end + return errors +end + +local ARMOUR_SLOTS = { + Helmet = true, + ["Body Armour"] = true, + Gloves = true, + Boots = true, +} +-- Unique equipment is only permitted where something has granted the matching +-- "Your Mercenary can equip Unique ..." flag. Body Armour has no such flag. +-- Re-evaluate when GGG adds a Unique Body Armour permission modifier. +local UNIQUE_FLAG_BY_SLOT = { + ["Weapon 1"] = "MercenaryCanEquipUniqueArms", + ["Weapon 2"] = "MercenaryCanEquipUniqueArms", + Helmet = "MercenaryCanEquipUniqueHelmets", + Gloves = "MercenaryCanEquipUniqueGloves", + Boots = "MercenaryCanEquipUniqueBoots", + Amulet = "MercenaryCanEquipUniqueAmulets", + ["Ring 1"] = "MercenaryCanEquipUniqueRings", + ["Ring 2"] = "MercenaryCanEquipUniqueRings", + Belt = "MercenaryCanEquipUniqueBelts", +} +local UNIQUE_SLOT_DESCRIPTION = { + MercenaryCanEquipUniqueArms = "Unique Weapons, Shields and Quivers", + MercenaryCanEquipUniqueHelmets = "Unique Helmets", + MercenaryCanEquipUniqueGloves = "Unique Gloves", + MercenaryCanEquipUniqueBoots = "Unique Boots", + MercenaryCanEquipUniqueAmulets = "Unique Amulets", + MercenaryCanEquipUniqueRings = "Unique Rings", + MercenaryCanEquipUniqueBelts = "Unique Belts", +} + +function MercenaryTools.isSlotSupported(slotName) + local parentSlot = slotName:match("^(.-) Abyssal Socket %d+$") + return contains(MercenaryTools.equipmentSlots, parentSlot or slotName) +end + +-- Same PoB object, or the same PoE API uniqueID when that persistent identity exists. +function MercenaryTools.samePhysicalItem(item, other) + if not item or not other then + return false + end + if item.id and other.id and item.id == other.id then + return true + end + return item.uniqueID ~= nil and item.uniqueID ~= "" and item.uniqueID == other.uniqueID +end + +function MercenaryTools.playerEquipsPhysicalItem(item, playerItemSet, items) + if not item or not playerItemSet then + return false + end + for _, playerSlot in pairs(playerItemSet) do + if type(playerSlot) == "table" and playerSlot.selItemId and playerSlot.selItemId ~= 0 then + if playerSlot.selItemId == item.id then + return true + end + if MercenaryTools.samePhysicalItem(item, items and items[playerSlot.selItemId]) then + return true + end + end + end + return false +end + +function MercenaryTools.validateEquippedItem(item, slotName, context) + if not MercenaryTools.isSlotSupported(slotName) then + return false, "slot is not supported by Mercenaries" + end + local parentSlot, abyssalSocketIndex = slotName:match("^(.-) Abyssal Socket (%d+)$") + if parentSlot then + local parentItem = MercenaryTools.equippedItem(context.itemSet, context.items, parentSlot, context.override, context.mercenaryItemSetId) + if not parentItem or (parentItem.abyssalSocketCount or 0) < tonumber(abyssalSocketIndex) then + return false, "parent item does not have this Abyssal Socket" + end + end + local mercenaryData = context.mercenaryData + local profile = context.profile + local mercBuild = mercenaryData.builds[profile.buildId] + local class = mercBuild and mercenaryData.classes[mercBuild.classId] + if not mercBuild or not class then + return false, "select a Mercenary build first" + end + local isArmourEquipment = ARMOUR_SLOTS[slotName] or item.type == "Shield" + if isArmourEquipment then + if not class.attributeId or class.attributeId == "" then + return false, "Selected Mercenary class is missing attribute data" + end + local itemRequirements = item.requirements or { } + local attributes = class.attributeId + local attributeCount, requiredAttributeCount, hasAssociatedRequirement = 0, 0, false + for _, attribute in ipairs({ "Str", "Dex", "Int" }) do + if attributes:find(attribute, 1, true) then attributeCount = attributeCount + 1 end + end + for _, requirement in ipairs({ { "Str", "str" }, { "Dex", "dex" }, { "Int", "int" } }) do + local required = (itemRequirements[requirement[2]] or 0) > 0 + local associated = attributes:find(requirement[1], 1, true) ~= nil + if required then + requiredAttributeCount = requiredAttributeCount + 1 + hasAssociatedRequirement = hasAssociatedRequirement or associated + end + if attributeCount > 1 and required and not associated then + return false, "armour attribute alignment does not match "..class.attributeName + end + end + if attributeCount == 1 and (not hasAssociatedRequirement or requiredAttributeCount > 2) then + return false, "armour attribute alignment does not match "..class.attributeName + end + end + local requiredFoundLevel = MercenaryTools.requiredFoundAreaLevel(item.requirements and item.requirements.level) + if (profile.foundAreaLevel or 0) < requiredFoundLevel then + return false, "requires Mercenary level "..requiredFoundLevel + end + if (item.rarity == "UNIQUE" or item.rarity == "RELIC") and not (item.type == "Jewel" and item.base and item.base.subType == "Abyss") then + local requiredFlag = UNIQUE_FLAG_BY_SLOT[slotName] + if not requiredFlag then + return false, "Unique items are never permitted in this slot" + elseif context.playerHasFlag(requiredFlag) == false then + return false, "requires a modifier allowing your Mercenary to equip "..UNIQUE_SLOT_DESCRIPTION[requiredFlag] + end + end + if slotName == "Weapon 1" or slotName == "Weapon 2" then + local allowedTypes = slotName == "Weapon 1" and mercBuild.weaponConfiguration.mainHandTypes or mercBuild.weaponConfiguration.offHandTypes + if not contains(allowedTypes, item.type) then + return false, item.type.." is not valid in this weapon slot for the selected build" + end + end + if context.itemSet ~= context.playerItemSet and MercenaryTools.playerEquipsPhysicalItem(item, context.playerItemSet, context.items) then + return false, "the same physical item is equipped by the player" + end + return true +end + +function MercenaryTools.equipmentErrors(context) + local errors = { } + local function equippedLookup(slotName) + return MercenaryTools.equippedItem(context.itemSet, context.items, slotName, context.override, context.mercenaryItemSetId) + end + local mercBuild = context.mercenaryData.builds[context.profile.buildId] + if mercBuild and mercBuild.weaponConfiguration.offHandRequired then + if not equippedLookup("Weapon 2") then + t_insert(errors, "Weapon 2: selected build requires a "..t_concat(mercBuild.weaponConfiguration.offHandTypes, " or ")) + end + end + local function checkSlot(slotName) + local item = equippedLookup(slotName) + if item then + if not context.isItemValidForSlot(item, slotName, context.itemSet, equippedLookup) then + t_insert(errors, slotName..": invalid base slot or weapon configuration") + else + local valid, reason = MercenaryTools.validateEquippedItem(item, slotName, context) + if not valid then + t_insert(errors, slotName..": "..reason) + end + end + end + end + for _, slotName in ipairs(MercenaryTools.equipmentSlots) do + checkSlot(slotName) + for index = 1, 6 do + checkSlot(slotName.." Abyssal Socket "..index) + end + end + return errors +end + +return MercenaryTools diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index bc1f7b97366..da997e8da37 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -1249,15 +1249,18 @@ local preFlagList = { ["^socketed vaal skills [hgd][ae][via][enl] "] = { addToSkill = { type = "SocketedIn", slotName = "{SlotName}", keyword = "vaal" } }, ["^socketed projectile spells [hgdf][aei][viar][enl] "] = { addToSkill = { type = "SocketedIn", slotName = "{SlotName}" }, tagList = { { type = "SkillType", skillType= SkillType.Projectile }, { type = "SkillType", skillType = SkillType.Spell } } }, -- Enemy modifiers - ["^enemies withered by you [th]a[vk]e "] = { tag = { type = "MultiplierThreshold", var = "WitheredStack", threshold = 1 }, applyToEnemy = true }, + ["^enemies withered by you [th]a[vk]e "] = { tag = { type = "MultiplierThreshold", var = "WitheredStack", threshold = 1, sourceOwned = true }, applyToEnemy = true }, ["^enemies (%a+) by you take "] = function(cond) - return { tag = { type = "Condition", var = cond:gsub("^%a", string.upper) }, applyToEnemy = true, modSuffix = "Taken" } + return { tag = { type = "Condition", var = cond:gsub("^%a", string.upper), sourceOwned = true }, applyToEnemy = true, modSuffix = "Taken" } end, ["^enemies (%a+) by "] = function(cond) return { tag = { type = "Condition", var = cond:gsub("^%a", string.upper) }, applyToEnemy = true } end, ["^enemies (%a+) by you have "] = function(cond) - return { tag = { type = "Condition", var = cond:gsub("^%a", string.upper) }, applyToEnemy = true } + return { tag = { type = "Condition", var = cond:gsub("^%a", string.upper), sourceOwned = true }, applyToEnemy = true } + end, + ["^enemies (%a+) by you "] = function(cond) + return { tag = { type = "Condition", var = cond:gsub("^%a", string.upper), sourceOwned = true }, applyToEnemy = true } end, ["^while a pinnacle atlas boss is in your presence, enemies you've hit recently have "] = function(cond) return { playerTagList = { { type = "Condition", var = "HitRecently" }, { type = "ActorCondition", actor = "enemy", var = "PinnacleBoss" } }, applyToEnemy = true } @@ -1269,12 +1272,12 @@ local preFlagList = { return { playerTag = { type = "Condition", var = "HitRecently" }, applyToEnemy = true } end, ["^hits against enemies (%a+) by you have "] = function(cond) - return { tag = { type = "ActorCondition", actor = "enemy", var = cond:gsub("^%a", string.upper) } } + return { tag = { type = "ActorCondition", actor = "enemy", var = cond:gsub("^%a", string.upper), sourceOwned = true } } end, - ["^enemies shocked or frozen by you take "] = { tag = { type = "Condition", varList = { "Shocked","Frozen" } }, applyToEnemy = true, modSuffix = "Taken" }, - ["^enemies affected by your spider's webs [thd][ae][avk][el] "] = { tag = { type = "MultiplierThreshold", var = "Spider's WebStack", threshold = 1 }, applyToEnemy = true }, - ["^enemies you curse take "] = { tag = { type = "Condition", var = "Cursed" }, applyToEnemy = true, modSuffix = "Taken" }, - ["^enemies you curse "] = { tag = { type = "Condition", var = "Cursed" }, applyToEnemy = true }, + ["^enemies shocked or frozen by you take "] = { tag = { type = "Condition", varList = { "Shocked","Frozen" }, sourceOwned = true }, applyToEnemy = true, modSuffix = "Taken" }, + ["^enemies affected by your spider's webs [thd][ae][avk][el] "] = { tag = { type = "MultiplierThreshold", var = "Spider's WebStack", threshold = 1, sourceOwned = true }, applyToEnemy = true }, + ["^enemies you curse take "] = { tag = { type = "Condition", var = "Cursed", sourceOwned = true }, applyToEnemy = true, modSuffix = "Taken" }, + ["^enemies you curse "] = { tag = { type = "Condition", var = "Cursed", sourceOwned = true }, applyToEnemy = true }, ["^nearby enemies take "] = { modSuffix = "Taken", applyToEnemy = true }, ["^nearby enemies have "] = { applyToEnemy = true }, ["^nearby enemies deal "] = { applyToEnemy = true }, @@ -1309,7 +1312,7 @@ local preFlagList = { ["^blink arrow and mirror arrow have "] = { tag = { type = "SkillName", skillNameList = { "Blink Arrow", "Mirror Arrow" }, includeTransfigured = true } }, ["attacks with energy blades "] = { flags = ModFlag.Attack, tag = { type = "Condition", var = "AffectedByEnergyBlade" } }, ["^for each nearby corpse, "] = { tag = { type = "Multiplier", var = "NearbyCorpse" } }, - ["^enemies in your link beams have "] = { tag = { type = "Condition", var = "BetweenYouAndLinkedTarget" }, applyToEnemy = true }, + ["^enemies in your link beams have "] = { tag = { type = "Condition", var = "BetweenYouAndLinkedTarget", sourceOwned = true }, applyToEnemy = true }, ["^consecrated ground you create a?l?s?o? ?grants "] = { tag = { type = "Condition", var = "OnConsecratedGround" } }, -- While in the presence of... ["^while a unique enemy is in your presence, "] = { tag = { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" } }, @@ -2040,7 +2043,7 @@ end table.sort(skillIds) for _, id in ipairs(skillIds) do local grantedEffect = data.skills[id] - if not grantedEffect.hidden or grantedEffect.fromItem or grantedEffect.fromTree then + if not grantedEffect.mercenary and (not grantedEffect.hidden or grantedEffect.fromItem or grantedEffect.fromTree) then gemIdLookup[grantedEffect.name:lower()] = grantedEffect.id end end @@ -2295,21 +2298,21 @@ local specialModList = { ["you cannot gain rage during soul gain prevention"] = { mod("RageRegen", "MORE", -100, { type = "Condition", var = "SoulGainPrevention" }) }, ["hits that deal elemental damage remove exposure to those elements and inflict exposure to other elements exposure inflicted this way applies (%-%d+)%% to resistances"] = function(num) return { flag("ElementalEquilibrium"), - mod("EnemyModifier", "LIST", { mod = mod("FireExposure", "BASE", num, { type = "Condition", varList={ "HitByColdDamage","HitByLightningDamage" } }) }), - mod("EnemyModifier", "LIST", { mod = mod("ColdExposure", "BASE", num, { type = "Condition", varList={ "HitByFireDamage","HitByLightningDamage" } }) }), - mod("EnemyModifier", "LIST", { mod = mod("LightningExposure", "BASE", num, { type = "Condition", varList={ "HitByFireDamage","HitByColdDamage" } }) }), + mod("EnemyModifier", "LIST", { mod = mod("FireExposure", "BASE", num, { type = "Condition", varList={ "HitByColdDamage","HitByLightningDamage" }, sourceOwned = true }) }), + mod("EnemyModifier", "LIST", { mod = mod("ColdExposure", "BASE", num, { type = "Condition", varList={ "HitByFireDamage","HitByLightningDamage" }, sourceOwned = true }) }), + mod("EnemyModifier", "LIST", { mod = mod("LightningExposure", "BASE", num, { type = "Condition", varList={ "HitByFireDamage","HitByColdDamage" }, sourceOwned = true }) }), } end, ["enemies you hit with elemental damage temporarily get (%+%d+)%% resistance to those elements and (%-%d+)%% resistance to other elements"] = function(plus, _, minus) minus = tonumber(minus) return { flag("ElementalEquilibrium"), flag("ElementalEquilibriumLegacy"), - mod("EnemyModifier", "LIST", { mod = mod("FireResist", "BASE", plus, { type = "Condition", var = "HitByFireDamage" }) }), - mod("EnemyModifier", "LIST", { mod = mod("FireResist", "BASE", minus, { type = "Condition", var = "HitByFireDamage", neg = true }, { type = "Condition", varList={ "HitByColdDamage","HitByLightningDamage" } }) }), - mod("EnemyModifier", "LIST", { mod = mod("ColdResist", "BASE", plus, { type = "Condition", var = "HitByColdDamage" }) }), - mod("EnemyModifier", "LIST", { mod = mod("ColdResist", "BASE", minus, { type = "Condition", var = "HitByColdDamage", neg = true }, { type = "Condition", varList={ "HitByFireDamage","HitByLightningDamage" } }) }), - mod("EnemyModifier", "LIST", { mod = mod("LightningResist", "BASE", plus, { type = "Condition", var = "HitByLightningDamage" }) }), - mod("EnemyModifier", "LIST", { mod = mod("LightningResist", "BASE", minus, { type = "Condition", var = "HitByLightningDamage", neg = true }, { type = "Condition", varList={ "HitByFireDamage","HitByColdDamage" } }) }), + mod("EnemyModifier", "LIST", { mod = mod("FireResist", "BASE", plus, { type = "Condition", var = "HitByFireDamage", sourceOwned = true }) }), + mod("EnemyModifier", "LIST", { mod = mod("FireResist", "BASE", minus, { type = "Condition", var = "HitByFireDamage", neg = true, sourceOwned = true }, { type = "Condition", varList={ "HitByColdDamage","HitByLightningDamage" }, sourceOwned = true }) }), + mod("EnemyModifier", "LIST", { mod = mod("ColdResist", "BASE", plus, { type = "Condition", var = "HitByColdDamage", sourceOwned = true }) }), + mod("EnemyModifier", "LIST", { mod = mod("ColdResist", "BASE", minus, { type = "Condition", var = "HitByColdDamage", neg = true, sourceOwned = true }, { type = "Condition", varList={ "HitByFireDamage","HitByLightningDamage" }, sourceOwned = true }) }), + mod("EnemyModifier", "LIST", { mod = mod("LightningResist", "BASE", plus, { type = "Condition", var = "HitByLightningDamage", sourceOwned = true }) }), + mod("EnemyModifier", "LIST", { mod = mod("LightningResist", "BASE", minus, { type = "Condition", var = "HitByLightningDamage", neg = true, sourceOwned = true }, { type = "Condition", varList={ "HitByFireDamage","HitByColdDamage" }, sourceOwned = true }) }), } end, ["projectile attack hits deal up to 30%% more damage to targets at the start of their movement, dealing less damage to targets as the projectile travels farther"] = { flag("PointBlank") }, @@ -2593,7 +2596,7 @@ local specialModList = { ["you have your maximum fortification"] = { flag("Condition:Fortified"), flag("Condition:HaveMaxFortification") }, ["you have (%d+) fortification"] = function(num) return { mod("MinimumFortification", "BASE", num) } end, ["nearby allies count as having fortification equal to yours"] = { mod("ExtraAura", "LIST", { onlyAllies = true, mod = mod("YourFortifyEqualToParent", "FLAG", true, { type = "GlobalEffect", effectType = "Global", unscalable = true } ) }) }, - ["enemies taunted by you cannot evade attacks"] = { mod("EnemyModifier", "LIST", { mod = flag("CannotEvade", { type = "Condition", var = "Taunted" }) }) }, + ["enemies taunted by you cannot evade attacks"] = { mod("EnemyModifier", "LIST", { mod = flag("CannotEvade", { type = "Condition", var = "Taunted", sourceOwned = true }) }) }, ["if you've impaled an enemy recently, you and nearby allies have %+(%d+) to armour"] = function (num) return { mod("ExtraAura", "LIST", { mod = mod("Armour", "BASE", num) }, { type = "Condition", var = "ImpaledRecently" }) } end, ["your hits permanently intimidate enemies that are on full life"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Intimidated", { type = "Condition", var = "ChampionIntimidate" }) }) }, ["you and allies affected by your placed banners regenerate ([%d%.]+)%% of life per second for each stage"] = function(num) return { @@ -3528,9 +3531,9 @@ local specialModList = { ["(%d+)%% of physical damage from hits with this weapon is converted to a random element"] = function(num) return { mod("PhysicalDamageConvertToRandom", "BASE", num, { type = "Condition", var = "{Hand}Attack" }) } end, ["(%d+)%% of physical damage converted to a random element"] = function(num) return { mod("PhysicalDamageConvertToRandom", "BASE", num ) } end, ["nearby enemies convert (%d+)%% of their (%a+) damage to (%a+)"] = function(num, _, damageFrom, damageTo) return { mod("EnemyModifier", "LIST", { mod = mod((damageFrom:gsub("^%l", string.upper)).."DamageConvertTo"..(damageTo:gsub("^%l", string.upper)), "BASE", num ) }), } end, - ["enemies ignited by you have (%d+)%% of (%a+) damage they deal converted to (%a+)"] = function(num, _, damageFrom, damageTo) return { mod("EnemyModifier", "LIST", { mod = mod((damageFrom:gsub("^%l", string.upper)).."DamageConvertTo"..(damageTo:gsub("^%l", string.upper)), "BASE", num, { type = "Condition", var = "Ignited" }) }), } end, - ["enemies shocked by you have (%d+)%% of (%a+) damage they deal converted to (%a+)"] = function(num, _, damageFrom, damageTo) return { mod("EnemyModifier", "LIST", { mod = mod((damageFrom:gsub("^%l", string.upper)).."DamageConvertTo"..(damageTo:gsub("^%l", string.upper)), "BASE", num, { type = "Condition", var = "Shocked" }) }), } end, - ["enemies poisoned by you have (%d+)%% of (%a+) damage they deal converted to (%a+)"] = function(num, _, damageFrom, damageTo) return { mod("EnemyModifier", "LIST", { mod = mod((damageFrom:gsub("^%l", string.upper)).."DamageConvertTo"..(damageTo:gsub("^%l", string.upper)), "BASE", num, { type = "Condition", var = "Poisoned" }) }), } end, + ["enemies ignited by you have (%d+)%% of (%a+) damage they deal converted to (%a+)"] = function(num, _, damageFrom, damageTo) return { mod("EnemyModifier", "LIST", { mod = mod((damageFrom:gsub("^%l", string.upper)).."DamageConvertTo"..(damageTo:gsub("^%l", string.upper)), "BASE", num, { type = "Condition", var = "Ignited", sourceOwned = true }) }), } end, + ["enemies shocked by you have (%d+)%% of (%a+) damage they deal converted to (%a+)"] = function(num, _, damageFrom, damageTo) return { mod("EnemyModifier", "LIST", { mod = mod((damageFrom:gsub("^%l", string.upper)).."DamageConvertTo"..(damageTo:gsub("^%l", string.upper)), "BASE", num, { type = "Condition", var = "Shocked", sourceOwned = true }) }), } end, + ["enemies poisoned by you have (%d+)%% of (%a+) damage they deal converted to (%a+)"] = function(num, _, damageFrom, damageTo) return { mod("EnemyModifier", "LIST", { mod = mod((damageFrom:gsub("^%l", string.upper)).."DamageConvertTo"..(damageTo:gsub("^%l", string.upper)), "BASE", num, { type = "Condition", var = "Poisoned", sourceOwned = true }) }), } end, ["shield crush and spectral shield throw do not gain added physical damage based on armour or evasion on shield"] = { flag("Condition:ShieldThrowCrushNoArmourEvasion", { type = "SkillName", skillNameList = { "Spectral Shield Throw", "Shield Crush" }, includeTransfigured = true })}, ["shield crush and spectral shield throw gains (%d+) to (%d+) added lightning damage per (%d+) energy shield on shield"] = function(_, min, max, num) return { mod("LightningMin", "BASE", min, 0, 0, { type = "Condition", var = "OffHandAttack" }, { type = "PerStat", stat = "EnergyShieldOnWeapon 2", div = num }, { type = "SkillName", skillNameList = { "Spectral Shield Throw", "Shield Crush" }, includeTransfigured = true }), @@ -3589,7 +3592,7 @@ local specialModList = { ["on non%-channelling attack, set a life flask with greater than %d+%% of maximum charges remaining to (%d+)%% for each charge removed this way, that attack gains %+(%d+)%% to damage over time multiplier"] = function(chargesConsumedPercent, _, damage) return { mod("DotMultiplier", "BASE", tonumber(damage), { type = "PercentStat", stat = "LifeFlaskCharges", percent = 100 - chargesConsumedPercent, floor = true }, { type = "SkillType", skillType = SkillType.Channel, neg = true }, { type = "SkillType", skillType = SkillType.Attack }) } end, - ["enemies poisoned by you cannot deal critical strikes"] = { mod("EnemyModifier", "LIST", { mod = flag("NeverCrit", { type = "Condition", var = "Poisoned" }) }), mod("EnemyModifier", "LIST", { mod = flag("Condition:NeverCrit", { type = "Condition", var = "Poisoned" })}) }, + ["enemies poisoned by you cannot deal critical strikes"] = { mod("EnemyModifier", "LIST", { mod = flag("NeverCrit", { type = "Condition", var = "Poisoned", sourceOwned = true }) }), mod("EnemyModifier", "LIST", { mod = flag("Condition:NeverCrit", { type = "Condition", var = "Poisoned", sourceOwned = true })}) }, ["marked enemy cannot deal critical strikes"] = { mod("EnemyModifier", "LIST", { mod = flag("NeverCrit", { type = "Condition", var = "Marked" }) }), mod("EnemyModifier", "LIST", { mod = flag("Condition:NeverCrit", { type = "Condition", var = "Marked" })}) }, ["marked enemy cannot evade attacks"] = { mod("EnemyModifier", "LIST", { mod = flag("CannotEvade", { type = "Condition", var = "Marked" }) }) }, ["hits against you cannot be critical strikes if you've been stunned recently"] = { mod("EnemyModifier", "LIST", { mod = flag("NeverCrit") }, {type = "Condition", var = "StunnedRecently" }), mod("EnemyModifier", "LIST", { mod = flag("Condition:NeverCrit")}, {type = "Condition", var = "StunnedRecently" })}, @@ -3695,7 +3698,7 @@ local specialModList = { }, ["you can inflict up to (%d+) ignites on an enemy"] = function(num) return { flag("IgniteCanStack"), mod("IgniteStacks", "OVERRIDE", num) } end, ["you can inflict an additional ignite on [ea][an]c?h? enemy"] = { flag("IgniteCanStack"), mod("IgniteStacks", "BASE", 1) }, - ["enemies chilled by you take (%d+)%% increased burning damage"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("FireDamageTakenOverTime", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Chilled" }) } end, + ["enemies chilled by you take (%d+)%% increased burning damage"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("FireDamageTakenOverTime", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Chilled", sourceOwned = true }) } end, ["damaging ailments deal damage (%d+)%% faster"] = function(num) return { mod("IgniteBurnFaster", "INC", num), mod("BleedFaster", "INC", num), mod("PoisonFaster", "INC", num) } end, ["damaging ailments you inflict deal damage (%d+)%% faster while affected by malevolence"] = function(num) return { mod("IgniteBurnFaster", "INC", num, { type = "Condition", var = "AffectedByMalevolence" }), @@ -3730,11 +3733,11 @@ local specialModList = { ["(%d+)%% chance for ignites inflicted with shock nova or storm call to deal (%d+)%% more damage"] = function(num, _, more) return { mod("Damage", "MORE", tonumber(more) * num / 100, nil, 0, KeywordFlag.Ignite, { type = "SkillName", skillNameList = { "Shock Nova", "Storm Call" }, includeTransfigured = true}), } end, - ["enemies ignited by you during f?l?a?s?k? ?effect take (%d+)%% increased damage"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Ignited" }) } end, + ["enemies ignited by you during f?l?a?s?k? ?effect take (%d+)%% increased damage"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Ignited", sourceOwned = true }) } end, ["enemies ignited by you take chaos damage instead of fire damage from ignite"] = { flag("IgniteToChaos") }, ["enemies chilled by your hits are shocked"] = { - mod("ShockBase", "BASE", data.nonDamagingAilment["Shock"].default, { type = "ActorCondition", actor = "enemy", var = "ChilledByYourHits" }), - mod("EnemyModifier", "LIST", { mod = flag("Condition:Shocked", { type = "Condition", var = "ChilledByYourHits" }) }) + mod("ShockBase", "BASE", data.nonDamagingAilment["Shock"].default, { type = "ActorCondition", actor = "enemy", var = "ChilledByYourHits", sourceOwned = true }), + mod("EnemyModifier", "LIST", { mod = flag("Condition:Shocked", { type = "Condition", var = "ChilledByYourHits", sourceOwned = true }) }) }, ["cannot inflict ignite"] = { flag("CannotIgnite") }, ["cannot inflict freeze or chill"] = { flag("CannotFreeze"), flag("CannotChill") }, @@ -3854,8 +3857,8 @@ local specialModList = { } end, ["chance to avoid being shocked applies to all elemental ailments"] = { flag("ShockAvoidAppliesToElementalAilments") }, -- typo / old wording change ["modifiers to chance to avoid being shocked apply to all elemental ailments"] = { flag("ShockAvoidAppliesToElementalAilments") }, - ["enemies permanently take (%d+)%% increased damage for each second they've ever been frozen by you, up to a maximum of (%d+)%%"] = function(num, _, limit) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num, { type = "Condition", var = "FrozenByYou" }, { type = "Multiplier", var = "FrozenByYouSeconds", limit = limit / num }) }) } end, - ["enemies permanently take (%d+)%% increased damage for each second they've ever been chilled by you, up to a maximum of (%d+)%%"] = function(num, _, limit) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num, { type = "Condition", var = "ChilledByYou" }, { type = "Multiplier", var = "ChilledByYouSeconds", limit = limit / num }) }) } end, + ["enemies permanently take (%d+)%% increased damage for each second they've ever been frozen by you, up to a maximum of (%d+)%%"] = function(num, _, limit) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num, { type = "Condition", var = "FrozenByYou", sourceOwned = true }, { type = "Multiplier", var = "FrozenByYouSeconds", limit = limit / num, sourceOwned = true }) }) } end, + ["enemies permanently take (%d+)%% increased damage for each second they've ever been chilled by you, up to a maximum of (%d+)%%"] = function(num, _, limit) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num, { type = "Condition", var = "ChilledByYou", sourceOwned = true }, { type = "Multiplier", var = "ChilledByYouSeconds", limit = limit / num, sourceOwned = true }) }) } end, ["modifiers to chance to suppress spell damage also apply to chance to avoid elemental ailments at (%d+)%% of their value"] = function(num) return { mod("SpellSuppressionAppliesToAilmentAvoidancePercent", "BASE", num), flag("SpellSuppressionAppliesToAilmentAvoidance") @@ -4032,10 +4035,10 @@ local specialModList = { mod("CurseEffect", "INC", tonumber(num), { type = "Multiplier", actor = "enemy", var = "CurseDurationExpired", limit = tonumber(limit), limitTotal = true }, { type = "SkillType", skillType = SkillType.Aura, neg = true }, { type = "SkillType", skillType = SkillType.Hex }) } end, ["enemies cursed by you have malediction if (%d+)%% of curse duration expired"] = function(num) return { - mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "MultiplierThreshold", var = "CurseExpired", threshold = tonumber(num) }, { type = "ActorCondition", var = "Cursed" }) }), + mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "MultiplierThreshold", var = "CurseExpired", threshold = tonumber(num) }, { type = "ActorCondition", actor = "enemy", var = "Cursed", sourceOwned = true }) }), } end, ["enemies cursed by you are hindered if (%d+)%% of curse duration expired"] = function(num) return { - mod("EnemyModifier", "LIST", { mod = flag("Condition:Hindered", { type = "MultiplierThreshold", var = "CurseExpired", threshold = tonumber(num) }, { type = "ActorCondition", var = "Cursed" }) }), + mod("EnemyModifier", "LIST", { mod = flag("Condition:Hindered", { type = "MultiplierThreshold", var = "CurseExpired", threshold = tonumber(num) }, { type = "ActorCondition", actor = "enemy", var = "Cursed", sourceOwned = true }) }), } end, ["excommunicate enemies on melee hit for (%d+) seconds"] = { flag("Condition:CanExcommunicate") }, ["auras from your skills can only affect you"] = { flag("SelfAurasOnlyAffectYou") }, @@ -4098,7 +4101,7 @@ local specialModList = { mod("EnemyModifier", "LIST", { mod = mod("ChaosResist", "BASE", num) }), } end, ["enemies ignited or chilled by you have (%-%d+)%% to elemental resistances"] = function(num) return { - mod("EnemyModifier", "LIST", { mod = mod("ElementalResist", "BASE", num )}, { type = "ActorCondition", actor = "enemy", varList = { "Ignited", "Chilled" } }) + mod("EnemyModifier", "LIST", { mod = mod("ElementalResist", "BASE", num )}, { type = "ActorCondition", actor = "enemy", varList = { "Ignited", "Chilled" }, sourceOwned = true }) } end, ["reserves (%d+)%% of nearby enemy monsters' life"] = function(num) return {mod("EnemyModifier", "LIST", { mod = mod("LifeReservationPercent", "BASE", num) })} end, ["nearby enemy monsters have at least (%d+)%% of life reserved"] = function(num) return {mod("EnemyModifier", "LIST", { mod = mod("LifeReservationPercent", "BASE", num) })} end, @@ -4188,7 +4191,7 @@ local specialModList = { ["warcries count as having (%d+) additional nearby enemies"] = function(num) return { mod("Multiplier:WarcryNearbyEnemies", "BASE", num), } end, - ["enemies taunted by your warcries take (%d+)%% increased damage"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num, { type = "Condition", var = "Taunted" }) }, { type = "Condition", var = "UsedWarcryRecently" }) } end, + ["enemies taunted by your warcries take (%d+)%% increased damage"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num, { type = "Condition", var = "Taunted", sourceOwned = true }) }, { type = "Condition", var = "UsedWarcryRecently" }) } end, ["warcries have minimum of (%d+) power"] = { flag("CryWolfMinimumPower") }, ["warcries have infinite power"] = { flag("WarcryInfinitePower") }, ["your warcries do not grant buffs or charges to you"] = { flag("CannotGainWarcryBuffs") }, @@ -4361,7 +4364,7 @@ local specialModList = { ["gain adrenaline for 1 second when you change stance"] = { flag("Condition:Adrenaline", { type = "Condition", var = "StanceChangeLastSecond" }) }, ["with a searching eye jewel socketed, maim enemies for (%d) seconds on hit with attacks"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Maimed", nil, ModFlag.Attack) }, { type = "Condition", var = "HaveSearchingEyeJewelIn{SlotName}" }) }, ["with a searching eye jewel socketed, blind enemies for (%d) seconds on hit with attacks"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Blinded", nil, ModFlag.Attack) }, { type = "Condition", var = "HaveSearchingEyeJewelIn{SlotName}" }) }, - ["enemies maimed by you take (%d+)%% increased damage over time"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTakenOverTime", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Maimed" }) } end, + ["enemies maimed by you take (%d+)%% increased damage over time"] = function(num) return { mod("EnemyModifier", "LIST", { mod = mod("DamageTakenOverTime", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Maimed", sourceOwned = true }) } end, ["(%d+)%% increased defences while you have at least four linked targets"] = function(num) return { mod("Defences", "INC", num, { type = "MultiplierThreshold", var = "LinkedTargets", threshold = 4 }) } end, ["your movement speed is equal to the highest movement speed among linked players"] = { flag("MovementSpeedEqualHighestLinkedPlayers", { type = "MultiplierThreshold", var = "LinkedTargets", threshold = 1 }), }, ["(%d+)%% increased movement speed while you have at least two linked targets"] = function(num) return { mod("MovementSpeed", "INC", num, { type = "MultiplierThreshold", var = "LinkedTargets", threshold = 2 }) } end, @@ -5037,6 +5040,37 @@ local specialModList = { mod("Armour", "INC", num, { type = "Multiplier", var = "StationarySeconds", limit = tonumber(limit / num) }, { type = "Condition", var = "Stationary" }), } end, ["(%d+)%% of damage from hits is taken from your r?a?i?s?e?d? ?spectres' life before you"] = function(num) return { mod("takenFromSpectresBeforeYou", "BASE", num) } end, + -- The damage penalty this node's reminder text describes is not stated on the + -- node, so it is applied to the Mercenary actor by `calcs.initMercenary` + -- through `MercenaryTools.permanentDamageMore` rather than sourced from here. + ["you can hire a mercenary permanently"] = { flag("CanHirePermanentMercenary") }, + ["your mercenary and their minions have (%d+)%% increased maximum life"] = function(num) return { + mod("MercenaryModifier", "LIST", { mod = mod("Life", "INC", num) }), + mod("MercenaryMinionModifier", "LIST", { mod = mod("Life", "INC", num) }), + } end, + ["your mercenary and their minions deal (%d+)%% increased damage"] = function(num) return { + mod("MercenaryModifier", "LIST", { mod = mod("Damage", "INC", num) }), + mod("MercenaryMinionModifier", "LIST", { mod = mod("Damage", "INC", num) }), + } end, + ["your mercenary taunts on hit"] = { flag("MercenaryTauntsOnHit") }, + ["your mercenary has (%d+)%% increased effect of non%-curse auras from skills"] = function(num) return { + -- Wiki: increases the effect of the Mercenary's own non-curse aura skills. + mod("MercenaryModifier", "LIST", { mod = mod("AuraEffect", "INC", num, { type = "SkillType", skillType = SkillType.Aura }, { type = "SkillType", skillType = SkillType.AppliesCurse, neg = true }) }), + } end, + ["your mercenary can equip unique weapons, shields and quivers"] = { flag("MercenaryCanEquipUniqueArms") }, + ["your mercenary can equip unique helmets"] = { flag("MercenaryCanEquipUniqueHelmets") }, + ["your mercenary can equip unique gloves"] = { flag("MercenaryCanEquipUniqueGloves") }, + ["your mercenary can equip unique boots"] = { flag("MercenaryCanEquipUniqueBoots") }, + ["your mercenary can equip unique amulets"] = { flag("MercenaryCanEquipUniqueAmulets") }, + ["your mercenary can equip unique rings"] = { flag("MercenaryCanEquipUniqueRings") }, + ["your mercenary can equip unique belts"] = { flag("MercenaryCanEquipUniqueBelts") }, + ["your mercenary and their minions deal (%d+)%% more damage for each unique item they have equipped"] = function(num) return { + mod("MercenaryModifier", "LIST", { mod = mod("Damage", "MORE", num, { type = "Multiplier", var = "UniqueItem" }) }), + mod("MercenaryMinionModifier", "LIST", { mod = mod("Damage", "MORE", num, { type = "Multiplier", var = "UniqueItem" }) }), + } end, + ["increases and reductions to light radius also apply to effect of your link skill buffs on your mercenary"] = { flag("LightRadiusAppliesToMercenaryLinkEffect") }, + ["if your mercenary's life is higher than your own, (%d+)%% of damage from hits is taken from your mercenary's life before you"] = function(num) return { mod("LoyalBodyguardRedirect", "BASE", num) } end, + ["if your mercenary's life is lower than your own, (%d+)%% of damage they take is recouped as life"] = function(num) return { mod("MercenaryLifeRecoup", "BASE", num) } end, ["(%d+)%% of damage from hits is taken from your nearest totem's life before you"] = function(num) return { mod("takenFromTotemsBeforeYou", "BASE", num, { type = "Condition", var = "HaveTotem" }) } end, ["(%d+)%% of damage from hits is taken from void spawns' life before you per void spawn"] = function(num) return { mod("takenFromVoidSpawnBeforeYou", "BASE", num, { type = "PerStat", stat = "ActiveVoidSpawnLimit" }) } end, ["(%a+) resistance cannot be penetrated"] = function(_, res) return { flag("EnemyCannotPen"..(res:gsub("^%l", string.upper)).."Resistance") } end, @@ -5067,7 +5101,7 @@ local specialModList = { -- Intimidate ["permanently intimidate enemies on block"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Intimidated") }, { type = "Condition", var = "BlockedRecently" }) }, ["with a murderous eye jewel socketed, intimidate enemies for (%d) seconds on hit with attacks"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Intimidated") }, { type = "Condition", var = "HaveMurderousEyeJewelIn{SlotName}" }) }, - ["enemies taunted by your warcries are intimidated"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Intimidated", { type = "Condition", var = "Taunted" }) }, { type = "Condition", var = "UsedWarcryRecently" }) }, + ["enemies taunted by your warcries are intimidated"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Intimidated", { type = "Condition", var = "Taunted", sourceOwned = true }) }, { type = "Condition", var = "UsedWarcryRecently" }) }, ["intimidate enemies for (%d+) seconds on block while holding a shield"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Intimidated") }, { type = "Condition", var = "BlockedRecently" }, { type = "Condition", var = "UsingShield" }) }, ["intimidate enemies on hit if you've cast (.-) in the past (%d+) seconds"] = function (_, curse) return { mod("EnemyModifier", "LIST", { mod = flag("Condition:Intimidated") }, nil, ModFlag.Hit, { type = "Condition", var = "SelfCast"..curse:gsub("^%l", string.upper):gsub(" %l", string.upper):gsub(" ", "") }) @@ -5478,9 +5512,9 @@ local specialModList = { ["your hits can't be evaded by blinded enemies"] = { flag("CannotBeEvaded", { type = "ActorCondition", actor = "enemy", var = "Blinded" }) }, ["blind does not affect your chance to hit"] = { flag("UnaffectedByBlind") }, ["unaffected by blind"] = { flag("UnaffectedByBlind") }, - ["enemies blinded by you while you are blinded have malediction"] = { mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "Condition", var = "Blinded" }) }, { type = "Condition", var = "Blinded" }, { type = "Condition", var = "CannotBeBlinded", neg = true }) }, - ["enemies blinded by you have malediction"] = { mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "Condition", var = "Blinded" }) }) }, - ["enemies ignited by you during effect have malediction"] = { mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "Condition", var = "Ignited" }) }) }, + ["enemies blinded by you while you are blinded have malediction"] = { mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "Condition", var = "Blinded", sourceOwned = true }) }, { type = "Condition", var = "Blinded" }, { type = "Condition", var = "CannotBeBlinded", neg = true }) }, + ["enemies blinded by you have malediction"] = { mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "Condition", var = "Blinded", sourceOwned = true }) }) }, + ["enemies ignited by you during effect have malediction"] = { mod("EnemyModifier", "LIST", { mod = flag("HasMalediction", { type = "Condition", var = "Ignited", sourceOwned = true }) }) }, ["skills which throw traps have blood magic"] = { flag("CostLifeInsteadOfMana", { type = "SkillType", skillType = SkillType.Trapped }) }, ["skills which throw traps cost life instead of mana"] = { flag("CostLifeInsteadOfMana", { type = "SkillType", skillType = SkillType.Trapped }) }, ["strength provides no bonus to maximum life"] = { flag("NoStrBonusToLife") }, @@ -5957,6 +5991,11 @@ local unsupportedModList = { ["properties are doubled while in a breach"] = true, ["mirrored"] = true, ["split"] = true, + -- Link Skill buffs are modelled as always applied, so PoB has no attachment + -- duration for this to remove. + ["link skills have infinite attachment duration"] = true, + -- PoB does not model either actor dying, so it has no death to prevent. + ["if your linked mercenary dies, the link owner does not also die"] = true, } -- Special lookups used for various modifier forms @@ -6996,6 +7035,9 @@ local unsupported = { } local count = 0 --local foo = io.open("../unsupported.txt", "w") --foo:close() + +local ConfigScope = require("Modules.ConfigScope") + return { parseMod = function(line, isComb) if not cache[line] then @@ -7015,7 +7057,9 @@ return { end end end - return unpack(copyTable(cache[line])) + local cached = copyTable(cache[line]) + ConfigScope.stampSourceOwnedOnMods(cached[1]) + return unpack(cached) end, - parseModCache = cache + parseModCache = cache, } diff --git a/src/Modules/SkillOptions.lua b/src/Modules/SkillOptions.lua new file mode 100644 index 00000000000..f6700d9bdf6 --- /dev/null +++ b/src/Modules/SkillOptions.lua @@ -0,0 +1,13 @@ +return { + sortGemTypeList = { + { label = "Full DPS", type = "FullDPS" }, + { label = "Combined DPS", type = "CombinedDPS" }, + { label = "Hit DPS", type = "TotalDPS" }, + { label = "Average Hit", type = "AverageDamage" }, + { label = "DoT DPS", type = "TotalDot" }, + { label = "Bleed DPS", type = "BleedDPS" }, + { label = "Ignite DPS", type = "IgniteDPS" }, + { label = "Poison DPS", type = "TotalPoisonDPS" }, + { label = "Effective Hit Pool", type = "TotalEHP" }, + }, +}