diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index af8896f64c3..652c162438f 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -23,6 +23,19 @@ describe("TestSkills", function() assert.are.equals(round(205 * 1.44), build.calcsTab.mainEnv.minion.modDB:Sum("BASE", build.calcsTab.mainEnv.minion.mainSkill.skillCfg, "ChaosMin")) end) + it("applies Aspect of the Brine King's chilling aura", function() + build.itemsTab:CreateDisplayItemFromRaw("New Item\nCoral Amulet\nGrants Level 20 Aspect of the Brine King Skill") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Freezing Pulse 20/0 1\n") + runCallback("OnFrame") + + local env = build.calcsTab.mainEnv + assert.is_true(env.enemy.modDB:Flag(nil, "Condition:Chilled")) + assert.are.equals(15, build.calcsTab.mainOutput.CurrentChill) + assert.are.equals(50, env.player.mainSkill.skillModList:Sum("INC", env.player.mainSkill.skillCfg, "EnemyChillEffect")) + assert.are.equals(10, env.player.mainSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "ColdPenetration")) + end) + it("Test Mirage Archer using triggered skill", function() build.itemsTab:CreateDisplayItemFromRaw([[+3 Bow Thicket Bow diff --git a/src/Data/Skills/other.lua b/src/Data/Skills/other.lua index 9b96b5bbf26..1b6484acd12 100644 --- a/src/Data/Skills/other.lua +++ b/src/Data/Skills/other.lua @@ -225,6 +225,102 @@ skills["AilmentBearer"] = { [20] = { cooldown = 0.5, levelRequirement = 70, storedUses = 1, cost = { Mana = 13, }, }, }, } +skills["AspectOfArakaali"] = { + name = "Aspect of Arakaali", + hidden = true, + color = 4, + description = "While active, you inflict Wither on hit, and Wither you inflict will be reflected back to you. Additionally, for each stack of Wither on you, your Life recovery rate is increased.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Spell] = true, [SkillType.HasReservation] = true, [SkillType.Instant] = true, [SkillType.Chaos] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "skill_stat_descriptions", + castTime = 0, + fromItem = true, + statMap = { + ["active_skill_buff_life_recovery_rate_+%_per_wither_on_self_to_grant"] = { + mod("LifeRecoveryRate", "INC", nil, 0, 0, { type = "Multiplier", var = "WitheredStack", limit = 15 }, { type = "GlobalEffect", effectType = "Buff" }), + }, + }, + baseFlags = { + cast = true, + }, + baseMods = { + flag("Condition:CanWither", { type = "GlobalEffect", effectType = "Buff" }), + flag("Condition:CanBeWithered", { type = "GlobalEffect", effectType = "Buff" }), + }, + constantStats = { + { "active_skill_buff_wither_on_hit_%_chance_to_grant", 100 }, + { "active_skill_buff_life_recovery_rate_+%_per_wither_on_self_to_grant", 3 }, + }, + stats = { + }, + levels = { + [20] = { cooldown = 0.5, levelRequirement = 1, manaReservationPercent = 25, storedUses = 1, }, + }, +} +skills["AspectOfLunaris"] = { + name = "Aspect of Lunaris", + hidden = true, + color = 4, + description = "While active, taking Physical or Elemental Damage will grant you either Lunar Protection or Lunar Resistance, respectively. Aspect of Lunaris lessens incoming Physical Damage for each Lunar Protection on you, and lessens incoming Elemental Damage for each Lunar Resistance on you. These buffs can both stack up to eight times.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Spell] = true, [SkillType.HasReservation] = true, [SkillType.Duration] = true, [SkillType.Cooldown] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0, + fromItem = true, + statMap = { + ["lunaris_aspect_skill_physical_damage_taken_+%_final_per_phys_rebuff"] = { + mod("PhysicalDamageTaken", "MORE", nil, 0, 0, { type = "Multiplier", var = "LunarProtection", limit = 8 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Lunar Protection" }), + }, + ["lunaris_aspect_skill_elemental_damage_taken_+%_final_per_ele_rebuff"] = { + mod("ElementalDamageTaken", "MORE", nil, 0, 0, { type = "Multiplier", var = "LunarResistance", limit = 8 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Lunar Resistance" }), + }, + }, + baseFlags = { + cast = true, + duration = true, + }, + constantStats = { + { "base_skill_effect_duration", 3000 }, + }, + stats = { + "lunaris_aspect_skill_elemental_damage_taken_+%_final_per_ele_rebuff", + "lunaris_aspect_skill_physical_damage_taken_+%_final_per_phys_rebuff", + }, + levels = { + [20] = { -2, -2, cooldown = 0.5, levelRequirement = 1, manaReservationPercent = 25, storedUses = 1, statInterpolation = { 1, 1, }, }, + }, +} +skills["AspectOfSolaris"] = { + name = "Aspect of Solaris", + hidden = true, + color = 4, + description = "While active, inflicts Fire Exposure on enemies within its radius. Additionally, periodically applies a Sunscald debuff to enemies within its radius, with each Sunscald debuff increasing the effect of exposure on affected enemies. Sunscald can stack up to five times.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Spell] = true, [SkillType.HasReservation] = true, [SkillType.Instant] = true, [SkillType.Fire] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, [SkillType.Duration] = true, }, + statDescriptionScope = "debuff_skill_stat_descriptions", + castTime = 0, + fromItem = true, + statMap = { + ["solaris_aspect_debuff_exposure_effect_+%_to_apply"] = { + mod("ExposureEffect", "INC", nil, 0, 0, { type = "Multiplier", var = "SunscaldStack", limit = 5 }, { type = "Condition", var = "Effective" }, { type = "GlobalEffect", effectType = "Buff" }), + }, + }, + baseFlags = { + cast = true, + duration = true, + }, + baseMods = { + mod("EnemyModifier", "LIST", { mod = mod("FireExposure", "BASE", -10) }, 0, 0, { type = "Condition", var = "Effective" }, { type = "GlobalEffect", effectType = "Buff" }), + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 40 }, + { "base_skill_effect_duration", 4000 }, + { "solaris_aspect_debuff_interval_ms", 1000 }, + { "solaris_aspect_debuff_exposure_effect_+%_to_apply", 15 }, + }, + stats = { + }, + levels = { + [20] = { cooldown = 0.5, levelRequirement = 1, manaReservationPercent = 25, storedUses = 1, }, + }, +} skills["AspectOfTheAvian"] = { name = "Aspect of the Avian", hidden = true, @@ -268,6 +364,39 @@ skills["AspectOfTheAvian"] = { [35] = { 15, 15, 18, 18, cooldown = 0.5, levelRequirement = 1, manaReservationPercent = 25, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, }, }, } +skills["AspectOfTheBrineKing"] = { + name = "Aspect of the Brine King", + hidden = true, + color = 4, + description = "While active, inflicts Chill on enemies within it's radius, while also increasing the strength of Chill you inflict and causing Damage you deal to Chilled enemies to penetrate some of their Cold Resistance.", + skillTypes = { [SkillType.Buff] = true, [SkillType.Spell] = true, [SkillType.HasReservation] = true, [SkillType.Instant] = true, [SkillType.Cold] = true, [SkillType.InstantNoRepeatWhenHeld] = true, [SkillType.InstantShiftAttackForLeftMouse] = true, [SkillType.Cooldown] = true, }, + statDescriptionScope = "buff_skill_stat_descriptions", + castTime = 0, + fromItem = true, + statMap = { + ["active_skill_buff_chill_effect_+%_to_grant"] = { + mod("EnemyChillEffect", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }), + }, + ["cold_penetration_%_vs_chilled_enemies"] = { + mod("ColdPenetration", "BASE", nil, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Chilled" }, { type = "GlobalEffect", effectType = "Buff" }), + }, + }, + baseFlags = { + cast = true, + guaranteedChill = true, + }, + constantStats = { + { "active_skill_base_area_of_effect_radius", 60 }, + { "active_skill_buff_chill_effect_+%_to_grant", 50 }, + { "active_skill_buff_cold_penetration_%_vs_chilled_enemies_to_grant", 10 }, + }, + stats = { + "cold_penetration_%_vs_chilled_enemies", + }, + levels = { + [20] = { 10, cooldown = 0.5, levelRequirement = 1, manaReservationPercent = 25, storedUses = 1, statInterpolation = { 1, }, }, + }, +} skills["AspectOfTheCat"] = { name = "Aspect of the Cat", hidden = true, diff --git a/src/Export/Skills/other.txt b/src/Export/Skills/other.txt index f7563292bff..461e621fd71 100644 --- a/src/Export/Skills/other.txt +++ b/src/Export/Skills/other.txt @@ -76,6 +76,42 @@ return function(skills, mod, flag, skill) fromTree = true, #mods +#skill AspectOfArakaali +#flags cast + fromItem = true, + statMap = { + ["active_skill_buff_life_recovery_rate_+%_per_wither_on_self_to_grant"] = { + mod("LifeRecoveryRate", "INC", nil, 0, 0, { type = "Multiplier", var = "WitheredStack", limit = 15 }, { type = "GlobalEffect", effectType = "Buff" }), + }, + }, +#baseMod flag("Condition:CanWither", { type = "GlobalEffect", effectType = "Buff" }) +#baseMod flag("Condition:CanBeWithered", { type = "GlobalEffect", effectType = "Buff" }) +#mods + +#skill AspectOfLunaris +#flags cast duration + fromItem = true, + statMap = { + ["lunaris_aspect_skill_physical_damage_taken_+%_final_per_phys_rebuff"] = { + mod("PhysicalDamageTaken", "MORE", nil, 0, 0, { type = "Multiplier", var = "LunarProtection", limit = 8 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Lunar Protection" }), + }, + ["lunaris_aspect_skill_elemental_damage_taken_+%_final_per_ele_rebuff"] = { + mod("ElementalDamageTaken", "MORE", nil, 0, 0, { type = "Multiplier", var = "LunarResistance", limit = 8 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Lunar Resistance" }), + }, + }, +#mods + +#skill AspectOfSolaris +#flags cast duration + fromItem = true, + statMap = { + ["solaris_aspect_debuff_exposure_effect_+%_to_apply"] = { + mod("ExposureEffect", "INC", nil, 0, 0, { type = "Multiplier", var = "SunscaldStack", limit = 5 }, { type = "Condition", var = "Effective" }, { type = "GlobalEffect", effectType = "Buff" }), + }, + }, +#baseMod mod("EnemyModifier", "LIST", { mod = mod("FireExposure", "BASE", -10) }, 0, 0, { type = "Condition", var = "Effective" }, { type = "GlobalEffect", effectType = "Buff" }) +#mods + #skill AspectOfTheAvian #flags cast duration fromItem = true, @@ -95,6 +131,19 @@ return function(skills, mod, flag, skill) }, #mods +#skill AspectOfTheBrineKing +#flags cast guaranteedChill + fromItem = true, + statMap = { + ["active_skill_buff_chill_effect_+%_to_grant"] = { + mod("EnemyChillEffect", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff" }), + }, + ["cold_penetration_%_vs_chilled_enemies"] = { + mod("ColdPenetration", "BASE", nil, 0, 0, { type = "ActorCondition", actor = "enemy", var = "Chilled" }, { type = "GlobalEffect", effectType = "Buff" }), + }, + }, +#mods + #skill AspectOfTheCat #flags cast duration fromItem = true, diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 95e90c38252..528d3237b60 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -1295,6 +1295,7 @@ function calcs.perform(env, skipEHP) end local hasGuaranteedBonechill = false + local guaranteedChillSkills = { } -- Banners if modDB:Flag(nil,"Condition:BannerPlanted") then @@ -1391,9 +1392,8 @@ function calcs.perform(env, skipEHP) modDB:NewMod("SelfScorchOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) end end - elseif activeSkill.skillTypes[SkillType.ChillingArea] or (activeSkill.skillTypes[SkillType.NonHitChill] and not activeSkill.skillModList:Flag(nil, "CannotChill")) then - local effect = data.nonDamagingAilment.Chill.default * calcLib.mod(activeSkill.skillModList, activeSkill.skillCfg, "EnemyChillEffect") - modDB:NewMod("ChillOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) + 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) enemyDB:NewMod("Condition:Chilled", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) if activeSkill.skillData.supportBonechill then hasGuaranteedBonechill = true @@ -3316,6 +3316,12 @@ function calcs.perform(env, skipEHP) end end + -- Calculate guaranteed chills after buffs so chilling areas benefit from active buff modifiers. + for _, activeSkill in ipairs(guaranteedChillSkills) do + local effect = data.nonDamagingAilment.Chill.default * calcLib.mod(activeSkill.skillModList, activeSkill.skillCfg, "EnemyChillEffect") + modDB:NewMod("ChillOverride", "BASE", effect, activeSkill.activeEffect.grantedEffect.name) + end + -- Fix the configured impale stacks on the enemy -- If the config is missing (blank), then use the maximum number of stacks -- If the config is larger than the maximum number of stacks, replace it with the correct maximum @@ -3581,6 +3587,11 @@ function calcs.perform(env, skipEHP) 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) + 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, "") diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 98c98b6b9c8..6e612731595 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -258,6 +258,17 @@ return { { 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") end }, + { label = "Aspect of Lunaris:", ifSkill = "Aspect of Lunaris" }, + { var = "aspectOfLunarisLunarProtection", type = "countAllowZero", label = "# of Lunar Protection:", ifSkill = "Aspect of Lunaris", tooltip = "Gained when you take ^xB97123Physical ^7Damage, up to 8 stacks.", defaultPlaceholderState = 8, apply = function(val, modList, enemyModList) + modList:NewMod("Multiplier:LunarProtection", "BASE", val, "Config") + end }, + { var = "aspectOfLunarisLunarResistance", type = "countAllowZero", label = "# of Lunar Resistance:", ifSkill = "Aspect of Lunaris", tooltip = "Gained when you take Elemental Damage, up to 8 stacks.", defaultPlaceholderState = 8, apply = function(val, modList, enemyModList) + modList:NewMod("Multiplier:LunarResistance", "BASE", val, "Config") + end }, + { label = "Aspect of Solaris:", ifSkill = "Aspect of Solaris" }, + { var = "aspectOfSolarisSunscaldStacks", type = "countAllowZero", label = "# of Sunscald Stacks:", ifSkill = "Aspect of Solaris", tooltip = "Each Sunscald increases the effect of ^xB97123Fire Exposure ^7on affected enemies by 15%, up to 5 stacks.", defaultPlaceholderState = 5, apply = function(val, modList, enemyModList) + modList:NewMod("Multiplier:SunscaldStack", "BASE", val, "Config", { type = "Condition", var = "Effective" }) + end }, { label = "Aspect of the Avian:", ifSkill = "Aspect of the Avian" }, { var = "aspectOfTheAvianAviansMight", type = "check", label = "Is Avian's Might active?", ifSkill = "Aspect of the Avian", apply = function(val, modList, enemyModList) modList:NewMod("Condition:AviansMightActive", "FLAG", true, "Config")