Skip to content

Commit c14157c

Browse files
committed
Merge branch 'dev' into spectre-updates
2 parents 5bd66a7 + 0fc3283 commit c14157c

37 files changed

Lines changed: 1127 additions & 381 deletions

CONTRIBUTING.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,14 @@ Files in `/Data` `/Export` and `/TreeData` can be massive and cause the EmmyLua
177177
```json
178178
{
179179
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
180+
"runtime": {
181+
"version": "LuaJIT"
182+
},
180183
"workspace": {
181184
"ignoreGlobs": [
182-
"src/Data/**.lua",
183-
"src/TreeData/**.lua",
184-
"src/Modules/ModParser.lua"
185+
"**/src/Data/**/*.lua",
186+
"**/src/TreeData/**/*.lua",
187+
"**/src/Modules/ModParser.lua"
185188
]
186189
}
187190
}

spec/System/TestDefence_spec.lua

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,53 @@ describe("TestDefence", function()
378378
assert.are.equals(15, build.calcsTab.calcsOutput.LightningResistOverCap)
379379
end)
380380

381+
it("ward chance to not break increases effective hit pool", function()
382+
build.configTab.input.enemyIsBoss = "None"
383+
build.configTab.input.customMods = "\z
384+
+940 to maximum life\n\z
385+
+200 to Ward\n\z
386+
"
387+
build.configTab:BuildModList()
388+
runCallback("OnFrame")
389+
assert.are.equals(987, build.calcsTab.calcsOutput.TotalEHP)
390+
assert.are.equals(1200, build.calcsTab.calcsOutput.PhysicalMaximumHitTaken)
391+
392+
build.configTab.input.customMods = "\z
393+
+940 to maximum life\n\z
394+
+200 to Ward\n\z
395+
Ward has a 50% chance to not Break\n\z
396+
"
397+
build.configTab:BuildModList()
398+
runCallback("OnFrame")
399+
assert.are.equals(994, build.calcsTab.calcsOutput.TotalEHP)
400+
assert.are.equals(1200, build.calcsTab.calcsOutput.PhysicalMaximumHitTaken)
401+
end)
402+
403+
it("small hits bypass unbroken ward", function()
404+
build.configTab.input.enemyIsBoss = "None"
405+
build.configTab.input.customMods = "\z
406+
+940 to maximum life\n\z
407+
+200 to Ward\n\z
408+
Damage taken bypasses Unbroken Ward if the Hit deals less Damage than 15% of Ward\n\z
409+
"
410+
build.configTab:BuildModList()
411+
runCallback("OnFrame")
412+
assert.are.equals(350, build.calcsTab.calcsOutput.TotalEHP)
413+
assert.are.equals(1200, build.calcsTab.calcsOutput.PhysicalMaximumHitTaken)
414+
415+
local poolsRemaining = poolsRemainingAfterTypeMaxHit("Physical")
416+
assert.are.equals(0, poolsRemaining.Ward)
417+
assert.are.equals(0, poolsRemaining.Life)
418+
419+
poolsRemaining = build.calcsTab.calcs.reducePoolsByDamage(nil, { Physical = 29 }, build.calcsTab.calcsEnv.player)
420+
assert.are.equals(200, poolsRemaining.Ward)
421+
assert.are.equals(971, poolsRemaining.Life)
422+
423+
poolsRemaining = build.calcsTab.calcs.reducePoolsByDamage(nil, { Physical = 30 }, build.calcsTab.calcsEnv.player)
424+
assert.are.equals(0, poolsRemaining.Ward)
425+
assert.are.equals(1000, poolsRemaining.Life)
426+
end)
427+
381428
-- fun part
382429
it("armoured max hits", function()
383430
build.configTab.input.enemyIsBoss = "None"
@@ -945,8 +992,19 @@ describe("TestDefence", function()
945992

946993
-- Get the base + Shabby Jerkin to make this test more adaptable to changes
947994
local ironReflexesArmour = build.calcsTab.mainOutput.Armour - baseArmour - baseEvasion
995+
assert.are.equals(ironReflexesArmour + baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
996+
997+
build.configTab.input.customMods = [[
998+
Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating
999+
you have no dexterity
1000+
Gain no armour from equipped body armour
1001+
]]
1002+
build.configTab:BuildModList()
1003+
runCallback("OnFrame")
1004+
-- Iron Reflexes and Prospero's Protection
1005+
assert.are.equals(baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
9481006

949-
print("build.calcsTab.mainOutput.Armour:" .. build.calcsTab.mainOutput.Armour)
1007+
--print("build.calcsTab.mainOutput.Armour:" .. build.calcsTab.mainOutput.Armour)
9501008

9511009
build.configTab.input.customMods = [[
9521010
Armour from Equipped Body Armour is doubled
@@ -955,7 +1013,6 @@ describe("TestDefence", function()
9551013
]]
9561014
build.configTab:BuildModList()
9571015
runCallback("OnFrame")
958-
9591016
-- Evasion from Body Armour is converted to Armour before being doubled
9601017
assert.are.equals(2*ironReflexesArmour + baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
9611018

@@ -967,25 +1024,21 @@ describe("TestDefence", function()
9671024
]]
9681025
build.configTab:BuildModList()
9691026
runCallback("OnFrame")
970-
9711027
-- Only the base armour from the chest is affected.
9721028
-- Armour converted with Iron Reflexes still applies
973-
assert.are.equals(2*ironReflexesArmour + baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
1029+
assert.are.equals(baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
1030+
9741031
build.configTab.input.customMods = [[
9751032
Armour from Equipped Body Armour is doubled
9761033
Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating
977-
Gain no armour from equipped body armour
9781034
defences from equipped body armour are doubled if it has no socketed gems
9791035
you have no dexterity
9801036
]]
9811037
build.configTab:BuildModList()
9821038
runCallback("OnFrame")
983-
984-
-- Oath Of Maji double defences stack with Unbreakable
9851039
assert.are.equals(2*2*ironReflexesArmour + baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
9861040

9871041
build.configTab.input.customMods = [[
988-
Armour from Equipped Body Armour is doubled
9891042
Armour from Equipped Body Armour is doubled
9901043
Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating
9911044
Gain no armour from equipped body armour
@@ -994,7 +1047,17 @@ describe("TestDefence", function()
9941047
]]
9951048
build.configTab:BuildModList()
9961049
runCallback("OnFrame")
1050+
assert.are.equals(baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
9971051

1052+
build.configTab.input.customMods = [[
1053+
Armour from Equipped Body Armour is doubled
1054+
Armour from Equipped Body Armour is doubled
1055+
Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating
1056+
defences from equipped body armour are doubled if it has no socketed gems
1057+
you have no dexterity
1058+
]]
1059+
build.configTab:BuildModList()
1060+
runCallback("OnFrame")
9981061
-- Mod form unbreakable should apply only once
9991062
assert.are.equals(2*2*ironReflexesArmour + baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
10001063

@@ -1004,14 +1067,37 @@ describe("TestDefence", function()
10041067
Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating
10051068
Gain no armour from equipped body armour
10061069
defences from equipped body armour are doubled if it has no socketed gems
1007-
defences from equipped body armour are doubled if it has no socketed gems
10081070
you have no dexterity
10091071
]]
10101072
build.configTab:BuildModList()
10111073
runCallback("OnFrame")
1074+
assert.are.equals(baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
10121075

1076+
build.configTab.input.customMods = [[
1077+
Armour from Equipped Body Armour is doubled
1078+
Armour from Equipped Body Armour is doubled
1079+
Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating
1080+
defences from equipped body armour are doubled if it has no socketed gems
1081+
defences from equipped body armour are doubled if it has no socketed gems
1082+
you have no dexterity
1083+
]]
1084+
build.configTab:BuildModList()
1085+
runCallback("OnFrame")
10131086
-- Oath Of Maji should apply only once
10141087
assert.are.equals(2*2*ironReflexesArmour + baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
1088+
1089+
build.configTab.input.customMods = [[
1090+
Armour from Equipped Body Armour is doubled
1091+
Armour from Equipped Body Armour is doubled
1092+
Converts all Evasion Rating to Armour. Dexterity provides no bonus to Evasion Rating
1093+
Gain no armour from equipped body armour
1094+
defences from equipped body armour are doubled if it has no socketed gems
1095+
defences from equipped body armour are doubled if it has no socketed gems
1096+
you have no dexterity
1097+
]]
1098+
build.configTab:BuildModList()
1099+
runCallback("OnFrame")
1100+
assert.are.equals(baseArmour + baseEvasion, build.calcsTab.mainOutput.Armour)
10151101
end)
10161102

10171103
it("MoM + EB", function()

spec/System/TestItemTools_spec.lua

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,42 @@ describe("TestItemTools", function()
4545
assert.are.equals(expected, result)
4646
end)
4747
end
48-
end)
48+
49+
it("uses the displayed item slot for anoint comparison tooltips", function()
50+
if not common.classes.ItemsTab then
51+
LoadModule("Classes/ItemsTab")
52+
end
53+
local item = new("Item", [[
54+
Rarity: Rare
55+
Dire Thread
56+
Cord Belt
57+
Can be Anointed
58+
]])
59+
local overrides = { }
60+
local fakeItemsTab = setmetatable({
61+
displayItem = item,
62+
build = {
63+
spec = { allocNodes = { } },
64+
calcsTab = {
65+
GetMiscCalculator = function()
66+
return function(override)
67+
table.insert(overrides, override)
68+
return { }
69+
end
70+
end,
71+
},
72+
AddStatComparesToTooltip = function()
73+
return 1
74+
end,
75+
},
76+
}, common.classes.ItemsTab)
77+
local tooltip = {
78+
AddLine = function() end,
79+
}
80+
81+
fakeItemsTab:AppendAnointTooltip(tooltip, { id = 1, dn = "Acrimony" })
82+
83+
assert.are.equals("Belt", overrides[1].repSlotName)
84+
assert.are.equals("Belt", overrides[2].repSlotName)
85+
end)
86+
end)

spec/System/TestSkills_spec.lua

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,38 @@ describe("TestAttacks", function()
100100
assert.True(build.calcsTab.mainEnv.enemyDB:Sum("BASE", nil, "FireResist") < 0)
101101
end)
102102

103+
it("Defaults Blade Blast to the skill's blade cap", function()
104+
build.skillsTab:PasteSocketGroup("Blade Blast 20/0 1\n")
105+
runCallback("OnFrame")
106+
107+
local mainSocketGroup = build.skillsTab.socketGroupList[build.mainSocketGroup]
108+
local activeSkill = mainSocketGroup.displaySkillList[mainSocketGroup.mainActiveSkill]
109+
local calcsSkillSelectControls = build.calcsTab.sectionList[1].controls
110+
build:RefreshSkillSelectControls(calcsSkillSelectControls, build.calcsTab.input.skill_number, "Calcs")
111+
112+
assert.are.equals("50", build.controls.mainSkillStageCount.buf)
113+
assert.are.equals("50", calcsSkillSelectControls.mainSkillStageCount.buf)
114+
assert.are.equals(50, activeSkill.skillData.stagesMax)
115+
assert.are.equals(50, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "Multiplier:BladeBlastStage"))
116+
assert.are.equals(49, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "Multiplier:BladeBlastStageAfterFirst"))
117+
118+
local cappedAverageDamage = build.calcsTab.mainOutput.AverageDamage
119+
local cappedTotalDPS = build.calcsTab.mainOutput.TotalDPS
120+
local cappedCombinedDPS = build.calcsTab.mainOutput.CombinedDPS
121+
activeSkill.activeEffect.srcInstance.skillStageCount = 51
122+
build.modFlag = true
123+
build.buildFlag = true
124+
runCallback("OnFrame")
125+
126+
activeSkill = mainSocketGroup.displaySkillList[mainSocketGroup.mainActiveSkill]
127+
assert.are.equals("51", build.controls.mainSkillStageCount.buf)
128+
assert.are.equals(50, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "Multiplier:BladeBlastStage"))
129+
assert.are.equals(49, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "Multiplier:BladeBlastStageAfterFirst"))
130+
assert.are.equals(cappedAverageDamage, build.calcsTab.mainOutput.AverageDamage)
131+
assert.are.equals(cappedTotalDPS, build.calcsTab.mainOutput.TotalDPS)
132+
assert.are.equals(cappedCombinedDPS, build.calcsTab.mainOutput.CombinedDPS)
133+
end)
134+
103135
it("Test Adrenaline affecting blight max stage count", function()
104136
build.skillsTab:PasteSocketGroup("Blight 20/0 1\n")
105137
runCallback("OnFrame")

spec/System/TestTreeTab_spec.lua

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
describe("TreeTab", function()
2+
local originalClusterNodeMap
3+
local originalMasteryEffects
4+
5+
before_each(function()
6+
newBuild()
7+
originalClusterNodeMap = build.spec.tree.clusterNodeMap
8+
originalMasteryEffects = build.spec.tree.masteryEffects
9+
end)
10+
11+
after_each(function()
12+
build.spec.tree.clusterNodeMap = originalClusterNodeMap
13+
build.spec.tree.masteryEffects = originalMasteryEffects
14+
end)
15+
16+
it("adds separate power report entries for mastery effects", function()
17+
local treeTab = build.treeTab
18+
local parentNode = { id = 2 }
19+
local masteryNode = {
20+
id = 1,
21+
type = "Mastery",
22+
dn = "Two Hand Mastery",
23+
power = {
24+
masteryEffects = {
25+
[101] = { singleStat = 10, pathPower = 10 },
26+
[102] = { singleStat = 20, pathPower = 20 },
27+
},
28+
},
29+
masteryEffects = {
30+
{ effect = 101 },
31+
{ effect = 102 },
32+
},
33+
path = { parentNode, false },
34+
x = 10,
35+
y = 20,
36+
}
37+
masteryNode.path[2] = masteryNode
38+
39+
treeTab.build.displayStats = {
40+
{ stat = "Damage", label = "Damage", fmt = ".1f" },
41+
}
42+
treeTab.build.spec.nodes = {
43+
[masteryNode.id] = masteryNode,
44+
}
45+
treeTab.build.spec.masterySelections = { }
46+
treeTab.build.spec.tree.clusterNodeMap = { }
47+
treeTab.build.spec.tree.masteryEffects = {
48+
[101] = { id = 101, sd = { "Gain 10 Damage" }, stats = { "Gain 10 Damage" } },
49+
[102] = { id = 102, sd = { "Gain 20 Damage" }, stats = { "Gain 20 Damage" } },
50+
}
51+
treeTab.build.calcsTab.mainEnv = { grantedPassives = { } }
52+
53+
local report = treeTab:BuildPowerReportList({ stat = "Damage", label = "Damage" })
54+
55+
assert.are.same(2, #report)
56+
assert.are.same("Mastery", report[1].type)
57+
assert.are.same("Two Hand Mastery: Gain 20 Damage", report[1].name)
58+
assert.are.same(20, report[1].power)
59+
assert.are.same(2, report[1].pathDist)
60+
assert.are.same(10, report[2].power)
61+
assert.are.same("Two Hand Mastery: Gain 10 Damage", report[2].name)
62+
end)
63+
end)

0 commit comments

Comments
 (0)