Skip to content

Commit 669d9fa

Browse files
LocalIdentityLocalIdentityPeechey
authored
Initial Support for Crucible Mods on items (#6071)
* Initial Support for Crucible Mods on items * Support for Crucible Mods (#6076) * add new button for crucible mods, separate by node show button only for weapons and shields * add button to remove crucible mods * refactor node dropdowns * Fix Notable export * Fix projectile speed stat * "Remove" button UI refactor "Allocate" mods - substitute id for name * checkLine update * dynamic buttons for normal,unique rarity remove crucibleControl as it is not needed * populate dropdown with active crucible mods * unique staff, sword, helmet * unique helmet update * Add blank parsing for crucible uniques * canHaveMod refactor, Quick is smart * refactor custom tagging --------- Co-authored-by: LocalIdentity <localidentity2@gmail.com> --------- Co-authored-by: LocalIdentity <localidentity2@gmail.com> Co-authored-by: Peechey <92683202+Peechey@users.noreply.github.com>
1 parent 22ca845 commit 669d9fa

File tree

8 files changed

+2881
-15
lines changed

8 files changed

+2881
-15
lines changed

src/Classes/Item.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,12 @@ function ItemClass:ParseRaw(raw)
737737
self.canHaveTwoEnchants = true
738738
self.canHaveThreeEnchants = true
739739
self.canHaveFourEnchants = true
740+
elseif lineLower == "has a crucible passive skill tree with only support passive skills" then
741+
self.canHaveOnlySupportSkillsCrucibleTree = true
742+
elseif lineLower == "has a crucible passive skill tree" then
743+
self.canHaveShieldCrucibleTree = true
744+
elseif lineLower == "has a two handed sword crucible passive skill tree" then
745+
self.canHaveTwoHandedSwordCrucibleTree = true
740746
end
741747

742748
if data.itemBases[line] then

src/Classes/ItemsTab.lua

Lines changed: 174 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,9 @@ holding Shift will put it in the second.]])
797797
end
798798

799799
-- Section: Custom modifiers
800+
-- if either Custom or Crucible mod buttons are shown, create the control for the list of mods
800801
self.controls.displayItemSectionCustom = new("Control", {"TOPLEFT",self.controls.displayItemSectionAffix,"BOTTOMLEFT"}, 0, 0, 0, function()
801-
return self.controls.displayItemAddCustom:IsShown() and 28 + self.displayItem.customCount * 22 or 0
802+
return (self.controls.displayItemAddCustom:IsShown() or self.controls.displayItemAddCrucible:IsShown()) and 28 + self.displayItem.customCount * 22 or 0
802803
end)
803804
self.controls.displayItemAddCustom = new("ButtonControl", {"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, 0, 0, 120, 20, "Add modifier...", function()
804805
self:AddCustomModifierToDisplayItem()
@@ -807,6 +808,17 @@ holding Shift will put it in the second.]])
807808
return self.displayItem and (self.displayItem.rarity == "MAGIC" or self.displayItem.rarity == "RARE")
808809
end
809810

