Skip to content

Commit 130e0ec

Browse files
author
LocalIdentity
committed
Merge branch 'dev'
2 parents adda267 + 84c4e64 commit 130e0ec

92 files changed

Lines changed: 88520 additions & 24508 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
11
# Changelog
22

3+
## [v0.18.0](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/tree/v0.18.0) (2026/06/04)
4+
5+
[Full Changelog](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/compare/v0.17.1...v0.18.0)
6+
7+
8+
## What's Changed
9+
### New to Path of Building
10+
- Add missing 0.5 skill gems [\#2067](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2067) ([LocalIdentity](https://github.com/LocalIdentity))
11+
- Add new 0.5 Spectres [\#2026](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2026) ([Blitz54](https://github.com/Blitz54))
12+
- Add new 0.5 Minions [\#2084](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2084) ([LocalIdentity](https://github.com/LocalIdentity))
13+
- Add support for Eye of Winter ground damage buffs [\#2069](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2069) ([LocalIdentity](https://github.com/LocalIdentity))
14+
- Add support for Flask instant recovery belt mod [\#2068](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2068) ([LocalIdentity](https://github.com/LocalIdentity))
15+
- Add support for additional Warcry Empowers [\#2071](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2071) ([Peechey](https://github.com/Peechey))
16+
- Preserve skill selection on character reimport [\#2079](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2079) ([LocalIdentity](https://github.com/LocalIdentity))
17+
- Disable right click to paste in the notes tab [\#2085](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2085) ([LocalIdentity](https://github.com/LocalIdentity))
18+
### User Interface
19+
- Show Runic item headers and change "Ward" text on items to "Runic Ward" [\#2059](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2059) ([Blitz54](https://github.com/Blitz54))
20+
### Fixed Calculations
21+
- Fix Shrine sceptre Auras not making linked buffs have no Spirit cost [\#2077](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2077) ([LocalIdentity](https://github.com/LocalIdentity))
22+
- Fix Volcanic Eruption not scaling with Projectile damage [\#2062](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2062) ([MrHB212](https://github.com/MrHB212))
23+
- Fix Smith of Kitava Flowing Metal node not working [\#2016](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2016) ([vaisest](https://github.com/vaisest))
24+
- Fix some bonded Rune affects applying without Wisdom of the Maji [\#2076](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2076) ([LocalIdentity](https://github.com/LocalIdentity))
25+
- Fix Cold damage contributing to stun buildup [\#2070](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2070) ([LocalIdentity](https://github.com/LocalIdentity))
26+
### Fixed Behaviours
27+
- Fix Crafted mods not importing from items [\#2064](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2064) ([LocalIdentity](https://github.com/LocalIdentity))
28+
- Fix Gloves not importing when using Way of the Stonefist [\#2072](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2072) ([Eucelia](https://github.com/Eucelia))
29+
- Fix trade search not working [\#2020](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2020) ([vaisest](https://github.com/vaisest))
30+
- Fix Jewel mod sorting not working [\#2074](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2074) ([LocalIdentity](https://github.com/LocalIdentity))
31+
- Fix Comet not showing DPS values [\#2046](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2046) ([LocalIdentity](https://github.com/LocalIdentity))
32+
- Fix parsing for Hollow Palm Technique [\#2063](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/2063) ([Eucelia](https://github.com/Eucelia))
33+
34+
35+
336
## [v0.17.1](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/tree/v0.17.1) (2026/06/02)
437

538
[Full Changelog](https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/compare/v0.17.0...v0.17.1)

changelog.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
VERSION[0.18.0][2026/06/04]
2+
3+
--- New to Path of Building ---
4+
* Add missing 0.5 skill gems (LocalIdentity)
5+
* Add new 0.5 Spectres (Blitz54)
6+
* Add new 0.5 Minions (LocalIdentity)
7+
* Add support for Eye of Winter ground damage buffs (LocalIdentity)
8+
* Add support for Flask instant recovery belt mod (LocalIdentity)
9+
* Add support for additional Warcry Empowers (Peechey)
10+
* Preserve skill selection on character reimport (LocalIdentity)
11+
* Disable right click to paste in the notes tab (LocalIdentity)
12+
13+
--- User Interface ---
14+
* Show Runic item headers and change "Ward" text on items to "Runic Ward" (Blitz54)
15+
16+
--- Fixed Calculations ---
17+
* Fix Shrine sceptre Auras not making linked buffs have no Spirit cost (LocalIdentity)
18+
* Fix Volcanic Eruption not scaling with Projectile damage (MrHB212)
19+
* Fix Smith of Kitava Flowing Metal node not working (vaisest)
20+
* Fix some bonded Rune affects applying without Wisdom of the Maji (LocalIdentity)
21+
* Fix Cold damage contributing to stun buildup (LocalIdentity)
22+
23+
--- Fixed Behaviours ---
24+
* Fix Crafted mods not importing from items (LocalIdentity)
25+
* Fix Gloves not importing when using Way of the Stonefist (Eucelia)
26+
* Fix trade search not working (vaisest)
27+
* Fix Jewel mod sorting not working (LocalIdentity)
28+
* Fix Comet not showing DPS values (LocalIdentity)
29+
* Fix parsing for Hollow Palm Technique (Eucelia)
30+
31+
132
VERSION[0.17.1][2026/06/02]
233

334
--- Fixed Crashes ---

manifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version='1.0' encoding='UTF-8'?>
22
<PoBVersion>
3-
<Version number="0.17.1" />
3+
<Version number="0.18.0" />
44
<Source part="default" url="https://raw.githubusercontent.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/{branch}/" />
55
<Source part="runtime" platform="win32" url="https://raw.githubusercontent.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/{branch}/runtime/" />
66
<Source part="program" url="https://raw.githubusercontent.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/{branch}/src/" />
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
describe("TestImportReimport", function()
2+
local DEFAULT_CHARACTER_LEVEL = 12
3+
local DEFAULT_ITEM_LEVEL = 10
4+
local TEST_IMPORT_ITEM_ID = "test-import-item-1"
5+
6+
before_each(function()
7+
newBuild()
8+
end)
9+
10+
local function makeGemProperties(level)
11+
return {
12+
{ name = "Level", values = { { tostring(level), 0 } } },
13+
{ name = "Quality", values = { { "+0%", 0 } } },
14+
}
15+
end
16+
17+
local function makeGemEntry(support, typeLine, level, socketedItems)
18+
return {
19+
support = support,
20+
typeLine = typeLine,
21+
properties = makeGemProperties(level),
22+
socketedItems = socketedItems,
23+
}
24+
end
25+
26+
-- Build a minimal import item so the tests stay focused on state, not fixture noise.
27+
local function makeImportItem(itemTypeLine, inventoryId, itemId)
28+
return {
29+
id = itemId or TEST_IMPORT_ITEM_ID,
30+
frameType = 0,
31+
name = "",
32+
typeLine = itemTypeLine,
33+
inventoryId = inventoryId,
34+
ilvl = DEFAULT_ITEM_LEVEL,
35+
properties = {},
36+
}
37+
end
38+
39+
-- Build a minimal import payload so the tests stay focused on state, not fixture noise.
40+
local function buildImportPayload(items, skills)
41+
return {
42+
level = DEFAULT_CHARACTER_LEVEL,
43+
equipment = items,
44+
skills = skills,
45+
}
46+
end
47+
48+
local function reimportSkillsWithOptions(itemTypeLine, inventoryId, skills, clearItems)
49+
build.importTab.controls.charImportItemsClearSkills.state = true
50+
build.importTab.controls.charImportItemsClearItems.state = clearItems
51+
build.importTab:ImportItemsAndSkills(buildImportPayload({
52+
makeImportItem(itemTypeLine, inventoryId),
53+
}, skills))
54+
runCallback("OnFrame")
55+
end
56+
57+
local function reimportSingleGemWithOptions(itemTypeLine, inventoryId, gemName, clearItems)
58+
reimportSkillsWithOptions(itemTypeLine, inventoryId, {
59+
makeGemEntry(false, gemName, 20),
60+
}, clearItems)
61+
end
62+
63+
local function reimportSingleGem(itemTypeLine, inventoryId, gemName)
64+
reimportSingleGemWithOptions(itemTypeLine, inventoryId, gemName, false)
65+
end
66+
67+
local function assertReimportPreservesSkillSubstate(itemTypeLine, inventoryId, gemName, fieldName, fieldValue)
68+
build.skillsTab:PasteSocketGroup(string.format([[
69+
%s 20/0 1
70+
]], gemName))
71+
runCallback("OnFrame")
72+
73+
local socketGroup = build.skillsTab.socketGroupList[1]
74+
local srcInstance = socketGroup.displaySkillList[1].activeEffect.srcInstance
75+
srcInstance[fieldName] = fieldValue
76+
srcInstance[fieldName.."Calcs"] = fieldValue
77+
build.modFlag = true
78+
build.buildFlag = true
79+
runCallback("OnFrame")
80+
81+
reimportSingleGem(itemTypeLine, inventoryId, gemName)
82+
83+
socketGroup = build.skillsTab.socketGroupList[1]
84+
srcInstance = socketGroup.displaySkillList[1].activeEffect.srcInstance
85+
assert.are.equal(fieldValue, srcInstance[fieldName])
86+
assert.are.equal(fieldValue, srcInstance[fieldName.."Calcs"])
87+
end
88+
89+
it("preserves full DPS state and manually disabled gems when reimporting items and skills", function()
90+
build.skillsTab:PasteSocketGroup([[
91+
Slot: Gloves
92+
Dark Effigy 1/0 1
93+
Controlled Destruction 1/0 DISABLED 1
94+
]])
95+
runCallback("OnFrame")
96+
97+
local socketGroup = build.skillsTab.socketGroupList[1]
98+
socketGroup.includeInFullDPS = true
99+
socketGroup.mainActiveSkill = 2
100+
runCallback("OnFrame")
101+
102+
build.importTab.controls.charImportItemsClearSkills.state = true
103+
build.importTab.controls.charImportItemsClearItems.state = false
104+
build.importTab:ImportItemsAndSkills(buildImportPayload({
105+
makeImportItem("Wrapped Cap", "Helm"),
106+
}, {
107+
makeGemEntry(false, "Dark Effigy", 2, {
108+
makeGemEntry(true, "Controlled Destruction", 1),
109+
}),
110+
}))
111+
runCallback("OnFrame")
112+
113+
socketGroup = build.skillsTab.socketGroupList[1]
114+
assert.is_true(socketGroup.includeInFullDPS)
115+
assert.are.equal(2, socketGroup.mainActiveSkill)
116+
assert.are.equal(2, socketGroup.gemList[1].level)
117+
assert.is_false(socketGroup.gemList[2].enabled)
118+
end)
119+
120+
it("preserves full DPS state and disabled gems when reimporting with deleted equipment", function()
121+
build.skillsTab:PasteSocketGroup([[
122+
Dark Effigy 1/0 1
123+
Controlled Destruction 1/0 DISABLED 1
124+
]])
125+
runCallback("OnFrame")
126+
127+
local socketGroup = build.skillsTab.socketGroupList[1]
128+
socketGroup.includeInFullDPS = true
129+
socketGroup.mainActiveSkill = 2
130+
runCallback("OnFrame")
131+
132+
reimportSkillsWithOptions("Wrapped Cap", "Helm", {
133+
makeGemEntry(false, "Dark Effigy", 2, {
134+
makeGemEntry(true, "Controlled Destruction", 1),
135+
}),
136+
}, true)
137+
138+
socketGroup = build.skillsTab.socketGroupList[1]
139+
assert.is_true(socketGroup.includeInFullDPS)
140+
assert.are.equal(2, socketGroup.mainActiveSkill)
141+
assert.are.equal(2, socketGroup.gemList[1].level)
142+
assert.is_false(socketGroup.gemList[2].enabled)
143+
end)
144+
145+
it("preserves two socket groups when reimporting items and skills", function()
146+
build.skillsTab:PasteSocketGroup([[
147+
Dark Effigy 1/0 1
148+
Controlled Destruction 1/0 DISABLED 1
149+
]])
150+
runCallback("OnFrame")
151+
152+
build.skillsTab:PasteSocketGroup([[
153+
Fireball 20/0 1
154+
]])
155+
runCallback("OnFrame")
156+
157+
local darkEffigyGroup = build.skillsTab.socketGroupList[1]
158+
darkEffigyGroup.includeInFullDPS = true
159+
darkEffigyGroup.mainActiveSkill = 2
160+
local fireballGroup = build.skillsTab.socketGroupList[2]
161+
fireballGroup.enabled = false
162+
runCallback("OnFrame")
163+
164+
build.importTab.controls.charImportItemsClearSkills.state = true
165+
build.importTab.controls.charImportItemsClearItems.state = false
166+
build.importTab:ImportItemsAndSkills(buildImportPayload({
167+
makeImportItem("Wrapped Cap", "Helm", "test-import-item-helmet"),
168+
makeImportItem("Linen Wraps", "Gloves", "test-import-item-gloves"),
169+
}, {
170+
makeGemEntry(false, "Dark Effigy", 1, {
171+
makeGemEntry(true, "Controlled Destruction", 1),
172+
}),
173+
makeGemEntry(false, "Fireball", 20),
174+
}))
175+
runCallback("OnFrame")
176+
177+
local groupsByGem = {}
178+
for _, socketGroup in ipairs(build.skillsTab.socketGroupList) do
179+
groupsByGem[socketGroup.gemList[1].nameSpec] = socketGroup
180+
end
181+
182+
assert.are.equal(2, #build.skillsTab.socketGroupList)
183+
assert.is_not_nil(groupsByGem["Dark Effigy"])
184+
assert.is_not_nil(groupsByGem.Fireball)
185+
assert.is_true(groupsByGem["Dark Effigy"].includeInFullDPS)
186+
assert.are.equal(2, groupsByGem["Dark Effigy"].mainActiveSkill)
187+
assert.is_false(groupsByGem.Fireball.enabled)
188+
end)
189+
190+
it("preserves skill part selection when reimporting items and skills", function()
191+
assertReimportPreservesSkillSubstate("Twig Focus", "Offhand", "Dark Effigy", "skillPart", 2)
192+
end)
193+
194+
it("preserves stage count when reimporting items and skills", function()
195+
assertReimportPreservesSkillSubstate("Withered Wand", "Weapon", "Flameblast", "skillStageCount", 8)
196+
end)
197+
198+
it("preserves minion skill when reimporting items and skills", function()
199+
assertReimportPreservesSkillSubstate("Linen Wraps", "Gloves", "Skeletal Sniper", "skillMinionSkill", 2)
200+
end)
201+
202+
it("preserves minion skill stat set when reimporting items and skills", function()
203+
build.skillsTab:PasteSocketGroup([[
204+
Skeletal Sniper 20/0 1
205+
]])
206+
runCallback("OnFrame")
207+
208+
local socketGroup = build.skillsTab.socketGroupList[1]
209+
local activeEffect = socketGroup.displaySkillList[1].activeEffect
210+
local grantedEffectId = activeEffect.grantedEffect.id
211+
local srcInstance = activeEffect.srcInstance
212+
srcInstance.skillMinionSkill = 2
213+
srcInstance.skillMinionSkillCalcs = 2
214+
srcInstance.skillMinionSkillStatSetIndexLookup = { [grantedEffectId] = { [2] = 3 } }
215+
srcInstance.skillMinionSkillStatSetIndexLookupCalcs = { [grantedEffectId] = { [2] = 2 } }
216+
217+
reimportSingleGem("Linen Wraps", "Gloves", "Skeletal Sniper")
218+
219+
socketGroup = build.skillsTab.socketGroupList[1]
220+
activeEffect = socketGroup.displaySkillList[1].activeEffect
221+
grantedEffectId = activeEffect.grantedEffect.id
222+
srcInstance = activeEffect.srcInstance
223+
assert.are.equal(2, srcInstance.skillMinionSkill)
224+
assert.are.equal(2, srcInstance.skillMinionSkillCalcs)
225+
assert.are.equal(3, srcInstance.skillMinionSkillStatSetIndexLookup[grantedEffectId][2])
226+
assert.are.equal(2, srcInstance.skillMinionSkillStatSetIndexLookupCalcs[grantedEffectId][2])
227+
end)
228+
229+
it("preserves active skill stat set when reimporting items and skills", function()
230+
build.skillsTab:PasteSocketGroup([[
231+
Fireball 20/0 1
232+
]])
233+
runCallback("OnFrame")
234+
235+
local socketGroup = build.skillsTab.socketGroupList[1]
236+
local activeEffect = socketGroup.displaySkillList[1].activeEffect
237+
local grantedEffectId = activeEffect.grantedEffect.id
238+
local srcInstance = activeEffect.srcInstance
239+
srcInstance.statSet = { [grantedEffectId] = 3 }
240+
srcInstance.statSetCalcs = { [grantedEffectId] = 2 }
241+
242+
reimportSingleGem("Linen Wraps", "Gloves", "Fireball")
243+
244+
socketGroup = build.skillsTab.socketGroupList[1]
245+
activeEffect = socketGroup.displaySkillList[1].activeEffect
246+
grantedEffectId = activeEffect.grantedEffect.id
247+
srcInstance = activeEffect.srcInstance
248+
assert.are.equal(3, srcInstance.statSet[grantedEffectId])
249+
assert.are.equal(2, srcInstance.statSetCalcs[grantedEffectId])
250+
end)
251+
end)

spec/System/TestItemMods_spec.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ describe("TetsItemMods", function()
246246
{range:1}(15-20)% increased Cold Damage per 1% Missing Cold Resistance, up to a maximum of 300%
247247
{range:1}(15-20)% increased Fire Damage per 1% Missing Fire Resistance, up to a maximum of 300%]])
248248
build.itemsTab:AddDisplayItem()
249-
build.skillsTab:PasteSocketGroup("Slot: Weapon 1\nFireball 20/0 Default 1\n")
249+
build.skillsTab:PasteSocketGroup("Slot: Weapon 1\nFireball 20/0 1\n")
250250
runCallback("OnFrame")
251251

252252
assert.are_not.equals(340, build.calcsTab.mainEnv.modDB:Sum("INC", "FireDamage"))

spec/System/TestItemParse_spec.lua

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,18 @@ describe("TestItemParse", function()
329329
assert.truthy(item.explicitModLines[1].custom)
330330
end)
331331

332+
it("crafted", function()
333+
local item = new("Item", raw("{crafted}+8 to Strength"))
334+
assert.truthy(item.explicitModLines[1].crafted)
335+
end)
336+
337+
it("preserves crafted mod lines when rebuilding raw text", function()
338+
local item = new("Item", raw("+8 to Strength"))
339+
item.explicitModLines[1].crafted = true
340+
item:BuildAndParseRaw()
341+
assert.truthy(item.explicitModLines[1].crafted)
342+
end)
343+
332344
it("enchant", function()
333345
local item = new("Item", raw("+8 to Strength (enchant)"))
334346
assert.are.equals(1, #item.enchantModLines)
@@ -448,6 +460,22 @@ describe("TestItemParse", function()
448460
end
449461
end)
450462

463+
it("keeps bonded rune stats separate from normal rune stats", function()
464+
local item = new("Item", [[
465+
Rarity: Rare
466+
Test Body
467+
Rusted Cuirass
468+
]])
469+
item.itemSocketCount = 1
470+
item.runes = { "Lesser Body Rune" }
471+
item:UpdateRunes()
472+
473+
assert.are.equals(3, #item.runeModLines)
474+
assert.are.equals("+30 to maximum Life", item.runeModLines[1].line)
475+
assert.are.equals("Bonded: +20 to maximum Life", item.runeModLines[2].line)
476+
assert.are.equals("Bonded: +20 to maximum Mana", item.runeModLines[3].line)
477+
end)
478+
451479
it("multi-line rune mod", function()
452480
-- Thruldana is Bow-only as well
453481
local item = new("Item", [[

0 commit comments

Comments
 (0)