diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index 8075f75884c..e00abec4821 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -7,6 +7,167 @@ describe("TestSkills", function() -- newBuild() takes care of resetting everything in setup() end) + local function gemTooltipText(gem) + local tooltip = new("Tooltip"):Tooltip() + require("Classes.GemTooltip").AddGemTooltip(tooltip, build, gem) + local lines = {} + for _, line in ipairs(tooltip.lines) do + table.insert(lines, line.text) + end + return table.concat(lines, "\n") + end + + it("separates socketed and global modifiers from the same item on a support gem", function() + build.itemsTab:CreateDisplayItemFromRaw("Rarity: RARE\nTest Helmet\nHubris Circlet\nSockets: B-B\nImplicits: 0\n+2 to Level of Socketed Gems\n+10% to Quality of Socketed Gems\n+1 to Level of all Support Gems\n+3% to Quality of all Support Gems") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Slot: Helmet\nFireball 20/0 1\nControlled Destruction 20/5 1\n") + runCallback("OnFrame") + + local gem = build.skillsTab.socketGroupList[1].gemList[2] + assert.are.equals(23, gem.displayEffect.level) + assert.are.equals(28, gem.displayEffect.quality) + local text = gemTooltipText(gem) + assert.is_truthy(text:find("+2 Levels from Item", 1, true)) + assert.is_truthy(text:find("+1 Levels from Global Modifiers", 1, true)) + assert.is_truthy(text:find("+10% Quality from Item", 1, true)) + assert.is_truthy(text:find("+3% Quality from Global Modifiers", 1, true)) + assert.is_truthy(text:find("+10% Quality from Socket Colour", 1, true)) + assert.is_nil(text:find("from Supports", 1, true)) + end) + + it("includes negative item and global modifiers in gem tooltips and breakdowns", function() + build.itemsTab:CreateDisplayItemFromRaw("Rarity: RARE\nTest Helmet\nHubris Circlet\nSockets: G\nImplicits: 0\n-5 to Level of Socketed Gems\n-10% to Quality of Socketed Gems") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Slot: Helmet\nFireball 20/20 1\n") + build.configTab.input.customMods = "-1 to Level of all Spell Skill Gems\n-2% to Quality of all Skill Gems" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(14, build.calcsTab.mainOutput.GemLevel) + assert.are.equals(8, build.calcsTab.mainOutput.GemQuality) + local text = gemTooltipText(build.skillsTab.socketGroupList[1].gemList[1]) + assert.is_truthy(text:find("-5 Levels from Item", 1, true)) + assert.is_truthy(text:find("-1 Levels from Global Modifiers", 1, true)) + assert.is_truthy(text:find("-10% Quality from Item", 1, true)) + assert.is_truthy(text:find("-2% Quality from Global Modifiers", 1, true)) + local breakdown = build.calcsTab.calcsEnv.player.breakdown + assert.is_truthy(table.concat(breakdown.GemLevel, "\n"):find("- 5 ^8(level from items)", 1, true)) + assert.is_truthy(table.concat(breakdown.GemLevel, "\n"):find("- 1 ^8(level from global modifiers)", 1, true)) + assert.is_truthy(table.concat(breakdown.GemQuality, "\n"):find("- 10 ^8(quality from items)", 1, true)) + assert.is_truthy(table.concat(breakdown.GemQuality, "\n"):find("- 2 ^8(quality from global modifiers)", 1, true)) + end) + + it("shows the applied level cap without losing the source bonuses", function() + build.skillsTab:PasteSocketGroup("Fireball 20/0 1\n") + build.configTab.input.customMods = "+30 to Level of all Spell Skill Gems" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(40, build.calcsTab.mainEnv.player.mainSkill.activeEffect.level) + assert.are.equals(40, build.calcsTab.mainOutput.GemLevel) + local text = gemTooltipText(build.skillsTab.socketGroupList[1].gemList[1]) + assert.is_truthy(text:find("+30 Levels from Global Modifiers", 1, true)) + assert.is_truthy(text:find("Limited to Level 40", 1, true)) + local breakdown = table.concat(build.calcsTab.calcsEnv.player.breakdown.GemLevel, "\n") + assert.is_truthy(breakdown:find("+ 30 ^8(level from global modifiers)", 1, true)) + assert.is_truthy(breakdown:find("Limited to Level 40", 1, true)) + assert.is_truthy(breakdown:find("= 40", 1, true)) + end) + + it("includes item and global bonuses in gem totals alongside supports and socket quality", function() + build.itemsTab:CreateDisplayItemFromRaw("Rarity: RARE\nTest Robe\nSage's Robe\nSockets: B-R-G\nImplicits: 0\n+2 to Level of Socketed Fire Gems\n+3 to Level of Socketed Projectile Gems\n+10% to Quality of Socketed Gems\n+4% to Quality of Socketed Fire Gems") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Slot: Body Armour\nFireball 20/5 1\nEmpower 3/0 1\nEnhance 3/0 1\n") + build.configTab.input.customMods = "+1 to Level of all Spell Skill Gems\n+2 to Level of all Fire Skill Gems\n+5% to Quality of all Skill Gems\n+3% to Quality of all Fire Skill Gems" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(30, build.calcsTab.mainEnv.player.mainSkill.activeEffect.level) + assert.are.equals(53, build.calcsTab.mainEnv.player.mainSkill.activeEffect.quality) + assert.are.equals(30, build.calcsTab.mainOutput.GemLevel) + assert.are.equals(53, build.calcsTab.mainOutput.GemQuality) + + local text = gemTooltipText(build.skillsTab.socketGroupList[1].gemList[1]) + assert.is_truthy(text:find("20 Levels from Gem (Max)", 1, true)) + assert.is_truthy(text:find("+5 Levels from Item", 1, true)) + assert.is_truthy(text:find("+3 Levels from Global Modifiers", 1, true)) + assert.is_truthy(text:find("+2 Levels from Supports", 1, true)) + assert.is_truthy(text:find("+14% Quality from Item", 1, true)) + assert.is_truthy(text:find("+8% Quality from Global Modifiers", 1, true)) + assert.is_truthy(text:find("+16% Quality from Support", 1, true)) + assert.is_truthy(text:find("+10% Quality from Socket Colour", 1, true)) + + local levelBreakdown = table.concat(build.calcsTab.calcsEnv.player.breakdown.GemLevel, "\n") + assert.is_truthy(levelBreakdown:find("+ 5 ^8(level from items)", 1, true)) + assert.is_truthy(levelBreakdown:find("+ 3 ^8(level from global modifiers)", 1, true)) + assert.is_truthy(levelBreakdown:find("+ 2 ^8(level from support)", 1, true)) + assert.is_truthy(levelBreakdown:find("= 30", 1, true)) + local qualityBreakdown = table.concat(build.calcsTab.calcsEnv.player.breakdown.GemQuality, "\n") + assert.is_truthy(qualityBreakdown:find("+ 14 ^8(quality from items)", 1, true)) + assert.is_truthy(qualityBreakdown:find("+ 8 ^8(quality from global modifiers)", 1, true)) + assert.is_truthy(qualityBreakdown:find("+ 16 ^8(quality from support)", 1, true)) + assert.is_truthy(qualityBreakdown:find("+ 10 ^8(quality from socket colour)", 1, true)) + assert.is_truthy(qualityBreakdown:find("= 53", 1, true)) + + -- Exercise the visible breakdown tables, not just the calculation summary. + local checkedBreakdowns = 0 + for _, calcSection in ipairs(build.calcsTab.sectionList) do + if calcSection.id == "SkillTypeStats" then + for _, row in ipairs(calcSection.subSection[1].data) do + if row.label == "Gem Level" or row.label == "Gem Quality" then + checkedBreakdowns = checkedBreakdowns + 1 + local breakdown = build.calcsTab.controls.breakdown + breakdown:SetBreakdownData(row[1]) + local groups = {} + for _, section in ipairs(breakdown.sectionList) do + if section.type == "TABLE" then + local name = section.rowList[1].mod.name + groups[name] = 0 + for _, modifier in ipairs(section.rowList) do + assert.are.equals(name, modifier.mod.name, "Each gem bonus category needs its own table") + groups[name] = groups[name] + modifier.value + end + end + end + if row.label == "Gem Level" then + assert.same({ GemLevel = 20, GemItemLevel = 5, GemGlobalLevel = 3, GemSupportLevel = 2 }, groups) + else + assert.same({ GemQuality = 5, GemItemQuality = 14, GemGlobalQuality = 8, GemSupportQuality = 16, GemSocketQuality = 10 }, groups) + end + end + end + end + end + assert.are.equals(2, checkedBreakdowns) + end) + + it("shows socketed gem levels from a helmet as item bonuses in the tooltip", function() + build.itemsTab:CreateDisplayItemFromRaw("Rarity: RARE\nTest Helmet\nHubris Circlet\nSockets: G\nImplicits: 0\n+6 to Level of Socketed Gems") + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Slot: Helmet\nTornado 18/0 1\n") + runCallback("OnFrame") + + local text = gemTooltipText(build.skillsTab.socketGroupList[1].gemList[1]) + assert.is_truthy(text:find("Level: " .. colorCodes.MAGIC .. "24", 1, true)) + assert.is_truthy(text:find("18 Levels from Gem", 1, true)) + assert.is_truthy(text:find("+6 Levels from Item", 1, true)) + assert.is_nil(text:find("Levels from Global Modifiers", 1, true)) + assert.is_nil(text:find("Levels from Supports", 1, true)) + end) + + it("breaks down Tornado's gem level and global levels in its tooltip", function() + build.skillsTab:PasteSocketGroup("Tornado 18/0 1\n") + build.configTab.input.customMods = "+4 to Level of all Spell Skill Gems" + build.configTab:BuildModList() + runCallback("OnFrame") + + local text = gemTooltipText(build.skillsTab.socketGroupList[1].gemList[1]) + assert.is_truthy(text:find("Level: " .. colorCodes.MAGIC .. "22", 1, true)) + assert.is_truthy(text:find("18 Levels from Gem", 1, true)) + assert.is_truthy(text:find("+4 Levels from Global Modifiers", 1, true)) + assert.is_nil(text:find("Levels from Supports", 1, true)) + end) + it("adds envy, ensures +1 level keeps level 25 Envy", function() build.itemsTab:CreateDisplayItemFromRaw("New Item\nAssassin Bow\nGrants Level 1 Summon Raging Spirit\nGrants Level 25 Envy Skill") build.itemsTab:AddDisplayItem() diff --git a/src/Classes/GemTooltip.lua b/src/Classes/GemTooltip.lua index 4709a99827b..567abf1bae8 100644 --- a/src/Classes/GemTooltip.lua +++ b/src/Classes/GemTooltip.lua @@ -32,13 +32,24 @@ local function addCommonGemInfo(tooltip, build, gemInstance, grantedEffect, addL local displayInstance = gemInstance.displayEffect or gemInstance local grantedEffectLevel = grantedEffect.levels[displayInstance.level] or {} if addLevel then - tooltip:AddLine(fontSizeBig, string.format("^x7F7F7FLevel: ^7%d%s%s", - gemInstance.level, - ((displayInstance.level > gemInstance.level) and " (" .. colorCodes.MAGIC .. "+" .. (displayInstance.level - gemInstance.level) .. "^7)") or - ((displayInstance.level < gemInstance.level) and " (" .. colorCodes.WARNING .. "-" .. (gemInstance.level - displayInstance.level) .. "^7)") or - "", - (gemInstance.level >= (gemInstance.gemData.naturalMaxLevel or math.huge)) and " (Max)" or "" - ), "FONTIN SC") + local globalLevels = displayInstance.globalLevel or 0 + local itemLevels = displayInstance.itemLevel or 0 + local supportLevels = displayInstance.supportLevel or 0 + local maxLevel = gemInstance.level >= (gemInstance.gemData.naturalMaxLevel or math.huge) and " (Max)" or "" + if itemLevels ~= 0 or globalLevels ~= 0 or supportLevels ~= 0 then + tooltip:AddLine(fontSizeBig, "^x7F7F7FLevel: " .. colorCodes.MAGIC .. displayInstance.level, "FONTIN SC") + tooltip:AddLine(fontSizeBig, string.format("^7%d Levels from Gem%s", gemInstance.level, maxLevel), "FONTIN SC") + for _, source in ipairs({ { itemLevels, "Item" }, { globalLevels, "Global Modifiers" }, { supportLevels, "Supports" } }) do + if source[1] ~= 0 then + tooltip:AddLine(fontSizeBig, (source[1] > 0 and colorCodes.MAGIC or colorCodes.WARNING) .. string.format("%+d Levels from %s", source[1], source[2]), "FONTIN SC") + end + end + if displayInstance.level ~= gemInstance.level + itemLevels + globalLevels + supportLevels then + tooltip:AddLine(fontSizeBig, "^x7F7F7FLimited to Level " .. displayInstance.level, "FONTIN SC") + end + else + tooltip:AddLine(fontSizeBig, string.format("^x7F7F7FLevel: ^7%d%s", gemInstance.level, maxLevel), "FONTIN SC") + end end if grantedEffect.support then if grantedEffectLevel.manaMultiplier then @@ -141,20 +152,15 @@ local function addCommonGemInfo(tooltip, build, gemInstance, grantedEffect, addL if gemInstance.quality > 0 then tooltip:AddLine(fontSizeBig, string.format("^x7F7F7FQuality: +%s%d%%", colorCodes.MAGIC, gemInstance.quality), "FONTIN SC") end - local function formatQuality(number, suffix) - return colorCodes.MAGIC .. string.format("+%d%% Quality from %s", number, suffix) - end - if (displayInstance.itemQuality or 0) > 0 then - tooltip:AddLine(fontSizeBig, formatQuality(displayInstance.itemQuality, "Item"), "FONTIN SC") - end - if (displayInstance.supportQuality or 0) > 0 then - tooltip:AddLine(fontSizeBig, formatQuality(displayInstance.supportQuality, "Support"), "FONTIN SC") - end - if (displayInstance.globalQuality or 0) > 0 then - tooltip:AddLine(fontSizeBig, formatQuality(displayInstance.globalQuality, "Global Modifiers"), "FONTIN SC") - end - if (displayInstance.socketQuality or 0) > 0 then - tooltip:AddLine(fontSizeBig, formatQuality(displayInstance.socketQuality, "Socket Colour"), "FONTIN SC") + for _, source in ipairs({ + { displayInstance.itemQuality or 0, "Item" }, + { displayInstance.globalQuality or 0, "Global Modifiers" }, + { displayInstance.supportQuality or 0, "Supports" }, + { displayInstance.socketQuality or 0, "Socket Colour" }, + }) do + if source[1] ~= 0 then + tooltip:AddLine(fontSizeBig, (source[1] > 0 and colorCodes.MAGIC or colorCodes.WARNING) .. string.format("%+d%% Quality from %s", source[1], source[2]), "FONTIN SC") + end end end tooltip:AddSeparator(10) diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index de16231644e..2b9392e1e0e 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -559,9 +559,11 @@ function calcs.buildActiveSkillModList(env, activeSkill) for _, supportProperty in ipairs(skillModList:Tabulate("LIST", activeSkill.skillCfg, "SupportedGemProperty")) do local value = supportProperty.value if value.keyword == "grants_active_skill" and activeSkill.activeEffect.gemData and not activeSkill.activeEffect.gemData.tags.support then - -- save quality increases for use in tooltips + -- Save level and quality increases for use in tooltips if value.key == "quality" then activeEffect.supportQuality = (activeEffect.supportQuality or 0) + value.value + elseif value.key == "level" then + activeEffect.supportLevel = (activeEffect.supportLevel or 0) + value.value end activeEffect[value.key] = activeEffect[value.key] + value.value skillModList:NewMod("GemSupport".. value.key:gsub("^%l", string.upper), "BASE", value.value, supportProperty.mod.source, #supportProperty.mod > 0 and supportProperty.mod[1] or nil) @@ -570,7 +572,7 @@ function calcs.buildActiveSkillModList(env, activeSkill) for _, gemProperty in ipairs((activeSkill.activeEffect.gemPropertyInfo or {})) do local value = gemProperty.value - skillModList:NewMod("GemItem".. value.key:gsub("^%l", string.upper), "BASE", value.value, gemProperty.mod.source, #gemProperty.mod > 0 and gemProperty.mod[1] or nil) + skillModList:NewMod("Gem" .. gemProperty.sourceType .. value.key:gsub("^%l", string.upper), "BASE", value.value, gemProperty.mod.source, #gemProperty.mod > 0 and gemProperty.mod[1] or nil) end -- Add active gem modifiers diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index c7f75eda6c4..1a6657c43ae 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -3940,19 +3940,22 @@ function calcs.perform(env, skipEHP) if mainSkill.activeEffect.level then local baseLevel = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemLevel") local totalItemLevel = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemItemLevel") + local totalGlobalLevel = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemGlobalLevel") local totalSupportLevel = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemSupportLevel") output.GemHasLevel = true - output.GemLevel = baseLevel + totalSupportLevel + totalItemLevel + output.GemLevel = mainSkill.activeEffect.level if env.player.breakdown then env.player.breakdown.GemLevel = {} t_insert(env.player.breakdown.GemLevel, s_format("%d ^8(level from gem)", baseLevel)) - if totalSupportLevel > 0 then - t_insert(env.player.breakdown.GemLevel, s_format("+ %d ^8(level from support)", totalSupportLevel)) + for _, source in ipairs({ { totalItemLevel, "items" }, { totalGlobalLevel, "global modifiers" }, { totalSupportLevel, "support" } }) do + if source[1] ~= 0 then + t_insert(env.player.breakdown.GemLevel, s_format("%s %d ^8(level from %s)", source[1] > 0 and "+" or "-", math.abs(source[1]), source[2])) + end end - if totalItemLevel > 0 then - t_insert(env.player.breakdown.GemLevel, s_format("+ %d ^8(level from items)", totalItemLevel)) + if output.GemLevel ~= baseLevel + totalItemLevel + totalGlobalLevel + totalSupportLevel then + t_insert(env.player.breakdown.GemLevel, s_format("^8Limited to Level %d", output.GemLevel)) end t_insert(env.player.breakdown.GemLevel, s_format("= %d", output.GemLevel)) end @@ -3962,23 +3965,20 @@ function calcs.perform(env, skipEHP) if mainSkill.activeEffect.quality then local baseQuality = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemQuality") local totalItemQuality = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemItemQuality") + local totalGlobalQuality = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemGlobalQuality") local totalSupportQuality = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemSupportQuality") local socketQuality = mainSkill.skillModList:Sum("BASE", mainSkill.skillCfg, "GemSocketQuality") output.GemHasQuality = true - output.GemQuality = baseQuality + totalSupportQuality + totalItemQuality + socketQuality + output.GemQuality = baseQuality + totalSupportQuality + totalItemQuality + totalGlobalQuality + socketQuality if env.player.breakdown then env.player.breakdown.GemQuality = {} t_insert(env.player.breakdown.GemQuality, s_format("%d ^8(quality from gem)", baseQuality)) - if totalSupportQuality > 0 then - t_insert(env.player.breakdown.GemQuality, s_format("+ %d ^8(quality from support)", totalSupportQuality)) - end - if totalItemQuality > 0 then - t_insert(env.player.breakdown.GemQuality, s_format("+ %d ^8(quality from items)", totalItemQuality)) - end - if socketQuality > 0 then - t_insert(env.player.breakdown.GemQuality, s_format("+ %d ^8(quality from socket)", socketQuality)) + for _, source in ipairs({ { totalItemQuality, "items" }, { totalGlobalQuality, "global modifiers" }, { totalSupportQuality, "support" }, { socketQuality, "socket colour" } }) do + if source[1] ~= 0 then + t_insert(env.player.breakdown.GemQuality, s_format("%s %d ^8(quality from %s)", source[1] > 0 and "+" or "-", math.abs(source[1]), source[2])) + end end t_insert(env.player.breakdown.GemQuality, s_format("= %d", output.GemQuality)) end diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index e6b2284aa57..0f5b1c7f1ca 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -710,8 +710,8 @@ return { } } } }, { 1, "SkillTypeStats", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Skill type-specific Stats", data = { - { label = "Gem Level", haveOutput = "GemHasLevel", { format = "{0:output:GemLevel}", { breakdown = "GemLevel" }, { modName = { "GemLevel" }, cfg = "skill" },{ modName = { "GemSupportLevel" }, cfg = "skill" }, { modName = { "GemItemLevel" }, cfg = "skill" }, }, }, - { label = "Gem Quality", haveOutput = "GemHasQuality", { format = "{0:output:GemQuality}", { breakdown = "GemQuality" }, { modName = { "GemQuality", "GemSupportQuality", "GemItemQuality", "GemSocketQuality" }, cfg = "skill" }, }, }, + { label = "Gem Level", haveOutput = "GemHasLevel", { format = "{0:output:GemLevel}", { breakdown = "GemLevel" }, { modName = { "GemLevel" }, cfg = "skill" }, { modName = { "GemItemLevel" }, cfg = "skill" }, { modName = { "GemGlobalLevel" }, cfg = "skill" }, { modName = { "GemSupportLevel" }, cfg = "skill" }, }, }, + { label = "Gem Quality", haveOutput = "GemHasQuality", { format = "{0:output:GemQuality}%", { breakdown = "GemQuality" }, { modName = { "GemQuality" }, cfg = "skill" }, { modName = { "GemItemQuality" }, cfg = "skill" }, { modName = { "GemGlobalQuality" }, cfg = "skill" }, { modName = { "GemSupportQuality" }, cfg = "skill" }, { modName = { "GemSocketQuality" }, cfg = "skill" }, }, }, { label = "Mana Cost", color = colorCodes.MANA, haveOutput = "ManaHasCost", { format = "{0:output:ManaCost}", { breakdown = "ManaCost" }, { modName = manaCost, cfg = "skill" }, }, }, { label = "Mana % Cost", color = colorCodes.MANA, haveOutput = "ManaPercentHasCost", { format = "{0:output:ManaPercentCost}", { breakdown = "ManaPercentCost" }, { modName = manaCost, cfg = "skill" }, }, }, { label = "Mana per second", color = colorCodes.MANA, haveOutput = "ManaPerSecondHasCost", { format = "{2:output:ManaPerSecondCost}", { breakdown = "ManaPerSecondCost" }, { modName = manaCost, cfg = "skill" }, }, }, diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 70301168360..cc537bf9951 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -394,24 +394,21 @@ local function applyGemMods(effect, modList) match = false end if match then - -- save quality increases for use in tooltips - if value.key == "quality" then - local isSocketed = false - for _, tag in ipairs(mod.mod) do - if tag.type == "SocketedIn" then - isSocketed = true - break - end - end - if isSocketed then - effect.itemQuality = (effect.itemQuality or 0) + value.value - else - effect.globalQuality = (effect.globalQuality or 0) + value.value + local sourceType = "Global" + for _, tag in ipairs(mod.mod) do + if tag.type == "SocketedIn" then + sourceType = "Item" + break end end + -- Keep separate totals for the gem tooltip and source categories for Calcs. + if value.key == "level" or value.key == "quality" then + local property = sourceType:lower() .. value.key:gsub("^%l", string.upper) + effect[property] = (effect[property] or 0) + value.value + end effect[value.key] = (effect[value.key] or 0) + value.value effect.gemPropertyInfo = effect.gemPropertyInfo or {} - t_insert(effect.gemPropertyInfo, mod) + t_insert(effect.gemPropertyInfo, { mod = mod.mod, value = value, sourceType = sourceType }) end end end