Skip to content
Open
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
8 changes: 4 additions & 4 deletions src/Classes/CompareEntry.lua
Original file line number Diff line number Diff line change
Expand Up @@ -344,14 +344,14 @@ function CompareEntryClass:RefreshSkillSelectControls(controls, mainGroup, suffi
if not activeEffect then return end

-- Skill parts
if activeEffect.grantedEffect.parts and #activeEffect.grantedEffect.parts > 1 then
if activeSkill.skillPartList and #activeSkill.skillPartList > 1 then
controls.mainSkillPart.shown = true
wipeTable(controls.mainSkillPart.list)
for i, part in ipairs(activeEffect.grantedEffect.parts) do
for i, part in ipairs(activeSkill.skillPartList) do
t_insert(controls.mainSkillPart.list, { val = i, label = part.name })
end
controls.mainSkillPart.selIndex = activeEffect.srcInstance["skillPart"..suffix] or 1
local selectedPart = activeEffect.grantedEffect.parts[controls.mainSkillPart.selIndex]
local selectedPart = activeSkill.skillPartList[controls.mainSkillPart.selIndex]
if selectedPart and selectedPart.stages then
controls.mainSkillStageCount.shown = true
controls.mainSkillStageCount.buf = tostring(activeEffect.srcInstance["skillStageCount"..suffix] or selectedPart.stagesMin or 1)
Expand All @@ -365,7 +365,7 @@ function CompareEntryClass:RefreshSkillSelectControls(controls, mainGroup, suffi
end

-- Stage count (for multi-stage skills without parts)
if activeSkill.skillFlags and activeSkill.skillFlags.multiStage and not (activeEffect.grantedEffect.parts and #activeEffect.grantedEffect.parts > 1) then
if activeSkill.skillFlags and activeSkill.skillFlags.multiStage and not (activeSkill.skillPartList and #activeSkill.skillPartList > 1) then
controls.mainSkillStageCount.shown = true
controls.mainSkillStageCount.buf = tostring(activeEffect.srcInstance["skillStageCount"..suffix] or activeSkill.skillData.stagesMin or 1)
end
Expand Down
17 changes: 17 additions & 0 deletions src/Classes/GemSelectControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ function GemSelectClass:CalcOutputWithThisGem(calcFunc, gemData, useFullDPS)
local gemList = self.skillsTab.displayGroup.gemList
local displayGemList = self.skillsTab.displayGroup.displayGemList
local oldGem
local skillPartSelections = { }
-- Some candidate supports can temporarily make an active skill incompatible
-- with its selected part. The comparison calculation must not persist the
-- resulting fallback to the default part in the actual build.
for _, socketGroup in ipairs(self.skillsTab.socketGroupList) do
for _, gemInstance in ipairs(socketGroup.gemList) do
t_insert(skillPartSelections, {
gemInstance = gemInstance,
skillPart = gemInstance.skillPart,
skillPartCalcs = gemInstance.skillPartCalcs,
})
end
end

-- the imbuedSupport control actively switches to the latest index of the current displayGroup's gemList so we can use the canSupport filtering
if self.imbuedSelect then
Expand Down Expand Up @@ -99,6 +112,10 @@ function GemSelectClass:CalcOutputWithThisGem(calcFunc, gemData, useFullDPS)
gemInstance.displayEffect = nil
-- Calculate the impact of using this gem
local output = calcFunc(nil, useFullDPS)
for _, selection in ipairs(skillPartSelections) do
selection.gemInstance.skillPart = selection.skillPart
selection.gemInstance.skillPartCalcs = selection.skillPartCalcs
end
-- Put the original gem back into the list
if oldGem then
gemInstance.gemData = oldGem.gemData
Expand Down
56 changes: 56 additions & 0 deletions src/Classes/SkillsTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,33 @@ will automatically apply to the skill.]]
return label
end

self.controls.brandRecallSourceLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.imbuedSupportLabel, "BOTTOMLEFT" }, { 0, 12, 0, 16 }, "^7Recalled brand:")
self.controls.brandRecallSourceLabel.shown = function()
for _, gem in ipairs(self.displayGroup and self.displayGroup.gemList or {}) do
local effect = gem.grantedEffect or (gem.gemData and gem.gemData.grantedEffect)
if effect and effect.id == "BrandRecall" then
return true
end
end
return false
end
self.controls.brandRecallSource = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.brandRecallSourceLabel, "RIGHT" }, { 8, 0, 300, 20 }, {}, function(index, value)
local source = value.group
if source and not source.brandRecallId then
-- Keep references stable when groups are reordered or removed. Include dangling
-- references when allocating IDs so a deleted source cannot be replaced silently.
local nextId = 1
for _, group in ipairs(self.socketGroupList) do
nextId = math.max(nextId, (group.brandRecallId or 0) + 1, (group.brandRecallSourceId or 0) + 1)
end
source.brandRecallId = nextId
end
self.displayGroup.brandRecallSourceId = source and source.brandRecallId
self:AddUndoState()
self.build.buildFlag = true
end)
self.controls.brandRecallSource.tooltipText = "Adds 20% of the selected brand's cost per active brand to Brand Recall's cost and uses that brand for recalled DPS."

