Skip to content

Commit 553509e

Browse files
committed
Merge branch 'advanced_copy_paste' of https://github.com/Wires77/PathOfBuilding into advanced_copy_paste
2 parents b2f5aec + d71f089 commit 553509e

35 files changed

Lines changed: 1266 additions & 481 deletions

CONTRIBUTING.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,15 @@ More tests can be added to this folder to test specific functionality, or new te
224224
Please try to include tests for your new features in your pull request. Additionally, if your pr breaks a test that should be passing please update it accordingly.
225225

226226
### Debugging tests
227-
When running tests with a docker container it is possible to use EmmyLua for debugging. Follow the instructions for inserting the debugger snippet as shown above in [Visual Studio Code](#Visual-Studio-Code), then uncomment the `dbg.waitIDE()` line.
228-
229-
After running `docker-compose up` the code will wait at that line until a debugger is attached. This will allow stepping through any code that is internal to POB but will not work for busted related code. Note that this only works for unit tests described above.
227+
When running tests with a docker container it is possible to use EmmyLua for debugging. Paste in the following right under `function launch:OnInit()` in `./src/Launch.lua`:
228+
```lua
229+
package.cpath = package.cpath .. ";/usr/local/bin/?.so"
230+
local dbg = require("emmy_core")
231+
-- This port must match the IDE Code configuration. Default is 9966.
232+
dbg.tcpListen("localhost", 9966)
233+
dbg.waitIDE()
234+
```
235+
After running `docker-compose up` the code will wait at the `dbg.waitIDE()` line until a debugger is attached. This will allow stepping through any code that is internal to POB but will not work for busted related code. Note that this only works for unit tests described above.
230236

231237
## Path of Building development tutorials
232238

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/TestItemParse_spec.lua

Lines changed: 85 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,13 @@ describe("TestItemParse", function()
392392
assert.truthy(item.explicitModLines[1].synthesis)
393393
end)
394394

395+
it("unscalable", function()
396+
local item = new("Item", raw("{unscalable}+8 to Strength"))
397+
assert.truthy(item.explicitModLines[1].unscalable)
398+
item = new("Item", raw("+8 to Strength - Unscalable Value"))
399+
assert.truthy(item.explicitModLines[1].unscalable)
400+
end)
401+
395402
it("multiple bases", function()
396403
local item = new("Item", [[
397404
Ashcaller
@@ -466,93 +473,94 @@ describe("TestItemParse", function()
466473
end)
467474
end)
468475

469-
describe("TestAdvancedItemParse", function()
470-
it("parses item", function()
471-
local advancedItem = new("Item", [[
472-
Item Class: Belts
473-
Rarity: Rare
474-
Beast Snare
475-
Cord Belt
476-
--------
477-
Requirements:
478-
Level: 51
479-
--------
480-
Item Level: 83
481-
--------
482-
Allocates Surveillance (enchant)
483-
--------
484-
{ Implicit Modifier }
485-
Can be Anointed
486-
--------
487-
{ Fractured Prefix Modifier "Thorny" (Tier: 2) — Damage, Physical }
488-
Reflects 3(1-4) Physical Damage to Melee Attackers
476+
describe("TestAdvancedItemParse #item", function()
477+
local function raw(s, base)
478+
base = base or "Plate Vest"
479+
return "Rarity: Rare\nName\n"..base.."\n"..s
480+
end
481+
482+
it("parses to craft", function()
483+
local item = new("Item", raw([[
489484
{ Prefix Modifier "Fecund" (Tier: 1) — Life }
490485
+142(130-144) to maximum Life
491-
{ Prefix Modifier "Glowing" (Tier: 9) — Defences, Energy Shield }
492-
+15(13-15) to maximum Energy Shield
493-
{ Suffix Modifier "of the Tempest" (Tier: 4) — Elemental, Lightning, Resistance }
494-
+34(30-35)% to Lightning Resistance
486+
]], "Cord Belt"))
487+
assert.are.equals("IncreasedLife9", item.prefixes[1].modId)
488+
assert.are.equals(0.857, item.prefixes[1].range)
489+
assert.are.equals("life", item.explicitModLines[1].modTags[1])
490+
item = new("Item", raw([[
495491
{ Master Crafted Suffix Modifier "of Craft" (Rank: 3) — Elemental, Cold, Resistance }
496492
+35(29-35)% to Cold Resistance
497-
--------
498-
Fractured Item
499-
]])
493+
]], "Cord Belt"))
494+
assert.truthy(item.explicitModLines[1].crafted)
495+
end)
500496

501-
local equivalentCraftItem = new("Item", [[
502-
Beast Snare
503-
Cord Belt
504-
Crafted: true
505-
Prefix: {range:0.599}AttackerTakesDamage1
506-
Prefix: {range:0.859}IncreasedLife9
507-
Prefix: {range:0.845}IncreasedEnergyShield4
508-
Suffix: {range:0.732}LightningResist5
509-
Suffix: None
510-
Suffix: None
511-
LevelReq: 51
512-
Implicits: 1
513-
{crafted}Allocates Surveillance
514-
Can be Anointed
515-
+15 to maximum Energy Shield
516-
+142 to maximum Life
517-
+34% to Lightning Resistance
518-
Reflects 3 Physical Damage to Melee Attackers
519-
{tags:elemental,cold,resistance}{crafted}{range:1}+(29-35)% to Cold Resistance
520-
]])
497+
it("parses correct range", function()
498+
local item = new("Item", raw([[
499+
{ Prefix Modifier "Freezing" (Tier: 5) — Damage, Elemental, Cold, Caster — 8% Increased }
500+
Adds 17(16-20) to 35(30-36) Cold Damage to Spells
501+
]], "Void Sceptre"))
502+
assert.are.equals("Adds 17 to 35 Cold Damage to Spells", item.explicitModLines[1].line)
503+
end)
521504

522-
assert.are.equals(advancedItem:BuildRaw(), equivalentCraftItem:BuildRaw())
505+
-- GGG scales each mod line separately here, but PoB scales them both together, so this parsing is a bit wonky
506+
it("parses multi-line mod", function()
507+
local item = new("Item", raw([[
508+
{ Prefix Modifier "Warlock's" (Tier: 4) — Mana, Damage, Caster }
509+
32(30-37)% increased Spell Damage
510+
+46(42-47) to maximum Mana
511+
]], "Royal Staff"))
512+
assert.are.equals("SpellDamageAndManaOnTwoHandWeapon4", item.prefixes[1].modId)
513+
assert.are.equals(0.286, item.prefixes[1].range)
514+
assert.are.equals(0.8, item.explicitModLines[2].range)
515+
end)
523516

524-
local catalyst = new("Item", [[
525-
Item Class: Amulets
526-
Rarity: Unique
527-
Astramentis
528-
Onyx Amulet
529-
--------
530-
Quality (Attribute Modifiers): +20% (augmented)
531-
--------
532-
Requirements:
533-
Level: 20
534-
--------
535-
Item Level: 80
536-
--------
537-
Allocates Weathered Hunter (enchant)
517+
it("resets linePrefix", function()
518+
local item = new("Item", raw([[
519+
{ Prefix Modifier "Warlock's" (Tier: 4) — Mana, Damage, Caster }
520+
32(30-37)% increased Spell Damage
521+
+46(42-47) to maximum Mana
538522
--------
539-
{ Implicit Modifier — Attribute — 20% Increased }
540-
+16(10-16) to all Attributes
523+
+15 to maximum life
524+
]], "Royal Staff"))
525+
assert.are_not.equals("mana", item.explicitModLines[3].modTags[1])
526+
end)
527+
528+
it("parses vaaled catalyst", function()
529+
local item = new("Item", raw([[
530+
Quality (Attribute Modifiers): +19% (augmented)
531+
{ Unique Modifier — Attribute — 19% Increased }
532+
+120(80-100) to all Attributes
541533
(Attributes are Strength, Dexterity, and Intelligence)
542-
--------
543-
{ Unique Modifier — Attribute — 20% Increased }
544-
+86(80-100) to all Attributes
534+
]], "Onyx Amulet"))
535+
assert.are.equals(142, item.baseModList[1].value)
536+
-- assert.falsy(item.explicitModLines[1].range) -- Not sure why this is returning 0.5
537+
assert.are.equals(6, item.catalyst)
538+
assert.are.equals(19, item.catalystQuality)
539+
end)
540+
541+
it("parses vaaled catalyst within range", function()
542+
local item = new("Item", raw([[
543+
Quality (Attribute Modifiers): +19% (augmented)
544+
{ Unique Modifier — Attribute — 19% Increased }
545+
+95(80-100) to all Attributes
545546
(Attributes are Strength, Dexterity, and Intelligence)
546-
{ Unique Modifier — Physical, Attack }
547-
-4 Physical Damage taken from Attack Hits
548-
--------
549-
Mindless rage will shake the world,
550-
Cunning lies will bend it.
551-
Reckless haste will break the world,
552-
And into darkness send it.
553-
--------
554-
Note: ~b/o 50 chaos
555-
]])
547+
]], "Onyx Amulet"))
548+
assert.are.equals(113, item.baseModList[1].value)
549+
assert.are.equals(0.75, item.explicitModLines[1].range)
550+
assert.are.equals(6, item.catalyst)
551+
assert.are.equals(19, item.catalystQuality)
552+
end)
553+
554+
it("doesn't scale unscalable", function()
555+
local item = new("Item", raw([[
556+
Quality (Life and Mana Modifiers): +20% (augmented)
557+
{ Unique Modifier — Life, Defences, Energy Shield, Minion, Gem }
558+
Socketed Golem Skills gain 20% of Maximum Life as Extra Maximum Energy Shield — Unscalable Value
559+
]]))
560+
assert.are.equals(20, item.baseModList[1].value.mod.value)
561+
end)
562+
563+
it("parses junk", function()
556564
local godTestItem = new("Item", [[
557565
Item Class: Sceptres
558566
Rarity: Unique

0 commit comments

Comments
 (0)