811+
-- Section: Crucible modifiers
812+
-- if the Add modifier button is not shown, take its place, otherwise move it to the right of it
813+
self.controls.displayItemAddCrucible = new("ButtonControl", {"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, function()
814+
return (self.controls.displayItemAddCustom:IsShown() and 128) or 0
815+
end, 0, 150, 20, "Add Crucible mod...", function()
816+
self:AddCrucibleModifierToDisplayItem()
817+
end)
818+
self.controls.displayItemAddCrucible.shown = function()
819+
return self.displayItem and (self.displayItem:GetPrimarySlot() == "Weapon 1" or self.displayItem.type == "Shield" or self.displayItem.canHaveShieldCrucibleTree)
820+
end
821+
810822
-- Section: Modifier Range
811823
self.controls.displayItemSectionRange = new("Control", {"TOPLEFT",self.controls.displayItemSectionCustom,"BOTTOMLEFT"}, 0, 0, 0, function()
812824
return self.displayItem.rangeLineList[1] and 28 or 0
@@ -1664,25 +1676,35 @@ end
16641676
function ItemsTabClass:UpdateCustomControls()
16651677
local item = self.displayItem
16661678
local i = 1
1667-
if item.rarity == "MAGIC" or item.rarity == "RARE" then
1668-
for index, modLine in ipairs(item.explicitModLines) do
1669-
if modLine.custom or modLine.crafted then
1679+
local modLines = copyTable(item.explicitModLines)
1680+
if item.crucibleModLines and #item.crucibleModLines > 0 then
1681+
for _, line in ipairs(item.crucibleModLines) do
1682+
t_insert(modLines, line)
1683+
end
1684+
end
1685+
if item.rarity == "MAGIC" or item.rarity == "RARE" or item.crucibleModLines then
1686+
for index, modLine in ipairs(modLines) do
1687+
if modLine.custom or modLine.crafted or modLine.crucible then
16701688
local line = itemLib.formatModLine(modLine)
16711689
if line then
1672-
if not self.controls["displayItemCustomModifier"..i] then
1673-
self.controls["displayItemCustomModifier"..i] = new("LabelControl", {"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, 55, i * 22 + 4, 0, 16)
1674-
self.controls["displayItemCustomModifierLabel"..i] = new("LabelControl", {"RIGHT",self.controls["displayItemCustomModifier"..i],"LEFT"}, -2, 0, 0, 16)
1675-
self.controls["displayItemCustomModifierRemove"..i] = new("ButtonControl", {"LEFT",self.controls["displayItemCustomModifier"..i],"RIGHT"}, 4, 0, 70, 20, "^7Remove")
1690+
if not self.controls["displayItemCustomModifierRemove"..i] then
1691+
self.controls["displayItemCustomModifierRemove"..i] = new("ButtonControl", {"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, 0, i * 22 + 4, 70, 20, "^7Remove")
1692+
self.controls["displayItemCustomModifier"..i] = new("LabelControl", {"LEFT",self.controls["displayItemCustomModifierRemove"..i],"RIGHT"}, 65, 0, 0, 16)
1693+
self.controls["displayItemCustomModifierLabel"..i] = new("LabelControl", {"LEFT",self.controls["displayItemCustomModifierRemove"..i],"RIGHT"}, 5, 0, 0, 16)
16761694
end
1677-
self.controls["displayItemCustomModifier"..i].shown = true
1695+
self.controls["displayItemCustomModifierRemove"..i].shown = true
16781696
local label = itemLib.formatModLine(modLine)
16791697
if DrawStringCursorIndex(16, "VAR", label, 330, 10) < #label then
16801698
label = label:sub(1, DrawStringCursorIndex(16, "VAR", label, 310, 10)) .. "..."
16811699
end
16821700
self.controls["displayItemCustomModifier"..i].label = label
1683-
self.controls["displayItemCustomModifierLabel"..i].label = modLine.crafted and "^7Crafted:" or "^7Custom:"
1701+
self.controls["displayItemCustomModifierLabel"..i].label = modLine.crafted and " ^7Crafted:" or modLine.crucible and "^7Crucible:" or " ^7Custom:"
16841702
self.controls["displayItemCustomModifierRemove"..i].onClick = function()
1685-
t_remove(item.explicitModLines, index)
1703+
if index > #item.explicitModLines then
1704+
t_remove(item.crucibleModLines, index - #item.explicitModLines)
1705+
else
1706+
t_remove(item.explicitModLines, index)
1707+
end
16861708
item:BuildAndParseRaw()
16871709
local id = item.id
16881710
self:CreateDisplayItemFromRaw(item:BuildRaw())
@@ -1694,8 +1716,8 @@ function ItemsTabClass:UpdateCustomControls()
16941716
end
16951717
end
16961718
item.customCount = i - 1
1697-
while self.controls["displayItemCustomModifier"..i] do
1698-
self.controls["displayItemCustomModifier"..i].shown = false
1719+
while self.controls["displayItemCustomModifierRemove"..i] do
1720+
self.controls["displayItemCustomModifierRemove"..i].shown = false
16991721
i = i + 1
17001722
end
17011723
end
@@ -1712,12 +1734,22 @@ function ItemsTabClass:UpdateDisplayItemRangeLines()
17121734
end
17131735
end
17141736

1737+
local function checkLineForAllocates(line, nodes)
1738+
if nodes and string.match(line, "Allocates") then
1739+
local nodeId = tonumber(string.match(line, "%d+"))
1740+
if nodes[nodeId] then
1741+
return "Allocates "..nodes[nodeId].name
1742+
end
1743+
end
1744+
return line
1745+
end
1746+
17151747
function ItemsTabClass:AddModComparisonTooltip(tooltip, mod)
17161748
local slotName = self.displayItem:GetPrimarySlot()
17171749
local newItem = new("Item", self.displayItem:BuildRaw())
17181750

17191751
for _, subMod in ipairs(mod) do
1720-
t_insert(newItem.explicitModLines, { line = subMod, modTags = mod.modTags, [mod.type] = true })
1752+
t_insert(newItem.explicitModLines, { line = checkLineForAllocates(subMod, self.build.spec.nodes), modTags = mod.modTags, [mod.type] = true })
17211753
end
17221754

17231755
newItem:BuildAndParseRaw()
@@ -2565,6 +2597,134 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
25652597
main:OpenPopup(710, 105, "Add Modifier to Item", controls, "save", sourceList[controls.source.selIndex].sourceId == "CUSTOM" and "custom")
25662598
end
25672599

2600+
-- Opens the crucible modifier popup
2601+
function ItemsTabClass:AddCrucibleModifierToDisplayItem()
2602+
local controls = { }
2603+
local modList = {[1] = {"None"}, [2] = {"None"}, [3] = {"None"}, [4] = {"None"}, [5] = {"None"}}
2604+
local itemModMap, nodeSelections = { }, { }
2605+
local function getLabelFromMod(mod)
2606+
local label = copyTable(mod)
2607+
for index, line in ipairs(mod) do
2608+
label[index] = checkLineForAllocates(line, self.build.spec.nodes)
2609+
end
2610+
return table.concat(label, "/")
2611+
end
2612+
local function itemCanHaveMod(mod)
2613+
local keyMap = { }
2614+
for index, key in ipairs(mod.weightKey) do
2615+
keyMap[key] = index
2616+
end
2617+
if self.displayItem.canHaveOnlySupportSkillsCrucibleTree then
2618+
return keyMap["crucible_unique_staff"] and mod.weightVal[keyMap["crucible_unique_staff"]] ~= 0
2619+
end
2620+
if self.displayItem.canHaveShieldCrucibleTree then
2621+
return self.displayItem:GetModSpawnWeight(mod, { ["crucible_unique_helmet"] = true, ["shield"] = true }) > 0
2622+
elseif self.displayItem.canHaveTwoHandedSwordCrucibleTree then
2623+
self.displayItem.base.tags["one_hand_weapon"] = nil
2624+
return self.displayItem:GetModSpawnWeight(mod, { ["two_hand_weapon"] = true }) > 0
2625+
end
2626+
return self.displayItem:GetModSpawnWeight(mod) > 0
2627+
end
2628+
local function buildCrucibleMods()
2629+
for i, mod in pairs(self.build.data.crucible) do
2630+
if itemCanHaveMod(mod) then
2631+
-- item mod must match the whole mod, whether that's one line or two
2632+
if itemModMap[checkLineForAllocates(mod[1], self.build.spec.nodes)] and ((mod[2] and itemModMap[checkLineForAllocates(mod[2], self.build.spec.nodes)]) or not mod[2]) then
2633+
-- for multi nodes, if the first location is taken, use second
2634+
-- works for multi vs single node, ambiguous for multi vs multi (3,4 vs 3,4) but both mods load
2635+
if nodeSelections[mod.nodeLocation[1]] and mod.nodeLocation[2] then
2636+
nodeSelections[mod.nodeLocation[2]] = i
2637+
-- nodeSelections[nodeId] = defaultOrder, used later to match with sorted modList to get selIndex
2638+
else
2639+
nodeSelections[mod.nodeLocation[1]] = i
2640+
end
2641+
end
2642+
for _, location in ipairs(mod.nodeLocation) do
2643+
t_insert(modList[location], {
2644+
label = getLabelFromMod(mod) .. " - Tier: " .. mod.tier,
2645+
mod = mod,
2646+
affixType = mod.type,
2647+
type = "crucible",
2648+
defaultOrder = i,
2649+
})
2650+
end
2651+
end
2652+
end
2653+
for _, tierList in ipairs(modList) do
2654+
table.sort(tierList, function(a, b)
2655+
if b ~= "None" then
2656+
if a.affixType ~= b.affixType then
2657+
return a.affixType == "Spawn" and b.affixType == "MergeOnly"
2658+
else
2659+
return a.defaultOrder < b.defaultOrder
2660+
end
2661+
end
2662+
end)
2663+
end
2664+
end
2665+
local function addModifier()
2666+
local item = new("Item", self.displayItem:BuildRaw())
2667+
item.id = self.displayItem.id
2668+
item.crucibleModLines = { }
2669+
local listMod = {
2670+
modList[1][controls.modSelectNode1.selIndex],
2671+
modList[2][controls.modSelectNode2.selIndex],
2672+
modList[3][controls.modSelectNode3.selIndex],
2673+
modList[4][controls.modSelectNode4.selIndex],
2674+
modList[5][controls.modSelectNode5.selIndex],
2675+
}
2676+
for _, nodeMod in ipairs(listMod) do
2677+
if nodeMod ~= "None" then
2678+
for index, line in ipairs(nodeMod.mod) do
2679+
t_insert(item.crucibleModLines, { line = checkLineForAllocates(line, self.build.spec.nodes), modTags = nodeMod.mod.modTags, [nodeMod.type] = true })
2680+
end
2681+
end
2682+
end
2683+
item:BuildAndParseRaw()
2684+
return item
2685+
end
2686+
-- set up name map to know what modLines the item has as we build the mods out
2687+
for _, mod in ipairs(self.displayItem.crucibleModLines) do
2688+
itemModMap[mod.line] = true
2689+
end
2690+
buildCrucibleMods()
2691+
local y = 45
2692+
for i = 1,5 do
2693+
controls["modSelectNode"..i.."Label"] = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, 95, y, 0, 16, "^7Node "..i..":")
2694+
controls["modSelectNode"..i] = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, 100, y, 555, 18, modList[i])
2695+
controls["modSelectNode"..i].tooltipFunc = function(tooltip, mode, index, value)
2696+
tooltip:Clear()
2697+
if mode ~= "OUT" and value and value ~= "None" then
2698+
for _, line in ipairs(value.mod) do
2699+
tooltip:AddLine(16, "^7"..checkLineForAllocates(line, self.build.spec.nodes))
2700+
end
2701+
self:AddModComparisonTooltip(tooltip, value.mod)
2702+
end
2703+
end
2704+
y = y + 22
2705+
end
2706+
-- populate dropdowns with item mods
2707+
for nodeId, defaultOrder in pairs(nodeSelections) do
2708+
for index, mod in pairs(modList[nodeId]) do
2709+
if defaultOrder == mod.defaultOrder then
2710+
controls["modSelectNode"..nodeId].selIndex = index
2711+
end
2712+
end
2713+
end
2714+
controls.save = new("ButtonControl", nil, -45, 157, 80, 20, "Add", function()
2715+
self:SetDisplayItem(addModifier())
2716+
main:ClosePopup()
2717+
end)
2718+
controls.save.tooltipFunc = function(tooltip)
2719+
tooltip:Clear()
2720+
self:AddItemTooltip(tooltip, addModifier())
2721+
end
2722+
controls.close = new("ButtonControl", nil, 45, 157, 80, 20, "Cancel", function()
2723+
main:ClosePopup()
2724+
end)
2725+
main:OpenPopup(710, 185, "Add Crucible Modifier to Item", controls, "save")
2726+
end
2727+
25682728
-- Opens the custom Implicit popup
25692729
function ItemsTabClass:AddImplicitToDisplayItem()
25702730
local controls = { }

0 commit comments

Comments
 (0)