Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4742,12 +4742,12 @@ c["Cannot Recover Life other than from Leech"]={{[1]={flags=0,keywordFlags=0,nam
c["Cannot Regenerate Mana if you haven't dealt a Critical Hit Recently"]={{[1]={[1]={neg=true,type="Condition",var="CritRecently"},flags=0,keywordFlags=0,name="NoManaRegen",type="FLAG",value=true}},nil}
c["Cannot be Blinded"]={{[1]={flags=0,keywordFlags=0,name="Condition:CannotBeBlinded",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="BlindImmune",type="FLAG",value=true}},nil}
c["Cannot be Blinded while on Full Life"]={{[1]={[1]={type="Condition",var="FullLife"},flags=0,keywordFlags=0,name="Condition:CannotBeBlinded",type="FLAG",value=true}},nil}
c["Cannot be Critically Hit while Parrying"]={nil,"Cannot be Critically Hit while Parrying "}
c["Cannot be Critically Hit while Parrying"]={{},"Critically Hit while Parrying "}
c["Cannot be Heavy Stunned while Sprinting"]={{[1]={[1]={type="Condition",var="Sprinting"},flags=0,keywordFlags=0,name="StunImmune",type="FLAG",value=true}},nil}
c["Cannot be Ignited"]={{[1]={flags=0,keywordFlags=0,name="IgniteImmune",type="FLAG",value=true}},nil}
c["Cannot be Light Stunned"]={{[1]={flags=0,keywordFlags=0,name="StunImmune",type="FLAG",value=true}},nil}
c["Cannot be Light Stunned by Deflected Hits"]={nil,"Cannot be Light Stunned by Deflected Hits "}
c["Cannot be Light Stunned if you haven't been Hit Recently"]={nil,"Cannot be Light Stunned if you haven't been Hit Recently "}
c["Cannot be Light Stunned by Deflected Hits"]={{},"Light Stunned by Deflected Hits "}
c["Cannot be Light Stunned if you haven't been Hit Recently"]={{[1]={[1]={neg=true,type="Condition",var="BeenHitRecently"},flags=0,keywordFlags=0,name="StunImmune",type="FLAG",value=true}},nil}
c["Cannot be Poisoned"]={{[1]={flags=0,keywordFlags=0,name="PoisonImmune",type="FLAG",value=true}},nil}
c["Cannot be Shocked"]={{[1]={flags=0,keywordFlags=0,name="ShockImmune",type="FLAG",value=true}},nil}
c["Cannot be Stunned"]={{[1]={flags=0,keywordFlags=0,name="StunImmune",type="FLAG",value=true}},nil}
Expand Down Expand Up @@ -5637,29 +5637,25 @@ c["Ignore Warcry Cooldowns"]={{[1]={[1]={skillType=63,type="SkillType"},flags=0,
c["Ignore all Movement Penalties from Armour"]={{[1]={flags=0,keywordFlags=0,name="Condition:IgnoreMovementPenalties",type="FLAG",value=true}},nil}
c["Immobilise enemies at 50% buildup instead of 100%"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="PoiseThreshold",type="MORE",value=-50}}}},nil}
c["Immune to Bleeding if Equipped Helmet has higher Armour than Evasion Rating"]={{[1]={[1]={type="Condition",var="HelmetArmourHigherThanEvasion"},flags=0,keywordFlags=0,name="BleedImmune",type="FLAG",value=true}},nil}
c["Immune to Bleeding while Shapeshifted"]={nil,"Immune to Bleeding while Shapeshifted "}
c["Immune to Bleeding while Shapeshifted Immune to Maim while Shapeshifted"]={nil,"Immune to Bleeding while Shapeshifted Immune to Maim while Shapeshifted "}
c["Immune to Bleeding while affected by an Archon Buff"]={nil,"Immune to Bleeding while affected by an Archon Buff "}
c["Immune to Bleeding while Shapeshifted"]={{[1]={[1]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="BleedImmune",type="FLAG",value=true}},nil}
c["Immune to Bleeding while affected by an Archon Buff"]={{},"Bleeding while affected by an Archon Buff "}
c["Immune to Chaos Damage and Bleeding"]={{[1]={flags=0,keywordFlags=0,name="ChaosInoculation",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ChaosDamageTaken",type="MORE",value=-100},[3]={flags=0,keywordFlags=0,name="BleedImmune",type="FLAG",value=true}},nil}
c["Immune to Chill if a majority of your Socketed Support Gems are Blue"]={{[1]={[1]={type="Condition",var="MajorityBlueSocketedSupports"},flags=0,keywordFlags=0,name="ChillImmune",type="FLAG",value=true}},nil}
c["Immune to Corrupted Blood"]={nil,"Immune to Corrupted Blood "}
c["Immune to Corrupted Blood 40% reduced Duration of Bleeding on You"]={nil,"Immune to Corrupted Blood 40% reduced Duration of Bleeding on You "}
c["Immune to Corrupted Blood"]={{[1]={flags=0,keywordFlags=0,name="CorruptedBloodImmune",type="FLAG",value=true}},nil}
c["Immune to Elemental Ailments while on Consecrated Ground if you have at least 150 Devotion"]={{[1]={[1]={type="Condition",var="OnConsecratedGround"},[2]={stat="Devotion",threshold=150,type="StatThreshold"},flags=0,keywordFlags=0,name="ElementalAilmentImmune",type="FLAG",value=true}},nil}
c["Immune to Exposure"]={nil,"Immune to Exposure "}
c["Immune to Exposure Unaffected by Elemental Weakness"]={nil,"Immune to Exposure Unaffected by Elemental Weakness "}
c["Immune to Exposure"]={{[1]={flags=0,keywordFlags=0,name="ExposureImmune",type="FLAG",value=true}},nil}
c["Immune to Freeze"]={{[1]={flags=0,keywordFlags=0,name="FreezeImmune",type="FLAG",value=true}},nil}
c["Immune to Freeze and Chill while affected by an Archon Buff"]={nil,"Immune to Freeze and Chill while affected by an Archon Buff "}
c["Immune to Hinder"]={nil,"Immune to Hinder "}
c["Immune to Hinder Immune to Maim"]={nil,"Immune to Hinder Immune to Maim "}
c["Immune to Freeze and Chill while affected by an Archon Buff"]={{},"Freeze and Chill while affected by an Archon Buff "}
c["Immune to Hinder"]={{[1]={flags=0,keywordFlags=0,name="HinderImmune",type="FLAG",value=true}},nil}
c["Immune to Ignite"]={{[1]={flags=0,keywordFlags=0,name="IgniteImmune",type="FLAG",value=true}},nil}
c["Immune to Ignite if a majority of your Socketed Support Gems are Red"]={{[1]={[1]={type="Condition",var="MajorityRedSocketedSupports"},flags=0,keywordFlags=0,name="IgniteImmune",type="FLAG",value=true}},nil}
c["Immune to Maim"]={nil,"Immune to Maim "}
c["Immune to Maim while Shapeshifted"]={nil,"Immune to Maim while Shapeshifted "}
c["Immune to Maim"]={{[1]={flags=0,keywordFlags=0,name="MaimImmune",type="FLAG",value=true}},nil}
c["Immune to Maim while Shapeshifted"]={{[1]={[1]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="MaimImmune",type="FLAG",value=true}},nil}
c["Immune to Poison"]={{[1]={flags=0,keywordFlags=0,name="PoisonImmune",type="FLAG",value=true}},nil}
c["Immune to Poison if Equipped Helmet has higher Evasion Rating than Armour"]={{[1]={[1]={type="Condition",var="HelmetEvasionHigherThanArmour"},flags=0,keywordFlags=0,name="PoisonImmune",type="FLAG",value=true}},nil}
c["Immune to Shock"]={{[1]={flags=0,keywordFlags=0,name="ShockImmune",type="FLAG",value=true}},nil}
c["Immune to Shock if a majority of your Socketed Support Gems are Green"]={{[1]={[1]={type="Condition",var="MajorityGreenSocketedSupports"},flags=0,keywordFlags=0,name="ShockImmune",type="FLAG",value=true}},nil}
c["Immune to Shock while affected by an Archon Buff"]={nil,"Immune to Shock while affected by an Archon Buff "}
c["Immune to Shock while affected by an Archon Buff"]={{},"Shock while affected by an Archon Buff "}
c["Increases Movement Speed by 25%, plus 1% per 500 Evasion Rating, up to a maximum of 75%"]={nil,"Increases Movement Speed by 25%, plus 1% per 500 Evasion Rating, up to a maximum of 75% "}
c["Increases Movement Speed by 25%, plus 1% per 500 Evasion Rating, up to a maximum of 75% Other Modifiers to Movement Speed except for Sprinting do not apply"]={nil,"Increases Movement Speed by 25%, plus 1% per 500 Evasion Rating, up to a maximum of 75% Other Modifiers to Movement Speed except for Sprinting do not apply "}
c["Increases Movement Speed by 25%, plus 1% per 600 Evasion Rating, up to a maximum of 75%"]={nil,"Increases Movement Speed by 25%, plus 1% per 600 Evasion Rating, up to a maximum of 75% "}
Expand Down
99 changes: 99 additions & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ local formList = {
["is doubled"] = "DOUBLED",
["doubles?"] = "DOUBLED",
["causes? double"] = "DOUBLED",
["^immunity to "] = "IMMUNE",
["^immune to being "] = "IMMUNE",
["^immune to "] = "IMMUNE",
["^cannot be "] = "IMMUNE",
}

-- Map of modifier names
Expand Down Expand Up @@ -6168,6 +6172,30 @@ local specialModList = {
for _, name in pairs(data.keystones) do
specialModList[name:lower()] = { mod("Keystone", "LIST", name) }
end
--[[ -- Conditional Immunities
-- NOTE: conditional mods with "Immune to ..." cannot be handled for PoE2 as they no longer start with "You are..." or similar prefixes that trigger a "FLAG" mod
specialModList["immune to (.-) w?h?i[lf]e? (.*)"] = = function(_, debuff, cond)
-- NOTE: this only handles cases for which unconditional immunity mods exist to avoid false positives that don't actually get calculated

-- look for static or dynamically phrased base immunity mod
local searchPrefix1 = "immun[ei]t?y? to " .. ailment and string.lower(debuff)
local searchPrefix2 = "immune to " .. ailment and string.lower(debuff)
local lowerAilment = ailment and string.lower(ailment) or ""
local validDebuff = (specialModList[searchPrefix1 .. lowerAilment] or specialModList[searchPrefix2 .. lowerAilment]) and true or false

-- look if condition exists
-- todo make more dynamic
local tagKey = (validDebuff and cond) and "while " .. string.lower(cond)

local condTag = tagKey and (modTagList[tagKey] or modFlagList) or nil
if condTag then

return { flag(firstToUpper(ailment) .. "Immune", condTag.tag) }
else
return nil
end
end
]]
local oldList = specialModList
specialModList = { }
for k, v in pairs(oldList) do
Expand Down Expand Up @@ -6309,6 +6337,29 @@ local flagTypes = {
["malediction"] = "HasMalediction",
}

-- Table to map "status" like "Bleeding" to correct effect like "BleedImmune"
local statusToEffectMap = {
["bleeding"] = "Bleed",
["blinded"] = "Blind",
["chilled"] = "Chill",
["cursed"] = "Curse",
["curses"] = "Curse",
["elemental ailments"] = "ElementalAilment",
["frozen"] = "Freeze",
["hindered"] = "Hinder",
["ignited"] = "Ignite",
["light stunned"] = "Stun",
["maimed"] = "Maim",
["poisoned"] = "Poison",
["shocked"] = "Shock",
-- NOTE: the following are possible, but not yet processed as of 2026-06-09
--["armour broken"] = "ArmourBreak",
--["critically hit"] = "Crit",
--["electrocuted"] = "Electrocute",
--["heavy stunned"] = "HeavyStun",
--["pinned"] = "Pin",
}

-- Build active skill name lookup
local skillNameList = {
[" corpse cremation " ] = { tag = { type = "SkillName", skillName = "Cremation", includeTransfigured = true }}, -- Sigh.
Expand Down Expand Up @@ -6628,6 +6679,54 @@ 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 == "IMMUNE" then
local effectLine = line:gsub("%s+$","") -- remove trailing spaces
local _, numWords = effectLine:gsub("%S+", "")
local multiEffect = effectLine:find(" and ")

local function getEffectFromStatus(statusString)
return statusToEffectMap[statusString:lower()] or statusString
end

-- Check number of words, as 99% of effects consist of only one or two words
-- NOTE: needs exception for wordings like "freeze and chill"
if multiEffect then
if numWords > 3 then
local preEff, postEff = effectLine:match("^(.-) and (.*)")
local _, preWordNum = preEff:gsub("%S+", "")
local _, postWordNum = postEff:gsub("%S+", "")
if preWordNum > 2 or postWordNum > 2 then
return { }, line -- more than 2 effects, likely a false positive
end
end
elseif (numWords < 1) or (numWords > 2) then
return { }, line -- no words or more than 2 unlikely for single effect
end

-- Process effect strings to valid mod names
local effect
if multiEffect then
effect = { }
effect[1], effect[2] = effectLine:match("^(.-) and (.*)") -- fuzzy match is fine here as length is already checked before
for i, _ in pairs(effect) do
effect[i] = getEffectFromStatus(effect[i])
effect[i] = combineToUpper(effect[i])
end
else
effect = getEffectFromStatus(effectLine)
effect = combineToUpper(effect)
end

if type(effect) == "table" then
modName = { effect[1] .. "Immune", effect[2] .. "Immune" }
modType = { type(modValue) == "table" and modValue.type or "FLAG", type(modValue) == "table" and modValue.type or "FLAG" }
modValue = { type(modValue) == "table" and modValue.value or true, type(modValue) == "table" and modValue.value or true }
else
modName = effect .. "Immune"
modType = type(modValue) == "table" and modValue.type or "FLAG"
modValue = type(modValue) == "table" and modValue.value or true
end
line = "" -- rest of the line already processed at this stage
elseif modForm == "OVERRIDE" then
modType = "OVERRIDE"
elseif modForm == "DOUBLED" then
Expand Down
Loading