-- Scroll bar
self.controls.scrollBarH = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 0, 18}, 100, "HORIZONTAL", true)

Expand Down Expand Up @@ -447,6 +474,8 @@ function SkillsTabClass:LoadSkill(node, skillSetId)
socketGroup.enabled = node.attrib.active == "true" or node.attrib.enabled == "true"
socketGroup.includeInFullDPS = node.attrib.includeInFullDPS and node.attrib.includeInFullDPS == "true"
socketGroup.groupCount = tonumber(node.attrib.groupCount)
socketGroup.brandRecallId = tonumber(node.attrib.brandRecallId)
socketGroup.brandRecallSourceId = tonumber(node.attrib.brandRecallSourceId)
socketGroup.label = node.attrib.label
socketGroup.slot = node.attrib.slot
socketGroup.source = node.attrib.source
Expand Down Expand Up @@ -590,6 +619,8 @@ function SkillsTabClass:Save(xml)
enabled = tostring(socketGroup.enabled),
includeInFullDPS = tostring(socketGroup.includeInFullDPS),
groupCount = socketGroup.groupCount ~= nil and tostring(socketGroup.groupCount),
brandRecallId = socketGroup.brandRecallId and tostring(socketGroup.brandRecallId),
brandRecallSourceId = socketGroup.brandRecallSourceId and tostring(socketGroup.brandRecallSourceId),
label = socketGroup.label,
slot = socketGroup.slot,
source = socketGroup.source,
Expand Down Expand Up @@ -686,11 +717,36 @@ function SkillsTabClass:Draw(viewPort, inputEvents)
self.anchorGroupDetail:SetAnchor("TOPLEFT",self.controls.groupList,"TOPRIGHT", 20, 0)
end

self:UpdateBrandRecallSourceList()
self:UpdateGemSlots()

self:DrawControls(viewPort)
end

function SkillsTabClass:UpdateBrandRecallSourceList()
local list = { { label = "None" } }
local selected = 1
local sourceId = self.displayGroup and self.displayGroup.brandRecallSourceId
for index, group in ipairs(self.socketGroupList) do
for _, skill in ipairs(group.displaySkillList or {}) do
if skill.skillTypes[SkillType.Brand] and not skill.skillFlags.disable then
t_insert(list, { label = index .. ": " .. (group.displayLabel or skill.activeEffect.grantedEffect.name), group = group })
if sourceId and group.brandRecallId == sourceId then
selected = #list
end
break
end
end
end
if sourceId and selected == 1 then
t_insert(list, { label = "Selected brand group unavailable" })
selected = #list
end
self.controls.brandRecallSource:SetList(list)
self.controls.brandRecallSource.selIndex = selected
self.anchorGemSlots:SetAnchor("TOPLEFT", self.controls.imbuedSupportLabel, "BOTTOMLEFT", 0, self.controls.brandRecallSourceLabel:IsShown() and 62 or 30)
end

