Skip to content
40 changes: 40 additions & 0 deletions src/Classes/ModDB.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ local ipairs = ipairs
local pairs = pairs
local select = select
local t_insert = table.insert
local t_remove = table.remove
local m_floor = math.floor
local m_min = math.min
local m_max = math.max
Expand Down Expand Up @@ -65,6 +66,45 @@ function ModDBClass:ReplaceModInternal(mod)
return false
end

---ConvertModInternal
--- Converts an existing mod with oldName to a new mod with a different name.
--- Moves the mod from the old name's bucket to the new name's bucket.
--- If no matching mod exists, then the function returns false
---@param oldName string @The name of the existing mod to find
---@param mod table @The new mod to replace it with
---@return boolean @Whether any mod was converted
function ModDBClass:ConvertModInternal(oldName, mod)
if not self.mods[oldName] then
if self.parent then
return self.parent:ConvertModInternal(oldName, mod)
end
return false
end

local oldList = self.mods[oldName]
for i = 1, #oldList do
local curMod = oldList[i]
if oldName == curMod.name and mod.type == curMod.type and mod.flags == curMod.flags and mod.keywordFlags == curMod.keywordFlags and mod.source == curMod.source and not curMod.converted then
-- Remove from old name's bucket
t_remove(oldList, i)
-- Add to new name's bucket
local newName = mod.name
if not self.mods[newName] then
self.mods[newName] = { }
end
mod.converted = true
t_insert(self.mods[newName], mod)
return true
end
end

if self.parent then
return self.parent:ConvertModInternal(oldName, mod)
end

return false
end

function ModDBClass:AddList(modList)
local mods = self.mods
for i, mod in ipairs(modList) do
Expand Down
21 changes: 21 additions & 0 deletions src/Classes/ModList.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ function ModListClass:ReplaceModInternal(mod)
return false
end

---ConvertModInternal
--- Converts an existing mod with oldName to a new mod with a different name.
--- If no matching mod exists, then the function returns false
---@param oldName string @The name of the existing mod to find
---@param mod table @The new mod to replace it with
---@return boolean @Whether any mod was converted
function ModListClass:ConvertModInternal(oldName, mod)
for i, curMod in ipairs(self) do
if oldName == curMod.name and mod.type == curMod.type and mod.flags == curMod.flags and mod.keywordFlags == curMod.keywordFlags and mod.source == curMod.source then
self[i] = mod
return true
end
end

if self.parent then
return self.parent:ConvertModInternal(oldName, mod)
end

return false
end

function ModListClass:MergeMod(mod, skipNonAdditive)
if mod.type == "BASE" or mod.type == "INC" or mod.type == "MORE" then
for i = 1, #self do
Expand Down
13 changes: 13 additions & 0 deletions src/Classes/ModStore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ function ModStoreClass:ReplaceMod(...)
end
end

---ConvertMod
--- Converts an existing mod to a new name, replacing it in the store.
--- Finds a mod matching oldName with the same type, flags, keywordFlags, and source as the new mod.
--- If no matching mod exists, the new mod is added instead.
---@param oldName string @The name of the existing mod to convert
---@param ... any @Parameters to be passed along to the modLib.createMod function (new name, type, value, source, ...)
function ModStoreClass:ConvertMod(oldName, ...)
local mod = mod_createMod(...)
if not self:ConvertModInternal(oldName, mod) then
self:AddMod(mod)
end
end

