From 68bf081f839e24a1c17a86cd18e5c7954f68e0b3 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Mon, 31 Jul 2023 02:33:41 +0200 Subject: [PATCH 01/19] FEAT: impl explode and extra support mods --- src/Modules/ModParser.lua | 49 ++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 1ea66bb546..2fca375396 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -1750,6 +1750,34 @@ local function triggerExtraSkill(name, level, noSupports, sourceSkill) } end end +local function extraSupport(name, level, slot) + local skillId = gemIdLookup[name] or gemIdLookup[name:gsub("^increased ","")] + + if itemSlotName == "main hand" then + slot = "Weapon 1" + elseif itemSlotName == "off hand" then + slot = "Weapon 2" + elseif slot then + slot = string.gsub(" "..slot, "%W%l", string.upper):sub(2) + else + slot = "{SlotName}" + end + + level = tonumber(level) + if skillId then + local gemId = data.gemForBaseName[data.skills[skillId].name .. " Support"] + if gemId then + return { + mod("ExtraSupport", "LIST", { skillId = data.gems[gemId].grantedEffectId, level = level }, { type = "SocketedIn", slotName = slot }), + mod("ExtraSupport", "LIST", { skillId = data.gems[gemId].secondaryGrantedEffectId, level = level }, { type = "SocketedIn", slotName = slot }) + } + else + return { + mod("ExtraSupport", "LIST", { skillId = skillId, level = level }, { type = "SocketedIn", slotName = slot }), + } + end + end +end local explodeFunc = function(chance, amount, type, ...) local amountNumber = tonumber(amount) or (amount == "tenth" and 10) or (amount == "quarter" and 25) @@ -1815,6 +1843,9 @@ local specialModList = { ["totems explode on death, dealing (%d+)%% of their life as (.+) damage"] = function(amount, _, type) -- Crucible weapon mod return explodeFunc(100, amount, type) end, + ["enemies you kill have ?a? ?(%d+)%% chance to explode, dealing (%d+)%% of their maximum life as (.+) damage"] = function(chance, _, amount, type) + return explodeFunc(chance, amount, type) + end, -- Keystones ["(%d+) rage regenerated for every (%d+) mana regeneration per second"] = function(num, _, div) return { mod("RageRegen", "BASE", num, {type = "PerStat", stat = "ManaRegen", div = tonumber(div) }) , @@ -2686,22 +2717,8 @@ local specialModList = { ["trigger commandment of inferno on critical strike"] = { mod("ExtraSkill", "LIST", { skillId = "UniqueEnchantmentOfInfernoOnCrit", level = 1, noSupports = true, triggered = true }) }, ["trigger (.+) on critical strike"] = function( _, skill) return triggerExtraSkill(skill, 1, true) end, ["triggers? (.+) when you take a critical strike"] = function( _, skill) return triggerExtraSkill(skill, 1, true) end, - ["socketed [%a+]* ?gems a?r?e? ?supported by level (%d+) (.+)"] = function(num, _, support) - local skillId = gemIdLookup[support] or gemIdLookup[support:gsub("^increased ","")] - if skillId then - local gemId = data.gemForBaseName[data.skills[skillId].name .. " Support"] - if gemId then - return { - mod("ExtraSupport", "LIST", { skillId = data.gems[gemId].grantedEffectId, level = num }, { type = "SocketedIn", slotName = "{SlotName}" }), - mod("ExtraSupport", "LIST", { skillId = data.gems[gemId].secondaryGrantedEffectId, level = num }, { type = "SocketedIn", slotName = "{SlotName}" }) - } - else - return { - mod("ExtraSupport", "LIST", { skillId = skillId, level = num }, { type = "SocketedIn", slotName = "{SlotName}" }), - } - end - end - end, + ["socketed [%a+]* ?gems a?r?e? ?supported by level (%d+) (.+)"] = function(num, _, support) return extraSupport(support, num) end, + ["skills from equipped (.+) are supported by level (%d+) (.+)"] = function(num, slot, level, support) return extraSupport(support, level, slot) end, ["socketed support gems can also support skills from your e?q?u?i?p?p?e?d? ?([%a%s]+)"] = function (_, itemSlotName) local targetItemSlotName = "Body Armour" if itemSlotName == "main hand" then From 175ccf318fea15102f42b7954fbe794445a5e4f7 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Mon, 31 Jul 2023 04:25:15 +0200 Subject: [PATCH 02/19] FEAT: impl new aura recovery mod --- src/Modules/ModParser.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 2fca375396..56ad8581d5 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -1099,6 +1099,7 @@ local preFlagList = { ["^when hit, "] = { }, ["^you and allies [hgd][ae][via][enl] "] = { }, ["^auras from your skills grant "] = { addToAura = true }, + ["^auras grant "] = { addToAura = true }, ["^you and nearby allies "] = { newAura = true }, ["^you and nearby allies [hgd][ae][via][enl] "] = { newAura = true }, ["^nearby allies [hgd][ae][via][enl] "] = { newAura = true, newAuraOnlyAllies = true }, From a0e63a3ca1841cb38d53b6f3b941c0a7b5acf99a Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:17:07 +0200 Subject: [PATCH 03/19] FEAT: impl between you and linked target mods --- src/Modules/ConfigOptions.lua | 3 +++ src/Modules/ModParser.lua | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 99fa421aa1..e99dbc9c1c 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -1580,6 +1580,9 @@ Huge sets the radius to 11. 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 the way of a Link skill?", ifEnemyCond = "BetweenYouAndLinkedTarget", 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 }, -- Section: Enemy Stats { section = "Enemy Stats", col = 3 }, { 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." }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 56ad8581d5..f455ff5042 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -1117,6 +1117,7 @@ local preFlagList = { ["^blink arrow and mirror arrow have "] = { tag = { type = "SkillName", skillNameList = { "Blink Arrow", "Mirror Arrow" } } }, ["attacks with energy blades "] = { flags = ModFlag.Attack, tag = { type = "Condition", var = "AffectedByEnergyBlade" } }, ["^for each nearby corpse, "] = { tag = { type = "Multiplier", var = "NearbyCorpse" } }, + ["^allies between you and linked targets have "] = { newAura = true, newAuraOnlyAllies = true, tag = { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" } }, -- While in the presence of... ["^while a unique enemy is in your presence, "] = { tag = { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" } }, ["^while a pinnacle atlas boss is in your presence, "] = { tag = { type = "ActorCondition", actor = "enemy", var = "PinnacleBoss" } }, @@ -2250,6 +2251,7 @@ local specialModList = { end return mods end, + ["enemies between you and linked targets cannot apply elemental ailments"] = { mod("AvoidElementalAilments", "BASE", 100, 0, 0, { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }, { type = "GlobalEffect", effectType = "Global", unscalable = true })}, ["immun[ei]t?y? to elemental ailments while focus?sed"] = function() local mods = { } for i, ailment in ipairs(data.elementalAilmentTypeList) do @@ -3234,6 +3236,7 @@ local specialModList = { ["nearby allies' damage with hits is lucky"] = { mod("ExtraAura", "LIST", { onlyAllies = true, mod = flag("LuckyHits") }) }, ["your damage with hits is lucky"] = { flag("LuckyHits") }, ["elemental damage with hits is lucky while you are shocked"] = { flag("ElementalLuckHits", { type = "Condition", var = "Shocked" }) }, + ["elemental damage with hits dealt by allies between you and linked targets is lucky"] = { flag("ElementalLuckHits", { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }) }, ["allies' aura buffs do not affect you"] = { flag("AlliesAurasCannotAffectSelf") }, ["(%d+)%% increased effect of non%-curse auras from your skills on enemies"] = function(num) return { mod("DebuffEffect", "INC", num, { type = "SkillType", skillType = SkillType.Aura }, { type = "SkillType", skillType = SkillType.AppliesCurse, neg = true }), From 90279c2411ea98dada339c405116f4bfaf5e7f8f Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:35:53 +0200 Subject: [PATCH 04/19] FEAT: impl Sentinel of Radiance mod Currently implemented as less damage taken as that's what the spreadsheet said. I think this may be possible to implement like frost shield or other "taken before you" mods given more info on stats of the sentinel. --- src/Modules/ConfigOptions.lua | 3 +++ src/Modules/ModParser.lua | 1 + 2 files changed, 4 insertions(+) diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index e99dbc9c1c..4e8a7afd9f 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -853,6 +853,9 @@ Huge sets the radius to 11. { var = "conditionSummonedGolemInPast10Sec", type = "check", label = "Summoned Golem in past 10 Seconds?", ifCond = "SummonedGolemInPast10Sec", apply = function(val, modList, enemyModList) modList:NewMod("Condition:SummonedGolemInPast10Sec", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, + { var = "conditionHaveRadianceSentinel", type = "check", label = "Do you have a Sentinel of Radiance?", ifCond = "HaveRadianceSentinel", apply = function(val, modList, enemyModList) + modList:NewMod("Condition:HaveRadianceSentinel", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) + end }, { var = "multiplierNearbyAlly", type = "count", label = "# of Nearby Allies:", ifMult = "NearbyAlly", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:NearbyAlly", "BASE", val, "Config", { type = "Condition", var = "Combat" }) end }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index f455ff5042..f249df5d3d 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -4003,6 +4003,7 @@ local specialModList = { } end, ["(%d+)%% of damage from hits is taken from your spectres' life before you"] = function(num) return { mod("takenFromSpectresBeforeYou", "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 sentinel of radiance's life before you"] = function(num) return { mod("DamageTaken", "MORE", -num, { type = "Condition", var = "HaveRadianceSentinel" }) } end, -- Knockback ["cannot knock enemies back"] = { flag("CannotKnockback") }, ["knocks back enemies if you get a critical strike with a staff"] = { mod("EnemyKnockbackChance", "BASE", 100, nil, ModFlag.Staff, { type = "Condition", var = "CriticalStrike" }) }, From 088a841b087cea2229b06591f963c859049c4d32 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Tue, 1 Aug 2023 05:09:16 +0200 Subject: [PATCH 05/19] FEAT: impl reserved mana as armor mod --- src/Modules/ModParser.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index f249df5d3d..e7cdcb77ef 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2251,7 +2251,6 @@ local specialModList = { end return mods end, - ["enemies between you and linked targets cannot apply elemental ailments"] = { mod("AvoidElementalAilments", "BASE", 100, 0, 0, { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }, { type = "GlobalEffect", effectType = "Global", unscalable = true })}, ["immun[ei]t?y? to elemental ailments while focus?sed"] = function() local mods = { } for i, ailment in ipairs(data.elementalAilmentTypeList) do @@ -2346,6 +2345,7 @@ local specialModList = { -- Guardian ["grants armour equal to (%d+)%% of your reserved life to you and nearby allies"] = function(num) return { mod("GrantReservedLifeAsAura", "LIST", { mod = mod("Armour", "BASE", num / 100) }) } end, ["grants maximum energy shield equal to (%d+)%% of your reserved mana to you and nearby allies"] = function(num) return { mod("GrantReservedManaAsAura", "LIST", { mod = mod("EnergyShield", "BASE", num / 100) }) } end, + ["grants armour equal to (%d+)%% of your reserved mana to you and nearby allies"] = function(num) return { mod("GrantReservedManaAsAura", "LIST", { mod = mod("Armour", "BASE", num / 100) }) } end, ["warcries cost no mana"] = { mod("ManaCost", "MORE", -100, nil, 0, KeywordFlag.Warcry) }, ["%+(%d+)%% chance to block attack damage for %d seconds? every %d seconds"] = function(num) return { mod("BlockChance", "BASE", num, { type = "Condition", var = "BastionOfHopeActive" }) } end, ["if you've blocked in the past %d+ seconds, you and nearby allies cannot be stunned"] = { mod("ExtraAura", "LIST", { mod = mod("AvoidStun", "BASE", 100) }, { type = "Condition", var = "BlockedRecently" }, { type = "GlobalEffect", effectType = "Global", unscalable = true }) }, @@ -2353,6 +2353,9 @@ local specialModList = { ["if you've cast a spell recently, you and nearby allies have %+(%d+)%% chance to block spell damage"] = function(num) return { mod("ExtraAura", "LIST", { mod = mod("SpellBlockChance", "BASE", num) }, { type = "Condition", var = "CastSpellRecently" }) } end, ["while there is at least one nearby ally, you and nearby allies deal (%d+)%% more damage"] = function(num) return { mod("ExtraAura", "LIST", { mod = mod("Damage", "MORE", num) }, { type = "MultiplierThreshold", var = "NearbyAlly", threshold = 1 }) } end, ["while there are at least five nearby allies, you and nearby allies have onslaught"] = { mod("ExtraAura", "LIST", { mod = flag("Onslaught") }, { type = "MultiplierThreshold", var = "NearbyAlly", threshold = 5 }) }, + ["elemental damage with hits dealt by allies between you and linked targets is lucky"] = { flag("ElementalLuckHits", { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }) }, + ["enemies between you and linked targets cannot apply elemental ailments"] = { mod("AvoidElementalAilments", "BASE", 100, 0, 0, { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }, { type = "GlobalEffect", effectType = "Global", unscalable = true })}, + ["(%d+)%% of damage from hits is taken from sentinel of radiance's life before you"] = function(num) return { mod("DamageTaken", "MORE", -num, { type = "Condition", var = "HaveRadianceSentinel" }) } end, -- Hierophant ["you and your totems regenerate ([%d%.]+)%% of life per second for each summoned totem"] = function (num) return { mod("LifeRegenPercent", "BASE", num, { type = "PerStat", stat = "TotemsSummoned" }), @@ -3236,7 +3239,6 @@ local specialModList = { ["nearby allies' damage with hits is lucky"] = { mod("ExtraAura", "LIST", { onlyAllies = true, mod = flag("LuckyHits") }) }, ["your damage with hits is lucky"] = { flag("LuckyHits") }, ["elemental damage with hits is lucky while you are shocked"] = { flag("ElementalLuckHits", { type = "Condition", var = "Shocked" }) }, - ["elemental damage with hits dealt by allies between you and linked targets is lucky"] = { flag("ElementalLuckHits", { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }) }, ["allies' aura buffs do not affect you"] = { flag("AlliesAurasCannotAffectSelf") }, ["(%d+)%% increased effect of non%-curse auras from your skills on enemies"] = function(num) return { mod("DebuffEffect", "INC", num, { type = "SkillType", skillType = SkillType.Aura }, { type = "SkillType", skillType = SkillType.AppliesCurse, neg = true }), @@ -4003,7 +4005,6 @@ local specialModList = { } end, ["(%d+)%% of damage from hits is taken from your spectres' life before you"] = function(num) return { mod("takenFromSpectresBeforeYou", "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 sentinel of radiance's life before you"] = function(num) return { mod("DamageTaken", "MORE", -num, { type = "Condition", var = "HaveRadianceSentinel" }) } end, -- Knockback ["cannot knock enemies back"] = { flag("CannotKnockback") }, ["knocks back enemies if you get a critical strike with a staff"] = { mod("EnemyKnockbackChance", "BASE", 100, nil, ModFlag.Staff, { type = "Condition", var = "CriticalStrike" }) }, From 0784fa1f06ee9dba8de0a8e4b2efdd5926e2c214 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Tue, 1 Aug 2023 06:21:05 +0200 Subject: [PATCH 06/19] FIX: use arbitrary taken before you instead of generic less dmg taken --- src/Modules/CalcDefence.lua | 86 +++++++++++++++++++++++++---------- src/Modules/ConfigOptions.lua | 6 +-- src/Modules/ModParser.lua | 2 +- 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 3fe57bb7b4..61731dbb1b 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -105,6 +105,9 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) if output.TotalVaalRejuvenationTotemLife then alliesTakenBeforeYou["vaalRejuvenationTotems"] = { remaining = output.TotalVaalRejuvenationTotemLife, percent = output.VaalRejuvenationTotemAllyDamageMitigation / 100 } end + if output.TotalRadianceSentinelLife then + alliesTakenBeforeYou["radianceSentinel"] = { remaining = output.TotalRadianceSentinelLife, percent = output.RadianceSentinelAllyDamageMitigation / 100 } + end -- soul link is not implemented yet if output.SoulLink then alliesTakenBeforeYou["soulLink"] = { remaining = output.SoulLink, percent = output.SoulLinkMitigation / 100 } @@ -1952,6 +1955,13 @@ function calcs.buildDefenceEstimations(env, actor) if output["VaalRejuvenationTotemAllyDamageMitigation"] ~= output["TotemAllyDamageMitigation"] then output["TotalVaalRejuvenationTotemLife"] = modDB:Sum("BASE", nil, "TotalVaalRejuvenationTotemLife") end + + -- from Sentinel of Radiance + output["RadianceSentinelAllyDamageMitigation"] = modDB:Sum("BASE", nil, "takenFromRadianceSentinelBeforeYou") + if output["RadianceSentinelAllyDamageMitigation"] ~= 0 then + output["TotalRadianceSentinelLife"] = modDB:Sum("BASE", nil, "TotalRadianceSentinelLife") + end + end -- Vaal Arctic Armour @@ -2038,6 +2048,9 @@ function calcs.buildDefenceEstimations(env, actor) if output.TotalVaalRejuvenationTotemLife then alliesTakenBeforeYou["vaalRejuvenationTotems"] = { remaining = output.TotalVaalRejuvenationTotemLife, percent = output.VaalRejuvenationTotemAllyDamageMitigation / 100 } end + if output.TotalRadianceSentinelLife then + alliesTakenBeforeYou["radianceSentinel"] = { remaining = output.TotalRadianceSentinelLife, percent = output.RadianceSentinelAllyDamageMitigation / 100 } + end local poolTable = { AlliesTakenBeforeYou = alliesTakenBeforeYou, @@ -2690,6 +2703,10 @@ function calcs.buildDefenceEstimations(env, actor) local poolProtected = output["TotalVaalRejuvenationTotemLife"] / (output["VaalRejuvenationTotemAllyDamageMitigation"] / 100) * (1 - output["VaalRejuvenationTotemAllyDamageMitigation"] / 100) output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - output["VaalRejuvenationTotemAllyDamageMitigation"] / 100) end + if output["TotalRadianceSentinelLife"] and output["TotalRadianceSentinelLife"] > 0 then + local poolProtected = output["TotalRadianceSentinelLife"] / (output["RadianceSentinelAllyDamageMitigation"] / 100) * (1 - output["RadianceSentinelAllyDamageMitigation"] / 100) + output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - output["RadianceSentinelAllyDamageMitigation"] / 100) + end end for _, damageType in ipairs(dmgTypeList) do @@ -2825,36 +2842,57 @@ function calcs.buildDefenceEstimations(env, actor) t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("= %.0f ^8maximum survivable enemy damage%s", finalMaxHit, useConversionSmoothing and " (approximate)" or "")) local poolsRemaining = calcs.reducePoolsByDamage(nil, takenDamages, actor) - local poolRemainingStrings = { - output.FrostShieldLife and output.FrostShieldLife > 0 and s_format("\t%d "..colorCodes.GEM.."Frost Shield Life ^7(%d remaining)", output.FrostShieldLife - poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining, poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining) or nil, - output.TotalSpectreLife and output.TotalSpectreLife > 0 and s_format("\t%d "..colorCodes.GEM.."Total Spectre Life ^7(%d remaining)", output.TotalSpectreLife - poolsRemaining.AlliesTakenBeforeYou["specters"].remaining, poolsRemaining.AlliesTakenBeforeYou["specters"].remaining) or nil, - output.TotalTotemLife and output.TotalTotemLife > 0 and s_format("\t%d "..colorCodes.GEM.."Total Totem Life ^7(%d remaining)", output.TotalTotemLife - poolsRemaining.AlliesTakenBeforeYou["totems"].remaining, poolsRemaining.AlliesTakenBeforeYou["totems"].remaining) or nil, - output.TotalVaalRejuvenationTotemLife and output.TotalVaalRejuvenationTotemLife > 0 and s_format("\t%d "..colorCodes.GEM.."Total Vaal Rejuvenation Totem Life ^7(%d remaining)", output.TotalVaalRejuvenationTotemLife - poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining, poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining) or nil, - output.sharedAegis and output.sharedAegis > 0 and s_format("\t%d "..colorCodes.GEM.."Shared Aegis charge ^7(%d remaining)", output.sharedAegis - poolsRemaining.Aegis.shared, poolsRemaining.Aegis.shared) or nil, - } + + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("^8Such a hit would drain the following:")) + if output.FrostShieldLife and output.FrostShieldLife > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Frost Shield Life ^7(%d remaining)", output.FrostShieldLife - poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining, poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining)) + end + if output.TotalSpectreLife and output.TotalSpectreLife > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Spectre Life ^7(%d remaining)", output.TotalSpectreLife - poolsRemaining.AlliesTakenBeforeYou["specters"].remaining, poolsRemaining.AlliesTakenBeforeYou["specters"].remaining)) + end + if output.TotalTotemLife and output.TotalTotemLife > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Totem Life ^7(%d remaining)", output.TotalTotemLife - poolsRemaining.AlliesTakenBeforeYou["totems"].remaining, poolsRemaining.AlliesTakenBeforeYou["totems"].remaining)) + end + if output.TotalVaalRejuvenationTotemLife and output.TotalVaalRejuvenationTotemLife > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Vaal Rejuvenation Totem Life ^7(%d remaining)", output.TotalVaalRejuvenationTotemLife - poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining, poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining)) + end + if output.TotalRadianceSentinelLife and output.TotalRadianceSentinelLife > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Sentinel of Radiance Life ^7(%d remaining)", output.TotalRadianceSentinelLife - poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining, poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining)) + end + if output.sharedAegis and output.sharedAegis > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Shared Aegis charge ^7(%d remaining)", output.sharedAegis - poolsRemaining.Aegis.shared, poolsRemaining.Aegis.shared)) + end local receivedElemental = false for takenType in pairs(takenDamages) do receivedElemental = receivedElemental or isElemental[takenType] - t_insert(poolRemainingStrings, output[takenType.."Aegis"] and output[takenType.."Aegis"] > 0 and s_format("\t%d "..colorCodes.GEM.."%s Aegis charge ^7(%d remaining)", output[takenType.."Aegis"] - poolsRemaining.Aegis[takenType], takenType, poolsRemaining.Aegis[takenType]) or nil) + if output[takenType.."Aegis"] and output[takenType.."Aegis"] > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."%s Aegis charge ^7(%d remaining)", output[takenType.."Aegis"] - poolsRemaining.Aegis[takenType], takenType, poolsRemaining.Aegis[takenType])) + end + end + if receivedElemental and output.sharedElementalAegis and output.sharedElementalAegis > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Elemental Aegis charge ^7(%d remaining)", output.sharedElementalAegis - poolsRemaining.Aegis.sharedElemental, poolsRemaining.Aegis.sharedElemental)) + end + if output.sharedGuardAbsorb and output.sharedGuardAbsorb > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.SCOURGE.."Shared Guard charge ^7(%d remaining)", output.sharedGuardAbsorb - poolsRemaining.Guard.shared, poolsRemaining.Guard.shared)) end - poolRemainingStrings = tableConcat(poolRemainingStrings, { - receivedElemental and output.sharedElementalAegis and output.sharedElementalAegis > 0 and s_format("\t%d "..colorCodes.GEM.."Elemental Aegis charge ^7(%d remaining)", output.sharedElementalAegis - poolsRemaining.Aegis.sharedElemental, poolsRemaining.Aegis.sharedElemental) or nil, - output.sharedGuardAbsorb and output.sharedGuardAbsorb > 0 and s_format("\t%d "..colorCodes.SCOURGE.."Shared Guard charge ^7(%d remaining)", output.sharedGuardAbsorb - poolsRemaining.Guard.shared, poolsRemaining.Guard.shared) or nil, - }) for takenType in pairs(takenDamages) do - t_insert(poolRemainingStrings, output[takenType.."GuardAbsorb"] and output[takenType.."GuardAbsorb"] > 0 and s_format("\n\t%d "..colorCodes.SCOURGE.."%s Guard charge ^7(%d remaining)", output[takenType.."GuardAbsorb"] - poolsRemaining.Guard[takenType], takenType, poolsRemaining.Guard[takenType]) or nil) - end - poolRemainingStrings = tableConcat(poolRemainingStrings, { - output.Ward and output.Ward > 0 and s_format("\t%d "..colorCodes.WARD.."Ward", output.Ward) or nil, - output.EnergyShieldRecoveryCap ~= poolsRemaining.EnergyShield and output.EnergyShieldRecoveryCap and output.EnergyShieldRecoveryCap > 0 and s_format("\t%d "..colorCodes.ES.."Energy Shield ^7(%d remaining)", output.EnergyShieldRecoveryCap - poolsRemaining.EnergyShield, poolsRemaining.EnergyShield) or nil, - output.ManaUnreserved ~= poolsRemaining.Mana and output.ManaUnreserved and output.ManaUnreserved > 0 and s_format("\t%d "..colorCodes.MANA.."Mana ^7(%d remaining)", output.ManaUnreserved - poolsRemaining.Mana, poolsRemaining.Mana) or nil, - poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime > 0 and s_format("\t%d "..colorCodes.LIFE.."Life ^7Loss Prevented", poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime) or nil, - s_format("\t%d "..colorCodes.LIFE.."Life ^7(%d remaining)", output.LifeRecoverable - poolsRemaining.Life, poolsRemaining.Life) - }) - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("^8Such a hit would drain the following:")) - for _, str in ipairs(poolRemainingStrings) do - t_insert(breakdown[damageType.."MaximumHitTaken"], str) + if output[takenType.."GuardAbsorb"] and output[takenType.."GuardAbsorb"] > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\n\t%d "..colorCodes.SCOURGE.."%s Guard charge ^7(%d remaining)", output[takenType.."GuardAbsorb"] - poolsRemaining.Guard[takenType], takenType, poolsRemaining.Guard[takenType])) + end + end + if output.Ward and output.Ward > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.WARD.."Ward", output.Ward)) + end + if output.EnergyShieldRecoveryCap ~= poolsRemaining.EnergyShield and output.EnergyShieldRecoveryCap and output.EnergyShieldRecoveryCap > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.ES.."Energy Shield ^7(%d remaining)", output.EnergyShieldRecoveryCap - poolsRemaining.EnergyShield, poolsRemaining.EnergyShield)) + end + if output.ManaUnreserved ~= poolsRemaining.Mana and output.ManaUnreserved and output.ManaUnreserved > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.MANA.."Mana ^7(%d remaining)", output.ManaUnreserved - poolsRemaining.Mana, poolsRemaining.Mana)) + end + if poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime > 0 then + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.LIFE.."Life ^7Loss Prevented", poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime)) end + t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.LIFE.."Life ^7(%d remaining)", output.LifeRecoverable - poolsRemaining.Life, poolsRemaining.Life)) end end diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 4e8a7afd9f..c008298a53 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -592,6 +592,9 @@ Huge sets the radius to 11. { var = "TotalTotemLife", type = "integer", label = "Total Totem Life:", ifOption = "conditionHaveTotem", ifMod = "takenFromTotemsBeforeYou", tooltip = "The total life of your Totems (excluding Vaal Rejuvenation Totem) that can be taken before yours (used by totem mastery)", apply = function(val, modList, enemyModList) modList:NewMod("TotalTotemLife", "BASE", val, "Config") end }, + { var = "TotalRadianceSentinelLife", type = "integer", label = "Total life pool of Sentinel of Radiance", ifMod = "takenFromRadianceSentinelBeforeYou", apply = function(val, modList, enemyModList) + modList:NewMod("TotalRadianceSentinelLife", "BASE", val, "Config") + end }, { var = "TotalVaalRejuvenationTotemLife", type = "integer", label = "Total Vaal Rejuvenation Totem Life:", ifSkill = { "Vaal Rejuvenation Totem" }, ifMod = "takenFromVaalRejuvenationTotemsBeforeYou", tooltip = "The total life of your Vaal Rejuvenation Totems that can be taken before yours", apply = function(val, modList, enemyModList) modList:NewMod("TotalVaalRejuvenationTotemLife", "BASE", val, "Config") end }, @@ -853,9 +856,6 @@ Huge sets the radius to 11. { var = "conditionSummonedGolemInPast10Sec", type = "check", label = "Summoned Golem in past 10 Seconds?", ifCond = "SummonedGolemInPast10Sec", apply = function(val, modList, enemyModList) modList:NewMod("Condition:SummonedGolemInPast10Sec", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "conditionHaveRadianceSentinel", type = "check", label = "Do you have a Sentinel of Radiance?", ifCond = "HaveRadianceSentinel", apply = function(val, modList, enemyModList) - modList:NewMod("Condition:HaveRadianceSentinel", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) - end }, { var = "multiplierNearbyAlly", type = "count", label = "# of Nearby Allies:", ifMult = "NearbyAlly", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:NearbyAlly", "BASE", val, "Config", { type = "Condition", var = "Combat" }) end }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index e7cdcb77ef..0b7dfbb079 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2355,7 +2355,7 @@ local specialModList = { ["while there are at least five nearby allies, you and nearby allies have onslaught"] = { mod("ExtraAura", "LIST", { mod = flag("Onslaught") }, { type = "MultiplierThreshold", var = "NearbyAlly", threshold = 5 }) }, ["elemental damage with hits dealt by allies between you and linked targets is lucky"] = { flag("ElementalLuckHits", { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }) }, ["enemies between you and linked targets cannot apply elemental ailments"] = { mod("AvoidElementalAilments", "BASE", 100, 0, 0, { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }, { type = "GlobalEffect", effectType = "Global", unscalable = true })}, - ["(%d+)%% of damage from hits is taken from sentinel of radiance's life before you"] = function(num) return { mod("DamageTaken", "MORE", -num, { type = "Condition", var = "HaveRadianceSentinel" }) } end, + ["(%d+)%% of damage from hits is taken from sentinel of radiance's life before you"] = function(num) return { mod("takenFromRadianceSentinelBeforeYou", "BASE", num) } end, -- Hierophant ["you and your totems regenerate ([%d%.]+)%% of life per second for each summoned totem"] = function (num) return { mod("LifeRegenPercent", "BASE", num, { type = "PerStat", stat = "TotemsSummoned" }), From 5bf1e00e8720e2878fb5c948522ac7c119356ee0 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:32:56 +0200 Subject: [PATCH 07/19] FIX: cache result of dmg type max hit str concat --- src/Modules/CalcDefence.lua | 52 +++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 61731dbb1b..4749ba926a 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -2797,10 +2797,12 @@ function calcs.buildDefenceEstimations(env, actor) else finalMaxHit = round(partMin / enemyDamageMult) end - output[damageType.."MaximumHitTaken"] = finalMaxHit + + local maxHitCurType = damageType.."MaximumHitTaken" + output[maxHitCurType] = finalMaxHit if breakdown then - breakdown[damageType.."MaximumHitTaken"] = { + breakdown[maxHitCurType] = { label = "Maximum hit damage breakdown", rowList = {}, colList = { @@ -2820,7 +2822,7 @@ function calcs.buildDefenceEstimations(env, actor) local incoming = finalMaxHit * enemyDamageMult * conversion / 100 local nanToZero = takenAmt == takenAmt and takenAmt or 0 takenDamages[takenType] = nanToZero - t_insert(breakdown[damageType.."MaximumHitTaken"].rowList, { + t_insert(breakdown[maxHitCurType].rowList, { type = s_format("%d%% as %s", conversion, takenType), pool = s_format("%d", output[takenType .."TotalHitPool"]), incoming = s_format("%.0f", incoming), @@ -2830,69 +2832,69 @@ function calcs.buildDefenceEstimations(env, actor) end local fullMulti = fullTaken / finalMaxHit / enemyDamageMult - t_insert(breakdown[damageType.."MaximumHitTaken"], "^8Maximum hit is calculated in reverse -") - t_insert(breakdown[damageType.."MaximumHitTaken"], "^8from health pools, via damage reductions, to the max hit:") - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("%d ^8(used pool)", fullTaken)) + t_insert(breakdown[maxHitCurType], "^8Maximum hit is calculated in reverse -") + t_insert(breakdown[maxHitCurType], "^8from health pools, via damage reductions, to the max hit:") + t_insert(breakdown[maxHitCurType], s_format("%d ^8(used pool)", fullTaken)) if round(fullMulti, 2) ~= 1 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("/ %.2f ^8(modifiers to damage taken)", fullMulti)) + t_insert(breakdown[maxHitCurType], s_format("/ %.2f ^8(modifiers to damage taken)", fullMulti)) end if enemyDamageMult ~= 1 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("/ %.2f ^8(modifiers to enemy damage)", enemyDamageMult)) + t_insert(breakdown[maxHitCurType], s_format("/ %.2f ^8(modifiers to enemy damage)", enemyDamageMult)) end - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("= %.0f ^8maximum survivable enemy damage%s", finalMaxHit, useConversionSmoothing and " (approximate)" or "")) + t_insert(breakdown[maxHitCurType], s_format("= %.0f ^8maximum survivable enemy damage%s", finalMaxHit, useConversionSmoothing and " (approximate)" or "")) local poolsRemaining = calcs.reducePoolsByDamage(nil, takenDamages, actor) - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("^8Such a hit would drain the following:")) + t_insert(breakdown[maxHitCurType], s_format("^8Such a hit would drain the following:")) if output.FrostShieldLife and output.FrostShieldLife > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Frost Shield Life ^7(%d remaining)", output.FrostShieldLife - poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining, poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Frost Shield Life ^7(%d remaining)", output.FrostShieldLife - poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining, poolsRemaining.AlliesTakenBeforeYou["frostShield"].remaining)) end if output.TotalSpectreLife and output.TotalSpectreLife > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Spectre Life ^7(%d remaining)", output.TotalSpectreLife - poolsRemaining.AlliesTakenBeforeYou["specters"].remaining, poolsRemaining.AlliesTakenBeforeYou["specters"].remaining)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Spectre Life ^7(%d remaining)", output.TotalSpectreLife - poolsRemaining.AlliesTakenBeforeYou["specters"].remaining, poolsRemaining.AlliesTakenBeforeYou["specters"].remaining)) end if output.TotalTotemLife and output.TotalTotemLife > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Totem Life ^7(%d remaining)", output.TotalTotemLife - poolsRemaining.AlliesTakenBeforeYou["totems"].remaining, poolsRemaining.AlliesTakenBeforeYou["totems"].remaining)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Totem Life ^7(%d remaining)", output.TotalTotemLife - poolsRemaining.AlliesTakenBeforeYou["totems"].remaining, poolsRemaining.AlliesTakenBeforeYou["totems"].remaining)) end if output.TotalVaalRejuvenationTotemLife and output.TotalVaalRejuvenationTotemLife > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Vaal Rejuvenation Totem Life ^7(%d remaining)", output.TotalVaalRejuvenationTotemLife - poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining, poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Vaal Rejuvenation Totem Life ^7(%d remaining)", output.TotalVaalRejuvenationTotemLife - poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining, poolsRemaining.AlliesTakenBeforeYou["vaalRejuvenationTotems"].remaining)) end if output.TotalRadianceSentinelLife and output.TotalRadianceSentinelLife > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Total Sentinel of Radiance Life ^7(%d remaining)", output.TotalRadianceSentinelLife - poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining, poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Total Sentinel of Radiance Life ^7(%d remaining)", output.TotalRadianceSentinelLife - poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining, poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining)) end if output.sharedAegis and output.sharedAegis > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Shared Aegis charge ^7(%d remaining)", output.sharedAegis - poolsRemaining.Aegis.shared, poolsRemaining.Aegis.shared)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Shared Aegis charge ^7(%d remaining)", output.sharedAegis - poolsRemaining.Aegis.shared, poolsRemaining.Aegis.shared)) end local receivedElemental = false for takenType in pairs(takenDamages) do receivedElemental = receivedElemental or isElemental[takenType] if output[takenType.."Aegis"] and output[takenType.."Aegis"] > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."%s Aegis charge ^7(%d remaining)", output[takenType.."Aegis"] - poolsRemaining.Aegis[takenType], takenType, poolsRemaining.Aegis[takenType])) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."%s Aegis charge ^7(%d remaining)", output[takenType.."Aegis"] - poolsRemaining.Aegis[takenType], takenType, poolsRemaining.Aegis[takenType])) end end if receivedElemental and output.sharedElementalAegis and output.sharedElementalAegis > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.GEM.."Elemental Aegis charge ^7(%d remaining)", output.sharedElementalAegis - poolsRemaining.Aegis.sharedElemental, poolsRemaining.Aegis.sharedElemental)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.GEM.."Elemental Aegis charge ^7(%d remaining)", output.sharedElementalAegis - poolsRemaining.Aegis.sharedElemental, poolsRemaining.Aegis.sharedElemental)) end if output.sharedGuardAbsorb and output.sharedGuardAbsorb > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.SCOURGE.."Shared Guard charge ^7(%d remaining)", output.sharedGuardAbsorb - poolsRemaining.Guard.shared, poolsRemaining.Guard.shared)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.SCOURGE.."Shared Guard charge ^7(%d remaining)", output.sharedGuardAbsorb - poolsRemaining.Guard.shared, poolsRemaining.Guard.shared)) end for takenType in pairs(takenDamages) do if output[takenType.."GuardAbsorb"] and output[takenType.."GuardAbsorb"] > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\n\t%d "..colorCodes.SCOURGE.."%s Guard charge ^7(%d remaining)", output[takenType.."GuardAbsorb"] - poolsRemaining.Guard[takenType], takenType, poolsRemaining.Guard[takenType])) + t_insert(breakdown[maxHitCurType], s_format("\n\t%d "..colorCodes.SCOURGE.."%s Guard charge ^7(%d remaining)", output[takenType.."GuardAbsorb"] - poolsRemaining.Guard[takenType], takenType, poolsRemaining.Guard[takenType])) end end if output.Ward and output.Ward > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.WARD.."Ward", output.Ward)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.WARD.."Ward", output.Ward)) end if output.EnergyShieldRecoveryCap ~= poolsRemaining.EnergyShield and output.EnergyShieldRecoveryCap and output.EnergyShieldRecoveryCap > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.ES.."Energy Shield ^7(%d remaining)", output.EnergyShieldRecoveryCap - poolsRemaining.EnergyShield, poolsRemaining.EnergyShield)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.ES.."Energy Shield ^7(%d remaining)", output.EnergyShieldRecoveryCap - poolsRemaining.EnergyShield, poolsRemaining.EnergyShield)) end if output.ManaUnreserved ~= poolsRemaining.Mana and output.ManaUnreserved and output.ManaUnreserved > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.MANA.."Mana ^7(%d remaining)", output.ManaUnreserved - poolsRemaining.Mana, poolsRemaining.Mana)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.MANA.."Mana ^7(%d remaining)", output.ManaUnreserved - poolsRemaining.Mana, poolsRemaining.Mana)) end if poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime > 0 then - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.LIFE.."Life ^7Loss Prevented", poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.LIFE.."Life ^7Loss Prevented", poolsRemaining.LifeLossLostOverTime + poolsRemaining.LifeBelowHalfLossLostOverTime)) end - t_insert(breakdown[damageType.."MaximumHitTaken"], s_format("\t%d "..colorCodes.LIFE.."Life ^7(%d remaining)", output.LifeRecoverable - poolsRemaining.Life, poolsRemaining.Life)) + t_insert(breakdown[maxHitCurType], s_format("\t%d "..colorCodes.LIFE.."Life ^7(%d remaining)", output.LifeRecoverable - poolsRemaining.Life, poolsRemaining.Life)) end end From 599a81d559eed5b792ba1b9e5c7d1d020681144d Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:15:33 +0200 Subject: [PATCH 08/19] FEAT: code for generally supporting have no mods --- src/Classes/ModStore.lua | 4 ++-- src/Modules/CalcOffence.lua | 14 +++++++------- src/Modules/CalcSetup.lua | 5 ++++- src/Modules/Calcs.lua | 16 ++++++++++++---- src/Modules/ModParser.lua | 5 +++++ 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index 9cbe3b4551..de7d8478ac 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -513,7 +513,7 @@ function ModStoreClass:EvalMod(mod, cfg) if tag.actor then target = self.actor[tag.actor] and self.actor[tag.actor].modDB end - if target then + if target and (tag.var or tag.varList) then if tag.varList then for _, var in pairs(tag.varList) do if target:GetCondition(var, cfg) then @@ -524,7 +524,7 @@ function ModStoreClass:EvalMod(mod, cfg) else match = target:GetCondition(tag.var, cfg) end - elseif tag.actor and cfg and tag.var == nil and tag.varList == nil and tag.actor == cfg.actor then + elseif tag.actor and cfg and tag.actor == cfg.actor then match = true end if tag.neg then diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index b4a7490d9b..0c686c472f 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -2766,7 +2766,7 @@ function calcs.offence(env, actor, activeSkill) resist = resist > 0 and resist * (1 - (skillModList:Sum("BASE", nil, "PartialIgnoreEnemyPhysicalDamageReduction") / 100)) or resist end else - resist = calcResistForType(damageType) + resist = calcResistForType(damageType, dotCfg) if (skillModList:Flag(cfg, "ChaosDamageUsesLowestResistance") and damageType == "Chaos") or (skillModList:Flag(cfg, "ElementalDamageUsesLowestResistance") and isElemental[damageType]) then -- Default to using the current damage type @@ -2777,7 +2777,7 @@ function calcs.offence(env, actor, activeSkill) -- Find the lowest resist of all the elements and use that if it's lower for _, eleDamageType in ipairs(dmgTypeList) do if isElemental[eleDamageType] and useThisResist(eleDamageType) and damageType ~= eleDamageType then - local currentElementResist = calcResistForType(eleDamageType) + local currentElementResist = calcResistForType(eleDamageType, dotCfg) -- If it's explicitly lower, then use the resist and update which element we're using to account for penetration if resist > currentElementResist then resist = currentElementResist @@ -3814,7 +3814,7 @@ function calcs.offence(env, actor, activeSkill) skillFlags.duration = true local effMult = 1 if env.mode_effective then - local resist = calcResistForType("Chaos") + local resist = calcResistForType("Chaos", dotCfg) local takenInc = enemyDB:Sum("INC", dotCfg, "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime") local takenMore = enemyDB:More(dotCfg, "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime") effMult = (1 - resist / 100) * (1 + takenInc / 100) * takenMore @@ -4077,7 +4077,7 @@ function calcs.offence(env, actor, activeSkill) local effMult = 1 if env.mode_effective then if skillModList:Flag(cfg, "IgniteToChaos") then - local resist = calcResistForType("Chaos") + local resist = calcResistForType("Chaos", dotCfg) local takenInc = enemyDB:Sum("INC", dotCfg, "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime") local takenMore = enemyDB:More(dotCfg, "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime") effMult = (1 - resist / 100) * (1 + takenInc / 100) * takenMore @@ -4087,7 +4087,7 @@ function calcs.offence(env, actor, activeSkill) globalBreakdown.IgniteEffMult = breakdown.effMult("Chaos", resist, 0, takenInc, effMult, takenMore, sourceRes, true) end else - local resist = calcResistForType("Fire") + local resist = calcResistForType("Fire", dotCfg) local takenInc = enemyDB:Sum("INC", dotCfg, "DamageTaken", "DamageTakenOverTime", "FireDamageTaken", "FireDamageTakenOverTime", "ElementalDamageTaken") local takenMore = enemyDB:More(dotCfg, "DamageTaken", "DamageTakenOverTime", "FireDamageTaken", "FireDamageTakenOverTime", "ElementalDamageTaken") effMult = (1 - resist / 100) * (1 + takenInc / 100) * takenMore @@ -4109,7 +4109,7 @@ function calcs.offence(env, actor, activeSkill) local groundMult = m_max(skillModList:Max(nil, "IgniteDpsAsBurningGround") or 0, enemyDB:Max(nil, "IgniteDpsAsBurningGround") or 0) if groundMult > 0 then -- Always use fire eff multi - local resist = calcResistForType("Fire") + local resist = calcResistForType("Fire", dotCfg) local takenInc = enemyDB:Sum("INC", dotCfg, "DamageTaken", "DamageTakenOverTime", "FireDamageTaken", "FireDamageTakenOverTime", "ElementalDamageTaken") local takenMore = enemyDB:More(dotCfg, "DamageTaken", "DamageTakenOverTime", "FireDamageTaken", "FireDamageTakenOverTime", "ElementalDamageTaken") local fireEffMult = (1 - resist / 100) * (1 + takenInc / 100) * takenMore @@ -4507,7 +4507,7 @@ function calcs.offence(env, actor, activeSkill) local dotCfg = activeSkill.decayCfg local effMult = 1 if env.mode_effective then - local resist = calcResistForType("Chaos") + local resist = calcResistForType("Chaos", dotCfg) local takenInc = enemyDB:Sum("INC", nil, "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime") local takenMore = enemyDB:More(nil, "DamageTaken", "DamageTakenOverTime", "ChaosDamageTaken", "ChaosDamageTakenOverTime") effMult = (1 - resist / 100) * (1 + takenInc / 100) * takenMore diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 5bfcb2f6e6..4d3adab394 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -349,6 +349,8 @@ function calcs.initEnv(build, mode, override, specEnv) enemyDB.actor = env.enemy env.player.enemy = env.enemy env.enemy.enemy = env.player + enemyDB.actor.player = env.player + env.modDB.actor.player = env.player -- Set up requirements tracking env.requirementsTableItems = { } @@ -503,7 +505,8 @@ function calcs.initEnv(build, mode, override, specEnv) -- Initialise enemy modifier database calcs.initModDB(env, enemyDB) enemyDB:NewMod("Accuracy", "BASE", env.data.monsterAccuracyTable[env.enemyLevel], "Base") - + enemyDB:NewMod("Condition:AgainstDamageOverTime", "FLAG", true, "Base", ModFlag.Dot, { type = "ActorCondition", actor = "player", var = "Combat" }) + -- Add mods from the config tab env.modDB:AddList(build.configTab.modList) env.enemyDB:AddList(build.configTab.enemyModList) diff --git a/src/Modules/Calcs.lua b/src/Modules/Calcs.lua index 3d658bef86..e266da494e 100644 --- a/src/Modules/Calcs.lua +++ b/src/Modules/Calcs.lua @@ -541,10 +541,12 @@ function calcs.buildOutput(build, mode) else addVarTag(env.minionConditionsUsed, tag, mod) end - elseif tag.type == "ActorCondition" and tag.actor == "enemy" then - addVarTag(env.enemyConditionsUsed, tag, mod) - elseif tag.type == "ActorCondition" and tag.actor == "parent" then - addVarTag(env.conditionsUsed, tag, mod) + elseif tag.type == "ActorCondition" and tag.var then + if tag.actor == "enemy" then + addTo(env.enemyConditionsUsed, tag.var, mod) + else + addTo(env.conditionsUsed, tag.var, mod) + end elseif tag.type == "Multiplier" or tag.type == "MultiplierThreshold" then if not tag.actor then if actor == env.player then @@ -596,6 +598,12 @@ function calcs.buildOutput(build, mode) break elseif tag.type == "Condition" then addVarTag(env.enemyConditionsUsed, tag, mod) + elseif tag.type == "ActorCondition" and tag.var then + if tag.actor == "enemy" or tag.actor == "player" then + addTo(env.conditionsUsed, tag.var, mod) + else + addTo(env.enemyConditionsUsed, tag.var, mod) + end elseif tag.type == "Multiplier" or tag.type == "MultiplierThreshold" then if not tag.actor then addVarTag(env.enemyMultipliersUsed, tag, mod) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 0b7dfbb079..69cdb45b75 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -115,6 +115,7 @@ local formList = { ["^are "] = "FLAG", ["^gain "] = "FLAG", ["^you gain "] = "FLAG", + ["no "] = "OVERRIDE", } -- Map of modifier names @@ -1418,6 +1419,7 @@ local modTagList = { ["wh[ie][ln]e? you have no energy shield"] = { tag = { type = "Condition", var = "HaveEnergyShield", neg = true } }, ["if you have energy shield"] = { tag = { type = "Condition", var = "HaveEnergyShield" } }, ["while stationary"] = { tag = { type = "Condition", var = "Stationary" } }, + ["while you are stationary"] = { tag = { type = "ActorCondition", actor = "player", var = "Stationary" }}, ["while moving"] = { tag = { type = "Condition", var = "Moving" } }, ["while channelling"] = { tag = { type = "Condition", var = "Channelling" } }, ["while channelling snipe"] = { tag = { type = "Condition", var = "Channelling" } }, @@ -5389,6 +5391,9 @@ local function parseMod(line, order) modName = type(modValue) == "table" and modValue.name or modValue modType = type(modValue) == "table" and modValue.type or "FLAG" modValue = type(modValue) == "table" and modValue.value or true + elseif modForm == "OVERRIDE" then + modValue = 0 + modType = "OVERRIDE" end if not modName then return { }, line From e3b3cca6fc0f7711daa7c0756320efdbe6001585 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Fri, 4 Aug 2023 04:50:08 +0200 Subject: [PATCH 09/19] FEAT: impl resistance conversion mods --- src/Modules/CalcDefence.lua | 33 +++++++++++++++++++++++++++++++++ src/Modules/ModParser.lua | 8 ++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 4749ba926a..cc19b4dabc 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -314,6 +314,39 @@ function calcs.defence(env, actor) end end + -- Process Resistance conversion mods + for _, resFrom in ipairs(resistTypeList) do + local maxRes + for _, resTo in ipairs(resistTypeList) do + local conversionRate = modDB:Sum("BASE", nil, resFrom.."MaxResConvertTo"..resTo) / 100 + if conversionRate ~= 0 then + if not maxRes then + maxRes = 0 + for _, mod in ipairs(modDB:Tabulate("BASE", nil, resFrom.."ResistMax")) do + if mod.mod.source ~= "Base" then + maxRes = maxRes + mod.value + end + end + end + if maxRes ~= 0 then + modDB:NewMod(resTo.."ResistMax", "BASE", maxRes * conversionRate) + end + end + end + end + + for _, resFrom in ipairs(resistTypeList) do + local res + for _, resTo in ipairs(resistTypeList) do + local conversionRate = modDB:Sum("BASE", nil, resFrom.."ResConvertTo"..resTo) / 100 + if conversionRate ~= 0 then + if not res then res = modDB:Sum("BASE", nil, resFrom.."Resist") end + modDB:NewMod(resTo.."Resist", "BASE", res * conversionRate) + end + end + end + + for _, elem in ipairs(resistTypeList) do local min, max, total, totemTotal, totemMax min = data.misc.ResistFloor diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 69cdb45b75..c927778e32 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2777,6 +2777,14 @@ local specialModList = { ["increases and reductions to cast speed also apply to trap throwing speed"] = { flag("CastSpeedAppliesToTrapThrowingSpeed") }, ["increases and reductions to armour also apply to energy shield recharge rate at (%d+)%% of their value"] = function(num) return { flag("ArmourAppliesToEnergyShieldRecharge"), mod("ImprovedArmourAppliesToEnergyShieldRecharge", "MAX", num) } end, ["increases and reductions to projectile speed also apply to damage with bows"] = { flag("ProjectileSpeedAppliesToBowDamage") }, + ["modifiers to maximum (%a+) resistance apply to maximum (%a+) and (%a+) resistances"] = function(_, resFrom, resTo1, resTo2) return { + mod((resFrom:gsub("^%l", string.upper)).."MaxResConvertTo"..(resTo1:gsub("^%l", string.upper)), "BASE", 100), + mod((resFrom:gsub("^%l", string.upper)).."MaxResConvertTo"..(resTo2:gsub("^%l", string.upper)), "BASE", 100), + } end, + ["modifiers to (%a+) resistance apply to (%a+) and (%a+) resistances at (%d+)%% value"] = function(_, resFrom, resTo1, resTo2, rate) return { + mod((resFrom:gsub("^%l", string.upper)).."ResConvertTo"..(resTo1:gsub("^%l", string.upper)), "BASE", rate), + mod((resFrom:gsub("^%l", string.upper)).."ResConvertTo"..(resTo2:gsub("^%l", string.upper)), "BASE", rate), + } end, ["gain (%d+)%% of bow physical damage as extra damage of each element"] = function(num) return { mod("PhysicalDamageGainAsLightning", "BASE", num, nil, ModFlag.Bow), mod("PhysicalDamageGainAsCold", "BASE", num, nil, ModFlag.Bow), From efeb1b631fb73e9c4181f894c3f6f7530885b6ff Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Sun, 6 Aug 2023 10:54:54 +0200 Subject: [PATCH 10/19] FEAT: impl extra jewel func code for new chief mod --- src/Classes/ModStore.lua | 45 ++++++++++++++++++++++----------- src/Modules/CalcSetup.lua | 39 ++++++++++++++++++++++++++++- src/Modules/Main.lua | 2 +- src/Modules/ModParser.lua | 52 +++++++++++++++++++++------------------ 4 files changed, 98 insertions(+), 40 deletions(-) diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index de7d8478ac..a981f954c3 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -535,31 +535,48 @@ function ModStoreClass:EvalMod(mod, cfg) end elseif tag.type == "ItemCondition" then local match = false - local searchCond = tag.var + local searchCond = tag.searchCond + local rarityCond = tag.rarityCond + local allSlots = tag.allSlots local itemSlot = tag.itemSlot:gsub("(%l)(%w*)", function(a,b) return string.upper(a)..b end):gsub('^%s*(.-)%s*$', '%1') - local bCheckAllAppropriateSlots = tag.allSlots - if searchCond and itemSlot then + local bCheckAllAppropriateSlots = tag.bothSlots + local items + if allSlots then + items = self.actor.itemList + elseif self.actor.itemList then + items = {self.actor.itemList[itemSlot] or (cfg and cfg.item)} if bCheckAllAppropriateSlots then - local match1 = false - local match2 = false local itemSlot1 = self.actor.itemList[itemSlot .. " 1"] local itemSlot2 = self.actor.itemList[itemSlot .. " 2"] if itemSlot1 and itemSlot1.name:match("Kalandra's Touch") then itemSlot1 = itemSlot2 end if itemSlot2 and itemSlot2.name:match("Kalandra's Touch") then itemSlot2 = itemSlot1 end - if itemSlot1 then - match1 = itemSlot1:FindModifierSubstring(searchCond:lower(), itemSlot:lower()) + if itemSlot1 and itemSlot2 then + t_insert(items, itemSlot1) + t_insert(items, itemSlot2) end - if itemSlot2 then - match2 = itemSlot2:FindModifierSubstring(searchCond:lower(), itemSlot:lower()) + end + end + if items and #items > 0 then + if searchCond then + for _, item in pairs(items) do + if not item:FindModifierSubstring(searchCond:lower(), itemSlot:lower()) then + match = false + break + end + match = true end - match = match1 and match2 - else - if self.actor.itemList[itemSlot] then - match = self.actor.itemList[itemSlot]:FindModifierSubstring(searchCond:lower(), itemSlot:lower()) + end + if rarityCond then + for _, item in pairs(items) do + if item.rarity ~= rarityCond then + match = false + break + end + match = true end end end - if tag.neg then + if tag.neg or not cfg then match = not match end if not match then diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 4d3adab394..8df4e92102 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -385,6 +385,9 @@ function calcs.initEnv(build, mode, override, specEnv) enemyDB = env.enemyDB end + env.extraJewelFuncs = new("ModList") + env.extraJewelFuncs.actor = env.player + -- Set buff mode local buffMode if mode == "CALCS" then @@ -533,6 +536,13 @@ function calcs.initEnv(build, mode, override, specEnv) local allocatedMasteryCount = env.spec.allocatedMasteryCount local allocatedMasteryTypeCount = env.spec.allocatedMasteryTypeCount local allocatedMasteryTypes = copyTable(env.spec.allocatedMasteryTypes) + + for _, node in pairs(env.spec.allocNodes) do + for _, mod in ipairs(node.finalModList:Tabulate("LIST", nil, "ExtraJewelFunc")) do + env.extraJewelFuncs:AddMod(mod.mod) + end + end + if not accelerate.nodeAlloc then -- Build list of passive nodes local nodes @@ -643,7 +653,7 @@ function calcs.initEnv(build, mode, override, specEnv) jewelLimits[limitKey] = (jewelLimits[limitKey] or 0) + 1 end end - if item and item.jewelRadiusIndex then + if item and (item.jewelRadiusIndex or #env.extraJewelFuncs > 0) then -- Jewel has a radius, add it to the list local funcList = item.jewelData.funcList or { { type = "Self", func = function(node, out, data) -- Default function just tallies all stats in radius @@ -673,6 +683,33 @@ function calcs.initEnv(build, mode, override, specEnv) end end end + for _, funcData in ipairs(env.extraJewelFuncs:List({item = item}, "ExtraJewelFunc")) do + local node = env.spec.nodes[slot.nodeId] + local radius + for index, data in pairs(data.jewelRadius) do + if funcData.radius == data.label then + radius = index + break + end + end + t_insert(env.radiusJewelList, { + nodes = node.nodesInRadius and node.nodesInRadius[radius] or { }, + func = funcData.func, + type = funcData.type, + item = item, + nodeId = slot.nodeId, + attributes = node.attributesInRadius and node.attributesInRadius[radius] or { }, + data = { } + }) + if funcData.type ~= "Self" and node.nodesInRadius then + -- Add nearby unallocated nodes to the extra node list + for nodeId, node in pairs(node.nodesInRadius[radius]) do + if not env.allocNodes[nodeId] then + env.extraRadiusNodeList[nodeId] = env.spec.nodes[nodeId] + end + end + end + end end end end diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index a5740c5178..172ec4f33c 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -228,7 +228,7 @@ function main:SaveModCache() local out = io.open("Data/ModCache.lua", "w") out:write('local c=...') for line, dat in pairs(modLib.parseModCache) do - if not dat[1] or not dat[1][1] or dat[1][1].name ~= "JewelFunc" then + if not dat[1] or not dat[1][1] or (dat[1][1].name ~= "JewelFunc" and dat[1][1].name ~= "ExtraJewelFunc") then out:write('c["', line:gsub("\n","\\n"), '"]={') if dat[1] then writeLuaTable(out, dat[1]) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index c927778e32..5778bcfff4 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -14,6 +14,28 @@ local function firstToUpper(str) return (str:gsub("^%l", string.upper)) end +-- Radius jewels that modify other nodes +local function getSimpleConv(srcList, dst, type, remove, factor) + return function(node, out, data) + if node then + for _, src in pairs(srcList) do + for _, mod in ipairs(node.modList) do + if mod.name == src and mod.type == type then + if remove then + out:MergeNewMod(src, type, -mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + if factor then + out:MergeNewMod(dst, type, math.floor(mod.value * factor), mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + else + out:MergeNewMod(dst, type, mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + end + end + end + end + end +end + local conquerorList = { ["xibaqua"] = { id = 1, type = "vaal" }, ["zerphi"] = { id = 2, type = "vaal" }, @@ -1379,9 +1401,9 @@ local modTagList = { ["while unarmed"] = { tag = { type = "Condition", var = "Unarmed" } }, ["while you are unencumbered"] = { tag = { type = "Condition", var = "Unencumbered" } }, ["equipped bow"] = { tag = { type = "Condition", var = "UsingBow" } }, - ["if equipped ([%a%s]+) has an ([%a%s]+) modifier"] = function (_, itemSlotName, conditionSubstring) return { tag = { type = "ItemCondition", var = conditionSubstring, itemSlot = itemSlotName } } end, - ["if both equipped ([%a%s]+) have ([%a%s]+) modifiers"] = function (_, itemSlotName, conditionSubstring) return { tag = { type = "ItemCondition", var = conditionSubstring, itemSlot = itemSlotName:sub(1, #itemSlotName - 1), allSlots = true } } end, - ["if there are no ([%a%s]+) modifiers on equipped ([%a%s]+)"] = function (_, conditionSubstring, itemSlotName) return { tag = { type = "ItemCondition", var = conditionSubstring, itemSlot = itemSlotName, neg = true } } end, + ["if equipped ([%a%s]+) has an ([%a%s]+) modifier"] = function (_, itemSlotName, conditionSubstring) return { tag = { type = "ItemCondition", searchCond = conditionSubstring, itemSlot = itemSlotName } } end, + ["if both equipped ([%a%s]+) have ([%a%s]+) modifiers"] = function (_, itemSlotName, conditionSubstring) return { tag = { type = "ItemCondition", searchCond = conditionSubstring, itemSlot = itemSlotName:sub(1, #itemSlotName - 1), bothSlots = true } } end, + ["if there are no ([%a%s]+) modifiers on equipped ([%a%s]+)"] = function (_, conditionSubstring, itemSlotName) return { tag = { type = "ItemCondition", searchCond = conditionSubstring, itemSlot = itemSlotName, neg = true } } end, ["with a normal item equipped"] = { tag = { type = "MultiplierThreshold", var = "NormalItem", threshold = 1 } }, ["with a magic item equipped"] = { tag = { type = "MultiplierThreshold", var = "MagicItem", threshold = 1 } }, ["with a rare item equipped"] = { tag = { type = "MultiplierThreshold", var = "RareItem", threshold = 1 } }, @@ -2167,6 +2189,9 @@ local specialModList = { mod("Damage", "MORE", num, { type = "Multiplier", var = "EnduranceChargesLostRecently", limit = tonumber(limit), limitTotal = true }), } end, ["(%d+)%% more damage if you've lost an endurance charge in the past 8 seconds"] = function(num) return { mod("Damage", "MORE", num, { type = "Condition", var = "LostEnduranceChargeInPast8Sec" }) } end, + ["non%-unique jewels cause increases and reductions to other damage types in (%a+) radius to be transformed to apply (%a+) damage"] = function(_, radius, dmgType) return { + mod("ExtraJewelFunc", "LIST", {radius = (radius:gsub("^%l", string.upper)), type = "Other", func = getSimpleConv({ "PhysicalDamage","ColdDamage","LightningDamage","ChaosDamage" }, (dmgType:gsub("^%l", string.upper)).."Damage", "INC", true)}, {type = "ItemCondition", itemSlot = "{SlotName}", rarityCond = "UNIQUE", neg = true}), + } end, --["trigger level (%d+) (.+) when you attack with a non%-vaal slam skill near an enemy"] = function(num, _, skill) return triggerExtraSkill(skill, num) end, -- Deadeye ["projectiles pierce all nearby targets"] = { flag("PierceAllTargets") }, @@ -4846,27 +4871,6 @@ for gemId, gemData in pairs(data.gems) do end end --- Radius jewels that modify other nodes -local function getSimpleConv(srcList, dst, type, remove, factor) - return function(node, out, data) - if node then - for _, src in pairs(srcList) do - for _, mod in ipairs(node.modList) do - if mod.name == src and mod.type == type then - if remove then - out:MergeNewMod(src, type, -mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) - end - if factor then - out:MergeNewMod(dst, type, math.floor(mod.value * factor), mod.source, mod.flags, mod.keywordFlags, unpack(mod)) - else - out:MergeNewMod(dst, type, mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) - end - end - end - end - end - end -end local jewelOtherFuncs = { ["Strength from Passives in Radius is Transformed to Dexterity"] = getSimpleConv({ "Str" }, "Dex", "BASE", true), ["Dexterity from Passives in Radius is Transformed to Strength"] = getSimpleConv({ "Dex" }, "Str", "BASE", true), From 1f843dbb489ec71a6178aed618dcf2eaba083033 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Mon, 7 Aug 2023 03:22:28 +0200 Subject: [PATCH 11/19] FEAT: impl mod on all other slots condition --- src/Classes/ModStore.lua | 29 ++++++++++++++--------------- src/Modules/ModParser.lua | 1 + 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index a981f954c3..5621b64bc8 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -534,11 +534,12 @@ function ModStoreClass:EvalMod(mod, cfg) return end elseif tag.type == "ItemCondition" then + local matches = {} local match = false local searchCond = tag.searchCond local rarityCond = tag.rarityCond local allSlots = tag.allSlots - local itemSlot = tag.itemSlot:gsub("(%l)(%w*)", function(a,b) return string.upper(a)..b end):gsub('^%s*(.-)%s*$', '%1') + local itemSlot = tag.itemSlot:lower():gsub("(%l)(%w*)", function(a,b) return string.upper(a)..b end):gsub('^%s*(.-)%s*$', '%1') local bCheckAllAppropriateSlots = tag.bothSlots local items if allSlots then @@ -556,30 +557,28 @@ function ModStoreClass:EvalMod(mod, cfg) end end end - if items and #items > 0 then + if items and #items > 0 or allSlots then if searchCond then - for _, item in pairs(items) do - if not item:FindModifierSubstring(searchCond:lower(), itemSlot:lower()) then - match = false - break + for slot, item in pairs(items) do + if slot ~= itemSlot or not tag.excludeSelf then + t_insert(matches, item:FindModifierSubstring(searchCond:lower(), itemSlot:lower())) end - match = true end end if rarityCond then for _, item in pairs(items) do - if item.rarity ~= rarityCond then - match = false - break - end - match = true + t_insert(matches, item.rarity == rarityCond) end end end - if tag.neg or not cfg then - match = not match + for _, bool in ipairs(matches) do + if bool then + match = not tag.neg + break + end + match = tag.neg == true end - if not match then + if not match and #matches > 0 then return end elseif tag.type == "SocketedIn" then diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 5778bcfff4..916f1b910c 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -1404,6 +1404,7 @@ local modTagList = { ["if equipped ([%a%s]+) has an ([%a%s]+) modifier"] = function (_, itemSlotName, conditionSubstring) return { tag = { type = "ItemCondition", searchCond = conditionSubstring, itemSlot = itemSlotName } } end, ["if both equipped ([%a%s]+) have ([%a%s]+) modifiers"] = function (_, itemSlotName, conditionSubstring) return { tag = { type = "ItemCondition", searchCond = conditionSubstring, itemSlot = itemSlotName:sub(1, #itemSlotName - 1), bothSlots = true } } end, ["if there are no ([%a%s]+) modifiers on equipped ([%a%s]+)"] = function (_, conditionSubstring, itemSlotName) return { tag = { type = "ItemCondition", searchCond = conditionSubstring, itemSlot = itemSlotName, neg = true } } end, + ["if there are no (%a+) modifiers on other equipped items"] = function(_, conditionSubstring) return {tag = { type = "ItemCondition", searchCond = conditionSubstring, itemSlot = "{SlotName}", allSlots = true, excludeSelf = true, neg = true }} end, ["with a normal item equipped"] = { tag = { type = "MultiplierThreshold", var = "NormalItem", threshold = 1 } }, ["with a magic item equipped"] = { tag = { type = "MultiplierThreshold", var = "MagicItem", threshold = 1 } }, ["with a rare item equipped"] = { tag = { type = "MultiplierThreshold", var = "RareItem", threshold = 1 } }, From 289ef984766a8ce8cf962c0328f498d2df27071e Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Mon, 7 Aug 2023 03:29:05 +0200 Subject: [PATCH 12/19] FEAT: add new uniques --- src/Data/Uniques/Special/New.lua | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Data/Uniques/Special/New.lua b/src/Data/Uniques/Special/New.lua index 12bd3d5818..50ef4efbc2 100644 --- a/src/Data/Uniques/Special/New.lua +++ b/src/Data/Uniques/Special/New.lua @@ -5,7 +5,37 @@ data.uniques.new = { -- New - +[[ +Kitava's Hunger +Majestic Plate +88% increased Armour +Recover 2% of Life on Kill +37% Increased Stun and Block Recovery ++910 to maximum Life if there are no Life Modifiers on other Equipped items +]], +[[ +Arohongui's Tending +Coral Amulet +Regenerate 4.4 Mana per second +37% increased Life Recovery from Flasks +26% increased Mana Recovery from Flasks +Life Flasks used while on Low Life apply Recovery Instantly +Mana Flasks used while on Low Mana apply Recovery Instantly +]], +[[ +Bound Fate +Cloth Belt ++28 to Dexterity ++26 to Intelligence ++64 to Maximum Life +Every 5 seconds, gain one of the following for 5 seconds: +Your Hits are always Critical Strikes +Hits against you always are Critical Strikes +Attacks cannot Hit you +Attacks against you always Hit +Your Damage with Hits is Lucky +Damage of Hits against you is Lucky +]], -- Reworked } From e226f7b0ec32a4d00a3f7f49e39e3654f3431816 Mon Sep 17 00:00:00 2001 From: Wires77 Date: Thu, 17 Aug 2023 01:43:22 -0500 Subject: [PATCH 13/19] Wording fixes, new unique --- src/Data/Uniques/Special/New.lua | 7 ++++++ src/Data/Uniques/boots.lua | 1 + src/Modules/ConfigOptions.lua | 2 +- src/Modules/ModParser.lua | 41 +++++++++++++++++++------------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/Data/Uniques/Special/New.lua b/src/Data/Uniques/Special/New.lua index 50ef4efbc2..689ce48c96 100644 --- a/src/Data/Uniques/Special/New.lua +++ b/src/Data/Uniques/Special/New.lua @@ -35,6 +35,13 @@ Attacks cannot Hit you Attacks against you always Hit Your Damage with Hits is Lucky Damage of Hits against you is Lucky +]],[[ +Maata's Teaching +Karui Sceptre ++37 to Intelligence +42% increased Critical Strike Chance ++2 to Level of all Minion Skill Gems +Minions' Base Attack Critical Strike Chance is equal to the Critical Strike Chance of your Main Hand Weapon" ]], -- Reworked diff --git a/src/Data/Uniques/boots.lua b/src/Data/Uniques/boots.lua index d7681c759c..d5cc750fcc 100644 --- a/src/Data/Uniques/boots.lua +++ b/src/Data/Uniques/boots.lua @@ -767,6 +767,7 @@ Adds 1 to 80 Chaos Damage to Attacks {variant:2}25% increased Movement Speed {variant:1}+1 to Maximum number of Skeletons {variant:2}Summoned Skeleton Warriors are Permanent and Follow you +{variant:2}Summon Skeletons cannot Summon more than 1 Skeleton Warrior ]],[[ Replica Alberon's Warpath Soldier Boots diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 4ccd83f1ef..287ac375ef 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -1596,7 +1596,7 @@ Huge sets the radius to 11. 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 the way of a Link skill?", 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", 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 }, -- Section: Enemy Stats diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 9239f10937..c754b3b7f8 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -137,7 +137,7 @@ local formList = { ["^are "] = "FLAG", ["^gain "] = "FLAG", ["^you gain "] = "FLAG", - ["no "] = "OVERRIDE", + ["is (%d)%%? "] = "OVERRIDE", } -- Map of modifier names @@ -1102,7 +1102,7 @@ local preFlagList = { end, ["^enemies you've hit recently have "] = function(cond) return { playerTag = { type = "Condition", var = "HitRecently" }, applyToEnemy = true } - end, + end, ["^hits against enemies (%a+) by you have "] = function(cond) return { tag = { type = "ActorCondition", actor = "enemy", var = cond:gsub("^%a", string.upper) } } end, @@ -1113,7 +1113,7 @@ local preFlagList = { ["^nearby enemies take "] = { modSuffix = "Taken", applyToEnemy = true }, ["^nearby enemies have "] = { applyToEnemy = true }, ["^nearby enemies deal "] = { applyToEnemy = true }, - ["^nearby enemies "] = { applyToEnemy = true }, + ["^nearby enemies'? "] = { applyToEnemy = true }, ["against you"] = { applyToEnemy = true, actorEnemy = true }, ["^hits against you "] = { applyToEnemy = true, flags = ModFlag.Hit }, ["^enemies near your totems deal "] = { applyToEnemy = true }, @@ -1140,7 +1140,8 @@ local preFlagList = { ["^blink arrow and mirror arrow have "] = { tag = { type = "SkillName", skillNameList = { "Blink Arrow", "Mirror Arrow" } } }, ["attacks with energy blades "] = { flags = ModFlag.Attack, tag = { type = "Condition", var = "AffectedByEnergyBlade" } }, ["^for each nearby corpse, "] = { tag = { type = "Multiplier", var = "NearbyCorpse" } }, - ["^allies between you and linked targets have "] = { newAura = true, newAuraOnlyAllies = true, tag = { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" } }, + ["^linked targets and allies in your link beams have "] = { newAura = true, newAuraOnlyAllies = true }, + ["^enemies in your link beams have "] = { tag = { type = "Condition", var = "BetweenYouAndLinkedTarget" }, applyToEnemy = true }, -- While in the presence of... ["^while a unique enemy is in your presence, "] = { tag = { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" } }, ["^while a pinnacle atlas boss is in your presence, "] = { tag = { type = "ActorCondition", actor = "enemy", var = "PinnacleBoss" } }, @@ -1822,7 +1823,7 @@ end -- List of special modifiers local specialModList = { -- Explode mods - ["enemies you kill have a (%d+)%% chance to explode, dealing a (.+) of their maximum life as (.+) damage"] = function(chance, _, amount, type) -- Obliteration, Unspeakable Gifts (chaos cluster), synth implicit mod, current crusader body mod + ["enemies you kill have ?a? ?(%d+)%% chance to explode, dealing ?a? ?(%d+)%% of their maximum life as (.+) damage"] = function(chance, _, amount, type) -- Obliteration; Unspeakable Gifts (chaos cluster); synth implicit mod; crusader body mod; Hinekora, Death's Fury return explodeFunc(chance, amount, type) end, ["enemies you kill while using pride have (%d+)%% chance to explode, dealing a (.+) of their maximum life as (.+) damage"] = function(chance, _, amount, type) -- Sublime Vision @@ -1870,9 +1871,6 @@ local specialModList = { ["totems explode on death, dealing (%d+)%% of their life as (.+) damage"] = function(amount, _, type) -- Crucible weapon mod return explodeFunc(100, amount, type) end, - ["enemies you kill have ?a? ?(%d+)%% chance to explode, dealing (%d+)%% of their maximum life as (.+) damage"] = function(chance, _, amount, type) - return explodeFunc(chance, amount, type) - end, -- Keystones ["(%d+) rage regenerated for every (%d+) mana regeneration per second"] = function(num, _, div) return { mod("RageRegen", "BASE", num, {type = "PerStat", stat = "ManaRegen", div = tonumber(div) }) , @@ -2190,8 +2188,15 @@ local specialModList = { mod("Damage", "MORE", num, { type = "Multiplier", var = "EnduranceChargesLostRecently", limit = tonumber(limit), limitTotal = true }), } end, ["(%d+)%% more damage if you've lost an endurance charge in the past 8 seconds"] = function(num) return { mod("Damage", "MORE", num, { type = "Condition", var = "LostEnduranceChargeInPast8Sec" }) } end, - ["non%-unique jewels cause increases and reductions to other damage types in (%a+) radius to be transformed to apply (%a+) damage"] = function(_, radius, dmgType) return { - mod("ExtraJewelFunc", "LIST", {radius = (radius:gsub("^%l", string.upper)), type = "Other", func = getSimpleConv({ "PhysicalDamage","ColdDamage","LightningDamage","ChaosDamage" }, (dmgType:gsub("^%l", string.upper)).."Damage", "INC", true)}, {type = "ItemCondition", itemSlot = "{SlotName}", rarityCond = "UNIQUE", neg = true}), + ["non%-unique jewels cause increases and reductions to other damage types in a (%a+) radius to be transformed to apply to (%a+) damage"] = function(_, radius, dmgType) return { + mod("ExtraJewelFunc", "LIST", {radius = firstToUpper(radius), type = "Other", func = getSimpleConv({ "PhysicalDamage","FireDamage","ColdDamage","LightningDamage","ChaosDamage","ElementalDamage" }, (dmgType:gsub("^%l", string.upper)).."Damage", "INC", true)}, {type = "ItemCondition", itemSlot = "{SlotName}", rarityCond = "UNIQUE", neg = true}), + } end, + ["non%-unique jewels cause small and notable passive skills in a (%a+) radius to also grant %+(%d+) to (%a+)"] = function(_, radius, val, attr) return { + mod("ExtraJewelFunc", "LIST", {radius = (radius:gsub("^%l", string.upper)), type = "Other", func = function(node, out, data) + if node and (node.type == "Notable" or node.type == "Normal") then + out:NewMod(firstToUpper(attr):match("^%a%l%l"), "BASE", val, data.modSource) + end + end}, {type = "ItemCondition", itemSlot = "{SlotName}", rarityCond = "UNIQUE", neg = true}), } end, --["trigger level (%d+) (.+) when you attack with a non%-vaal slam skill near an enemy"] = function(num, _, skill) return triggerExtraSkill(skill, num) end, -- Deadeye @@ -2381,9 +2386,8 @@ local specialModList = { ["if you've cast a spell recently, you and nearby allies have %+(%d+)%% chance to block spell damage"] = function(num) return { mod("ExtraAura", "LIST", { mod = mod("SpellBlockChance", "BASE", num) }, { type = "Condition", var = "CastSpellRecently" }) } end, ["while there is at least one nearby ally, you and nearby allies deal (%d+)%% more damage"] = function(num) return { mod("ExtraAura", "LIST", { mod = mod("Damage", "MORE", num) }, { type = "MultiplierThreshold", var = "NearbyAlly", threshold = 1 }) } end, ["while there are at least five nearby allies, you and nearby allies have onslaught"] = { mod("ExtraAura", "LIST", { mod = flag("Onslaught") }, { type = "MultiplierThreshold", var = "NearbyAlly", threshold = 5 }) }, - ["elemental damage with hits dealt by allies between you and linked targets is lucky"] = { flag("ElementalLuckHits", { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }) }, - ["enemies between you and linked targets cannot apply elemental ailments"] = { mod("AvoidElementalAilments", "BASE", 100, 0, 0, { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }, { type = "GlobalEffect", effectType = "Global", unscalable = true })}, - ["(%d+)%% of damage from hits is taken from sentinel of radiance's life before you"] = function(num) return { mod("takenFromRadianceSentinelBeforeYou", "BASE", num) } end, + ["enemies in your link beams cannot apply elemental ailments"] = { mod("AvoidElementalAilments", "BASE", 100, 0, 0, { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }, { type = "GlobalEffect", effectType = "Global", unscalable = true })}, + ["(%d+)%% of damage from hits is taken from your sentinel of radiance's life before you"] = function(num) return { mod("takenFromRadianceSentinelBeforeYou", "BASE", num) } end, -- Hierophant ["you and your totems regenerate ([%d%.]+)%% of life per second for each summoned totem"] = function (num) return { mod("LifeRegenPercent", "BASE", num, { type = "PerStat", stat = "TotemsSummoned" }), @@ -2805,11 +2809,11 @@ local specialModList = { ["increases and reductions to cast speed also apply to trap throwing speed"] = { flag("CastSpeedAppliesToTrapThrowingSpeed") }, ["increases and reductions to armour also apply to energy shield recharge rate at (%d+)%% of their value"] = function(num) return { flag("ArmourAppliesToEnergyShieldRecharge"), mod("ImprovedArmourAppliesToEnergyShieldRecharge", "MAX", num) } end, ["increases and reductions to projectile speed also apply to damage with bows"] = { flag("ProjectileSpeedAppliesToBowDamage") }, - ["modifiers to maximum (%a+) resistance apply to maximum (%a+) and (%a+) resistances"] = function(_, resFrom, resTo1, resTo2) return { + ["modifiers to maximum (%a+) resistance also apply to maximum (%a+) and (%a+) resistances"] = function(_, resFrom, resTo1, resTo2) return { mod((resFrom:gsub("^%l", string.upper)).."MaxResConvertTo"..(resTo1:gsub("^%l", string.upper)), "BASE", 100), mod((resFrom:gsub("^%l", string.upper)).."MaxResConvertTo"..(resTo2:gsub("^%l", string.upper)), "BASE", 100), } end, - ["modifiers to (%a+) resistance apply to (%a+) and (%a+) resistances at (%d+)%% value"] = function(_, resFrom, resTo1, resTo2, rate) return { + ["modifiers to (%a+) resistance also apply to (%a+) and (%a+) resistances at (%d+)%% of their value"] = function(_, resFrom, resTo1, resTo2, rate) return { mod((resFrom:gsub("^%l", string.upper)).."ResConvertTo"..(resTo1:gsub("^%l", string.upper)), "BASE", rate), mod((resFrom:gsub("^%l", string.upper)).."ResConvertTo"..(resTo2:gsub("^%l", string.upper)), "BASE", rate), } end, @@ -4900,7 +4904,7 @@ local jewelOtherFuncs = { ["Increases and Reductions to Life in Radius are Transformed to apply to Mana at 200% of their value"] = getSimpleConv({ "Life" }, "Mana", "INC", true, 2), ["Increases and Reductions to Physical Damage in Radius are Transformed to apply to Cold Damage"] = getSimpleConv({ "PhysicalDamage" }, "ColdDamage", "INC", true), ["Increases and Reductions to Cold Damage in Radius are Transformed to apply to Physical Damage"] = getSimpleConv({ "ColdDamage" }, "PhysicalDamage", "INC", true), - ["Increases and Reductions to other Damage Types in Radius are Transformed to apply to Fire Damage"] = getSimpleConv({ "PhysicalDamage","ColdDamage","LightningDamage","ChaosDamage" }, "FireDamage", "INC", true), + ["Increases and Reductions to other Damage Types in Radius are Transformed to apply to Fire Damage"] = getSimpleConv({ "PhysicalDamage","ColdDamage","LightningDamage","ChaosDamage","ElementalDamage" }, "FireDamage", "INC", true), ["Passives granting Lightning Resistance or all Elemental Resistances in Radius also grant Chance to Block Spells at 35% of its value"] = getSimpleConv({ "LightningResist","ElementalResist" }, "SpellBlockChance", "BASE", false, 0.35), ["Passives granting Lightning Resistance or all Elemental Resistances in Radius also grant Chance to Block Spell Damage at 35% of its value"] = getSimpleConv({ "LightningResist","ElementalResist" }, "SpellBlockChance", "BASE", false, 0.35), ["Passives granting Lightning Resistance or all Elemental Resistances in Radius also grant Chance to Block Spell Damage at 50% of its value"] = getSimpleConv({ "LightningResist","ElementalResist" }, "SpellBlockChance", "BASE", false, 0.5), @@ -5262,6 +5266,10 @@ local function parseMod(line, order) preFlag = preFlag(unpack(preFlagCap)) end + if lineLower:match("enemies' fire resistance is 0%%") then + local x = 1 + end + -- Check for skill name at the start of the line local skillTag skillTag, line = scan(line, preSkillNameList) @@ -5421,7 +5429,6 @@ local function parseMod(line, order) modType = type(modValue) == "table" and modValue.type or "FLAG" modValue = type(modValue) == "table" and modValue.value or true elseif modForm == "OVERRIDE" then - modValue = 0 modType = "OVERRIDE" end if not modName then From e9f0e61ae6424826fa64b93f4c3190c227495e6e Mon Sep 17 00:00:00 2001 From: Wires77 Date: Thu, 17 Aug 2023 01:46:34 -0500 Subject: [PATCH 14/19] Remove debugging lines --- src/Modules/ModParser.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index c754b3b7f8..89b7d2086e 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -5266,10 +5266,6 @@ local function parseMod(line, order) preFlag = preFlag(unpack(preFlagCap)) end - if lineLower:match("enemies' fire resistance is 0%%") then - local x = 1 - end - -- Check for skill name at the start of the line local skillTag skillTag, line = scan(line, preSkillNameList) From c7c72682828c912953d3e07b0478958b13a6b80a Mon Sep 17 00:00:00 2001 From: Wires77 Date: Thu, 17 Aug 2023 01:56:11 -0500 Subject: [PATCH 15/19] Adding fire mastery explosion mod --- src/Modules/ModParser.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 89b7d2086e..5d28226693 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -1860,6 +1860,9 @@ local specialModList = { ["bleeding enemies you kill explode, dealing (%d+)%% of their maximum life as (.+) damage"] = function(amount, _, type) -- Haemophilia return explodeFunc(100, amount, type, { type = "ActorCondition", actor = "enemy", var = "Bleeding" }) end, + ["burning enemies you kill have a (%d+)%% chance to explode, dealing a (.+) of their maximum life as (.+) damage"] = function(amount, _, type) -- Haemophilia + return explodeFunc(100, amount, type, { type = "ActorCondition", actor = "enemy", var = "Burning" }) + end, ["non-aura curses you inflict are not removed from dying enemies"] = {}, ["enemies near corpses affected by your curses are blinded"] = { mod("EnemyModifier", "LIST", { mod = flag("Condition:Blinded") }, { type = "MultiplierThreshold", var = "NearbyCorpse", threshold = 1 }, { type = "ActorCondition", actor = "enemy", var = "Cursed" }) }, ["enemies killed near corpses affected by your curses explode, dealing (%d+)%% of their life as (.+) damage"] = function(amount, _, type) -- Asenath's Gentle Touch From eceebf143bbcc323c2628c5842447ec1d73ce4b7 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Thu, 17 Aug 2023 21:19:40 +0200 Subject: [PATCH 16/19] FIX: use ailment immunity flags from #6297 --- src/Modules/ModParser.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 5d28226693..ef37029d16 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2389,7 +2389,13 @@ local specialModList = { ["if you've cast a spell recently, you and nearby allies have %+(%d+)%% chance to block spell damage"] = function(num) return { mod("ExtraAura", "LIST", { mod = mod("SpellBlockChance", "BASE", num) }, { type = "Condition", var = "CastSpellRecently" }) } end, ["while there is at least one nearby ally, you and nearby allies deal (%d+)%% more damage"] = function(num) return { mod("ExtraAura", "LIST", { mod = mod("Damage", "MORE", num) }, { type = "MultiplierThreshold", var = "NearbyAlly", threshold = 1 }) } end, ["while there are at least five nearby allies, you and nearby allies have onslaught"] = { mod("ExtraAura", "LIST", { mod = flag("Onslaught") }, { type = "MultiplierThreshold", var = "NearbyAlly", threshold = 5 }) }, - ["enemies in your link beams cannot apply elemental ailments"] = { mod("AvoidElementalAilments", "BASE", 100, 0, 0, { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" }, { type = "GlobalEffect", effectType = "Global", unscalable = true })}, + ["enemies in your link beams cannot apply elemental ailments"] = function() + local mods = {} + for _, ailmentType in ipairs(data.elementalAilmentTypeList) do + t_insert(mods, flag(ailmentType.."Immune", { type = "ActorCondition", actor = "enemy", var = "BetweenYouAndLinkedTarget" })) + end + return mods + end, ["(%d+)%% of damage from hits is taken from your sentinel of radiance's life before you"] = function(num) return { mod("takenFromRadianceSentinelBeforeYou", "BASE", num) } end, -- Hierophant ["you and your totems regenerate ([%d%.]+)%% of life per second for each summoned totem"] = function (num) return { From 24264aa5ef00705fea9298e113973de5f63bceb7 Mon Sep 17 00:00:00 2001 From: Wires77 Date: Fri, 18 Aug 2023 00:48:49 -0500 Subject: [PATCH 17/19] Late breaking Chieftain change --- src/Modules/ModParser.lua | 2 +- src/TreeData/3_22/tree.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index ef37029d16..761a5374e2 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -137,7 +137,7 @@ local formList = { ["^are "] = "FLAG", ["^gain "] = "FLAG", ["^you gain "] = "FLAG", - ["is (%d)%%? "] = "OVERRIDE", + ["is (%-?%d+)%%? "] = "OVERRIDE", } -- Map of modifier names diff --git a/src/TreeData/3_22/tree.lua b/src/TreeData/3_22/tree.lua index 385bb909df..08e38a7c52 100644 --- a/src/TreeData/3_22/tree.lua +++ b/src/TreeData/3_22/tree.lua @@ -11942,7 +11942,7 @@ return { ["isNotable"]= true, ["ascendancyName"]= "Chieftain", ["stats"]= { - "Nearby Enemies' Fire Resistance is 0% against Damage over Time while you are Stationary" + "Nearby Enemies' Fire Resistance is -20% against Damage over Time while you are Stationary" }, ["group"]= 6, ["orbit"]= 3, From ae41c35dba03a9dc7ee8ff85a97faedd96b50469 Mon Sep 17 00:00:00 2001 From: LocalIdentity <31035929+LocalIdentity@users.noreply.github.com> Date: Fri, 18 Aug 2023 17:54:01 +1000 Subject: [PATCH 18/19] Update mod ranges --- src/Data/Uniques/Special/New.lua | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Data/Uniques/Special/New.lua b/src/Data/Uniques/Special/New.lua index 689ce48c96..f0636d0dcb 100644 --- a/src/Data/Uniques/Special/New.lua +++ b/src/Data/Uniques/Special/New.lua @@ -8,26 +8,26 @@ data.uniques.new = { [[ Kitava's Hunger Majestic Plate -88% increased Armour -Recover 2% of Life on Kill -37% Increased Stun and Block Recovery -+910 to maximum Life if there are no Life Modifiers on other Equipped items +(60-100)% increased Armour +Recover (1-3)% of Life on Kill +(30-40)% Increased Stun and Block Recovery ++(700-1000) to maximum Life if there are no Life Modifiers on other Equipped items ]], [[ Arohongui's Tending Coral Amulet -Regenerate 4.4 Mana per second -37% increased Life Recovery from Flasks -26% increased Mana Recovery from Flasks +{tags:life}Regenerate (2-4) Life per second +{tags:life}(15-30)% increased Life Recovery from Flasks +{tags:mana}(15-30)% increased Mana Recovery from Flasks Life Flasks used while on Low Life apply Recovery Instantly Mana Flasks used while on Low Mana apply Recovery Instantly ]], [[ Bound Fate Cloth Belt -+28 to Dexterity -+26 to Intelligence -+64 to Maximum Life +{tags:jewellery_attribute}+(20-30) to Dexterity +{tags:jewellery_attribute}+(20-30) to Intelligence +{tags:life}+(60-80) to Maximum Life Every 5 seconds, gain one of the following for 5 seconds: Your Hits are always Critical Strikes Hits against you always are Critical Strikes @@ -38,8 +38,8 @@ Damage of Hits against you is Lucky ]],[[ Maata's Teaching Karui Sceptre -+37 to Intelligence -42% increased Critical Strike Chance ++(30-40) to Intelligence +(25-50)% increased Critical Strike Chance +2 to Level of all Minion Skill Gems Minions' Base Attack Critical Strike Chance is equal to the Critical Strike Chance of your Main Hand Weapon" ]], From bd530235708df0f088e24579cea125f9446da520 Mon Sep 17 00:00:00 2001 From: LocalIdentity <31035929+LocalIdentity@users.noreply.github.com> Date: Fri, 18 Aug 2023 18:06:44 +1000 Subject: [PATCH 19/19] Fix Amulet and belt --- src/Data/Uniques/Special/New.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Data/Uniques/Special/New.lua b/src/Data/Uniques/Special/New.lua index f0636d0dcb..18c11e7dd5 100644 --- a/src/Data/Uniques/Special/New.lua +++ b/src/Data/Uniques/Special/New.lua @@ -16,8 +16,10 @@ Recover (1-3)% of Life on Kill [[ Arohongui's Tending Coral Amulet +Implicits: 1 {tags:life}Regenerate (2-4) Life per second -{tags:life}(15-30)% increased Life Recovery from Flasks +{tags:mana}Regenerate (3-5) Mana per second +{tags:life}(30-40)% increased Life Recovery from Flasks {tags:mana}(15-30)% increased Mana Recovery from Flasks Life Flasks used while on Low Life apply Recovery Instantly Mana Flasks used while on Low Mana apply Recovery Instantly