function SkillsTabClass:CopySocketGroup(socketGroup)
local skillText = ""
if socketGroup.label and socketGroup.label:match("%S") then
Expand Down
9 changes: 4 additions & 5 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6278,8 +6278,7 @@ c["20% chance for Energy Shield Recharge to start when you Block 35% chance for
c["20% chance for Energy Shield Recharge to start when you Kill an Enemy"]={{[1]={[1]={type="Condition",var="KilledRecently"},flags=0,keywordFlags=0,name="EnergyShield",type="BASE",value=20}}," for Recharge to start "}
c["20% chance for Energy Shield Recharge to start when you Kill an Enemy 40% less Energy Shield Recharge Rate"]={{[1]={[1]={type="Condition",var="KilledRecently"},flags=0,keywordFlags=0,name="EnergyShield",type="BASE",value=20}}," for Recharge to start 40% less Energy Shield Recharge Rate "}
c["20% chance for Poisons inflicted with this Weapon to deal 300% more Damage"]={{[1]={[1]={type="Condition",var="{Hand}Attack"},[2]={skillType=1,type="SkillType"},flags=0,keywordFlags=2097152,name="Damage",type="MORE",value=60}},nil}
c["20% chance for Skills to not consume a Cooldown on use"]={{}," for Skills to not consume a Cooldown on use "}
c["20% chance for Skills to not consume a Cooldown on use Limited to 1 Runegraft of Time"]={{}," for Skills to not consume a Cooldown on use Limited to 1 Runegraft of Time "}
c["20% chance for Skills to not consume a Cooldown on use"]={{[1]={flags=0,keywordFlags=0,name="CooldownNotConsumedChance",type="BASE",value=20}},nil}
c["20% chance for used Retaliation Skills to remain Usable and not consume a Cooldown Use"]={{[1]={flags=0,keywordFlags=0,name="AdditionalCooldownUses",type="BASE",value=20}}," for used Retaliation Skills to remain Usable and not consume a "}
c["20% chance on Hit to remove all Impales from Enemy"]={{}," to remove all Impales from Enemy "}
c["20% chance on Hit to remove all Impales from Enemy Impales removed this way multiply their Reflected Damage for this Hit by the number of Hits they have left"]={{[1]={flags=4,keywordFlags=0,name="Damage",type="BASE",value=20}}," to remove all Impales from Enemy Impales removed this way multiply their Reflected for this Hit by the number of Hits they have left "}
Expand Down Expand Up @@ -10003,8 +10002,8 @@ c["5% increased Poison Duration"]={{[1]={flags=0,keywordFlags=0,name="EnemyPoiso
c["5% increased Poison Duration for each Poison you have inflicted Recently, up"]={{[1]={[1]={type="Multiplier",var="PoisonAppliedRecently"},flags=0,keywordFlags=0,name="EnemyPoisonDuration",type="INC",value=5}}," , up "}
c["5% increased Poison Duration for each Poison you have inflicted Recently, up to a maximum of 100%"]={{[1]={[1]={globalLimit=100,globalLimitKey="DurationPerPoisonRecently",type="Multiplier",var="PoisonAppliedRecently"},flags=0,keywordFlags=0,name="EnemyPoisonDuration",type="INC",value=5}},nil}
c["5% increased Projectile Damage per Power Charge"]={{[1]={[1]={type="Multiplier",var="PowerCharge"},flags=1024,keywordFlags=0,name="Damage",type="INC",value=5}},nil}
end)();(function()
c["5% increased Projectile Speed"]={{[1]={flags=0,keywordFlags=0,name="ProjectileSpeed",type="INC",value=5}},nil}
end)();(function()
c["5% increased Projectile Speed per Frenzy Charge"]={{[1]={[1]={type="Multiplier",var="FrenzyCharge"},flags=0,keywordFlags=0,name="ProjectileSpeed",type="INC",value=5}},nil}
c["5% increased Quantity of Gold Dropped by Slain Enemies"]={{}," Quantity of Gold Dropped by Slain Enemies "}
c["5% increased Quantity of Items found"]={{[1]={flags=0,keywordFlags=0,name="LootQuantity",type="INC",value=5}},nil}
Expand Down Expand Up @@ -15005,8 +15004,8 @@ c["Damage of Enemies Hitting you is Unlucky"]={nil,"Damage of Enemies Hitting yo
c["Damage of Enemies Hitting you is Unlucky Damage with Hits is Unlucky"]={nil,"Damage of Enemies Hitting you is Unlucky Damage with Hits is Unlucky "}
c["Damage of Enemies Hitting you is Unlucky while you are Cursed with Vulnerability"]={nil,"Damage of Enemies Hitting you is Unlucky while you are Cursed with Vulnerability "}
c["Damage of Enemies Hitting you is Unlucky while you are Cursed with Vulnerability You count as on Full Life while you are Cursed with Vulnerability"]={nil,"Damage of Enemies Hitting you is Unlucky while you are Cursed with Vulnerability You count as on Full Life while you are Cursed with Vulnerability "}
end)();(function()
c["Damage of Enemies Hitting you is Unlucky while you are on Full Life"]={nil,"Damage of Enemies Hitting you is Unlucky while you are on Full Life "}
end)();(function()
c["Damage of Enemies Hitting you is Unlucky while you are on Low Life"]={nil,"Damage of Enemies Hitting you is Unlucky while you are on Low Life "}
c["Damage of Enemies Hitting you is Unlucky while you have a Magic Ring Equipped"]={nil,"Damage of Enemies Hitting you is Unlucky while you have a Magic Ring Equipped "}
c["Damage of Enemies Hitting you is Unlucky while you have a Magic Ring Equipped You are Hexproof if you have a Magic Ring in right slot"]={nil,"Damage of Enemies Hitting you is Unlucky while you have a Magic Ring Equipped You are Hexproof if you have a Magic Ring in right slot "}
Expand Down Expand Up @@ -20007,8 +20006,8 @@ c["Skills Socketed in your Boots are Supported by level 20 High-Impact Mine"]={{
c["Skills Socketed in your Boots are Supported by level 20 Hypothermia"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportHypothermia"}}},nil}
c["Skills Socketed in your Boots are Supported by level 20 Ice Bite"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIceBite"}}},nil}
c["Skills Socketed in your Boots are Supported by level 20 Ignite Proliferation"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIgniteProliferation"}}},nil}
end)();(function()
c["Skills Socketed in your Boots are Supported by level 20 Immolate"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportImmolate"}}},nil}
end)();(function()
c["Skills Socketed in your Boots are Supported by level 20 Impale"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportImpale"}}},nil}
c["Skills Socketed in your Boots are Supported by level 20 Increased Area of Effect"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIncreasedAreaOfEffect"}}},nil}
c["Skills Socketed in your Boots are Supported by level 20 Increased Critical Damage"]={{[1]={[1]={slotName="Boots",type="SocketedIn"},flags=0,keywordFlags=0,name="ExtraSupport",type="LIST",value={appliesToGrantedSkills=true,level=20,skillId="SupportIncreasedCriticalDamage"}}},nil}
Expand Down
3 changes: 3 additions & 0 deletions src/Data/SkillStatMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2172,6 +2172,9 @@ return {
["brand_cannot_be_recalled"] = {
flag("Condition:CannotRecallBrand"),
},
["brand_recall_spend_%_of_recalled_brands_cost"] = {
skill("brandRecallCostPercent", nil),
},
-- Banner
["banner_buff_effect_+%_final_per_resource"] = {
mod("AuraEffect", "MORE", nil, 0, 0, { type = "Multiplier", var = "BannerValour" }, { type = "Condition", var = "BannerPlanted" }),
Expand Down
16 changes: 11 additions & 5 deletions src/Modules/Build.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1655,23 +1655,23 @@ function buildMode:RefreshSkillSelectControls(controls, mainGroup, suffix)
local activeSkill = displaySkillList[mainActiveSkill]
local activeEffect = activeSkill.activeEffect
if activeEffect then
if activeEffect.grantedEffect.parts and #activeEffect.grantedEffect.parts > 1 then
if activeSkill.skillPartList and #activeSkill.skillPartList > 1 then
controls.mainSkillPart.shown = true
wipeTable(controls.mainSkillPart.list)
for i, part in ipairs(activeEffect.grantedEffect.parts) do
for i, part in ipairs(activeSkill.skillPartList) do
t_insert(controls.mainSkillPart.list, { val = i, label = part.name })
end
controls.mainSkillPart.selIndex = activeEffect.srcInstance["skillPart"..suffix] or 1
if activeEffect.grantedEffect.parts[controls.mainSkillPart.selIndex].stages then
if activeSkill.skillPartList[controls.mainSkillPart.selIndex].stages then
controls.mainSkillStageCount.shown = true
controls.mainSkillStageCount.buf = tostring(activeEffect.srcInstance["skillStageCount"..suffix] or activeSkill.skillData.stagesMax or activeEffect.grantedEffect.parts[controls.mainSkillPart.selIndex].stagesMin or 1)
controls.mainSkillStageCount.buf = tostring(activeEffect.srcInstance["skillStageCount"..suffix] or activeSkill.skillData.stagesMax or activeSkill.skillPartList[controls.mainSkillPart.selIndex].stagesMin or 1)
end
end
if activeSkill.skillFlags.mine then
controls.mainSkillMineCount.shown = true
controls.mainSkillMineCount.buf = tostring(activeEffect.srcInstance["skillMineCount"..suffix] or "")
end
if activeSkill.skillFlags.multiStage and not (activeEffect.grantedEffect.parts and #activeEffect.grantedEffect.parts > 1) then
if activeSkill.skillFlags.multiStage and not (activeSkill.skillPartList and #activeSkill.skillPartList > 1) then
controls.mainSkillStageCount.shown = true
controls.mainSkillStageCount.buf = tostring(activeEffect.srcInstance["skillStageCount"..suffix] or activeSkill.skillData.stagesMax or activeSkill.skillData.stagesMin or 1)
end
Expand Down Expand Up @@ -2029,6 +2029,12 @@ function buildMode:AddDisplayStatList(statList, actor, actorName)
InsertIfNew(self.controls.warnings.lines, line)
end
end
for pool, warningFlag in pairs({["Life"] = "LifeCostChainWarningList", ["Mana"] = "ManaCostChainWarningList", ["Rage"] = "RageCostChainWarningList", ["Energy Shield"] = "ESCostChainWarningList", ["Unreserved Life %"] = "LifePercentCostChainWarningList", ["Unreserved Mana %"] = "ManaPercentCostChainWarningList"}) do
if actor.output[warningFlag] then
local resource = actor.output.EnergyShieldProtectsMana and pool == "Mana" and "Energy Shield and Mana" or pool
InsertIfNew(self.controls.warnings.lines, "Estimated total spending per use exceeds your available "..resource.." before recovery: "..table.concat(actor.output[warningFlag], ", "))
end
end
for pool, warningFlag in pairs({["Unreserved life"] = "LifePercentCostPercentCostWarningList", ["Unreserved Mana"] = "ManaPercentCostPercentCostWarningList"}) do
if actor.output[warningFlag] then
local line = "You do not have enough ".. pool .."% to use: "
Expand Down
Loading
Loading