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
3 changes: 0 additions & 3 deletions spec/System/TestAttacks_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -441,20 +441,17 @@ describe("TestAttacks", function()

build.itemsTab:CreateDisplayItemFromRaw(slowHighDmgMace)
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")
build.itemsTab.slots["Weapon 1"]:SetSelItemId(build.itemsTab.items[1].id)

build.itemsTab:CreateDisplayItemFromRaw(fastLowDmgMace)
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")
build.itemsTab.slots["Weapon 2"]:SetSelItemId(build.itemsTab.items[2].id)

build.configTab.input.customMods = [[
nearby enemies have 100% less armour
your hits can't be evaded
]]
build.configTab:BuildModList()
runCallback("OnFrame")
end

local function harmonicMean(a, b)
Expand Down
153 changes: 152 additions & 1 deletion spec/System/TestImportReimport_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,31 @@ Fireball 20/0 1
assert.are.equal(0, build.itemsTab.slots["Gloves Jewel Socket 2"].selItemId)
end)

it("resolves imported default attack variants from equipment when weapon requirements are absent", function()
for _, case in ipairs({
{ false, false, "1HMace" }, -- Unarmed Facebreaker fallback
{ "Wooden Club", false, "1HMace" },
{ "Wooden Club", "Splintered Tower Shield", "1HMace" },
{ "Wooden Club", "Wooden Club", "MaceMace" },
{ "Ironwood Greathammer", false, "2HMace" },
{ "Hardwood Spear", false, "Spear", "Spear Stab" },
{ "Hardwood Spear", "Leather Buckler", "SpearOffHand", "Spear Stab" },
{ "Hardwood Spear", "Splintered Tower Shield", "Spear", "Spear Stab" },
}) do
newBuild()
local equipment = { }
if case[1] then table.insert(equipment, makeImportItem(case[1], "Weapon", "main-hand")) end
if case[2] then table.insert(equipment, makeImportItem(case[2], "Offhand", "off-hand")) end
local skill = makeGemEntry(false, case[4] or "Mace Strike", 1, { makeGemEntry(true, "Minion Pact I", 1) })
build.importTab:ImportItemsAndSkills(buildImportPayload(equipment, { skill }))
local group = build.skillsTab.socketGroupList[1]
assert.are.equals(case[4] and 2 or 1, #build.skillsTab.socketGroupList) -- Spears also grant Spear Throw.
assert.are.equals("Metadata/Items/Gems/SkillGemPlayerDefault" .. case[3], group.gemList[1].gemData.id)
assert.are.equals(2, #group.gemList)
assert.are.equals("Minion Pact I", group.gemList[2].nameSpec)
end
end)

it("keeps an imported shield equipped with Bringer of Rain and a two-handed mace", function()
build.importTab.controls.charImportItemsClearItems.state = true
build.importTab.controls.charImportItemsClearSkills.state = true
Expand All @@ -283,7 +308,133 @@ Fireball 20/0 1

assert.are_not.equal(0, build.itemsTab.slots["Weapon 1 Swap"].selItemId)
assert.are_not.equal(0, build.itemsTab.slots["Weapon 2 Swap"].selItemId)
assert.are.equal("Metadata/Items/Gems/SkillGemPlayerDefault2HMace", build.skillsTab.socketGroupList[1].gemList[1].gemId)
assert.are.equal("Metadata/Items/Gems/SkillGemPlayerDefault2HMace", build.skillsTab.socketGroupList[1].gemList[1].gemData.id)
end)

it("imports level-one Spear Throw entries into auto-levelled default attack groups", function()
local spear1 = makeImportItem("Soaring Spear", "Weapon", "spear-1")
local spear2 = makeImportItem("Grand Spear", "Weapon2", "spear-2")
for _, spear in ipairs({ spear1, spear2 }) do
spear.grantedSkills = { { name = "Grants Skill", values = { { "Spear Throw", 25 } } } }
end
local payload = buildImportPayload({ spear1, spear2 }, {
makeGemEntry(false, "Spear Throw", 1, { makeGemEntry(true, "Minion Pact I", 1) }),
makeGemEntry(false, "Spear Throw", 1),
})
payload.level = 90
build.importTab.controls.charImportItemsClearSkills.state = true
for _ = 1, 2 do
build.importTab:ImportItemsAndSkills(payload)
runCallback("OnFrame")
local groups, supports = 0, 0
local slots = { }
for _, group in ipairs(build.skillsTab.socketGroupList) do
if group.gemList[1].skillId == "SpearThrowPlayer" then
groups = groups + 1
supports = supports + #group.gemList - 1
assert.are.equals("Default Attack", group.source)
assert.are.equals(20, group.gemList[1].level)
slots[group.slot] = true
end
end
assert.are.equals(2, groups)
assert.are.equals(1, supports)
assert.is_true(slots["Weapon 1"])
assert.is_true(slots["Weapon 1 Swap"])
end
end)

it("assigns imported skills to their only valid weapon set immediately", function()
build.importTab.controls.charImportItemsClearItems.state = true
build.importTab.controls.charImportItemsClearSkills.state = true

build.importTab:ImportItemsAndSkills(buildImportPayload({
makeImportItem("Crude Bow", "Weapon", "test-import-bow"),
}, {
makeGemEntry(false, "Mirage Archer", 20, {
makeGemEntry(false, "Ice Shot", 20),
}),
}))

local mirageArcher = build.skillsTab.socketGroupList[1]
assert.is_true(mirageArcher.set1)
assert.is_false(mirageArcher.set2)
end)

it("attaches imported item-granted skills to their generated source group", function()
build.importTab.controls.charImportItemsClearItems.state = true
build.importTab.controls.charImportItemsClearSkills.state = true

local sceptre = makeImportItem("Stoic Sceptre", "Offhand")
sceptre.explicitMods = { "Grants Skill: Level 20 Azmerian Wolf" }
build.importTab:ImportItemsAndSkills(buildImportPayload({ sceptre }, {
makeGemEntry(false, "Azmerian Wolf", 20, {
makeGemEntry(true, "Feeding Frenzy II", 1),
}),
}))
runCallback("OnFrame")

local wolfGroups = { }
for _, socketGroup in ipairs(build.skillsTab.socketGroupList) do
if socketGroup.gemList[1] and socketGroup.gemList[1].nameSpec == "Azmerian Wolf" then
table.insert(wolfGroups, socketGroup)
end
end
assert.are.equal(1, #wolfGroups)
assert.are.equal("Weapon 2", wolfGroups[1].slot)
assert.is_not_nil(wolfGroups[1].sourceItem)
assert.is_true(wolfGroups[1].gemList[1].fromItem)
assert.are.equal("Feeding Frenzy II", wolfGroups[1].gemList[2].nameSpec)
end)

it("downlevels item-granted skills to meet attribute requirements", function()
build.importTab.controls.charImportItemsClearItems.state = true
build.importTab.controls.charImportItemsClearSkills.state = true
build.configTab.modList:NewMod("Str", "BASE", 98 - build.calcsTab.mainOutput.Str, "Test")
build.configTab.modList:NewMod("Int", "BASE", 107 - build.calcsTab.mainOutput.Int, "Test")
local sceptre = makeImportItem("Stoic Sceptre", "Offhand")
sceptre.explicitMods = { "Grants Skill: Level 19 Discipline" }
local payload = buildImportPayload({ sceptre }, {
makeGemEntry(false, "Discipline", 19),
})
payload.level = 94
build.importTab:ImportItemsAndSkills(payload)
runCallback("OnFrame")

local discipline = build.skillsTab.socketGroupList[1].gemList[1]
assert.are.equal(19, discipline.sourceLevel)
assert.are.equal(18, discipline.level)
end)

it("attaches imported auto-levelled tree skills to their generated source group", function()
build.importTab.controls.charImportItemsClearItems.state = true
build.importTab.controls.charImportItemsClearSkills.state = true
build.characterLevel = 94
local wildProtectorNode = build.spec.nodes[62743]
wildProtectorNode.alloc = true
wildProtectorNode.allocMode = 0
build.spec.allocNodes[wildProtectorNode.id] = wildProtectorNode

local payload = buildImportPayload({}, {
makeGemEntry(false, "Wild Protector", 20, {
makeGemEntry(true, "Feeding Frenzy II", 1),
}),
})
payload.level = 94
build.importTab:ImportItemsAndSkills(payload)
runCallback("OnFrame")

local protectorGroups = { }
for _, socketGroup in ipairs(build.skillsTab.socketGroupList) do
if socketGroup.gemList[1] and socketGroup.gemList[1].nameSpec == "Wild Protector" then
table.insert(protectorGroups, socketGroup)
end
end
assert.are.equal(1, #protectorGroups)
assert.are.equal(wildProtectorNode, protectorGroups[1].sourceNode)
assert.is_true(protectorGroups[1].gemList[1].fromTree)
assert.are.equal(20, protectorGroups[1].gemList[1].level)
assert.are.equal("Feeding Frenzy II", protectorGroups[1].gemList[2].nameSpec)
end)

it("uses unique database and rune levels when importing unique items from account data", function()
Expand Down
5 changes: 2 additions & 3 deletions spec/System/TestItemMods_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -639,9 +639,8 @@ describe("TetsItemMods", function()
]])
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")
build.skillsTab:PasteSocketGroup("Leap Slam 20/0 1")
runCallback("OnFrame")
assert.True(build.calcsTab.calcsOutput.ChillEffectMod ~= nil)
local skill = build.calcsTab.mainEnv.player.mainSkill
assert.is_true(skill.skillModList:Flag(skill.weapon1Cfg, "CanChill"))
end)

it("ironbound", function()
Expand Down
15 changes: 13 additions & 2 deletions spec/System/TestItemParse_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ describe("TestItemParse", function()
assert.are.equals("UNIQUE", item.rarity)
end)

it("ignores display-only Spear Throw grants without affecting levelled item skills", function()
for _, line in ipairs({ "Grants Skill: Spear Throw", "grants skill: spear throw" }) do
local mods, extra = modLib.parseMod(line)
assert.are.same({ }, mods)
assert.is_nil(extra)
end
local item = new("Item"):Item(raw("Grants Skill: Spear Throw\nGrants Skill: Level 5 Fireball", "Hardwood Spear"))
assert.are.equals(1, #item.grantedSkills)
assert.are.equals("FireballPlayer", item.grantedSkills[1].skillId)
assert.are.equals(5, item.grantedSkills[1].level)
end)

--it("Defence", function()
-- local item = new("Item"):Item(raw("Armour: 25"))
-- assert.are.equals(25, item.armourData.Armour)
Expand Down Expand Up @@ -220,8 +232,7 @@ describe("TestItemParse", function()
assert.are.equals(2, #item.implicitModLines)
assert.are.equals("Bleeding you inflict deals Damage 11% faster", item.implicitModLines[1].line)
assert.are.equals("Grants Skill: Spear Throw", item.implicitModLines[2].line)
assert.are.equals(1, #item.grantedSkills)
assert.are.equals("SpearThrowPlayer", item.grantedSkills[1].skillId)
assert.are.equals(0, #item.grantedSkills)
assert.are.equals("Adds 39 to 62 Fire Damage", item.explicitModLines[1].line)

assert.are.equals("Grants Skill: Level (1-20) Volatile Dead", data.itemBases["Volatile Wand"].implicit)
Expand Down
35 changes: 35 additions & 0 deletions spec/System/TestItemsTab_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,41 @@ describe("TestItemsTab", function()
runCallback("OnFrame")
end)

it("compares weapons in the skill's assigned set, with Both following the Items tab", function()
build.skillsTab:PasteSocketGroup("Spark 20/0 1")
local group = build.skillsTab.displayGroup
build.mainSocketGroup = isValueInArray(build.skillsTab.socketGroupList, group)
local staff = new("Item"):Item("New Item\nWrapped Quarterstaff")
local slots
build.calcsTab.GetMiscCalculator = function()
return function(override)
table.insert(slots, override.repSlotName)
return { }
end, { }
end
build.AddStatComparesToTooltip = function() end
local slotOnlyTooltips = main.slotOnlyTooltips
for _, case in ipairs({
{ true, true, false, "Weapon 1" },
{ true, true, true, "Weapon 1 Swap" },
{ true, false, true, "Weapon 1" },
{ false, true, false, "Weapon 1 Swap" },
}) do
group.set1, group.set2 = case[1], case[2]
build.itemsTab.activeItemSet.useSecondWeaponSet = case[3]
build.buildFlag = true
runCallback("OnFrame")
for _, slotOnly in ipairs({ false, true }) do
main.slotOnlyTooltips = slotOnly
slots = { }
local shownSlot = case[3] and "Weapon 1 Swap" or "Weapon 1"
build.itemsTab:AddItemTooltip(new("Tooltip"):Tooltip(), staff, slotOnly and shownSlot or nil, true)
main.slotOnlyTooltips = slotOnlyTooltips
assert.are.same(slotOnly and { case[4] } or { case[4], case[4] }, slots)
end
end
end)

it("keeps item tooltips for socket slots without note buttons", function()
local item = new("Item"):Item([[Rarity: RARE
Test Jewel
Expand Down
30 changes: 30 additions & 0 deletions spec/System/TestPassiveSpec_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,36 @@ Item Level: 80
end
end)

it("builds opposite-set skill contexts with radius jewels", function()
local nodeId, node = firstNormalJewelSocket(build.spec)
build.spec:AllocNode(node)
socketJewel(nodeId, [[
Rarity: RARE
Test Mind
Time-Lost Sapphire
--------
Radius: Large
--------
Item Level: 80
--------
+10 to Intelligence
]])
build.skillsTab:PasteSocketGroup("Spark 20/0 1")
build.skillsTab:PasteSocketGroup("Elemental Weakness 20/0 1")
build.skillsTab.socketGroupList[1].set1 = true
build.skillsTab.socketGroupList[1].set2 = false
build.skillsTab.socketGroupList[2].set1 = false
build.skillsTab.socketGroupList[2].set2 = true
build.mainSocketGroup = 1
build.buildFlag = true

assert.has_no.errors(function()
runCallback("OnFrame")
end)
assert.True(#build.calcsTab.mainEnv.radiusJewelList > 0)
assert.are.equals(2, build.calcsTab.mainEnv.weaponSetEnvs[2].weaponSet)
end)

it("does not apply jewel socket passive skill effect to jewels in item-granted Zarokh's Gift", function()
local normalNodeId, normalNode = firstNormalJewelSocket(build.spec)
build.spec:AllocNode(normalNode)
Expand Down
Loading
Loading