function ModStoreClass:Combine(modType, cfg, ...)
if modType == "MORE" then
return self:More(cfg, ...)
Expand Down
9 changes: 3 additions & 6 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8413,7 +8413,7 @@ c["Elemental Ailments you inflict are Reflected to you Elemental Damage with Hit
c["Elemental Damage with Hits is Lucky while you are Shocked"]={{[1]={[1]={type="Condition",var="Shocked"},flags=0,keywordFlags=0,name="ElementalLuckHits",type="FLAG",value=true}},nil}
c["Elemental Damage you Deal with Hits is Resisted by lowest Elemental Resistance instead"]={{[1]={flags=0,keywordFlags=0,name="ElementalDamageUsesLowestResistance",type="FLAG",value=true}},nil}
c["Elemental Equilibrium"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Elemental Equilibrium"}},nil}
c["Elemental Hit's Added Damage cannot be replaced this way"]={nil,"Elemental Hit's Added Damage cannot be replaced this way "}
c["Elemental Hit's Added Damage cannot be replaced this way"]={{},nil}
c["Elemental Overload"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Elemental Overload"}},nil}
c["Elemental Resistance values as inverted"]={nil,"Elemental Resistance values as inverted "}
c["Elemental Resistance values as inverted Limited to 1 Runegraft of the Gauche"]={nil,"Elemental Resistance values as inverted Limited to 1 Runegraft of the Gauche "}
Expand Down Expand Up @@ -12581,11 +12581,8 @@ c["You count as on Low Life while you are Cursed with Vulnerability"]={{[1]={[1]
c["You do not inherently take less Damage for having Fortification"]={{[1]={flags=0,keywordFlags=0,name="Condition:NoFortificationMitigation",type="FLAG",value=true}},nil}
c["You gain 3 Grasping Vines when you take a Critical Strike"]={{}," Grasping Vines when you take a Critical Strike "}
c["You gain 3 Grasping Vines when you take a Critical Strike Nearby stationary Enemies gain a Grasping Vine every 0.5 seconds"]={{}," Grasping Vines when you take a Critical Strike Nearby stationary Enemies gain a Grasping Vine every 0.5 seconds "}
c["You gain Added Cold Damage instead of Added Damage of other types if Dexterity exceeds both other Attributes"]={nil,"Added Cold Damage instead of Added Damage of other types if Dexterity exceeds both other Attributes "}
c["You gain Added Cold Damage instead of Added Damage of other types if Dexterity exceeds both other Attributes You gain Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes"]={nil,"Added Cold Damage instead of Added Damage of other types if Dexterity exceeds both other Attributes You gain Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes "}
c["You gain Added Cold Damage instead of Added Damage of other types if Dexterity exceeds both other Attributes You gain Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes Elemental Hit's Added Damage cannot be replaced this way"]={nil,"Added Cold Damage instead of Added Damage of other types if Dexterity exceeds both other Attributes You gain Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes Elemental Hit's Added Damage cannot be replaced this way "}
c["You gain Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes"]={nil,"Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes "}
c["You gain Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes Elemental Hit's Added Damage cannot be replaced this way"]={nil,"Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes Elemental Hit's Added Damage cannot be replaced this way "}
c["You gain Added Cold Damage instead of Added Damage of other types if Dexterity exceeds both other Attributes"]={{[1]={[1]={type="Condition",var="DexSingleHighestAttribute"},flags=0,keywordFlags=0,name="AllAddedDamageAsCold",type="FLAG",value=true}},nil}
c["You gain Added Lighting Damage instead of Added Damage of other types if Intelligence exceeds both other Attributes"]={{[1]={[1]={type="Condition",var="IntSingleHighestAttribute"},flags=0,keywordFlags=0,name="AllAddedDamageAsLightning",type="FLAG",value=true}},nil}
c["You gain Divinity for 10 seconds on reaching maximum Divine Charges"]={{[1]={[1]={type="Condition",var="Divinity"},flags=0,keywordFlags=0,name="ElementalDamage",type="MORE",value=75},[2]={[1]={type="Condition",var="Divinity"},flags=0,keywordFlags=0,name="ElementalDamageTaken",type="MORE",value=-25}},nil}
c["You gain Onslaught for 1 seconds on Killing Taunted Enemies"]={{[1]={[1]={type="Condition",var="KilledTauntedEnemyRecently"},flags=0,keywordFlags=0,name="Condition:Onslaught",type="FLAG",value=true}},nil}
c["You gain Onslaught for 1 seconds per Endurance Charge when Hit"]={{[1]={[1]={type="Multiplier",var="EnduranceCharge"},flags=0,keywordFlags=0,name="Condition:Onslaught",type="FLAG",value=true}}," when Hit "}
Expand Down
29 changes: 29 additions & 0 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3048,6 +3048,35 @@ function calcs.offence(env, actor, activeSkill)

runSkillFunc("postCritFunc")

-- Added damage redirection (Cryogenesis)
-- Convert all added damage mods to the target type before the damage loop
-- so breakdowns show the redirected source correctly.
-- Base Elemental Hit is excluded per the node text.
local addedDamageRedirectType = nil
if skillModList:Flag(cfg, "AllAddedDamageAsLightning") then
addedDamageRedirectType = "Lightning"
elseif skillModList:Flag(cfg, "AllAddedDamageAsCold") then
addedDamageRedirectType = "Cold"
end
if addedDamageRedirectType then
for _, damageType in ipairs(dmgTypeList) do
if damageType ~= addedDamageRedirectType then
for _, value in ipairs(skillModList:Tabulate("BASE", cfg, damageType.."Min")) do
local mod = value.mod
if mod.source ~= "Skill:ElementalHit" then
skillModList:ConvertMod(damageType.."Min", addedDamageRedirectType.."Min", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, { type = "Cryogenesis Added Damage" }, unpack(mod))
end
end
for _, value in ipairs(skillModList:Tabulate("BASE", cfg, damageType.."Max")) do
local mod = value.mod
if mod.source ~= "Skill:ElementalHit" then
skillModList:ConvertMod(damageType.."Max", addedDamageRedirectType.."Max", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, { type = "Cryogenesis Added Damage" }, unpack(mod))
end
end
end
end
end

-- Calculate base hit damage
for _, damageType in ipairs(dmgTypeList) do
local damageTypeMin = damageType.."Min"
Expand Down
4 changes: 4 additions & 0 deletions src/Modules/CalcPerform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,8 @@ local function doActorAttribsConditions(env, actor)
condList["StrHighestAttribute"] = output.Str >= output.Dex and output.Str >= output.Int
condList["IntHighestAttribute"] = output.Int >= output.Str and output.Int >= output.Dex
condList["DexHighestAttribute"] = output.Dex >= output.Str and output.Dex >= output.Int
condList["IntSingleHighestAttribute"] = output.Int > output.Str and output.Int > output.Dex
condList["DexSingleHighestAttribute"] = output.Dex > output.Str and output.Dex > output.Int
end
end

Expand Down Expand Up @@ -453,6 +455,8 @@ local function doActorAttribsConditions(env, actor)
condList["StrHighestAttribute"] = output.Str >= output.Dex and output.Str >= output.Int
condList["IntHighestAttribute"] = output.Int >= output.Str and output.Int >= output.Dex
condList["DexHighestAttribute"] = output.Dex >= output.Str and output.Dex >= output.Int
condList["IntSingleHighestAttribute"] = output.Int > output.Str and output.Int > output.Dex
condList["DexSingleHighestAttribute"] = output.Dex > output.Str and output.Dex > output.Int
end
end

Expand Down
7 changes: 7 additions & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5286,6 +5286,13 @@ local specialModList = {
["consecrated path and purifying flame create profane ground instead of consecrated ground"] = {
flag("Condition:CreateProfaneGround"),
},
["you gain added cold damage instead of added damage of other types if dexterity exceeds both other attributes"] = {
flag("AllAddedDamageAsCold", { type = "Condition", var = "DexSingleHighestAttribute" }),
},
["you gain added lightn?ing damage instead of added damage of other types if intelligence exceeds both other attributes"] = {
flag("AllAddedDamageAsLightning", { type = "Condition", var = "IntSingleHighestAttribute" }),
},
["elemental hit's added damage cannot be replaced this way"] = { },
["you have consecrated ground around you while stationary if strength is your highest attribute"] = {
flag("Condition:OnConsecratedGround", { type = "Condition", var = "StrHighestAttribute" }, { type = "Condition", var = "Stationary" }),
},
Expand Down
Loading