diff --git a/.gitignore b/.gitignore
index e707d9bac5..0b875171d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ luajit/
spec/test_results.log
spec/test_generation.log
src/luacov.stats.out
+runtime/lua/debugger.lua
# Release
manifest-updated.xml
diff --git a/.gitignore.rej b/.gitignore.rej
new file mode 100644
index 0000000000..cdc562c394
--- /dev/null
+++ b/.gitignore.rej
@@ -0,0 +1,12 @@
+diff a/.gitignore b/.gitignore (rejected hunks)
+@@ -39,4 +40,8 @@ src/Data/TimelessJewelData/*.bin
+ runtime/imgui.ini
+ runtime/SimpleGraphic/SimpleGraphic.log
+
+-src/poe_api_response.json
+\ No newline at end of file
++src/poe_api_response.json
++runtime/SimpleGraphic/Screenshots
++
++.emmyrc.json
++.luarc.json
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5006e56841..7937115535 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -139,6 +139,14 @@ It is recommended to use it over the built-in Lua plugins.
Please note that EmmyLua is not available for other editors based on Visual Studio Code,
such as [VSCodium](https://vscodium.com) or [Eclipse Theia](https://theia-ide.org) but can be built from source if needed.
+Another alternative on VSCode is to use [sumneko's Lua language server](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) along with [actboy168's debugger](https://marketplace.visualstudio.com/items?itemName=actboy168.lua-debug). These can potentially offer more features than EmmyLua, such as conditional breakpoints.
+
+## Runtime environment
+
+It is recommended that you configure your IDE to include `src/_SimpleGraphic.def.lua` somehow. Path of Building runs inside a special Lua environment via SimpleGraphic which implements a small API. These are not defined inside the project, which means that the aforementioned meta/hint file is required for the IDE to know which functions exist. As the file is not included in code, it must be explicitly mentioned as a library in whichever language server you are using, or otherwise it will not be read.
+
+This file is normally not executed, but does contain basic implementations for parts of the API, which allows many parts of PoB to work without running inside SimpleGraphic. If you wish to test individual changes, it might be possible to do so through a script using Luajit directly. To do so, see HeadlessWrapper.lua for an example. It should be noted that some parts of the API (such as subscripts) are not implemented, which means some parts of PoB are unusable.
+
### Visual Studio Code
1. Create a new Debug Configuration of type EmmyLua New Debug
@@ -171,20 +179,60 @@ such as [VSCodium](https://vscodium.com) or [Eclipse Theia](https://theia-ide.or
1. In VSCode click Start Debugging (the green icon) or press F5
1. The debugger should connect
+You might also want to use actboy168 debugger. This is possible by using for example the following launch.json configuration:
+
+```json
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "πattach",
+ "type": "lua",
+ "request": "attach",
+ "stopOnEntry": false,
+ "address": "127.0.0.1:12306",
+ "luaVersion": "luajit",
+ },
+
+ ]
+}
+```
+
+Then, similarly to the EmmyLua example:
+
+1. Find the sub-folder that looks like `actboy168.lua-debug-x.y.z-win32-x64` in `%USERPROFILE%/.vscode/extensions`. Navigate to it and find the `debugger.lua` script under the script folder. Copy this to `runtime/lua`.
+2. Copy-paste the following code snippet into `launch:OnInit()`:
+ ```lua
+ local debugger = require("debugger"):start("127.0.0.1:12306")
+ -- debugger:event("wait") -- Uncomment this line if you want PoB to wait until the debugger is attached.
+ ```
+
+ Note that Linux developers using Wine might need to use the Windows debugger instead of using the VSCode debugger. This can be done by:
+
+ 1. Downloading the .vsix from the VSCode extension page
+ 2. Copying `extension/{script,runtime}` to the `runtime` folder of the PoB directory (i.e., `runtime/runtime`).
+ 3. Copying `debugger.lua` from `runtime/scripts/debugger.lua` to `runtime/lua/debugger.lua`.
+ 4. Using `local debugger = loadfile(GetRuntimePath().."/lua/debugger.lua")():start("127.0.0.1:12306")` instead of the above code to avoid issues with Wine backwards slashes
#### Excluding directories from EmmyLua
Depending on the amount of system ram you have available and the amount that gets assigned to the jvm running the emmylua language server you might run into issues when trying to debug Path of building.
-Files in `/Data` `/Export` and `/TreeData` can be massive and cause the EmmyLua language server to use a significant amount of memory. Sometimes causing the language server to crash. To avoid this and speed up initialization consider adding an `.emmyrc.json` file to the `.vscode` folder in the root of the Path of building folder with the following content:
+Files in `/Data` `/Export` and `/TreeData` can be massive and cause the EmmyLua language server to use a significant amount of memory. Sometimes causing the language server to crash. To avoid this and speed up initialization consider adding an `.emmyrc.json` to the root of the Path of building folder with the following content:
```json
{
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
"runtime": {
- "version": "LuaJIT"
+ "version": "LuaJIT",
+ // this is not technically correct as LoadModule behaviour can
+ // differ from require, but it is useful for now
+ "requireLikeFunction": ["LoadModule"],
},
"workspace": {
"ignoreGlobs": [
+ "**/*_spec.lua",
+ "spec/**/*.lua",
+ "runtime/lua/sha1/lua53_ops.lua",
"**/src/Data/**/*.lua",
"**/src/TreeData/**/*.lua",
"**/src/Modules/ModParser.lua"
@@ -193,6 +241,46 @@ Files in `/Data` `/Export` and `/TreeData` can be massive and cause the EmmyLua
}
```
+This file can be customised according to what you want. It is a good idea to ignore test files as these tend to add things to the global namespace, which will look confusing, and they are designed to be run by Busted. `lua53_ops.lua` produces errors and doesn't actually get imported when using LuaJIT. It can be useful to keep the data and mod parser files, but generally this will increase the time the LSP takes to index the project on startup.
+
+### Excluding directories from Sumneko's language server
+
+If you prefer to not use EmmyLua, the following configuration works well for Sumneko's VS Code extension:
+
+```json
+{
+ "Lua.workspace.ignoreDir": [
+ ".vscode",
+ // these files add things to global that aren't there in normal
+ // operation
+ "spec/*",
+ "src/Export/*",
+ "src/HeadlessWrapper.lua",
+
+ // this has lua 5.3 code which produces errors, but doesn't actually run
+ "src/runtime/lua/sha1/*",
+
+ // avoid overriding the below library setting
+ "src/_SimpleGraphic.def.lua",
+ ],
+ "Lua.diagnostics.disable": ["inject-field"],
+ // disables diagnostics even when you open one of the above
+ "Lua.diagnostics.ignoredFiles": "Disable",
+ "Lua.runtime.version": "LuaJIT",
+ "Lua.workspace.preloadFileSize": 1000,
+ // this is not technically correct as LoadModule behaviour can
+ // differ from require, but it is useful for now
+ "Lua.runtime.special": {
+ "LoadModule": "require"
+ },
+ "Lua.workspace.library": [
+ "src/_SimpleGraphic.def.lua"
+ ],
+}
+```
+
+The extension will automatically skip large files from being preloaded (controlled by `Lua.workspace.preloadFileSize`), so they don't have to be excluded. The configuration file can be found by pressing Ctrl-Shift-P and selecting `Preferences: Open Workspace Settings (JSON)`. If you wish to check test files, you can remove the "ignoredFiles" option and install the busted, LuaFileSystem, and luassert LuaLS addons through `Lua: Open Addon Manager`.
+
### PyCharm Community / IntelliJ Idea Community
1. Create a new "Debug Configuration" of type "Emmy Debugger(NEW)".
@@ -226,6 +314,13 @@ More tests can be added to this folder to test specific functionality, or new te
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.
+It is a good idea to prefer Docker due to it having a very reliable Lua setup. But if you have performance problems with it, installing `busted` locally might help as it tends to be faster to execute:
+
+1. Install Luajit (due to PoB accessing the jit library, it non-Luajit versions might not work)
+2. Install [Luarocks](https://luarocks.org/) (for example, through Scoop or your Linux package manager)
+3. Run `luarocks install busted`
+4. Run `busted --lua=luajit` to run the tests. You can also use e.g. `-p TestUtils_spec.lua` to run a specific file.
+
### Debugging tests
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`:
```lua
diff --git a/manifest.cfg.rej b/manifest.cfg.rej
new file mode 100644
index 0000000000..610e1be6b7
--- /dev/null
+++ b/manifest.cfg.rej
@@ -0,0 +1,10 @@
+diff a/manifest.cfg b/manifest.cfg (rejected hunks)
+@@ -10,7 +10,7 @@ exclude-directories =
+
+ [program]
+ path = src
+-exclude-files = HeadlessWrapper.lua,LaunchInstall.lua,Settings.xml
++exclude-files = HeadlessWrapper.lua,LaunchInstall.lua,Settings.xml,_SimpleGraphic.def.lua
+ exclude-directories = src/Export,src/TreeData,src/Builds,src/luacov.stats.out,src/Data/TimelessJewelData/BrutalRestraint.bin,src/Data/TimelessJewelData/ElegantHubris.bin,src/Data/TimelessJewelData/GloriousVanity.bin,src/Data/TimelessJewelData/LethalPride.bin,src/Data/TimelessJewelData/MilitantFaith.bin,src/Data/TimelessJewelData/HeroicTragedy.bin,src/Data/TimelessJewelData/AbyssAmanamu.bin,src/Data/TimelessJewelData/AbyssKurgal.bin,src/Data/TimelessJewelData/AbyssTecrod.bin,src/Data/TimelessJewelData/AbyssUlaman.bin,src/Data/TimelessJewelData/AbyssZorath.bin,src/poe_api_response.json
+
+ [tree]
diff --git a/spec/System/TestCommon_spec.lua b/spec/System/TestCommon_spec.lua
new file mode 100644
index 0000000000..61a848e14e
--- /dev/null
+++ b/spec/System/TestCommon_spec.lua
@@ -0,0 +1,96 @@
+describe("Common", function()
+ describe("Class creation and use", function()
+ it("produces error when parent constructors are not called", function()
+ local ParentClass = newClass("ConstructorTestParentClass")
+ function ParentClass:ConstructorTestParentClass()
+ return self
+ end
+ local ChildClass = newClass("ConstructorTestProblemChildClass", "ConstructorTestParentClass")
+ function ChildClass:ConstructorTestProblemChild()
+ -- Intentionally does not call self:ConstructorTestParentClass()
+ return self
+ end
+ common.classes.ConstructorTestParent = ParentClass
+ common.classes.ConstructorTestProblemChild = ChildClass
+
+ assert.has_error(function()
+ new("ConstructorTestProblemChild"):ConstructorTestProblemChild()
+ end, "Parent class 'ConstructorTestParentClass' of class 'ConstructorTestProblemChild' must be initialised")
+ common.classes.ConstructorTestParent = nil
+ common.classes.ConstructorTestProblemChild = nil
+ end)
+ it("produces an error if additional arguments are passed", function()
+ local StupidClass = newClass("NewAbuse")
+ function StupidClass:NewAbuse(someParam)
+ return self
+ end
+
+ common.classes.NewAbuse = StupidClass
+
+ assert.has_no.errors(function()
+ local newObj = new("NewAbuse"):NewAbuse("fish")
+ end)
+ assert.has_error(function()
+ local newObj = new("NewAbuse", "look I'm using the old syntax")
+ end)
+ end)
+ it("produces an error if it calls a parent class without giving it self", function()
+ local ParentClass = newClass("ConstructorTestParentClass")
+ function ParentClass:ConstructorTestParentClass()
+ return self
+ end
+
+ local ChildClass = newClass("ConstructorTestProblemChildClass", "ConstructorTestParentClass")
+ function ChildClass:ConstructorTestProblemChild()
+ self.ConstructorTestParentClass()
+ return self
+ end
+
+ common.classes.ConstructorTestParent = ParentClass
+ common.classes.ConstructorTestProblemChild = ChildClass
+
+ assert.has_error(function()
+ new("ConstructorTestProblemChild"):ConstructorTestProblemChild()
+ end)
+ common.classes.ConstructorTestParent = nil
+ common.classes.ConstructorTestProblemChild = nil
+ end)
+ it("produces an error if its constructor doesn't return the object", function()
+ local StupidClass = newClass("StupidClass")
+ function StupidClass:StupidClass()
+ end
+
+ common.classes.StupidClass = StupidClass
+
+ assert.has_error(function()
+ new("StupidClass"):StupidClass()
+ end, "Class StupidClass constructor did not return a value")
+ end)
+ it("produces an error if its constructor has not been called", function()
+ local StupidClass = newClass("StupidClass")
+ function StupidClass:StupidClass()
+ return self
+ end
+
+ function StupidClass:Clear()
+ end
+
+ common.classes.StupidClass = StupidClass
+
+ assert.has_error(function()
+ local object = new("StupidClass")
+ return object.lines
+ end)
+ assert.has_error(function()
+ local object = new("StupidClass")
+ object:Clear()
+ end)
+ assert.has_no.errors(function()
+ local object = new("StupidClass"):StupidClass()
+ local x = object.lines
+ object:Clear()
+ end)
+ common.classes.StupidClass = nil
+ end)
+ end)
+end)
\ No newline at end of file
diff --git a/spec/System/TestCompareBuySimilar_spec.lua b/spec/System/TestCompareBuySimilar_spec.lua
index 1f32189d42..6d31922015 100644
--- a/spec/System/TestCompareBuySimilar_spec.lua
+++ b/spec/System/TestCompareBuySimilar_spec.lua
@@ -32,7 +32,7 @@ Corrupted]])
end)
it("combines mods that are the same stat", function()
- local lifeDiamond = new("Item", [[
+ local lifeDiamond = new("Item"):Item([[
Test Subject
Diamond
Implicits: 0
@@ -47,7 +47,7 @@ Implicits: 0
assert.equal("+50 to Maximum Life", StripEscapes(entries[1].formattedLines[2]))
assert.equal(150, entries[1].value)
- local lifelessDiamond = new("Item", [[
+ local lifelessDiamond = new("Item"):Item([[
Test Subject
Diamond
Implicits: 0
@@ -62,7 +62,7 @@ Implicits: 0
end)
it("is not case-sensitive", function ()
- local funnyItem = new("Item", [[
+ local funnyItem = new("Item"):Item([[
Test Subject
Diamond
Implicits: 1
@@ -73,7 +73,7 @@ Implicits: 1
end)
it("does not combine implicit and explicit mods", function()
- local lifelessDiamond = new("Item", [[
+ local lifelessDiamond = new("Item"):Item([[
Test Subject
Diamond
Implicits: 1
diff --git a/spec/System/TestCompareBuySimilar_spec.lua.rej b/spec/System/TestCompareBuySimilar_spec.lua.rej
new file mode 100644
index 0000000000..263c038d1f
--- /dev/null
+++ b/spec/System/TestCompareBuySimilar_spec.lua.rej
@@ -0,0 +1,19 @@
+diff a/spec/System/TestCompareBuySimilar_spec.lua b/spec/System/TestCompareBuySimilar_spec.lua (rejected hunks)
+@@ -155,7 +155,7 @@ Implicits: 1
+ end
+
+ local function getUniqueQuery(name, baseName)
+- local item = new("Item", "Rarity: UNIQUE\n" .. name .. "\n" .. baseName .. "\nImplicits: 0")
++ local item = new("Item"):Item("Rarity: UNIQUE\n" .. name .. "\n" .. baseName .. "\nImplicits: 0")
+ local query = getQuery(openPopup(item, "Jewel"))
+ main:ClosePopup()
+ return query
+@@ -179,7 +179,7 @@ Implicits: 1
+ end)
+
+ it("preserves apostrophes in unique names", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: UNIQUE
+ Ralakesh's Impatience
+ Riveted Boots
diff --git a/spec/System/TestItemMods_spec.lua.rej b/spec/System/TestItemMods_spec.lua.rej
new file mode 100644
index 0000000000..b4b2e790e8
--- /dev/null
+++ b/spec/System/TestItemMods_spec.lua.rej
@@ -0,0 +1,55 @@
+diff a/spec/System/TestItemMods_spec.lua b/spec/System/TestItemMods_spec.lua (rejected hunks)
+@@ -719,7 +719,7 @@ describe("TetsItemMods", function()
+ end)
+
+ it("crafts modifiers from supported bases on rare-like uniques", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Item Class: Helmets
+ Rarity: Unique
+ Subsume the Source
+@@ -759,7 +759,7 @@ describe("TetsItemMods", function()
+ end)
+
+ it("uses the item base for rare-like modifier eligibility by default", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Item Class: Bows
+ Rarity: Unique
+ The Crimson Storm
+@@ -778,7 +778,7 @@ describe("TetsItemMods", function()
+ end)
+
+ it("keeps modifier metadata on duplicate variant tooltip lines", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Unique
+ Duplicate Variant Test
+ Plate Vest
+@@ -791,7 +791,7 @@ describe("TetsItemMods", function()
+ Implicits: 0
+ {variant:1}+10 to maximum Life
+ ]])
+- local tooltip = new("Tooltip")
++ local tooltip = new("Tooltip"):Tooltip()
+ build.itemsTab:AddItemTooltip(tooltip, item)
+
+ local count = 0
+@@ -805,7 +805,7 @@ describe("TetsItemMods", function()
+ end)
+
+ it("does not sort cluster jewel modifiers when the sorting control is hidden", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: RARE
+ New Item
+ Large Cluster Jewel
+@@ -880,7 +880,7 @@ describe("TetsItemMods", function()
+ end)
+
+ it("sorts crafted modifier replacements without retaining the selected modifier", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: RARE
+ New Item
+ Cobalt Jewel
diff --git a/spec/System/TestItemParse_spec.lua b/spec/System/TestItemParse_spec.lua
index 8034dc07b9..da4830c2e4 100644
--- a/spec/System/TestItemParse_spec.lua
+++ b/spec/System/TestItemParse_spec.lua
@@ -159,7 +159,7 @@ describe("TestItemParse", function()
end)
it("Prefix/Suffix", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
Prefix: {range:0.1}IncreasedLife1
Suffix: {range:0.2}ColdResist1
]]))
@@ -170,7 +170,7 @@ describe("TestItemParse", function()
end)
it("Implicits", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
Implicits: 2
+8 to Strength
+10 to Intelligence
@@ -1106,7 +1106,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("resets linePrefix", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
{ Prefix Modifier "Warlock's" (Tier: 4) β Mana, Damage, Caster }
32(30-37)% increased Spell Damage
+46(42-47) to maximum Mana
@@ -1117,7 +1117,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("resets linePostfix", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
{ Corruption Enhancement β Mana }
24(20-30)% increased Mana Regeneration Rate
--------
@@ -1127,7 +1127,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("parses vaaled catalyst", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
Quality (Attribute Modifiers): +19% (augmented)
{ Unique Modifier β Attribute β 19% Increased }
+120(80-100) to all Attributes
@@ -1140,7 +1140,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("parses vaaled catalyst within range", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
Quality (Attribute Modifiers): +19% (augmented)
{ Unique Modifier β Attribute β 19% Increased }
+95(80-100) to all Attributes
@@ -1153,7 +1153,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("doesn't scale unscalable", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
Quality (Life and Mana Modifiers): +20% (augmented)
{ Unique Modifier β Life, Defences, Energy Shield, Minion, Gem }
Socketed Golem Skills gain 20% of Maximum Life as Extra Maximum Energy Shield β Unscalable Value
@@ -1162,7 +1162,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("correctly matches conqueror mod", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
{ Suffix Modifier "of the Conquest" (Tier: 1) β Elemental, Cold }
10(8-10)% chance to Avoid Cold Damage from Hits
(No chance to avoid damage can be higher than 75%)
@@ -1173,7 +1173,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("parses enchant correctly #enchant", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
{ Corrupted Enhancement }
+8(6-10)% to Fire Resistance
]]))
@@ -1181,7 +1181,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("parses enchant with tags correctly #enchant", function()
- local item = new("Item", raw([[
+ local item = new("Item"):Item(raw([[
{ Corrupted Enhancement - Energy Shield }
+8(6-10)% to Fire Resistance
]]))
@@ -1190,7 +1190,7 @@ describe("TestAdvancedItemParse #item", function()
end)
it("parses junk", function()
- local godTestItem = new("Item", [[
+ local godTestItem = new("Item"):Item([[
Item Class: Sceptres
Rarity: Unique
Nebulis
@@ -1208,7 +1208,7 @@ describe("TestAdvancedItemParse #item", function()
Str: 104
Int: 122
--------
- Sockets: B R
+ Sockets: B R
--------
Item Level: 87
--------
diff --git a/spec/System/TestItemParse_spec.lua.rej b/spec/System/TestItemParse_spec.lua.rej
index 29cbba05d1..a5a7e4a9e7 100644
--- a/spec/System/TestItemParse_spec.lua.rej
+++ b/spec/System/TestItemParse_spec.lua.rej
@@ -1,42 +1,163 @@
diff a/spec/System/TestItemParse_spec.lua b/spec/System/TestItemParse_spec.lua (rejected hunks)
-@@ -525,6 +525,16 @@ describe("TestAdvancedItemParse #item", function()
- assert.are_not.equals("mana", item.explicitModLines[3].modTags[1])
- end)
-
-+ it("resets linePostfix", function()
-+ local item = new("Item", raw([[
-+ { Corruption Enhancement β Mana }
-+ 24(20-30)% increased Mana Regeneration Rate
-+ --------
-+ +15 to maximum life
-+ ]]))
-+ assert.falsy(item.explicitModLines[1].enchant)
-+ end)
-+
- it("parses vaaled catalyst", function()
- local item = new("Item", raw([[
- Quality (Attribute Modifiers): +19% (augmented)
-@@ -571,6 +581,23 @@ describe("TestAdvancedItemParse #item", function()
- -- assert.are.equals(1, item.explicitModLines[1].range) -- Not sure why this is returning 0.5
- end)
-
-+ it("parses enchant correctly #enchant", function()
-+ local item = new("Item", raw([[
-+ { Corrupted Enhancement }
-+ +8(6-10)% to Fire Resistance
-+ ]]))
-+ assert.are.equals(8, item.enchantModLines[1].modList[1].value)
-+ end)
-+
-+ it("parses enchant with tags correctly #enchant", function()
-+ local item = new("Item", raw([[
-+ { Corrupted Enhancement - Energy Shield }
-+ +8(6-10)% to Fire Resistance
-+ ]]))
-+ assert.are.equals(8, item.enchantModLines[1].modList[1].value)
-+ assert.are.equals("energyshield", item.enchantModLines[1].modTags[1])
-+ end)
-+
- it("parses junk", function()
- local godTestItem = new("Item", [[
- Item Class: Sceptres
+@@ -38,7 +38,7 @@ describe("TestItemParse", function()
+ cannotBeAnointed = true,
+ }
+
+- local item = new("Item", "Rarity: Normal\n" .. baseName)
++ local item = new("Item"):Item("Rarity: Normal\n" .. baseName)
+
+ assert.are.equals(1, #item.enchantModLines)
+ assert.are.equals("+10 to Strength", item.enchantModLines[1].line)
+@@ -147,7 +147,7 @@ describe("TestItemParse", function()
+ end)
+
+ it("Versioned grouped variants", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: UNIQUE
+ Versioned Grouped Test
+ Prismatic Ring
+@@ -397,7 +397,7 @@ describe("TestItemParse", function()
+ end)
+
+ it("ignores disabled modifiers in item conditions", function()
+- local item = new("Item", raw("{disabled}+100 to maximum Life"))
++ local item = new("Item"):Item(raw("{disabled}+100 to maximum Life"))
+ assert.is_false(item:FindModifierSubstring("life", "body armour"))
+ end)
+
+@@ -763,7 +763,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("parses allocated Crucible passive skills from advanced copy", function()
+- local item = new("Item", raw([[
++ local item = new("Item"):Item(raw([[
+ { Allocated Crucible Passive Skill (Tier: 1) }
+ -3% to Critical Strike Chance
+ +100% to Global Critical Strike Multiplier
+@@ -782,7 +782,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("ignores attribute requirements from socketed gems", function()
+- local item = new("Item", raw([[
++ local item = new("Item"):Item(raw([[
+ Requirements:
+ Str: 126 (unmet)
+ Dex: 185 (unmet)
+@@ -801,7 +801,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("orders fractured mods first and crafted mods last", function()
+- local item = new("Item", raw([[
++ local item = new("Item"):Item(raw([[
+ Item Level: 83
+ { Fractured Prefix Modifier "Cheetah's" (Tier: 2) β Speed }
+ 30% increased Movement Speed
+@@ -826,7 +826,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("matches same-name affixes using their advanced-copy ranges", function()
+- local item = new("Item", raw([[
++ local item = new("Item"):Item(raw([[
+ Item Level: 85
+ { Fractured Prefix Modifier "Essences" β Damage, Elemental, Fire, Attack }
+ Adds 100(80-109) to 179(162-189) Fire Damage
+@@ -844,7 +844,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("filters flask base properties and parses fixed-value advanced rolls", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Unique
+ Soul Catcher
+ Quartz Flask
+@@ -870,7 +870,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("preserves rolls from large advanced-copy ranges", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Unique
+ Elegant Hubris
+ Timeless Jewel
+@@ -887,7 +887,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("preserves independently rolled values on the same modifier line", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Unique
+ Prismweave
+ Rustic Sash
+@@ -902,7 +902,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("orders advanced-copy unique modifiers by their database stat order", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Unique
+ Geofri's Sanctuary
+ Elegant Ringmail
+@@ -931,7 +931,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("keeps the selected value from advanced-copy enum ranges", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Unique
+ The Dark Monarch
+ Lich's Circlet
+@@ -946,7 +946,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("parses punctuated enum and descending numeric ranges", function()
+- local gemItem = new("Item", [[
++ local gemItem = new("Item"):Item([[
+ Rarity: Unique
+ Replica Dragonfang's Flight
+ Onyx Amulet
+@@ -956,7 +956,7 @@ describe("TestAdvancedItemParse #item", function()
+ assert.are.equals("+3 to Level of all Lightning Tendrils Gems", gemItem.explicitModLines[1].line)
+ assert.is_true(#gemItem.explicitModLines[1].modList > 0)
+
+- local requirementItem = new("Item", [[
++ local requirementItem = new("Item"):Item([[
+ Rarity: Unique
+ Replica Dragonfang's Flight
+ Onyx Amulet
+@@ -969,7 +969,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("parses Memory Strands as an item property", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Magic
+ Imperial Maul of Revitalization
+ Weapon Range: 1.3 metres
+@@ -1110,7 +1110,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("does not apply disabled modifier magnitude", function()
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: UNIQUE
+ Magnitude Test
+ Plate Vest
+@@ -1342,7 +1342,7 @@ describe("TestAdvancedItemParse #item", function()
+ ]]
+ it("scales only prefixes for increased effect of prefixes for advanced copy format", function()
+ assert.equal(0, spellCrit())
+- local item = new("Item", realJewel)
++ local item = new("Item"):Item(realJewel)
+ build.itemsTab:AddItem(item)
+ build.itemsTab:EquipItemInSet(item, build.itemsTab.activeItemSetId)
+ runCallback("OnFrame")
+@@ -1351,7 +1351,7 @@ describe("TestAdvancedItemParse #item", function()
+ end)
+
+ it("does not apply scaling twice when saving and loading", function()
+- local item = new("Item", new("Item", realJewel):BuildRaw())
++ local item = new("Item"):Item(new("Item"):Item(realJewel):BuildRaw())
+ build.itemsTab:AddItem(item)
+ build.itemsTab:EquipItemInSet(item, build.itemsTab.activeItemSetId)
+ runCallback("OnFrame")
diff --git a/spec/System/TestItemTools_spec.lua.rej b/spec/System/TestItemTools_spec.lua.rej
new file mode 100644
index 0000000000..35d537f90d
--- /dev/null
+++ b/spec/System/TestItemTools_spec.lua.rej
@@ -0,0 +1,10 @@
+diff a/spec/System/TestItemTools_spec.lua b/spec/System/TestItemTools_spec.lua (rejected hunks)
+@@ -66,7 +66,7 @@ describe("TestItemTools", function()
+ if not common.classes.ItemsTab then
+ LoadModule("Classes/ItemsTab")
+ end
+- local item = new("Item", [[
++ local item = new("Item"):Item([[
+ Rarity: Rare
+ Dire Thread
+ Cord Belt
diff --git a/spec/System/TestPoEAPIAuth_spec.lua.rej b/spec/System/TestPoEAPIAuth_spec.lua.rej
new file mode 100644
index 0000000000..79f742c578
--- /dev/null
+++ b/spec/System/TestPoEAPIAuth_spec.lua.rej
@@ -0,0 +1,28 @@
+diff a/spec/System/TestPoEAPIAuth_spec.lua b/spec/System/TestPoEAPIAuth_spec.lua (rejected hunks)
+@@ -27,7 +27,7 @@ describe("PoEAPI auth", function()
+ callback(nil, "SSL connect error")
+ end
+
+- local api = new("PoEAPI")
++ local api = new("PoEAPI"):PoEAPI()
+ local callbackArgs
+ api:FetchAuthToken(function(errMsg)
+ callbackArgs = {
+@@ -51,7 +51,7 @@ describe("PoEAPI auth", function()
+ error("token exchange should not run for mismatched OAuth state")
+ end
+
+- local api = new("PoEAPI")
++ local api = new("PoEAPI"):PoEAPI()
+ local callbackArgs
+ api:FetchAuthToken(function(errMsg)
+ callbackArgs = {
+@@ -66,7 +66,7 @@ describe("PoEAPI auth", function()
+ assert.is_nil(api.authToken)
+ end)
+ it("stays usable after an error", function()
+- local api = new("PoEAPI", "token", "refresh", os.time() + 3600)
++ local api = new("PoEAPI"):PoEAPI("token", "refresh", os.time() + 3600)
+
+ -- Drive the network layer directly so we bypass ValidateAuth/token
+ -- refresh and exercise only DownloadWithRateLimit's limiter bookkeeping.
diff --git a/spec/System/TestTradeQueryCurrency_spec.lua b/spec/System/TestTradeQueryCurrency_spec.lua
index 2758a84363..fe6de69d40 100644
--- a/spec/System/TestTradeQueryCurrency_spec.lua
+++ b/spec/System/TestTradeQueryCurrency_spec.lua
@@ -2,7 +2,7 @@ describe("TradeQuery Currency Conversion", function()
local mock_tradeQuery
before_each(function()
- mock_tradeQuery = new("TradeQuery", { itemsTab = {} })
+ mock_tradeQuery = new("TradeQuery"):TradeQuery({ itemsTab = {} })
end)
describe("ConvertCurrencyToDivs", function()
diff --git a/spec/System/TestTradeQueryGenerator_spec.lua b/spec/System/TestTradeQueryGenerator_spec.lua
index fab1af3cf8..97fb12934b 100644
--- a/spec/System/TestTradeQueryGenerator_spec.lua
+++ b/spec/System/TestTradeQueryGenerator_spec.lua
@@ -1,5 +1,5 @@
describe("TradeQueryGenerator", function()
- local mock_queryGen = new("TradeQueryGenerator", { itemsTab = {} })
+ local mock_queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = {} })
describe("ProcessMod", function()
-- Pass: Mod line maps correctly to trade stat entry without error
diff --git a/spec/System/TestTradeQueryGenerator_spec.lua.rej b/spec/System/TestTradeQueryGenerator_spec.lua.rej
new file mode 100644
index 0000000000..b41bcaaf04
--- /dev/null
+++ b/spec/System/TestTradeQueryGenerator_spec.lua.rej
@@ -0,0 +1,28 @@
+diff a/spec/System/TestTradeQueryGenerator_spec.lua b/spec/System/TestTradeQueryGenerator_spec.lua (rejected hunks)
+@@ -16,7 +16,7 @@ describe("TradeQueryGenerator", function()
+
+ describe("Talisman mods", function()
+ it("only generates enchant weights when enabled", function()
+- local queryGen = new("TradeQueryGenerator", { itemsTab = { } })
++ local queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = {} })
+ local enchantMods = queryGen.modData.Enchant
+ queryGen.modData = { Explicit = { }, Implicit = { }, Enchant = enchantMods, Corrupted = { }, Scourge = { } }
+ queryGen.calcContext = { special = { }, options = { } }
+@@ -155,7 +155,7 @@ describe("TradeQueryGenerator", function()
+
+ describe("Filter prioritization", function()
+ it("counts socket and link constraints against MAX_FILTERS", function()
+- local queryGen = new("TradeQueryGenerator", { itemsTab = { items = { } } })
++ local queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = { items = {} } })
+ queryGen.modWeights = { }
+ for index = 1, 40 do
+ table.insert(queryGen.modWeights, {
+@@ -165,7 +165,7 @@ describe("TradeQueryGenerator", function()
+ })
+ end
+ queryGen.calcContext = {
+- testItem = new("Item", "Rarity: RARE\nNew Item\nGold Ring\nImplicits: 0"),
++ testItem = new("Item"):Item("Rarity: RARE\nNew Item\nGold Ring\nImplicits: 0"),
+ baseOutput = { },
+ baseStatValue = 0,
+ itemCategoryQueryStr = "accessory.ring",
diff --git a/spec/System/TestTradeQueryRateLimiter_spec.lua b/spec/System/TestTradeQueryRateLimiter_spec.lua
index 4542385fdf..c1457f2be0 100644
--- a/spec/System/TestTradeQueryRateLimiter_spec.lua
+++ b/spec/System/TestTradeQueryRateLimiter_spec.lua
@@ -3,7 +3,7 @@ describe("TradeQueryRateLimiter", function()
-- Pass: Extracts keys/values correctly
-- Fail: Nil/malformed values, indicating regex failure, breaking policy updates from API
it("parses basic headers", function()
- local limiter = new("TradeQueryRateLimiter")
+ local limiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
local headers = limiter:ParseHeader("X-Rate-Limit-Policy: test\nRetry-After: 5\nContent-Type: json")
assert.are.equal(headers["x-rate-limit-policy"], "test")
assert.are.equal(headers["retry-after"], "5")
@@ -15,7 +15,7 @@ describe("TradeQueryRateLimiter", function()
-- Pass: Extracts rules/limits/states accurately
-- Fail: Wrong buckets/windows, indicating parsing bug, enforcing incorrect rates
it("parses full policy", function()
- local limiter = new("TradeQueryRateLimiter")
+ local limiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
local header = "X-Rate-Limit-Policy: trade-search-request-limit\nX-Rate-Limit-Rules: Ip,Account\nX-Rate-Limit-Ip: 8:10:60,15:60:120\nX-Rate-Limit-Ip-State: 7:10:60,14:60:120\nX-Rate-Limit-Account: 2:5:60\nX-Rate-Limit-Account-State: 1:5:60\nRetry-After: 10"
local policies = limiter:ParsePolicy(header)
local policy = policies["trade-search-request-limit"]
@@ -30,7 +30,7 @@ describe("TradeQueryRateLimiter", function()
-- Pass: Reduces limits (e.g., 5 -> 4)
-- Fail: Unchanged limits, indicating margin ignored, risking user over-requests
it("applies margin to limits", function()
- local limiter = new("TradeQueryRateLimiter")
+ local limiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
limiter.limitMargin = 1
local header = "X-Rate-Limit-Policy: test\nX-Rate-Limit-Rules: Ip\nX-Rate-Limit-Ip: 5:10:60\nX-Rate-Limit-Ip-State: 4:10:60"
limiter:UpdateFromHeader(header)
@@ -42,7 +42,7 @@ describe("TradeQueryRateLimiter", function()
-- Pass: Delays past timestamp
-- Fail: Allows immediate request, indicating ignored cooldowns, causing 429 errors
it("blocks on retry-after", function()
- local limiter = new("TradeQueryRateLimiter")
+ local limiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
local now = os.time()
limiter.policies["test"] = {}
limiter.retryAfter["test"] = now + 10
@@ -53,7 +53,7 @@ describe("TradeQueryRateLimiter", function()
-- Pass: Calculates delay from timestamps
-- Fail: Allows request in limit, indicating state misread, over-throttling or bans
it("blocks on window limit", function()
- local limiter = new("TradeQueryRateLimiter")
+ local limiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
local now = os.time()
limiter.policies["test"] = { ["ip"] = { ["limits"] = { ["10"] = { ["request"] = 1, ["timeout"] = 60 } }, ["state"] = { ["10"] = { ["request"] = 1, ["timeout"] = 0 } } } }
limiter.requestHistory["test"] = { timestamps = {now - 5} }
@@ -67,7 +67,7 @@ describe("TradeQueryRateLimiter", function()
-- Pass: Removes old stamps, decrements to 1
-- Fail: Stale data persists, indicating aging bug, perpetual blocking
it("cleans up timestamps and decrements", function()
- local limiter = new("TradeQueryRateLimiter")
+ local limiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
limiter.policies["test"] = { ["ip"] = { ["state"] = { ["10"] = { ["request"] = 2, ["timeout"] = 0, ["decremented"] = nil } } } }
limiter.requestHistory["test"] = { timestamps = {os.time() - 15, os.time() - 5}, maxWindow=10, lastCheck=os.time() - 10 }
limiter:AgeOutRequests("test", os.time())
diff --git a/spec/System/TestTradeQueryRequests_spec.lua b/spec/System/TestTradeQueryRequests_spec.lua
index 309521fdaa..8fb665e871 100644
--- a/spec/System/TestTradeQueryRequests_spec.lua
+++ b/spec/System/TestTradeQueryRequests_spec.lua
@@ -12,7 +12,7 @@ describe("TradeQueryRequests", function()
return key
end
}
- local requests = new("TradeQueryRequests", mock_limiter)
+ local requests = new("TradeQueryRequests"):TradeQueryRequests(mock_limiter)
local function simulateRetry(requests, mock_limiter, policy, current_time)
local now = current_time
diff --git a/spec/System/TestTradeQuery_spec.lua.rej b/spec/System/TestTradeQuery_spec.lua.rej
new file mode 100644
index 0000000000..2d58f6da83
--- /dev/null
+++ b/spec/System/TestTradeQuery_spec.lua.rej
@@ -0,0 +1,39 @@
+diff a/spec/System/TestTradeQuery_spec.lua b/spec/System/TestTradeQuery_spec.lua (rejected hunks)
+@@ -3,8 +3,8 @@ describe("TradeQuery", function()
+ local mock_queryGen
+
+ before_each(function()
+- mock_tradeQuery = new("TradeQuery", { itemsTab = {} })
+- mock_queryGen = new("TradeQueryGenerator", { itemsTab = {} })
++ mock_tradeQuery = new("TradeQuery"):TradeQuery({ itemsTab = {} })
++ mock_queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = {} })
+ end)
+ describe("result dropdown tooltipFunc", function()
+ -- Builds a TradeQuery with the strict minimum needed for
+@@ -14,7 +14,7 @@ describe("TradeQuery", function()
+ -- lives behind a callback we never trigger, or is already initialized
+ -- by the TradeQuery constructor.
+ local function newTradeQuery(state)
+- local tq = new("TradeQuery", { itemsTab = {} })
++ local tq = new("TradeQuery"):TradeQuery({ itemsTab = {} })
+ tq.itemsTab.activeItemSet = {}
+ tq.itemsTab.slots = {}
+ tq.slotTables[1] = { slotName = "Ring 1" }
+@@ -34,7 +34,7 @@ describe("TradeQuery", function()
+ -- No sorted results at all -> first guard must short-circuit.
+ local tq = newTradeQuery({})
+ local dropdown = buildRow1Dropdown(tq)
+- local tooltip = new("Tooltip")
++ local tooltip = new("Tooltip"):Tooltip()
+
+ assert.has_no.errors(function()
+ dropdown.tooltipFunc(tooltip, "DROP", 1, nil)
+@@ -53,7 +53,7 @@ describe("TradeQuery", function()
+ })
+ local dropdown = buildRow1Dropdown(tq)
+ tq.resultTbl[1] = {}
+- local tooltip = new("Tooltip")
++ local tooltip = new("Tooltip"):Tooltip()
+
+ assert.has_no.errors(function()
+ dropdown.tooltipFunc(tooltip, "DROP", 1, nil)
diff --git a/src/Classes/BuildListControl.lua b/src/Classes/BuildListControl.lua
index 3f42430ce9..415483e0f6 100644
--- a/src/Classes/BuildListControl.lua
+++ b/src/Classes/BuildListControl.lua
@@ -74,8 +74,8 @@ end
function BuildListClass:RenameBuild(build, copyOnName)
local controls = { }
- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter the new name for this "..(build.folderName and "folder:" or "build:"))
- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, build.folderName or build.buildName, nil, "\\/:%*%?\"<>|%c", 100, function(buf)
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter the new name for this "..(build.folderName and "folder:" or "build:"))
+ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, build.folderName or build.buildName, nil, "\\/:%*%?\"<>|%c", 100, function(buf)
controls.save.enabled = false
if build.folderName then
if buf:match("%S") then
@@ -97,7 +97,7 @@ function BuildListClass:RenameBuild(build, copyOnName)
end
end
end)
- controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function()
+ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function()
local newBuildName = controls.edit.buf
if build.folderName then
if copyOnName then
@@ -132,7 +132,7 @@ function BuildListClass:RenameBuild(build, copyOnName)
self.listMode:SelectControl(self)
end)
controls.save.enabled = false
- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
main:ClosePopup()
self.listMode:SelectControl(self)
end)
diff --git a/src/Classes/BuildListControl.lua.rej b/src/Classes/BuildListControl.lua.rej
new file mode 100644
index 0000000000..c96c53de8b
--- /dev/null
+++ b/src/Classes/BuildListControl.lua.rej
@@ -0,0 +1,39 @@
+diff a/src/Classes/BuildListControl.lua b/src/Classes/BuildListControl.lua (rejected hunks)
+@@ -7,15 +7,18 @@ local ipairs = ipairs
+ local s_format = string.format
+ local buildListHelpers = LoadModule("Modules/BuildListHelpers")
+
+-local BuildListClass = newClass("BuildListControl", "ListControl", function(self, anchor, rect, listMode)
+- self.ListControl(anchor, rect, 20, "VERTICAL", false, listMode.list)
++---@class BuildListControl: ListControl
++local BuildListClass = newClass("BuildListControl", "ListControl")
++
++function BuildListClass:BuildListControl(anchor, rect, listMode)
++ self:ListControl(anchor, rect, 20, "VERTICAL", false, listMode.list)
+ self.listMode = listMode
+- self.colList = {
+- { width = function() return self:GetProperty("width") - 172 end },
++ self.colList = {
++ { width = function() return self:GetProperty("width") - 172 end },
+ { },
+ }
+ self.showRowSeparators = true
+- self.controls.path = new("PathControl", {"BOTTOM",self,"TOP"}, {0, -2, self.width, 24}, main.buildPath, listMode.subPath, function(subPath)
++ self.controls.path = new("PathControl"):PathControl({"BOTTOM",self,"TOP"}, {0, -2, self.width, 24}, main.buildPath, listMode.subPath, function(subPath)
+ listMode.subPath = subPath
+ listMode:BuildList()
+ self.selIndex = nil
+@@ -50,10 +53,11 @@ local BuildListClass = newClass("BuildListControl", "ListControl", function(self
+ end
+ end
+ self.dragTargetList = { self.controls.path, self }
+- self.controls.path.width = function ()
++ self.controls.path.width = function()
+ return self.width()
+ end
+-end)
++ return self
++end
+
+ function BuildListClass:SelByFullFileName(fullFileName)
+ if fullFileName then
diff --git a/src/Classes/ButtonControl.lua b/src/Classes/ButtonControl.lua
index a37c6fc658..e231280f5e 100644
--- a/src/Classes/ButtonControl.lua
+++ b/src/Classes/ButtonControl.lua
@@ -3,14 +3,18 @@
-- Class: Button Control
-- Basic button control.
--
-local ButtonClass = newClass("ButtonControl", "Control", "TooltipHost", function(self, anchor, rect, label, onClick, onHover, forceTooltip)
- self.Control(anchor, rect)
- self.TooltipHost()
+---@class ButtonControl: Control, TooltipHost
+local ButtonClass = newClass("ButtonControl", "Control", "TooltipHost")
+
+function ButtonClass:ButtonControl(anchor, rect, label, onClick, onHover, forceTooltip)
+ self:Control(anchor, rect)
+ self:TooltipHost()
self.label = label
self.onClick = onClick
self.onHover = onHover
self.forceTooltip = forceTooltip
-end)
+ return self
+end
function ButtonClass:Click()
if self:IsShown() and self:IsEnabled() then
diff --git a/src/Classes/CalcBreakdownControl.lua.rej b/src/Classes/CalcBreakdownControl.lua.rej
new file mode 100644
index 0000000000..efee2389f1
--- /dev/null
+++ b/src/Classes/CalcBreakdownControl.lua.rej
@@ -0,0 +1,33 @@
+diff a/src/Classes/CalcBreakdownControl.lua b/src/Classes/CalcBreakdownControl.lua (rejected hunks)
+@@ -13,19 +13,24 @@ local m_cos = math.cos
+ local m_pi = math.pi
+ local band = bit.band
+
+-local CalcBreakdownClass = newClass("CalcBreakdownControl", "Control", "ControlHost", function(self, calcsTab)
+- self.Control()
+- self.ControlHost()
++---@class CalcBreakdownControl: Control, ControlHost
++local CalcBreakdownClass = newClass("CalcBreakdownControl", "Control", "ControlHost")
++
++function CalcBreakdownClass:CalcBreakdownControl(calcsTab)
++ self:Control()
++ self:ControlHost()
+ self.calcsTab = calcsTab
+ self.shown = false
+- self.tooltip = new("Tooltip")
+- self.nodeViewer = new("PassiveTreeView")
++ self.tooltip = new("Tooltip"):Tooltip()
++ self.nodeViewer = new("PassiveTreeView"):PassiveTreeView()
+ self.rangeGuide = NewImageHandle()
+ self.rangeGuide:Load("Assets/range_guide.png")
+ self.uiOverlay = NewImageHandle()
+ self.uiOverlay:Load("Assets/game_ui_small.png")
+- self.controls.scrollBar = new("ScrollBarControl", {"RIGHT",self,"RIGHT"}, {-2, 0, 18, 0}, 80, "VERTICAL", true)
+-end)
++ self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({ "RIGHT", self, "RIGHT" }, { -2, 0, 18, 0 }, 80,
++ "VERTICAL", true)
++ return self
++end
+
+ function CalcBreakdownClass:IsMouseOver()
+ if not self:IsShown() then
diff --git a/src/Classes/CalcSectionControl.lua b/src/Classes/CalcSectionControl.lua
index ff7e557a43..ff3f5fa23b 100644
--- a/src/Classes/CalcSectionControl.lua
+++ b/src/Classes/CalcSectionControl.lua
@@ -33,7 +33,7 @@ local CalcSectionClass = newClass("CalcSectionControl", "Control", "ControlHost"
end
end
subSec.collapsed = subSec.defaultCollapsed
- self.controls["toggle"..i] = new("ButtonControl", {"TOPRIGHT",self,"TOPRIGHT"}, {-3, -13 + (16 * i), 16, 16}, function()
+ self.controls["toggle"..i] = new("ButtonControl"):ButtonControl({"TOPRIGHT",self,"TOPRIGHT"}, {-3, -13 + (16 * i), 16, 16}, function()
return subSec.collapsed and "+" or "-"
end, function()
subSec.collapsed = not subSec.collapsed
diff --git a/src/Classes/CalcSectionControl.lua.rej b/src/Classes/CalcSectionControl.lua.rej
new file mode 100644
index 0000000000..fc904c54a9
--- /dev/null
+++ b/src/Classes/CalcSectionControl.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Classes/CalcSectionControl.lua b/src/Classes/CalcSectionControl.lua (rejected hunks)
+@@ -56,7 +56,7 @@ function CalcSectionClass:CalcSectionControl(calcsTab, width, id, group, colour,
+ end
+ end
+ end
+- self.controls.popOut = new("ButtonControl", {"TOPRIGHT",self,"TOPRIGHT"}, {-22, 3, 16, 16}, "^", function()
++ self.controls.popOut = new("ButtonControl"):ButtonControl({"TOPRIGHT",self,"TOPRIGHT"}, {-22, 3, 16, 16}, "^", function()
+ self:ToggleOverlay()
+ end)
+ self.controls.popOut.shown = function()
diff --git a/src/Classes/CalcsTab.lua b/src/Classes/CalcsTab.lua
index 1f7e758d4d..e41ce900de 100644
--- a/src/Classes/CalcsTab.lua
+++ b/src/Classes/CalcsTab.lua
@@ -16,10 +16,16 @@ local buffModeDropList = {
{ label = "Effective DPS", buffMode = "EFFECTIVE" }
}
-local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Control", function(self, build)
- self.UndoHandler()
- self.ControlHost()
- self.Control()
+---@class CalcsTab: UndoHandler, ControlHost, Control
+---@field powerStat PowerStat?
+---@field nodePowerMaxDepth integer? Maximum distance for power report
+local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Control")
+
+---@param build Build
+function CalcsTabClass:CalcsTab(build)
+ self:UndoHandler()
+ self:ControlHost()
+ self:Control()
self.build = build
@@ -32,13 +38,13 @@ local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Contro
self.colWidth = 230
self.sectionList = { }
- self.controls.search = new("EditControl", {"TOPLEFT",self,"TOPLEFT"}, {4, 5, 260, 20}, "", "Search", "%c", 100, nil, nil, nil, true)
+ self.controls.search = new("EditControl"):EditControl({"TOPLEFT",self,"TOPLEFT"}, {4, 5, 260, 20}, "", "Search", "%c", 100, nil, nil, nil, true)
t_insert(self.controls, self.controls.search)
-- Special section for skill/mode selection
self:NewSection(3, "SkillSelect", 1, colorCodes.NORMAL, {{ defaultCollapsed = false, label = "View Skill Details", data = {
{ label = "Socket Group", { controlName = "mainSocketGroup",
- control = new("DropDownControl", nil, {0, 0, 300, 16}, nil, function(index, value)
+ control = new("DropDownControl"):DropDownControl(nil, {0, 0, 300, 16}, nil, function(index, value)
self.input.skill_number = index
self:AddUndoState()
self.build.buildFlag = true
@@ -77,7 +83,7 @@ local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Contro
self.build.buildFlag = true
end)
}, },{ label = "Skill Stages", playerFlag = "multiStage", { controlName = "mainSkillStageCount",
- control = new("EditControl", nil, {0, 0, 52, 16}, nil, nil, "%D", nil, function(buf)
+ control = new("EditControl"):EditControl(nil, {0, 0, 52, 16}, nil, nil, "%D", nil, function(buf)
local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number]
local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance
srcInstance.skillStageCountCalcs = tonumber(buf)
@@ -86,7 +92,7 @@ local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Contro
end)
}, },
{ label = "Active Mines", playerFlag = "mine", { controlName = "mainSkillMineCount",
- control = new("EditControl", nil, {0, 0, 52, 16}, nil, nil, "%D", nil, function(buf)
+ control = new("EditControl"):EditControl(nil, {0, 0, 52, 16}, nil, nil, "%D", nil, function(buf)
local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number]
local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance
srcInstance.skillMineCountCalcs = tonumber(buf)
@@ -158,8 +164,8 @@ local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Contro
} },
{ label = "Calculation Mode", {
controlName = "mode",
- control = new("DropDownControl", nil, {0, 0, 100, 16}, buffModeDropList, function(index, value)
- self.input.misc_buffMode = value.buffMode
+ control = new("DropDownControl"):DropDownControl(nil, {0, 0, 100, 16}, buffModeDropList, function(index, value)
+ self.input.misc_buffMode = value.buffMode
self:AddUndoState()
self.build.buildFlag = true
end, [[
@@ -186,18 +192,19 @@ Effective DPS: Curses and enemy properties (such as resistances and status condi
self:NewSection(unpack(section))
end
- self.controls.breakdown = new("CalcBreakdownControl", self)
+ self.controls.breakdown = new("CalcBreakdownControl"):CalcBreakdownControl(self)
- self.controls.scrollBar = new("ScrollBarControl", {"TOPRIGHT",self,"TOPRIGHT"}, {0, 0, 18, 0}, 50, "VERTICAL", true)
+ self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({"TOPRIGHT",self,"TOPRIGHT"}, {0, 0, 18, 0}, 50, "VERTICAL", true)
self.powerBuilderInitialized = nil
-end)
+ return self
+end
function CalcsTabClass:Load(xml, dbFileName)
for _, node in ipairs(xml) do
if type(node) == "table" then
if node.elem == "Input" then
if not node.attrib.name then
- launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing name attribute", fileName)
+ launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing name attribute", dbFileName)
return true
end
if node.attrib.number then
@@ -207,12 +214,12 @@ function CalcsTabClass:Load(xml, dbFileName)
elseif node.attrib.boolean then
self.input[node.attrib.name] = node.attrib.boolean == "true"
else
- launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing number, string or boolean attribute", fileName)
+ launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing number, string or boolean attribute", dbFileName)
return true
end
elseif node.elem == "Section" then
if not node.attrib.id then
- launch:ShowErrMsg("^1Error parsing '%s': 'Section' element missing id attribute", fileName)
+ launch:ShowErrMsg("^1Error parsing '%s': 'Section' element missing id attribute", dbFileName)
return true
end
for _, section in ipairs(self.sectionList) do
@@ -390,7 +397,7 @@ function CalcsTabClass:Draw(viewPort, inputEvents)
end
function CalcsTabClass:NewSection(width, ...)
- local section = new("CalcSectionControl", self, width * self.colWidth + 8 * (width - 1), ...)
+ local section = new("CalcSectionControl"):CalcSectionControl(self, width * self.colWidth + 8 * (width - 1), ...)
section.widthCols = width
t_insert(self.controls, section)
t_insert(self.sectionList, section)
diff --git a/src/Classes/CalcsTab.lua.rej b/src/Classes/CalcsTab.lua.rej
new file mode 100644
index 0000000000..e3006db3b4
--- /dev/null
+++ b/src/Classes/CalcsTab.lua.rej
@@ -0,0 +1,49 @@
+diff a/src/Classes/CalcsTab.lua b/src/Classes/CalcsTab.lua (rejected hunks)
+@@ -52,14 +58,14 @@ local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Contro
+ }
+ }, },
+ { label = "Active Skill", { controlName = "mainSkill",
+- control = new("DropDownControl", nil, {0, 0, 300, 16}, nil, function(index, value)
++ control = new("DropDownControl"):DropDownControl(nil, {0, 0, 300, 16}, nil, function(index, value)
+ local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number]
+ mainSocketGroup.mainActiveSkillCalcs = index
+ self.build.buildFlag = true
+ end)
+ }, },
+ { label = "Skill Part", playerFlag = "multiPart", { controlName = "mainSkillPart",
+- control = new("DropDownControl", nil, {0, 0, 250, 16}, nil, function(index, value)
++ control = new("DropDownControl"):DropDownControl(nil, {0, 0, 250, 16}, nil, function(index, value)
+ local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number]
+ local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance
+ srcInstance.skillPartCalcs = index
+@@ -85,13 +91,13 @@ local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Contro
+ end)
+ }, },
+ { label = "Show Minion Stats", flag = "haveMinion", { controlName = "showMinion",
+- control = new("CheckBoxControl", nil, {0, 0, 18}, nil, function(state)
++ control = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state)
+ self.input.showMinion = state
+ self:AddUndoState()
+ end, "Show stats for the minion instead of the player.")
+ }, },
+ { label = "Minion", flag = "minion", { controlName = "mainSkillMinion",
+- control = new("DropDownControl", nil, {0, 0, 160, 16}, nil, function(index, value)
++ control = new("DropDownControl"):DropDownControl(nil, {0, 0, 160, 16}, nil, function(index, value)
+ local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number]
+ local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance
+ if value.itemSetId then
+@@ -104,12 +110,12 @@ local CalcsTabClass = newClass("CalcsTab", "UndoHandler", "ControlHost", "Contro
+ end)
+ } },
+ { label = "Spectre Library", flag = "spectre", { controlName = "mainSkillMinionLibrary",
+- control = new("ButtonControl", nil, {0, 0, 100, 16}, "Manage Spectres...", function()
++ control = new("ButtonControl"):ButtonControl(nil, {0, 0, 100, 16}, "Manage Spectres...", function()
+ self.build:OpenSpectreLibrary()
+ end)
+ } },
+ { label = "Minion Skill", flag = "haveMinion", { controlName = "mainSkillMinionSkill",
+- control = new("DropDownControl", nil, {0, 0, 200, 16}, nil, function(index, value)
++ control = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 16}, nil, function(index, value)
+ local mainSocketGroup = self.build.skillsTab.socketGroupList[self.input.skill_number]
+ local srcInstance = mainSocketGroup.displaySkillListCalcs[mainSocketGroup.mainActiveSkillCalcs].activeEffect.srcInstance
+ srcInstance.skillMinionSkillCalcs = index
diff --git a/src/Classes/CheckBoxControl.lua.rej b/src/Classes/CheckBoxControl.lua.rej
new file mode 100644
index 0000000000..2498490bf0
--- /dev/null
+++ b/src/Classes/CheckBoxControl.lua.rej
@@ -0,0 +1,25 @@
+diff a/src/Classes/CheckBoxControl.lua b/src/Classes/CheckBoxControl.lua (rejected hunks)
+@@ -3,15 +3,19 @@
+ -- Class: Check Box Control
+ -- Basic check box control.
+ --
+-local CheckBoxClass = newClass("CheckBoxControl", "Control", "TooltipHost", function(self, anchor, rect, label, changeFunc, tooltipText, initialState)
++---@class CheckBoxControl: Control, TooltipHost
++local CheckBoxClass = newClass("CheckBoxControl", "Control", "TooltipHost")
++
++function CheckBoxClass:CheckBoxControl(anchor, rect, label, changeFunc, tooltipText, initialState)
+ rect[4] = rect[3] or 0
+- self.Control(anchor, rect)
+- self.TooltipHost(tooltipText)
++ self:Control(anchor, rect)
++ self:TooltipHost(tooltipText)
+ self.label = label
+ self.labelWidth = DrawStringWidth(self.width - 4, "VAR", label or "") + 5
+ self.changeFunc = changeFunc
+ self.state = initialState
+-end)
++ return self
++end
+
+ function CheckBoxClass:IsMouseOver()
+ if not self:IsShown() then
diff --git a/src/Classes/CompareBuySimilar.lua b/src/Classes/CompareBuySimilar.lua
index 37abf6b6a6..6ad293397c 100644
--- a/src/Classes/CompareBuySimilar.lua
+++ b/src/Classes/CompareBuySimilar.lua
@@ -40,7 +40,6 @@ for i, entry in ipairs(LISTED_STATUS_OPTIONS) do
end
-
-- Build the trade search URL based on popup selections
local function buildURL(item, slotName, controls, modEntries, defenceEntries, isUnique)
-- Determine realm and league from the popup's dropdowns
@@ -413,22 +412,22 @@ function M.openPopup(item, slotName, primaryBuild)
if isUnique then
-- Unique item name label
- controls.nameLabel = new("LabelControl", nil, {0, ctrlY, 0, 16}, "^x" .. (colorCodes[item.rarity] or "FFFFFF"):gsub("%^x","") .. item.name)
+ controls.nameLabel = new("LabelControl"):LabelControl(nil, {0, ctrlY, 0, 16}, "^x" .. (colorCodes[item.rarity] or "FFFFFF"):gsub("%^x","") .. item.name)
ctrlY = ctrlY + rowHeight
else
-- Category label
local categoryLabel = tradeHelpers.getTradeCategoryLabel(slotName, item)
- controls.categoryLabel = new("LabelControl", {"TOPLEFT", nil, "TOPLEFT"}, {leftMargin, ctrlY, 0, 16}, "^7Category: " .. categoryLabel)
+ controls.categoryLabel = new("LabelControl"):LabelControl({"TOPLEFT", nil, "TOPLEFT"}, {leftMargin, ctrlY, 0, 16}, "^7Category: " .. categoryLabel)
ctrlY = ctrlY + rowHeight
-- Base type checkbox
- controls.baseTypeCheck = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl)
- controls.baseTypeLabel = new("LabelControl", {"LEFT", controls.baseTypeCheck, "RIGHT"}, {4, 0, 0, 16}, "^7Use specific base: " .. (item.baseName or "Unknown"))
+ controls.baseTypeCheck = new("CheckBoxControl"):CheckBoxControl(nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl)
+ controls.baseTypeLabel = new("LabelControl"):LabelControl({"LEFT", controls.baseTypeCheck, "RIGHT"}, {4, 0, 0, 16}, "^7Use specific base: " .. (item.baseName or "Unknown"))
ctrlY = ctrlY + rowHeight
-- Item level
ctrlY = ctrlY + 4
- controls.ilvlLabel = new("LabelControl", {"TOPLEFT", nil, "TOPLEFT"}, {leftMargin, ctrlY, 0, 16}, "^7Item Level:")
+ controls.ilvlLabel = new("LabelControl"):LabelControl({"TOPLEFT", nil, "TOPLEFT"}, {leftMargin, ctrlY, 0, 16}, "^7Item Level:")
controls.ilvlMin = tradeHelpers.newPlainNumericEdit(nil, { minFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, "", "Min", 4, true, rebuildUrl)
controls.ilvlMax = tradeHelpers.newPlainNumericEdit(nil, { maxFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, "", "Max", 4, true, rebuildUrl)
ctrlY = ctrlY + rowHeight
@@ -436,8 +435,8 @@ function M.openPopup(item, slotName, primaryBuild)
-- Defence stat rows
for i, def in ipairs(defenceEntries) do
local prefix = "def" .. i
- controls[prefix .. "Check"] = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl)
- controls[prefix .. "Label"] = new("LabelControl", {"LEFT", controls[prefix .. "Check"], "RIGHT"}, {4, 0, 0, 16}, "^7" .. def.label)
+ controls[prefix .. "Check"] = new("CheckBoxControl"):CheckBoxControl(nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl)
+ controls[prefix .. "Label"] = new("LabelControl"):LabelControl({"LEFT", controls[prefix .. "Check"], "RIGHT"}, {4, 0, 0, 16}, "^7" .. def.label)
controls[prefix .. "Min"] = tradeHelpers.newPlainNumericEdit(nil, { minFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, tostring(m_floor(def.value)), "Min", 6, true, rebuildUrl)
controls[prefix .. "Max"] = tradeHelpers.newPlainNumericEdit(nil, { maxFieldX - popupWidth / 2, ctrlY, fieldW, fieldH }, "", "Max", 6, true, rebuildUrl)
ctrlY = ctrlY + rowHeight
@@ -466,7 +465,7 @@ function M.openPopup(item, slotName, primaryBuild)
-- adjust down by half a text row for each row over 1
local controlYPos = ctrlY + (rows - 1) * 8
local checkBoxXPos = -popupWidth/2 + leftMargin + checkboxSize/2
- controls[prefix .. "Check"] = new("CheckBoxControl", nil, {checkBoxXPos, controlYPos, checkboxSize}, "", rebuildUrl)
+ controls[prefix .. "Check"] = new("CheckBoxControl"):CheckBoxControl(nil, { checkBoxXPos, controlYPos, checkboxSize }, "", rebuildUrl)
controls[prefix .. "Check"].enabled = function() return canSearch end
@@ -493,7 +492,7 @@ function M.openPopup(item, slotName, primaryBuild)
-- labels anchor based on the first row instead of the middle row, so adjust upwards
local labelXOffset = (rows - 1) * -8
- controls[prefix .. "Label"] = new("LabelControl", {"LEFT", controls[prefix .. "Check"], "RIGHT"},{ 4, labelXOffset, 0, fontSize },
+ controls[prefix .. "Label"] = new("LabelControl"):LabelControl({ "LEFT", controls[prefix .. "Check"], "RIGHT" }, { 4, labelXOffset, 0, fontSize },
displayText)
-- when the trade site has a dropdown for the value, we opt to disable
-- the inputs as they are numeric
@@ -510,7 +509,7 @@ function M.openPopup(item, slotName, primaryBuild)
-- Search button
ctrlY = ctrlY + 8
- controls.search = new("ButtonControl", nil, {0, ctrlY, 110, 20}, "Open URL", function()
+ controls.search = new("ButtonControl"):ButtonControl(nil, { 0, ctrlY, 110, 20 }, "Open URL", function()
Copy(uri)
OpenURL(uri)
end, nil)
@@ -519,7 +518,7 @@ function M.openPopup(item, slotName, primaryBuild)
return uri and uri ~= ""
end
- controls.close = new("ButtonControl", nil, {popupWidth/2 - 50, ctrlY, 60, 20}, "Close", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, { popupWidth / 2 - 50, ctrlY, 60, 20 }, "Close", function()
main:ClosePopup()
end)
diff --git a/src/Classes/CompareBuySimilar.lua.rej b/src/Classes/CompareBuySimilar.lua.rej
new file mode 100644
index 0000000000..43803f8ad8
--- /dev/null
+++ b/src/Classes/CompareBuySimilar.lua.rej
@@ -0,0 +1,49 @@
+diff a/src/Classes/CompareBuySimilar.lua b/src/Classes/CompareBuySimilar.lua (rejected hunks)
+@@ -335,7 +334,7 @@ function M.openPopup(item, slotName, primaryBuild)
+ local tradeQuery = primaryBuild.itemsTab and primaryBuild.itemsTab.tradeQuery
+ local tradeQueryRequests = tradeQuery and tradeQuery.tradeQueryRequests
+ if not tradeQueryRequests then
+- tradeQueryRequests = new("TradeQueryRequests")
++ tradeQueryRequests = new("TradeQueryRequests"):TradeQueryRequests()
+ end
+
+ local function rebuildUrl()
+@@ -374,8 +373,8 @@ function M.openPopup(item, slotName, primaryBuild)
+ end
+
+ -- Realm dropdown
+- controls.realmLabel = new("LabelControl", {"TOPLEFT", nil, "TOPLEFT"}, {leftMargin, ctrlY, 0, 16}, "^7Realm:")
+- controls.realmDrop = new("DropDownControl", {"LEFT", controls.realmLabel, "RIGHT"}, {4, 0, 80, 20}, {"PC", "PS4", "Xbox"}, function(index, value)
++ controls.realmLabel = new("LabelControl"):LabelControl({"TOPLEFT", nil, "TOPLEFT"}, {leftMargin, ctrlY, 0, 16}, "^7Realm:")
++ controls.realmDrop = new("DropDownControl"):DropDownControl({"LEFT", controls.realmLabel, "RIGHT"}, {4, 0, 80, 20}, {"PC", "PS4", "Xbox"}, function(index, value)
+ local realmApiId = REALM_API_IDS[value] or "pc"
+ fetchLeaguesForRealm(realmApiId)
+ rebuildUrl()
+@@ -386,8 +385,8 @@ function M.openPopup(item, slotName, primaryBuild)
+ end
+
+ -- League dropdown
+- controls.leagueLabel = new("LabelControl", {"LEFT", controls.realmDrop, "RIGHT"}, {12, 0, 0, 16}, "^7League:")
+- controls.leagueDrop = new("DropDownControl", { "LEFT", controls.leagueLabel, "RIGHT" }, { 4, 0, 160, 20 },
++ controls.leagueLabel = new("LabelControl"):LabelControl({"LEFT", controls.realmDrop, "RIGHT"}, {12, 0, 0, 16}, "^7League:")
++ controls.leagueDrop = new("DropDownControl"):DropDownControl({"LEFT", controls.leagueLabel, "RIGHT" }, { 4, 0, 160, 20 },
+ { "Loading..." }, function(index, value)
+ local realmApiId = REALM_API_IDS[controls.realmDrop:GetSelValue()] or "pc"
+ M.lastLeagueByRealm = M.lastLeagueByRealm or {}
+@@ -397,14 +396,14 @@ function M.openPopup(item, slotName, primaryBuild)
+ controls.leagueDrop.enabled = function() return #controls.leagueDrop.list > 0 and controls.leagueDrop.list[1] ~= "Loading..." end
+
+ -- Listed status dropdown
+- controls.listedDrop = new("DropDownControl", { "TOPRIGHT", nil, "TOPRIGHT" }, { -leftMargin, ctrlY, 242, 20 }, LISTED_STATUS_LABELS, function(index, value)
++ controls.listedDrop = new("DropDownControl"):DropDownControl({ "TOPRIGHT", nil, "TOPRIGHT" }, { -leftMargin, ctrlY, 242, 20 }, LISTED_STATUS_LABELS, function(index, value)
+ M.lastListedIndex = index
+ rebuildUrl()
+ end)
+ if M.lastListedIndex then
+ controls.listedDrop:SetSel(M.lastListedIndex, true)
+ end
+- controls.listedLabel = new("LabelControl", {"RIGHT", controls.listedDrop, "LEFT"}, {-4, 0, 0, 16}, "^7Listed:")
++ controls.listedLabel = new("LabelControl"):LabelControl({"RIGHT", controls.listedDrop, "LEFT"}, {-4, 0, 0, 16}, "^7Listed:")
+
+ -- Fetch initial leagues for the selected realm
+ fetchLeaguesForRealm(REALM_API_IDS[controls.realmDrop:GetSelValue()] or "pc")
diff --git a/src/Classes/CompareEntry.lua b/src/Classes/CompareEntry.lua
index b74b78c02f..8bf2776140 100644
--- a/src/Classes/CompareEntry.lua
+++ b/src/Classes/CompareEntry.lua
@@ -9,8 +9,11 @@ local s_format = string.format
local m_min = math.min
local m_max = math.max
-local CompareEntryClass = newClass("CompareEntry", "ControlHost", function(self, xmlText, label)
- self.ControlHost()
+---@class CompareEntry: ControlHost
+local CompareEntryClass = newClass("CompareEntry", "ControlHost")
+
+function CompareEntryClass:CompareEntry(xmlText, label)
+ self:ControlHost()
self.label = label or "Comparison Build"
self.buildName = label or "Comparison Build"
@@ -46,13 +49,17 @@ local CompareEntryClass = newClass("CompareEntry", "ControlHost", function(self,
self.outputRevision = 1
-- Display stats (same as primary build uses)
- self.displayStats, self.minionDisplayStats, self.extraSaveStats = LoadModule("Modules/BuildDisplayStats")
+ local displayStatsModule = LoadModule("Modules/BuildDisplayStats")
+ self.displayStats = displayStatsModule.displayStats
+ self.minionDisplayStats = displayStatsModule.minionDisplayStats
+ self.extraSaveStats = displayStatsModule.extraSaveStats
-- Load from XML
if xmlText then
self:LoadFromXML(xmlText)
end
-end)
+ return self
+end
function CompareEntryClass:LoadFromXML(xmlText)
-- Parse the XML
@@ -100,14 +107,14 @@ function CompareEntryClass:LoadFromXML(xmlText)
-- Create tabs
-- PartyTab is replaced with a stub providing an empty enemyModList and actor
-- (CalcPerform.lua:1088 accesses build.partyTab.actor for party member buffs)
- local partyActor = { Aura = {}, Curse = {}, Warcry = {}, Link = {}, modDB = new("ModDB"), output = {} }
+ local partyActor = { Aura = {}, Curse = {}, Warcry = {}, Link = {}, modDB = new("ModDB"):ModDB(), output = {} }
partyActor.modDB.actor = partyActor
- self.partyTab = { enemyModList = new("ModList"), actor = partyActor }
- self.configTab = new("ConfigTab", self)
- self.itemsTab = new("ItemsTab", self)
- self.treeTab = new("TreeTab", self)
- self.skillsTab = new("SkillsTab", self)
- self.calcsTab = new("CalcsTab", self)
+ self.partyTab = { enemyModList = new("ModList"):ModList(), actor = partyActor }
+ self.configTab = new("ConfigTab"):ConfigTab(self)
+ self.itemsTab = new("ItemsTab"):ItemsTab(self)
+ self.treeTab = new("TreeTab"):TreeTab(self)
+ self.skillsTab = new("SkillsTab"):SkillsTab(self)
+ self.calcsTab = new("CalcsTab"):CalcsTab(self)
-- Set up savers table
self.savers = {
diff --git a/src/Classes/ComparePowerReportListControl.lua b/src/Classes/ComparePowerReportListControl.lua
index e57eb24993..59b94964fa 100644
--- a/src/Classes/ComparePowerReportListControl.lua
+++ b/src/Classes/ComparePowerReportListControl.lua
@@ -7,8 +7,11 @@
local t_insert = table.insert
local t_sort = table.sort
-local ComparePowerReportListClass = newClass("ComparePowerReportListControl", "ListControl", function(self, anchor, rect)
- self.ListControl(anchor, rect, 18, "VERTICAL", false)
+---@class ComparePowerReportListControl: ListControl
+local ComparePowerReportListClass = newClass("ComparePowerReportListControl", "ListControl")
+
+function ComparePowerReportListClass:ComparePowerReportListControl(anchor, rect)
+ self:ListControl(anchor, rect, 18, "VERTICAL", false)
local width = rect[3]
self.impactColumn = { width = width * 0.22, label = "", sortable = true }
@@ -22,7 +25,8 @@ local ComparePowerReportListClass = newClass("ComparePowerReportListControl", "L
self.colLabels = true
self.showRowSeparators = true
self.statusText = "Select a metric above to generate the power report."
-end)
+ return self
+end
function ComparePowerReportListClass:SetReport(stat, report)
self.impactColumn.label = stat and stat.label or ""
diff --git a/src/Classes/CompareTab.lua b/src/Classes/CompareTab.lua
index c8f00063cb..18b14093c7 100644
--- a/src/Classes/CompareTab.lua
+++ b/src/Classes/CompareTab.lua
@@ -115,9 +115,13 @@ local function matchFlags(reqFlags, notFlags, flags)
return true
end
-local CompareTabClass = newClass("CompareTab", "ControlHost", "Control", function(self, primaryBuild)
- self.ControlHost()
- self.Control()
+---@class CompareTab: ControlHost, Control
+local CompareTabClass = newClass("CompareTab", "ControlHost", "Control")
+
+---@param primaryBuild Build
+function CompareTabClass:CompareTab(primaryBuild)
+ self:ControlHost()
+ self:Control()
self.primaryBuild = primaryBuild
@@ -141,13 +145,13 @@ local CompareTabClass = newClass("CompareTab", "ControlHost", "Control", functio
self.treeOverlayMode = true
-- Tooltip for item hover in Items view
- self.itemTooltip = new("Tooltip")
+ self.itemTooltip = new("Tooltip"):Tooltip()
-- Items expanded mode (false = compact names only, true = full item details inline)
self.itemsExpandedMode = false
-- Tooltip for calcs hover breakdown
- self.calcsTooltip = new("Tooltip")
+ self.calcsTooltip = new("Tooltip"):Tooltip()
self.calcsShowOnlyDifferences = true
-- Interactive config controls state
@@ -176,21 +180,22 @@ local CompareTabClass = newClass("CompareTab", "ControlHost", "Control", functio
-- Controls for the comparison screen
self:InitControls()
-end)
+ return self
+end
function CompareTabClass:InitControls()
-- Sub-tab buttons
local subTabs = { "Summary", "Tree", "Skills", "Items", "Calcs", "Config" }
local subTabModes = { "SUMMARY", "TREE", "SKILLS", "ITEMS", "CALCS", "CONFIG" }
- self.controls.subTabAnchor = new("Control", nil, {0, 0, 0, 20})
+ self.controls.subTabAnchor = new("Control"):Control(nil, {0, 0, 0, 20})
for i, tabName in ipairs(subTabs) do
local mode = subTabModes[i]
local prevName = i > 1 and ("subTab" .. subTabs[i-1]) or "subTabAnchor"
local anchor = i == 1
and {"TOPLEFT", self.controls.subTabAnchor, "TOPLEFT"}
or {"LEFT", self.controls[prevName], "RIGHT"}
- self.controls["subTab" .. tabName] = new("ButtonControl", anchor, {i == 1 and 0 or 4, 0, 72, 20}, tabName, function()
+ self.controls["subTab" .. tabName] = new("ButtonControl"):ButtonControl(anchor, {i == 1 and 0 or 4, 0, 72, 20}, tabName, function()
-- Clear tree overlay compareSpec when leaving TREE mode
if self.compareViewMode == "TREE" and self.treeOverlayMode
and self.primaryBuild.treeTab and self.primaryBuild.treeTab.viewer then
@@ -211,8 +216,8 @@ function CompareTabClass:InitControls()
end
-- Build B selector dropdown
- self.controls.compareBuildLabel = new("LabelControl", {"TOPLEFT", self.controls.subTabAnchor, "TOPLEFT"}, {0, -88, 0, 16}, "^7Compare with:")
- self.controls.compareBuildSelect = new("DropDownControl", {"LEFT", self.controls.compareBuildLabel, "RIGHT"}, {4, 0, 250, 20}, {}, function(index, value)
+ self.controls.compareBuildLabel = new("LabelControl"):LabelControl({"TOPLEFT", self.controls.subTabAnchor, "TOPLEFT"}, {0, -88, 0, 16}, "^7Compare with:")
+ self.controls.compareBuildSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.compareBuildLabel, "RIGHT"}, {4, 0, 250, 20}, {}, function(index, value)
if index and index > 0 and index <= #self.compareEntries then
self.activeCompareIndex = index
self.treeSearchNeedsSync = true
@@ -223,12 +228,12 @@ function CompareTabClass:InitControls()
end
-- Import button (opens import popup)
- self.controls.importBtn = new("ButtonControl", {"LEFT", self.controls.compareBuildSelect, "RIGHT"}, {8, 0, 100, 20}, "Import...", function()
+ self.controls.importBtn = new("ButtonControl"):ButtonControl({"LEFT", self.controls.compareBuildSelect, "RIGHT"}, {8, 0, 100, 20}, "Import...", function()
self:OpenImportPopup()
end)
-- Re-import current build button
- self.controls.reimportBtn = new("ButtonControl", {"LEFT", self.controls.importBtn, "RIGHT"}, {4, 0, 140, 20}, "Re-import Current", function()
+ self.controls.reimportBtn = new("ButtonControl"):ButtonControl({"LEFT", self.controls.importBtn, "RIGHT"}, {4, 0, 140, 20}, "Re-import Current", function()
self:ReimportPrimary()
end)
self.controls.reimportBtn.tooltipFunc = function(tooltip)
@@ -255,7 +260,7 @@ function CompareTabClass:InitControls()
end
-- Remove comparison build button
- self.controls.removeBtn = new("ButtonControl", {"LEFT", self.controls.reimportBtn, "RIGHT"}, {4, 0, 70, 20}, "Remove", function()
+ self.controls.removeBtn = new("ButtonControl"):ButtonControl({"LEFT", self.controls.reimportBtn, "RIGHT"}, {4, 0, 70, 20}, "Remove", function()
if self.activeCompareIndex > 0 and self.activeCompareIndex <= #self.compareEntries then
self:RemoveBuild(self.activeCompareIndex)
end
@@ -272,9 +277,9 @@ function CompareTabClass:InitControls()
end
-- Tree spec selector for comparison build
- self.controls.compareSpecLabel = new("LabelControl", {"TOPLEFT", self.controls.subTabAnchor, "TOPLEFT"}, {0, -54, 0, 16}, "^7Tree set:")
+ self.controls.compareSpecLabel = new("LabelControl"):LabelControl({"TOPLEFT", self.controls.subTabAnchor, "TOPLEFT"}, {0, -54, 0, 16}, "^7Tree set:")
self.controls.compareSpecLabel.shown = setsEnabled
- self.controls.compareSpecSelect = new("DropDownControl", {"LEFT", self.controls.compareSpecLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
+ self.controls.compareSpecSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.compareSpecLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry and entry.treeTab and entry.treeTab.specList[index] then
entry:SetActiveSpec(index)
@@ -289,9 +294,9 @@ function CompareTabClass:InitControls()
self.controls.compareSpecSelect.enableDroppedWidth = true
-- Skill set selector for comparison build
- self.controls.compareSkillSetLabel = new("LabelControl", {"LEFT", self.controls.compareSpecSelect, "RIGHT"}, {8, 0, 0, 16}, "^7Skill set:")
+ self.controls.compareSkillSetLabel = new("LabelControl"):LabelControl({"LEFT", self.controls.compareSpecSelect, "RIGHT"}, {8, 0, 0, 16}, "^7Skill set:")
self.controls.compareSkillSetLabel.shown = setsEnabled
- self.controls.compareSkillSetSelect = new("DropDownControl", {"LEFT", self.controls.compareSkillSetLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
+ self.controls.compareSkillSetSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.compareSkillSetLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry and entry.skillsTab and entry.skillsTab.skillSetOrderList[index] then
entry:SetActiveSkillSet(entry.skillsTab.skillSetOrderList[index])
@@ -299,9 +304,9 @@ function CompareTabClass:InitControls()
end)
self.controls.compareSkillSetSelect.enabled = setsEnabled
-- Item set selector for comparison build
- self.controls.compareItemSetLabel = new("LabelControl", {"LEFT", self.controls.compareSkillSetSelect, "RIGHT"}, {8, 0, 0, 16}, "^7Item set:")
+ self.controls.compareItemSetLabel = new("LabelControl"):LabelControl({"LEFT", self.controls.compareSkillSetSelect, "RIGHT"}, {8, 0, 0, 16}, "^7Item set:")
self.controls.compareItemSetLabel.shown = setsEnabled
- self.controls.compareItemSetSelect = new("DropDownControl", {"LEFT", self.controls.compareItemSetLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
+ self.controls.compareItemSetSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.compareItemSetLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry and entry.itemsTab and entry.itemsTab.itemSetOrderList[index] then
entry:SetActiveItemSet(entry.itemsTab.itemSetOrderList[index])
@@ -309,9 +314,9 @@ function CompareTabClass:InitControls()
end)
self.controls.compareItemSetSelect.enabled = setsEnabled
-- Config set selector for comparison build
- self.controls.compareConfigSetLabel = new("LabelControl", {"LEFT", self.controls.compareItemSetSelect, "RIGHT"}, {8, 0, 0, 16}, "^7Config set:")
+ self.controls.compareConfigSetLabel = new("LabelControl"):LabelControl({"LEFT", self.controls.compareItemSetSelect, "RIGHT"}, {8, 0, 0, 16}, "^7Config set:")
self.controls.compareConfigSetLabel.shown = setsEnabled
- self.controls.compareConfigSetSelect = new("DropDownControl", {"LEFT", self.controls.compareConfigSetLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
+ self.controls.compareConfigSetSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.compareConfigSetLabel, "RIGHT"}, {2, 0, 150, 20}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry and entry.configTab then
local setId = entry.configTab.configSetOrderList[index]
@@ -487,7 +492,7 @@ function CompareTabClass:InitControls()
{ label = "Effective DPS", buffMode = "EFFECTIVE" },
}
-- Primary build calcs skill controls
- self.controls.primCalcsSocketGroup = new("DropDownControl", nil, {0, 0, 200, 18}, {}, function(index, value)
+ self.controls.primCalcsSocketGroup = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value)
self.primaryBuild.calcsTab.input.skill_number = index
self.primaryBuild.buildFlag = true
end)
@@ -495,7 +500,7 @@ function CompareTabClass:InitControls()
self.controls.primCalcsSocketGroup.maxDroppedWidth = 400
self.controls.primCalcsSocketGroup.enableDroppedWidth = true
- self.controls.primCalcsMainSkill = new("DropDownControl", nil, {0, 0, 200, 18}, {}, function(index, value)
+ self.controls.primCalcsMainSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value)
local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number]
if mainSocketGroup then
mainSocketGroup.mainActiveSkillCalcs = index
@@ -504,7 +509,7 @@ function CompareTabClass:InitControls()
end)
self.controls.primCalcsMainSkill.shown = false
- self.controls.primCalcsSkillPart = new("DropDownControl", nil, {0, 0, 150, 18}, {}, function(index, value)
+ self.controls.primCalcsSkillPart = new("DropDownControl"):DropDownControl(nil, {0, 0, 150, 18}, {}, function(index, value)
local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number]
if mainSocketGroup then
local displaySkillList = mainSocketGroup.displaySkillListCalcs
@@ -517,7 +522,7 @@ function CompareTabClass:InitControls()
end)
self.controls.primCalcsSkillPart.shown = false
- self.controls.primCalcsStageCount = new("EditControl", nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
+ self.controls.primCalcsStageCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number]
if mainSocketGroup then
local displaySkillList = mainSocketGroup.displaySkillListCalcs
@@ -530,7 +535,7 @@ function CompareTabClass:InitControls()
end)
self.controls.primCalcsStageCount.shown = false
- self.controls.primCalcsMineCount = new("EditControl", nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
+ self.controls.primCalcsMineCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number]
if mainSocketGroup then
local displaySkillList = mainSocketGroup.displaySkillListCalcs
@@ -543,13 +548,13 @@ function CompareTabClass:InitControls()
end)
self.controls.primCalcsMineCount.shown = false
- self.controls.primCalcsShowMinion = new("CheckBoxControl", nil, {0, 0, 18}, nil, function(state)
+ self.controls.primCalcsShowMinion = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state)
self.primaryBuild.calcsTab.input.showMinion = state
self.primaryBuild.buildFlag = true
end, "Show stats for the minion instead of the player.")
self.controls.primCalcsShowMinion.shown = false
- self.controls.primCalcsMinion = new("DropDownControl", nil, {0, 0, 140, 18}, {}, function(index, value)
+ self.controls.primCalcsMinion = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value)
local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number]
if mainSocketGroup then
local displaySkillList = mainSocketGroup.displaySkillListCalcs
@@ -569,7 +574,7 @@ function CompareTabClass:InitControls()
end)
self.controls.primCalcsMinion.shown = false
- self.controls.primCalcsMinionSkill = new("DropDownControl", nil, {0, 0, 140, 18}, {}, function(index, value)
+ self.controls.primCalcsMinionSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value)
local mainSocketGroup = self.primaryBuild.skillsTab.socketGroupList[self.primaryBuild.calcsTab.input.skill_number]
if mainSocketGroup then
local displaySkillList = mainSocketGroup.displaySkillListCalcs
@@ -623,7 +628,7 @@ function CompareTabClass:InitControls()
self.controls.cmpCalcsSocketGroup.maxDroppedWidth = 400
self.controls.cmpCalcsSocketGroup.enableDroppedWidth = true
- self.controls.cmpCalcsMainSkill = new("DropDownControl", nil, {0, 0, 200, 18}, {}, function(index, value)
+ self.controls.cmpCalcsMainSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry then
local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number]
@@ -635,7 +640,7 @@ function CompareTabClass:InitControls()
end)
self.controls.cmpCalcsMainSkill.shown = false
- self.controls.cmpCalcsSkillPart = new("DropDownControl", nil, {0, 0, 150, 18}, {}, function(index, value)
+ self.controls.cmpCalcsSkillPart = new("DropDownControl"):DropDownControl(nil, {0, 0, 150, 18}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry then
local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number]
@@ -651,7 +656,7 @@ function CompareTabClass:InitControls()
end)
self.controls.cmpCalcsSkillPart.shown = false
- self.controls.cmpCalcsStageCount = new("EditControl", nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
+ self.controls.cmpCalcsStageCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
local entry = self:GetActiveCompare()
if entry then
local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number]
@@ -667,7 +672,7 @@ function CompareTabClass:InitControls()
end)
self.controls.cmpCalcsStageCount.shown = false
- self.controls.cmpCalcsMineCount = new("EditControl", nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
+ self.controls.cmpCalcsMineCount = new("EditControl"):EditControl(nil, {0, 0, 52, 18}, "", nil, "%D", 5, function(buf)
local entry = self:GetActiveCompare()
if entry then
local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number]
@@ -683,7 +688,7 @@ function CompareTabClass:InitControls()
end)
self.controls.cmpCalcsMineCount.shown = false
- self.controls.cmpCalcsShowMinion = new("CheckBoxControl", nil, {0, 0, 18}, nil, function(state)
+ self.controls.cmpCalcsShowMinion = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state)
local entry = self:GetActiveCompare()
if entry then
entry.calcsTab.input.showMinion = state
@@ -692,7 +697,7 @@ function CompareTabClass:InitControls()
end, "Show stats for the minion instead of the player.")
self.controls.cmpCalcsShowMinion.shown = false
- self.controls.cmpCalcsMinion = new("DropDownControl", nil, {0, 0, 140, 18}, {}, function(index, value)
+ self.controls.cmpCalcsMinion = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry then
local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number]
@@ -715,7 +720,7 @@ function CompareTabClass:InitControls()
end)
self.controls.cmpCalcsMinion.shown = false
- self.controls.cmpCalcsMinionSkill = new("DropDownControl", nil, {0, 0, 140, 18}, {}, function(index, value)
+ self.controls.cmpCalcsMinionSkill = new("DropDownControl"):DropDownControl(nil, {0, 0, 140, 18}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry then
local mainSocketGroup = entry.skillsTab.socketGroupList[entry.calcsTab.input.skill_number]
@@ -765,7 +770,7 @@ function CompareTabClass:InitControls()
end)
self.controls.cmpCalcsMode.shown = false
- self.controls.calcsShowOnlyDifferencesCheck = new("CheckBoxControl", nil, {0, 0, 18}, "Show only differences", function(state)
+ self.controls.calcsShowOnlyDifferencesCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, "Show only differences", function(state)
self.calcsShowOnlyDifferences = state
end, "Show only rows that differ between both builds. Disable to include unchanged rows.")
self.controls.calcsShowOnlyDifferencesCheck.shown = function()
@@ -792,7 +797,7 @@ function CompareTabClass:InitControls()
end
-- Overlay toggle checkbox
- self.controls.treeOverlayCheck = new("CheckBoxControl", nil, {0, 0, 20}, "Overlay comparison", function(state)
+ self.controls.treeOverlayCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 20}, "Overlay comparison", function(state)
self.treeOverlayMode = state
self.treeSearchNeedsSync = true
if not state and self.primaryBuild.treeTab and self.primaryBuild.treeTab.viewer then
@@ -802,7 +807,7 @@ function CompareTabClass:InitControls()
self.controls.treeOverlayCheck.shown = treeFooterShown
-- Overlay-mode search (single search for primary viewer)
- self.controls.overlayTreeSearch = new("EditControl", nil, {0, 0, 300, 20}, "", "Search", "%c", 100, function(buf)
+ self.controls.overlayTreeSearch = new("EditControl"):EditControl(nil, {0, 0, 300, 20}, "", "Search", "%c", 100, function(buf)
if self.primaryBuild.treeTab and self.primaryBuild.treeTab.viewer then
self.primaryBuild.treeTab.viewer.searchStr = buf
end
@@ -812,7 +817,7 @@ function CompareTabClass:InitControls()
end
-- Items expanded mode toggle
- self.controls.itemsExpandedCheck = new("CheckBoxControl", nil, {0, 0, 20}, "Expanded mode", function(state)
+ self.controls.itemsExpandedCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 20}, "Expanded mode", function(state)
self.itemsExpandedMode = state
self.scrollY = 0
end)
@@ -824,9 +829,9 @@ function CompareTabClass:InitControls()
local itemsShown = function()
return self.compareViewMode == "ITEMS" and self:GetActiveCompare() ~= nil
end
- self.controls.primaryItemSetLabel = new("LabelControl", nil, {0, 0, 0, 16}, "^7Item set:")
+ self.controls.primaryItemSetLabel = new("LabelControl"):LabelControl(nil, {0, 0, 0, 16}, "^7Item set:")
self.controls.primaryItemSetLabel.shown = itemsShown
- self.controls.primaryItemSetSelect = new("DropDownControl", nil, {0, 0, 216, 20}, {}, function(index, value)
+ self.controls.primaryItemSetSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 216, 20}, {}, function(index, value)
if self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.itemSetOrderList[index] then
self.primaryBuild.itemsTab:SetActiveItemSet(self.primaryBuild.itemsTab.itemSetOrderList[index])
self.primaryBuild.itemsTab:AddUndoState()
@@ -836,9 +841,9 @@ function CompareTabClass:InitControls()
self.controls.primaryItemSetSelect.shown = itemsShown
-- Item set dropdown for compare build
- self.controls.compareItemSetLabel2 = new("LabelControl", nil, {0, 0, 0, 16}, "^7Item set:")
+ self.controls.compareItemSetLabel2 = new("LabelControl"):LabelControl(nil, {0, 0, 0, 16}, "^7Item set:")
self.controls.compareItemSetLabel2.shown = itemsShown
- self.controls.compareItemSetSelect2 = new("DropDownControl", nil, {0, 0, 216, 20}, {}, function(index, value)
+ self.controls.compareItemSetSelect2 = new("DropDownControl"):DropDownControl(nil, {0, 0, 216, 20}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry and entry.itemsTab and entry.itemsTab.itemSetOrderList[index] then
entry:SetActiveItemSet(entry.itemsTab.itemSetOrderList[index])
@@ -848,9 +853,9 @@ function CompareTabClass:InitControls()
self.controls.compareItemSetSelect2.shown = itemsShown
-- Tree set dropdown for primary build
- self.controls.primaryTreeSetLabel = new("LabelControl", nil, {0, 0, 0, 16}, "^7Tree set:")
+ self.controls.primaryTreeSetLabel = new("LabelControl"):LabelControl(nil, {0, 0, 0, 16}, "^7Tree set:")
self.controls.primaryTreeSetLabel.shown = itemsShown
- self.controls.primaryTreeSetSelect = new("DropDownControl", nil, {0, 0, 216, 20}, {}, function(index, value)
+ self.controls.primaryTreeSetSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 216, 20}, {}, function(index, value)
if self.primaryBuild.treeTab and self.primaryBuild.treeTab.specList[index] then
self.primaryBuild.modFlag = true
self.primaryBuild.treeTab:SetActiveSpec(index)
@@ -862,9 +867,9 @@ function CompareTabClass:InitControls()
self.controls.primaryTreeSetSelect.enableDroppedWidth = true
-- Tree set dropdown for compare build
- self.controls.compareTreeSetLabel = new("LabelControl", nil, {0, 0, 0, 16}, "^7Tree set:")
+ self.controls.compareTreeSetLabel = new("LabelControl"):LabelControl(nil, {0, 0, 0, 16}, "^7Tree set:")
self.controls.compareTreeSetLabel.shown = itemsShown
- self.controls.compareTreeSetSelect = new("DropDownControl", nil, {0, 0, 216, 20}, {}, function(index, value)
+ self.controls.compareTreeSetSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 216, 20}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry and entry.treeTab and entry.treeTab.specList[index] then
entry:SetActiveSpec(index)
@@ -879,13 +884,13 @@ function CompareTabClass:InitControls()
self.controls.compareTreeSetSelect.enableDroppedWidth = true
-- Footer anchor controls (side-by-side only)
- self.controls.leftFooterAnchor = new("Control", nil, {0, 0, 0, 20})
+ self.controls.leftFooterAnchor = new("Control"):Control(nil, {0, 0, 0, 20})
self.controls.leftFooterAnchor.shown = treeSideBySideShown
- self.controls.rightFooterAnchor = new("Control", nil, {0, 0, 0, 20})
+ self.controls.rightFooterAnchor = new("Control"):Control(nil, {0, 0, 0, 20})
self.controls.rightFooterAnchor.shown = treeSideBySideShown
-- Left side (primary build) spec/version controls (header, both modes)
- self.controls.leftSpecSelect = new("DropDownControl", nil, {0, 0, 180, 20}, {}, function(index, value)
+ self.controls.leftSpecSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 180, 20}, {}, function(index, value)
if self.primaryBuild.treeTab and self.primaryBuild.treeTab.specList[index] then
self.primaryBuild.modFlag = true
self.primaryBuild.treeTab:SetActiveSpec(index)
@@ -895,7 +900,7 @@ function CompareTabClass:InitControls()
self.controls.leftSpecSelect.maxDroppedWidth = 500
self.controls.leftSpecSelect.enableDroppedWidth = true
- self.controls.leftVersionSelect = new("DropDownControl", {"LEFT", self.controls.leftSpecSelect, "RIGHT"}, {4, 0, 100, 20}, self.treeVersionDropdownList, function(index, selected)
+ self.controls.leftVersionSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.leftSpecSelect, "RIGHT"}, {4, 0, 100, 20}, self.treeVersionDropdownList, function(index, selected)
if selected and selected.value and self.primaryBuild.spec and selected.value ~= self.primaryBuild.spec.treeVersion then
self.primaryBuild.treeTab:OpenVersionConvertPopup(selected.value, true)
end
@@ -903,7 +908,7 @@ function CompareTabClass:InitControls()
self.controls.leftVersionSelect.shown = treeFooterShown
-- Left search (footer, side-by-side only)
- self.controls.leftTreeSearch = new("EditControl", {"TOPLEFT", self.controls.leftFooterAnchor, "TOPLEFT"}, {0, 0, 200, 20}, "", "Search", "%c", 100, function(buf)
+ self.controls.leftTreeSearch = new("EditControl"):EditControl({"TOPLEFT", self.controls.leftFooterAnchor, "TOPLEFT"}, {0, 0, 200, 20}, "", "Search", "%c", 100, function(buf)
if self.primaryBuild.treeTab and self.primaryBuild.treeTab.viewer then
self.primaryBuild.treeTab.viewer.searchStr = buf
end
@@ -911,7 +916,7 @@ function CompareTabClass:InitControls()
self.controls.leftTreeSearch.shown = treeSideBySideShown
-- Right side (compare build) spec/version controls (header, both modes)
- self.controls.rightSpecSelect = new("DropDownControl", nil, {0, 0, 180, 20}, {}, function(index, value)
+ self.controls.rightSpecSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 180, 20}, {}, function(index, value)
local entry = self:GetActiveCompare()
if entry and entry.treeTab and entry.treeTab.specList[index] then
entry:SetActiveSpec(index)
@@ -925,7 +930,7 @@ function CompareTabClass:InitControls()
self.controls.rightSpecSelect.maxDroppedWidth = 500
self.controls.rightSpecSelect.enableDroppedWidth = true
- self.controls.rightVersionSelect = new("DropDownControl", {"LEFT", self.controls.rightSpecSelect, "RIGHT"}, {4, 0, 100, 20}, self.treeVersionDropdownList, function(index, selected)
+ self.controls.rightVersionSelect = new("DropDownControl"):DropDownControl({"LEFT", self.controls.rightSpecSelect, "RIGHT"}, {4, 0, 100, 20}, self.treeVersionDropdownList, function(index, selected)
local entry = self:GetActiveCompare()
if entry and selected and selected.value and entry.spec then
if selected.value ~= entry.spec.treeVersion then
@@ -936,7 +941,7 @@ function CompareTabClass:InitControls()
self.controls.rightVersionSelect.shown = treeFooterShown
-- Copy compared tree to primary build
- self.controls.copySpecBtn = new("ButtonControl", {"LEFT", self.controls.rightVersionSelect, "RIGHT"}, {4, 0, 76, 20}, "Copy tree", function()
+ self.controls.copySpecBtn = new("ButtonControl"):ButtonControl({"LEFT", self.controls.rightVersionSelect, "RIGHT"}, {4, 0, 76, 20}, "Copy tree", function()
self:CopyCompareSpecToPrimary(false)
end)
self.controls.copySpecBtn.shown = treeFooterShown
@@ -945,14 +950,14 @@ function CompareTabClass:InitControls()
return entry and entry.treeTab and entry.treeTab.specList[entry.treeTab.activeSpec] ~= nil
end
- self.controls.copySpecUseBtn = new("ButtonControl", {"LEFT", self.controls.copySpecBtn, "RIGHT"}, {2, 0, 100, 20}, "Copy and use", function()
+ self.controls.copySpecUseBtn = new("ButtonControl"):ButtonControl({"LEFT", self.controls.copySpecBtn, "RIGHT"}, {2, 0, 100, 20}, "Copy and use", function()
self:CopyCompareSpecToPrimary(true)
end)
self.controls.copySpecUseBtn.shown = treeFooterShown
self.controls.copySpecUseBtn.enabled = self.controls.copySpecBtn.enabled
-- Right search (footer, side-by-side only)
- self.controls.rightTreeSearch = new("EditControl", {"TOPLEFT", self.controls.rightFooterAnchor, "TOPLEFT"}, {0, 0, 200, 20}, "", "Search", "%c", 100, function(buf)
+ self.controls.rightTreeSearch = new("EditControl"):EditControl({"TOPLEFT", self.controls.rightFooterAnchor, "TOPLEFT"}, {0, 0, 200, 20}, "", "Search", "%c", 100, function(buf)
local entry = self:GetActiveCompare()
if entry and entry.treeTab and entry.treeTab.viewer then
entry.treeTab.viewer.searchStr = buf
@@ -961,7 +966,7 @@ function CompareTabClass:InitControls()
self.controls.rightTreeSearch.shown = treeSideBySideShown
-- Config view: "Copy Config from Compare Build" button
- self.controls.copyConfigBtn = new("ButtonControl", nil, {0, 0, 240, 20},
+ self.controls.copyConfigBtn = new("ButtonControl"):ButtonControl(nil, {0, 0, 240, 20},
"Copy Config from Compare Build",
function() self:CopyCompareConfig() end)
self.controls.copyConfigBtn.shown = function()
@@ -969,7 +974,7 @@ function CompareTabClass:InitControls()
end
-- Config view: "Show All / Hide Ineligible" toggle button
- self.controls.configToggleBtn = new("ButtonControl", nil, {0, 0, 240, 20},
+ self.controls.configToggleBtn = new("ButtonControl"):ButtonControl(nil, {0, 0, 240, 20},
function()
return self.configToggle and "Hide Ineligible Configurations" or "Show All Configurations"
end,
@@ -981,7 +986,7 @@ function CompareTabClass:InitControls()
end
-- Config view: search bar
- self.controls.configSearchEdit = new("EditControl", nil, {0, 0, 240, 20}, "", "Search", "%c", 100, nil, nil, nil, true)
+ self.controls.configSearchEdit = new("EditControl"):EditControl(nil, {0, 0, 240, 20}, "", "Search", "%c", 100, nil, nil, nil, true)
self.controls.configSearchEdit.shown = function()
return self.compareViewMode == "CONFIG" and self:GetActiveCompare() ~= nil
end
@@ -990,9 +995,9 @@ function CompareTabClass:InitControls()
local configShown = function()
return self.compareViewMode == "CONFIG" and self:GetActiveCompare() ~= nil
end
- self.controls.configPrimarySetLabel = new("LabelControl", nil, {0, 0, 0, 16}, "^7Config set:")
+ self.controls.configPrimarySetLabel = new("LabelControl"):LabelControl(nil, {0, 0, 0, 16}, "^7Config set:")
self.controls.configPrimarySetLabel.shown = configShown
- self.controls.configPrimarySetSelect = new("DropDownControl", nil, {0, 0, 150, 20}, nil, function(index, value)
+ self.controls.configPrimarySetSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 150, 20}, nil, function(index, value)
local configTab = self.primaryBuild.configTab
local setId = configTab.configSetOrderList[index]
if setId then
@@ -1020,7 +1025,7 @@ function CompareTabClass:InitControls()
t_insert(powerStatList, entry)
end
end
- self.controls.comparePowerStatSelect = new("DropDownControl", nil, {0, 0, 200, 20}, powerStatList, function(index, value)
+ self.controls.comparePowerStatSelect = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 20}, powerStatList, function(index, value)
if value and value.stat and value ~= self.comparePowerStat then
self.comparePowerStat = value
self.comparePowerDirty = true
@@ -1041,35 +1046,35 @@ function CompareTabClass:InitControls()
end
-- Category checkboxes
- self.controls.comparePowerTreeCheck = new("CheckBoxControl", nil, {0, 0, 18}, "Tree:", function(state)
+ self.controls.comparePowerTreeCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, "Tree:", function(state)
self.comparePowerCategories.treeNodes = state
self.comparePowerDirty = true
end, "Include passive tree nodes from compared build")
self.controls.comparePowerTreeCheck.shown = powerReportShown
self.controls.comparePowerTreeCheck.state = true
- self.controls.comparePowerItemsCheck = new("CheckBoxControl", nil, {0, 0, 18}, "Items:", function(state)
+ self.controls.comparePowerItemsCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, "Items:", function(state)
self.comparePowerCategories.items = state
self.comparePowerDirty = true
end, "Include items from compared build")
self.controls.comparePowerItemsCheck.shown = powerReportShown
self.controls.comparePowerItemsCheck.state = true
- self.controls.comparePowerGemsCheck = new("CheckBoxControl", nil, {0, 0, 18}, "Skill gems:", function(state)
+ self.controls.comparePowerGemsCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, "Skill gems:", function(state)
self.comparePowerCategories.skillGems = state
self.comparePowerDirty = true
end, "Include skill gem groups unique to compared build")
self.controls.comparePowerGemsCheck.shown = powerReportShown
self.controls.comparePowerGemsCheck.state = true
- self.controls.comparePowerSupportGemsCheck = new("CheckBoxControl", nil, {0, 0, 18}, "Support gems:", function(state)
+ self.controls.comparePowerSupportGemsCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, "Support gems:", function(state)
self.comparePowerCategories.supportGems = state
self.comparePowerDirty = true
end, "Include support gems from compared build's active skill")
self.controls.comparePowerSupportGemsCheck.shown = powerReportShown
self.controls.comparePowerSupportGemsCheck.state = true
- self.controls.comparePowerConfigCheck = new("CheckBoxControl", nil, {0, 0, 18}, "Config:", function(state)
+ self.controls.comparePowerConfigCheck = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, "Config:", function(state)
self.comparePowerCategories.config = state
self.comparePowerDirty = true
end, "Include config option differences from compared build")
@@ -1077,19 +1082,19 @@ function CompareTabClass:InitControls()
self.controls.comparePowerConfigCheck.state = true
-- Power report list control (static height, own scrollbar)
- self.controls.comparePowerReportList = new("ComparePowerReportListControl", nil, {0, 0, 750, 250})
+ self.controls.comparePowerReportList = new("ComparePowerReportListControl"):ComparePowerReportListControl(nil, {0, 0, 750, 250})
self.controls.comparePowerReportList.compareTab = self
self.controls.comparePowerReportList.shown = powerReportShown
-- Scrollbar for Calcs sub-tab
- self.controls.calcsScrollBar = new("ScrollBarControl", nil, {0, 0, 18, 0}, 50, "VERTICAL", true)
+ self.controls.calcsScrollBar = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 18, 0}, 50, "VERTICAL", true)
local calcsScrollBar = self.controls.calcsScrollBar
self.controls.calcsScrollBar.shown = function()
return self.compareViewMode == "CALCS" and self:GetActiveCompare() ~= nil and calcsScrollBar.enabled
end
-- Shared vertical scrollbar for Summary/Items/Skills/Config sub-tabs
- self.controls.viewScrollBar = new("ScrollBarControl", nil, {0, 0, 18, 0}, 50, "VERTICAL", true)
+ self.controls.viewScrollBar = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 18, 0}, 50, "VERTICAL", true)
local viewScrollBar = self.controls.viewScrollBar
self.controls.viewScrollBar.shown = function()
return self:GetActiveCompare() ~= nil
@@ -1099,14 +1104,14 @@ function CompareTabClass:InitControls()
end
-- Horizontal scrollbar for Items sub-tab
- self.controls.itemsHScrollBar = new("ScrollBarControl", nil, {0, 0, 0, LAYOUT.itemsHScrollBarHeight}, 60, "HORIZONTAL", true)
+ self.controls.itemsHScrollBar = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 0, LAYOUT.itemsHScrollBarHeight}, 60, "HORIZONTAL", true)
local itemsHScrollBar = self.controls.itemsHScrollBar
self.controls.itemsHScrollBar.shown = function()
return self.compareViewMode == "ITEMS" and self:GetActiveCompare() ~= nil and itemsHScrollBar.enabled
end
-- Horizontal scrollbar for Skills sub-tab
- self.controls.skillsHScrollBar = new("ScrollBarControl", nil, {0, 0, 0, LAYOUT.skillsHScrollBarHeight}, 60, "HORIZONTAL", true)
+ self.controls.skillsHScrollBar = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 0, LAYOUT.skillsHScrollBarHeight}, 60, "HORIZONTAL", true)
local skillsHScrollBar = self.controls.skillsHScrollBar
self.controls.skillsHScrollBar.shown = function()
return self.compareViewMode == "SKILLS" and self:GetActiveCompare() ~= nil and skillsHScrollBar.enabled
@@ -1177,7 +1182,7 @@ local function makeConfigControl(varData, inputTable, configTab, buildObj, sourc
local control
local pVal = inputTable[varData.var]
if varData.type == "check" then
- control = new("CheckBoxControl", nil, {0, 0, 18}, nil, function(state)
+ control = new("CheckBoxControl"):CheckBoxControl(nil, {0, 0, 18}, nil, function(state)
inputTable[varData.var] = state
configTab:UpdateControls()
configTab:BuildModList()
@@ -1188,7 +1193,7 @@ local function makeConfigControl(varData, inputTable, configTab, buildObj, sourc
or varData.type == "countAllowZero" or varData.type == "float" then
local filter = (varData.type == "integer" and "^%-%d")
or (varData.type == "float" and "^%d.") or "%D"
- control = new("EditControl", nil, {0, 0, 90, 18},
+ control = new("EditControl"):EditControl(nil, {0, 0, 90, 18},
tostring(pVal or ""), nil, filter, 7,
function(buf)
inputTable[varData.var] = tonumber(buf)
@@ -1197,7 +1202,7 @@ local function makeConfigControl(varData, inputTable, configTab, buildObj, sourc
buildObj.buildFlag = true
end)
elseif varData.type == "list" and varData.list then
- control = new("DropDownControl", nil, {0, 0, 150, 18},
+ control = new("DropDownControl"):DropDownControl(nil, {0, 0, 150, 18},
varData.list, function(index, value)
inputTable[varData.var] = value.val
configTab:UpdateControls()
@@ -1306,7 +1311,7 @@ end
-- Import a comparison build from XML text
function CompareTabClass:ImportBuild(xmlText, label)
- local entry = new("CompareEntry", xmlText, label)
+ local entry = new("CompareEntry"):CompareEntry(xmlText, label)
if entry and entry.calcsTab and entry.calcsTab.mainOutput then
t_insert(self.compareEntries, entry)
self.activeCompareIndex = #self.compareEntries
@@ -1390,7 +1395,7 @@ function CompareTabClass:CopyCompareSpecToPrimary(andUse)
-- Create new spec from source (same pattern as PassiveSpecListControl Copy)
-- Note: we don't copy jewels because they reference item IDs in the compared
-- build's itemsTab which don't exist in the primary build
- local newSpec = new("PassiveSpec", self.primaryBuild, sourceSpec.treeVersion)
+ local newSpec = new("PassiveSpec"):PassiveSpec(self.primaryBuild, sourceSpec.treeVersion)
newSpec.title = (sourceSpec.title or "Default") .. " (Compared)"
newSpec:RestoreUndoState(sourceSpec:CreateUndoState())
newSpec:BuildClusterJewelGraphs()
@@ -1492,7 +1497,7 @@ function CompareTabClass:CopyCompareItemToPrimary(slotName, compareEntry, andUse
local cItem = cSlot and compareEntry.itemsTab.items and compareEntry.itemsTab.items[cSlot.selItemId]
if not cItem or not cItem.raw then return end
- local newItem = new("Item", cItem.raw)
+ local newItem = new("Item"):Item(cItem.raw)
newItem:NormaliseQuality()
local pItemsTab = self.primaryBuild.itemsTab
pItemsTab:AddItem(newItem, true) -- true = noAutoEquip
@@ -1515,20 +1520,20 @@ function CompareTabClass:OpenImportPopup()
-- Use a local variable for state text so it doesn't go into the controls table
-- (PopupDialog iterates all controls table entries and expects them to be control objects)
local stateText = ""
- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Paste a build code or URL to import as comparison:")
- controls.input = new("EditControl", nil, {0, 50, 450, 20}, "", nil, nil, nil, nil, nil, nil, true)
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Paste a build code or URL to import as comparison:")
+ controls.input = new("EditControl"):EditControl(nil, {0, 50, 450, 20}, "", nil, nil, nil, nil, nil, nil, true)
controls.input.enterFunc = function()
if controls.input.buf and controls.input.buf ~= "" then
controls.go.onClick()
end
end
- controls.name = new("EditControl", nil, {0, 80, 450, 20}, "", "Name (optional)", nil, 100, nil)
- controls.state = new("LabelControl", {"TOPLEFT", controls.name, "BOTTOMLEFT"}, {0, 4, 0, 16})
+ controls.name = new("EditControl"):EditControl(nil, {0, 80, 450, 20}, "", "Name (optional)", nil, 100, nil)
+ controls.state = new("LabelControl"):LabelControl({"TOPLEFT", controls.name, "BOTTOMLEFT"}, {0, 4, 0, 16})
controls.state.label = function()
return stateText or ""
end
- controls.go = new("ButtonControl", nil, {-118, 130, 80, 20}, "Import", function()
+ controls.go = new("ButtonControl"):ButtonControl(nil, {-118, 130, 80, 20}, "Import", function()
local buf = controls.input.buf
if not buf or buf == "" then
return
@@ -1565,11 +1570,11 @@ function CompareTabClass:OpenImportPopup()
stateText = colorCodes.NEGATIVE .. "Invalid build code"
end
end)
- controls.importFolder = new("ButtonControl", nil, {0, 130, 140, 20}, "Import from Folder", function()
+ controls.importFolder = new("ButtonControl"):ButtonControl(nil, {0, 130, 140, 20}, "Import from Folder", function()
main:ClosePopup()
self:OpenImportFolderPopup()
end)
- controls.cancel = new("ButtonControl", nil, {118, 130, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {118, 130, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(500, 160, "Import Comparison Build", controls, "go", "input", "cancel")
@@ -1633,7 +1638,7 @@ function CompareTabClass:OpenImportFolderPopup()
controls.sort:SelByValue(sortMode, "sortMode")
-- Build list itself. Reuses BuildListControl (which provides the PathControl breadcrumbs)
- controls.buildList = new("BuildListControl", {"TOPLEFT", nil, "TOPLEFT"}, {15, 75, 0, 0}, listHost)
+ controls.buildList = new("BuildListControl"):BuildListControl({"TOPLEFT", nil, "TOPLEFT"}, {15, 75, 0, 0}, listHost)
controls.buildList.width = function() return 670 end
controls.buildList.height = function() return 355 end
@@ -1665,14 +1670,14 @@ function CompareTabClass:OpenImportFolderPopup()
-- Populate the initial list now that the control (and its path control) exist.
listHost:BuildList()
- controls.open = new("ButtonControl", {"TOPLEFT", nil, "TOPLEFT"}, {255, 465, 80, 20}, "Open", function()
+ controls.open = new("ButtonControl"):ButtonControl({"TOPLEFT", nil, "TOPLEFT"}, {255, 465, 80, 20}, "Open", function()
local sel = controls.buildList.selValue
if sel then
controls.buildList:LoadBuild(sel)
end
end)
controls.open.enabled = function() return controls.buildList.selValue ~= nil end
- controls.close = new("ButtonControl", {"TOPLEFT", nil, "TOPLEFT"}, {365, 465, 80, 20}, "Close", function()
+ controls.close = new("ButtonControl"):ButtonControl({"TOPLEFT", nil, "TOPLEFT"}, {365, 465, 80, 20}, "Close", function()
main:ClosePopup()
end)
@@ -2823,7 +2828,7 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories
local jewelSlots = self:GetJewelComparisonSlots(compareEntry)
for _, jEntry in ipairs(jewelSlots) do
if jEntry.cItem and jEntry.cItem.raw and not (jEntry.pItem and jEntry.pItem.name == jEntry.cItem.name) then
- local newItem = new("Item", jEntry.cItem.raw)
+ local newItem = new("Item"):Item(jEntry.cItem.raw)
newItem:NormaliseQuality()
local bestImpactVal = nil
@@ -3921,7 +3926,7 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents)
local calcFunc, calcBase = self.calcs.getMiscCalculator(self.primaryBuild)
if calcFunc then
-- Create a fresh item to evaluate
- local newItem = new("Item", hoverEquipItem.raw)
+ local newItem = new("Item"):Item(hoverEquipItem.raw)
newItem:NormaliseQuality()
-- Determine what's currently in the target slot
diff --git a/src/Classes/CompareTab.lua.rej b/src/Classes/CompareTab.lua.rej
new file mode 100644
index 0000000000..f5bbc36c8d
--- /dev/null
+++ b/src/Classes/CompareTab.lua.rej
@@ -0,0 +1,137 @@
+diff a/src/Classes/CompareTab.lua b/src/Classes/CompareTab.lua (rejected hunks)
+@@ -344,12 +349,12 @@ function CompareTabClass:InitControls()
+ -- ============================================================
+ -- Comparison build main skill selector (row between sets and sub-tabs)
+ -- ============================================================
+- self.controls.cmpSkillLabel = new("LabelControl", {"TOPLEFT", self.controls.subTabAnchor, "TOPLEFT"}, {0, -32, 0, 16}, "^7Skill:")
++ self.controls.cmpSkillLabel = new("LabelControl"):LabelControl({"TOPLEFT", self.controls.subTabAnchor, "TOPLEFT"}, {0, -32, 0, 16}, "^7Skill:")
+ self.controls.cmpSkillLabel.shown = setsEnabled
+ self.controls.cmpSkillLabel.anchor.collapse = true
+
+ -- Socket group dropdown
+- self.controls.cmpSocketGroup = new("DropDownControl", {"LEFT", self.controls.cmpSkillLabel, "RIGHT"}, {4, 0, 200, 20}, {}, function(index, value)
++ self.controls.cmpSocketGroup = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpSkillLabel, "RIGHT"}, {4, 0, 200, 20}, {}, function(index, value)
+ local entry = self:GetActiveCompare()
+ if entry then
+ entry:SetMainSocketGroup(index)
+@@ -361,7 +366,7 @@ function CompareTabClass:InitControls()
+ self.controls.cmpSocketGroup.anchor.collapse = true
+
+ -- Active skill within group
+- self.controls.cmpMainSkill = new("DropDownControl", {"LEFT", self.controls.cmpSocketGroup, "RIGHT"}, {4, 0, 225, 20}, {}, function(index, value)
++ self.controls.cmpMainSkill = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpSocketGroup, "RIGHT"}, {4, 0, 225, 20}, {}, function(index, value)
+ local entry = self:GetActiveCompare()
+ if entry then
+ local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup]
+@@ -375,7 +380,7 @@ function CompareTabClass:InitControls()
+ self.controls.cmpMainSkill.anchor.collapse = true
+
+ -- Skill part (multi-part skills)
+- self.controls.cmpSkillPart = new("DropDownControl", {"LEFT", self.controls.cmpMainSkill, "RIGHT"}, {4, 0, 200, 20}, {}, function(index, value)
++ self.controls.cmpSkillPart = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpMainSkill, "RIGHT"}, {4, 0, 200, 20}, {}, function(index, value)
+ local entry = self:GetActiveCompare()
+ if entry then
+ local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup]
+@@ -393,10 +398,10 @@ function CompareTabClass:InitControls()
+ self.controls.cmpSkillPart.anchor.collapse = true
+
+ -- Stage count
+- self.controls.cmpStageCountLabel = new("LabelControl", {"LEFT", self.controls.cmpSkillPart, "RIGHT"}, {6, 0, 0, 16}, "^7Stages:")
++ self.controls.cmpStageCountLabel = new("LabelControl"):LabelControl({"LEFT", self.controls.cmpSkillPart, "RIGHT"}, {6, 0, 0, 16}, "^7Stages:")
+ self.controls.cmpStageCountLabel.shown = function() return self.controls.cmpStageCount.shown end
+ self.controls.cmpStageCountLabel.anchor.collapse = true
+- self.controls.cmpStageCount = new("EditControl", {"LEFT", self.controls.cmpStageCountLabel, "RIGHT"}, {4, 0, 52, 20}, "", nil, "%D", 5, function(buf)
++ self.controls.cmpStageCount = new("EditControl"):EditControl({ "LEFT", self.controls.cmpStageCountLabel, "RIGHT" }, { 4, 0, 52, 20 }, "", nil, "%D", 5, function(buf)
+ local entry = self:GetActiveCompare()
+ if entry then
+ local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup]
+@@ -414,10 +419,10 @@ function CompareTabClass:InitControls()
+ self.controls.cmpStageCount.anchor.collapse = true
+
+ -- Mine count
+- self.controls.cmpMineCountLabel = new("LabelControl", {"LEFT", self.controls.cmpStageCount, "RIGHT"}, {6, 0, 0, 16}, "^7Mines:")
++ self.controls.cmpMineCountLabel = new("LabelControl"):LabelControl({"LEFT", self.controls.cmpStageCount, "RIGHT"}, {6, 0, 0, 16}, "^7Mines:")
+ self.controls.cmpMineCountLabel.shown = function() return self.controls.cmpMineCount.shown end
+ self.controls.cmpMineCountLabel.anchor.collapse = true
+- self.controls.cmpMineCount = new("EditControl", {"LEFT", self.controls.cmpMineCountLabel, "RIGHT"}, {4, 0, 52, 20}, "", nil, "%D", 5, function(buf)
++ self.controls.cmpMineCount = new("EditControl"):EditControl({ "LEFT", self.controls.cmpMineCountLabel, "RIGHT" }, { 4, 0, 52, 20 }, "", nil, "%D", 5, function(buf)
+ local entry = self:GetActiveCompare()
+ if entry then
+ local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup]
+@@ -435,7 +440,7 @@ function CompareTabClass:InitControls()
+ self.controls.cmpMineCount.anchor.collapse = true
+
+ -- Minion selector
+- self.controls.cmpMinion = new("DropDownControl", {"LEFT", self.controls.cmpMineCount, "RIGHT"}, {6, 0, 140, 20}, {}, function(index, value)
++ self.controls.cmpMinion = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpMineCount, "RIGHT"}, {6, 0, 140, 20}, {}, function(index, value)
+ local entry = self:GetActiveCompare()
+ if entry then
+ local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup]
+@@ -460,7 +465,7 @@ function CompareTabClass:InitControls()
+ self.controls.cmpMinion.anchor.collapse = true
+
+ -- Minion skill selector
+- self.controls.cmpMinionSkill = new("DropDownControl", {"LEFT", self.controls.cmpMinion, "RIGHT"}, {4, 0, 140, 20}, {}, function(index, value)
++ self.controls.cmpMinionSkill = new("DropDownControl"):DropDownControl({"LEFT", self.controls.cmpMinion, "RIGHT"}, {4, 0, 140, 20}, {}, function(index, value)
+ local entry = self:GetActiveCompare()
+ if entry then
+ local mainSocketGroup = entry.skillsTab.socketGroupList[entry.mainSocketGroup]
+@@ -582,14 +587,14 @@ function CompareTabClass:InitControls()
+ end)
+ self.controls.primCalcsMinionSkill.shown = false
+
+- self.controls.primCalcsMode = new("DropDownControl", nil, {0, 0, 120, 18}, calcsBuffModeDropList, function(index, value)
++ self.controls.primCalcsMode = new("DropDownControl"):DropDownControl(nil, {0, 0, 120, 18}, calcsBuffModeDropList, function(index, value)
+ self.primaryBuild.calcsTab.input.misc_buffMode = value.buffMode
+ self.primaryBuild.buildFlag = true
+ end)
+ self.controls.primCalcsMode.shown = false
+
+ -- Compare build calcs skill controls
+- self.controls.cmpCalcsSocketGroup = new("DropDownControl", nil, {0, 0, 200, 18}, {}, function(index, value)
++ self.controls.cmpCalcsSocketGroup = new("DropDownControl"):DropDownControl(nil, {0, 0, 200, 18}, {}, function(index, value)
+ local entry = self:GetActiveCompare()
+ if entry then
+ entry.calcsTab.input.skill_number = index
+@@ -708,7 +713,7 @@ function CompareTabClass:InitControls()
+ end)
+ self.controls.cmpCalcsMinionSkill.shown = false
+
+- self.controls.cmpCalcsMode = new("DropDownControl", nil, {0, 0, 120, 18}, calcsBuffModeDropList, function(index, value)
++ self.controls.cmpCalcsMode = new("DropDownControl"):DropDownControl(nil, {0, 0, 120, 18}, calcsBuffModeDropList, function(index, value)
+ local entry = self:GetActiveCompare()
+ if entry then
+ entry.calcsTab.input.misc_buffMode = value.buffMode
+@@ -1580,12 +1585,12 @@ function CompareTabClass:OpenImportFolderPopup()
+ end
+
+ -- Search box and sort dropdown sit above the build list.
+- controls.searchText = new("EditControl", {"TOPLEFT", nil, "TOPLEFT"}, {15, 25, 450, 20}, "", "Search", "%c%(%)", 100, function(buf)
++ controls.searchText = new("EditControl"):EditControl({"TOPLEFT", nil, "TOPLEFT"}, {15, 25, 450, 20}, "", "Search", "%c%(%)", 100, function(buf)
+ searchText = buf
+ listHost:FilterBuildList()
+ end, nil, nil, true)
+ controls.searchText:SetPlaceholder("(e.g. class:assassin myfilename)")
+- controls.sort = new("DropDownControl", {"TOPLEFT", nil, "TOPLEFT"}, {475, 25, 210, 20}, buildListHelpers.buildSortDropList, function(index, value)
++ controls.sort = new("DropDownControl"):DropDownControl({"TOPLEFT", nil, "TOPLEFT"}, {475, 25, 210, 20}, buildListHelpers.buildSortDropList, function(index, value)
+ sortMode = value.sortMode
+ main.buildSortMode = value.sortMode
+ listHost:SortList()
+@@ -2700,7 +2705,7 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories
+ local pSlot = self.primaryBuild.itemsTab and self.primaryBuild.itemsTab.slots[slotName]
+ local pItem = pSlot and self.primaryBuild.itemsTab.items[pSlot.selItemId]
+ if cItem and cItem.raw and not (pItem and pItem.name == cItem.name) then
+- local newItem = new("Item", cItem.raw)
++ local newItem = new("Item"):Item(cItem.raw)
+ newItem:NormaliseQuality()
+
+ -- if our comparison has abyssal jewels, but the primary build
+@@ -2723,7 +2728,7 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories
+ -- might not exist
+ if cmpJewel then
+ -- copy item
+- local itemCopy = new("Item", cmpJewel:BuildRaw())
++ local itemCopy = new("Item"):Item(cmpJewel:BuildRaw())
+ table.insert(cmpJewels, itemCopy)
+ self.primaryBuild.itemsTab:AddItem(itemCopy, false)
+
diff --git a/src/Classes/ConfigSetListControl.lua.rej b/src/Classes/ConfigSetListControl.lua.rej
new file mode 100644
index 0000000000..a8b29b9be5
--- /dev/null
+++ b/src/Classes/ConfigSetListControl.lua.rej
@@ -0,0 +1,66 @@
+diff a/src/Classes/ConfigSetListControl.lua b/src/Classes/ConfigSetListControl.lua (rejected hunks)
+@@ -7,10 +7,13 @@ local t_insert = table.insert
+ local t_remove = table.remove
+ local m_max = math.max
+
+-local ConfigSetListClass = newClass("ConfigSetListControl", "ListControl", function(self, anchor, rect, configTab)
+- self.ListControl(anchor, rect, 16, "VERTICAL", true, configTab.configSetOrderList)
++---@class ConfigSetListControl: ListControl
++local ConfigSetListClass = newClass("ConfigSetListControl", "ListControl")
++
++function ConfigSetListClass:ConfigSetListControl(anchor, rect, configTab)
++ self:ListControl(anchor, rect, 16, "VERTICAL", true, configTab.configSetOrderList)
+ self.configTab = configTab
+- self.controls.copy = new("ButtonControl", {"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
++ self.controls.copy = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
+ local configSet = configTab.configSets[self.selValue]
+ local newConfigSet = copyTable(configSet)
+ newConfigSet.id = 1
+@@ -23,30 +26,31 @@ local ConfigSetListClass = newClass("ConfigSetListControl", "ListControl", funct
+ self.controls.copy.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.delete = new("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
++ self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
+ self:OnSelDelete(self.selIndex, self.selValue)
+ end)
+ self.controls.delete.enabled = function()
+ return self.selValue ~= nil and #self.list > 1
+ end
+- self.controls.rename = new("ButtonControl", {"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
++ self.controls.rename = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
+ self:RenameSet(configTab.configSets[self.selValue])
+ end)
+ self.controls.rename.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.new = new("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
++ self.controls.new = new("ButtonControl"):ButtonControl({"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
+ self:RenameSet(configTab:NewConfigSet(), true)
+ end)
+-end)
++ return self
++end
+
+ function ConfigSetListClass:RenameSet(configSet, addOnName)
+ local controls = { }
+- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter name for this config set:")
+- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, configSet.title, nil, nil, 100, function(buf)
++ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this config set:")
++ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, configSet.title, nil, nil, 100, function(buf)
+ controls.save.enabled = buf:match("%S")
+ end)
+- controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function()
+ configSet.title = controls.edit.buf
+ self.configTab.modFlag = true
+ if addOnName then
+@@ -59,7 +63,7 @@ function ConfigSetListClass:RenameSet(configSet, addOnName)
+ main:ClosePopup()
+ end)
+ controls.save.enabled = false
+- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
++ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
+ if addOnName then
+ self.configTab.configSets[configSet.id] = nil
+ end
diff --git a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua
index 83c649b476..87c8ec96c8 100644
--- a/src/Classes/ConfigTab.lua
+++ b/src/Classes/ConfigTab.lua
@@ -47,15 +47,15 @@ local ConfigTabClass = newClass("ConfigTab", "UndoHandler", "ControlHost", "Cont
self.controls.setSelect.enabled = function()
return #self.configSetOrderList > 1
end
- self.controls.setLabel = new("LabelControl", { "RIGHT", self.controls.setSelect, "LEFT" }, { -2, 0, 0, 16 }, "^7Config set:")
- self.controls.setManage = new("ButtonControl", { "LEFT", self.controls.setSelect, "RIGHT" }, { 4, 0, 90, 20 }, "Manage...", function()
+ self.controls.setLabel = new("LabelControl"):LabelControl({ "RIGHT", self.controls.setSelect, "LEFT" }, { -2, 0, 0, 16 }, "^7Config set:")
+ self.controls.setManage = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.setSelect, "RIGHT" }, { 4, 0, 90, 20 }, "Manage...", function()
self:OpenConfigSetManagePopup()
end)
- self.controls.search = new("EditControl", { "TOPLEFT", self.controls.sectionAnchor, "TOPLEFT" }, { 8, 15, 360, 20 }, "", "Search", "%c", 100, function()
+ self.controls.search = new("EditControl"):EditControl({ "TOPLEFT", self.controls.sectionAnchor, "TOPLEFT" }, { 8, 15, 360, 20 }, "", "Search", "%c", 100, function()
self:UpdateControls()
end, nil, nil, true)
- self.controls.toggleConfigs = new("ButtonControl", { "LEFT", self.controls.search, "RIGHT" }, { 10, 0, 200, 20 }, function()
+ self.controls.toggleConfigs = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.search, "RIGHT" }, { 10, 0, 200, 20 }, function()
-- dynamic text
return self.toggleConfigs and "Hide Ineligible Configurations" or "Show All Configurations"
end, function()
@@ -141,7 +141,7 @@ local ConfigTabClass = newClass("ConfigTab", "UndoHandler", "ControlHost", "Cont
local lastSection
for _, varData in ipairs(varList) do
if varData.section then
- lastSection = new("SectionControl", {"TOPLEFT",self.controls.search,"BOTTOMLEFT"}, {0, 0, 360, 0}, varData.section)
+ lastSection = new("SectionControl"):SectionControl({"TOPLEFT",self.controls.search,"BOTTOMLEFT"}, {0, 0, 360, 0}, varData.section)
lastSection.varControlList = { }
lastSection.col = varData.col
lastSection.height = function(self)
@@ -176,14 +176,14 @@ local ConfigTabClass = newClass("ConfigTab", "UndoHandler", "ControlHost", "Cont
self.build.buildFlag = true
end)
elseif varData.type == "list" then
- control = new("DropDownControl", {"TOPLEFT",lastSection,"TOPLEFT"}, {234, 0, 118, 16}, varData.list, function(index, value)
+ control = new("DropDownControl"):DropDownControl({"TOPLEFT",lastSection,"TOPLEFT"}, {234, 0, 118, 16}, varData.list, function(index, value)
self.configSets[self.activeConfigSetId].input[varData.var] = value.val
self:AddUndoState()
self:BuildModList()
self.build.buildFlag = true
end)
elseif varData.type == "text" and not varData.resizable then
- control = new("EditControl", {"TOPLEFT",lastSection,"TOPLEFT"}, {8, 0, 344, 118}, "", nil, "^%C\t\n", nil, function(buf, placeholder)
+ control = new("EditControl"):EditControl({"TOPLEFT",lastSection,"TOPLEFT"}, {8, 0, 344, 118}, "", nil, "^%C\t\n", nil, function(buf, placeholder)
if placeholder then
self.configSets[self.activeConfigSetId].placeholder[varData.var] = tostring(buf)
else
@@ -194,7 +194,7 @@ local ConfigTabClass = newClass("ConfigTab", "UndoHandler", "ControlHost", "Cont
self.build.buildFlag = true
end, 16)
elseif varData.type == "text" and varData.resizable then
- control = new("ResizableEditControl", {"TOPLEFT",lastSection,"TOPLEFT"}, {8, 0, 344, 118, nil, nil, nil, 118 + 16 * 40}, "", nil, "^%C\t\n", nil, function(buf, placeholder)
+ control = new("ResizableEditControl"):ResizableEditControl({"TOPLEFT",lastSection,"TOPLEFT"}, {8, 0, 344, 118, nil, nil, nil, 118 + 16 * 40}, "", nil, "^%C\t\n", nil, function(buf, placeholder)
if placeholder then
self.configSets[self.activeConfigSetId].placeholder[varData.var] = tostring(buf)
else
@@ -205,7 +205,7 @@ local ConfigTabClass = newClass("ConfigTab", "UndoHandler", "ControlHost", "Cont
self.build.buildFlag = true
end, 16)
else
- control = new("Control", {"TOPLEFT",lastSection,"TOPLEFT"}, {234, 0, 16, 16})
+ control = new("Control"):Control({"TOPLEFT",lastSection,"TOPLEFT"}, {234, 0, 16, 16})
end
if varData.inactiveText then
@@ -549,7 +549,7 @@ local ConfigTabClass = newClass("ConfigTab", "UndoHandler", "ControlHost", "Cont
end
local labelControl = control
if varData.label and varData.type ~= "check" then
- labelControl = new("LabelControl", {"RIGHT",control,"LEFT"}, {-4, 0, 0, DrawStringWidth(14, "VAR", varData.label) > 228 and 12 or 14}, "^7"..varData.label)
+ labelControl = new("LabelControl"):LabelControl({"RIGHT",control,"LEFT"}, {-4, 0, 0, DrawStringWidth(14, "VAR", varData.label) > 228 and 12 or 14}, "^7"..varData.label)
t_insert(self.controls, labelControl)
end
if varData.var then
@@ -880,9 +880,9 @@ function ConfigTabClass:UpdateLevel()
end
function ConfigTabClass:BuildModList()
- local modList = new("ModList")
+ local modList = new("ModList"):ModList()
self.modList = modList
- local enemyModList = new("ModList")
+ local enemyModList = new("ModList"):ModList()
self.enemyModList = enemyModList
local input = self.configSets[self.activeConfigSetId].input
local placeholder = self.configSets[self.activeConfigSetId].placeholder
@@ -964,8 +964,8 @@ end
function ConfigTabClass:OpenConfigSetManagePopup()
main:OpenPopup(370, 290, "Manage Config Sets", {
- new("ConfigSetListControl", nil, {0, 50, 350, 200}, self),
- new("ButtonControl", nil, {0, 260, 90, 20}, "Done", function()
+ new("ConfigSetListControl"):ConfigSetListControl(nil, {0, 50, 350, 200}, self),
+ new("ButtonControl"):ButtonControl(nil, {0, 260, 90, 20}, "Done", function()
main:ClosePopup()
end),
})
diff --git a/src/Classes/ConfigTab.lua.rej b/src/Classes/ConfigTab.lua.rej
new file mode 100644
index 0000000000..c0a49e5894
--- /dev/null
+++ b/src/Classes/ConfigTab.lua.rej
@@ -0,0 +1,109 @@
+diff a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua (rejected hunks)
+@@ -15,15 +15,15 @@ local configVisibility = LoadModule("Modules/ConfigVisibility")
+ ---@class CustomModBlock: ControlHost, Control
+ local CustomModBlockClass = newClass("CustomModBlockControl", "ControlHost", "Control")
+
+-function CustomModBlockClass:CustomModBlockControl(self, anchor, rect, configTab, blockIndex, blockData)
+- self.Control(anchor, rect)
+- self.ControlHost()
++function CustomModBlockClass:CustomModBlockControl(anchor, rect, configTab, blockIndex, blockData)
++ self:Control(anchor, rect)
++ self:ControlHost()
+
+ self.configTab = configTab
+ self.blockIndex = blockIndex
+ self.blockData = blockData
+
+- self.controls.deleteBtn = new("ButtonControl", {"TOPLEFT", self, "TOPLEFT"}, {0, 0, 20, 18}, "^1X", function()
++ self.controls.deleteBtn = new("ButtonControl"):ButtonControl({"TOPLEFT", self, "TOPLEFT"}, {0, 0, 20, 18}, "^1X", function()
+ local customModsList = configTab.configSets[configTab.activeConfigSetId].customModsList
+ table.remove(customModsList, blockIndex)
+ if #customModsList == 0 then
+@@ -35,18 +35,18 @@ function CustomModBlockClass:CustomModBlockControl(self, anchor, rect, configTab
+ configTab.build.buildFlag = true
+ end)
+
+- self.controls.titleEdit = new("EditControl", {"LEFT", self.controls.deleteBtn, "RIGHT"}, {6, 0, 222, 18}, blockData.title or "", nil, nil, nil, function(buf)
++ self.controls.titleEdit = new("EditControl"):EditControl({"LEFT", self.controls.deleteBtn, "RIGHT"}, {6, 0, 222, 18}, blockData.title or "", nil, nil, nil, function(buf)
+ blockData.title = buf
+ configTab:AddUndoState()
+ configTab:BuildModList()
+ configTab.build.buildFlag = true
+ end)
+
+- self.controls.addModBtn = new("ButtonControl", {"LEFT", self.controls.titleEdit, "RIGHT"}, {6, 0, 58, 18}, "^7Add Mod", function()
++ self.controls.addModBtn = new("ButtonControl"):ButtonControl({"LEFT", self.controls.titleEdit, "RIGHT"}, {6, 0, 58, 18}, "^7Add Mod", function()
+ configTab:OpenAddModPopup(blockData)
+ end)
+
+- self.controls.enableCheck = new("CheckBoxControl", {"TOPRIGHT", self, "TOPRIGHT"}, {0, 0, 18}, "", function(state)
++ self.controls.enableCheck = new("CheckBoxControl"):CheckBoxControl({"TOPRIGHT", self, "TOPRIGHT"}, {0, 0, 18}, "", function(state)
+ blockData.enabled = state
+ configTab:AddUndoState()
+ configTab:BuildModList()
+@@ -86,7 +86,8 @@ function CustomModBlockClass:CustomModBlockControl(self, anchor, rect, configTab
+ end
+ return inactiveText
+ end
+-end)
++ return self
++end
+
+ function CustomModBlockClass:GetSize()
+ local textHeight = self.controls.textEdit and self.controls.textEdit.height or 80
+@@ -779,7 +780,7 @@ function ConfigTabClass:ConfigTab(build)
+ end
+ self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({"TOPRIGHT",self,"TOPRIGHT"}, {0, 0, 18, 0}, 50, "VERTICAL", true)
+ if self.customSection then
+- self.controls.customModsAddBlock = new("ButtonControl", {"TOPLEFT", self.customSection, "TOPLEFT"}, {8, 0, 120, 20}, "^7Add Mod Group", function()
++ self.controls.customModsAddBlock = new("ButtonControl"):ButtonControl({"TOPLEFT", self.customSection, "TOPLEFT"}, {8, 0, 120, 20}, "^7Add Mod Group", function()
+ local customModsList = self.configSets[self.activeConfigSetId].customModsList
+ t_insert(customModsList, { title = "Group " .. (#customModsList + 1), enabled = true, text = "" })
+ self:UpdateCustomModsControls()
+@@ -1276,7 +1277,7 @@ function ConfigTabClass:UpdateCustomModsControls()
+ self.customSection.varControlList = { self.controls.customModsAddBlock }
+
+ for index, block in ipairs(configSet.customModsList) do
+- local blockControl = new("CustomModBlockControl", {"TOPLEFT", self.customSection, "TOPLEFT"}, {8, 0, 344, 120}, self, index, block)
++ local blockControl = new("CustomModBlockControl"):CustomModBlockControl({"TOPLEFT", self.customSection, "TOPLEFT"}, {8, 0, 344, 120}, self, index, block)
+ t_insert(self.customModsBlockControls, blockControl)
+ t_insert(self.controls, blockControl)
+ t_insert(self.customSection.varControlList, blockControl)
+@@ -1497,7 +1498,7 @@ function ConfigTabClass:OpenAddModPopup(blockData)
+ end
+ end
+
+- controls.listControl = new("ListControl", {"TOPLEFT", nil, "TOPLEFT"}, {10, 20, 700, 454}, 16, "VERTICAL", false, displayList)
++ controls.listControl = new("ListControl"):ListControl({"TOPLEFT", nil, "TOPLEFT"}, {10, 20, 700, 454}, 16, "VERTICAL", false, displayList)
+ controls.listControl.font = "VAR"
+ controls.listControl.GetRowValue = function(self, column, index, value)
+ return value or ""
+@@ -1520,8 +1521,8 @@ function ConfigTabClass:OpenAddModPopup(blockData)
+ end
+ end
+
+- controls.searchLabel = new("LabelControl", {"TOPRIGHT", nil, "TOPLEFT"}, {65, 482, 0, 16}, "^7Search:")
+- controls.search = new("EditControl", {"TOPLEFT", nil, "TOPLEFT"}, {70, 482, 640, 18}, "", nil, "%c", 100, function()
++ controls.searchLabel = new("LabelControl"):LabelControl({"TOPRIGHT", nil, "TOPLEFT"}, {65, 482, 0, 16}, "^7Search:")
++ controls.search = new("EditControl"):EditControl({"TOPLEFT", nil, "TOPLEFT"}, {70, 482, 640, 18}, "", nil, "%c", 100, function()
+ updateDisplayList()
+ end, nil, nil, true)
+ controls.search.controls.buttonClear.shown = function()
+@@ -1530,7 +1531,7 @@ function ConfigTabClass:OpenAddModPopup(blockData)
+
+ updateDisplayList()
+
+- controls.save = new("ButtonControl", nil, {-45, 512, 80, 20}, "Add", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 512, 80, 20}, "Add", function()
+ local selIndex = controls.listControl.selIndex or 1
+ local selected = displayList[selIndex]
+ if selected and selected ~= "No matching modifiers found" then
+@@ -1551,7 +1552,7 @@ function ConfigTabClass:OpenAddModPopup(blockData)
+ return selected ~= nil and selected ~= "No matching modifiers found"
+ end
+
+- controls.close = new("ButtonControl", nil, {45, 512, 80, 20}, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl(nil, {45, 512, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ end)
+
diff --git a/src/Classes/Control.lua b/src/Classes/Control.lua
index 110eb6884e..d75ee730c5 100644
--- a/src/Classes/Control.lua
+++ b/src/Classes/Control.lua
@@ -6,6 +6,8 @@
local t_insert = table.insert
local m_floor = math.floor
+
+---@enum (key) AnchorPoint
local anchorPos = {
["TOPLEFT"] = { 0 , 0 },
["TOP"] = { 0.5, 0 },
@@ -41,8 +43,14 @@ local ControlClass = newClass("Control", function(self, anchor, rect)
if anchor then
self:SetAnchor(anchor[1], anchor[2], anchor[3], nil, nil, anchor[4])
end
-end)
+ return self
+end
+
+---@generic T
+---@alias Prop (fun(self: self): T) | T
+---@param name string
+---@return any value
function ControlClass:GetProperty(name)
if type(self[name]) == "function" then
return self[name](self)
diff --git a/src/Classes/Control.lua.rej b/src/Classes/Control.lua.rej
new file mode 100644
index 0000000000..6ba4e94f9b
--- /dev/null
+++ b/src/Classes/Control.lua.rej
@@ -0,0 +1,11 @@
+diff a/src/Classes/Control.lua b/src/Classes/Control.lua (rejected hunks)
+@@ -38,6 +38,9 @@ local rect = {
+ ---@field enabled boolean | fun(...: any): boolean
+ ---@field onFocusGained? fun()
+ ---@field onFocusLost? fun()
++---@field shown Prop
++---@field x Prop?
++---@field y Prop?
+ local ControlClass = newClass("Control")
+
+ ---@alias ControlAnchor [AnchorPoint, Control|ControlHost, AnchorPoint, boolean|nil]
diff --git a/src/Classes/ControlHost.lua b/src/Classes/ControlHost.lua
index 958447c512..592b71b016 100644
--- a/src/Classes/ControlHost.lua
+++ b/src/Classes/ControlHost.lua
@@ -4,9 +4,13 @@
-- Host for UI controls
--
-local ControlHostClass = newClass("ControlHost", function(self)
- self.controls = { }
-end)
+---@class ControlHost
+local ControlHostClass = newClass("ControlHost")
+
+function ControlHostClass:ControlHost()
+ self.controls = {}
+ return self
+end
function ControlHostClass:SelectControl(newSelControl)
if self.selControl == newSelControl then
diff --git a/src/Classes/DraggerControl.lua b/src/Classes/DraggerControl.lua
index de331cbb04..3aede08085 100644
--- a/src/Classes/DraggerControl.lua
+++ b/src/Classes/DraggerControl.lua
@@ -3,9 +3,12 @@
-- Class: Dragger Button Control
-- Dragger button control.
--
-local DraggerClass = newClass("DraggerControl", "Control", "TooltipHost", function(self, anchor, rect, label, onKeyDown, onKeyUp, onRightClick, onHover, forceTooltip)
- self.Control(anchor, rect)
- self.TooltipHost()
+---@class DraggerControl: Control, TooltipHost
+local DraggerClass = newClass("DraggerControl", "Control", "TooltipHost")
+
+function DraggerClass:DraggerControl(anchor, rect, label, onKeyDown, onKeyUp, onRightClick, onHover, forceTooltip)
+ self:Control(anchor, rect)
+ self:TooltipHost()
self.label = label
self.onKeyDown = onKeyDown
self.onKeyUp = onKeyUp
@@ -14,7 +17,8 @@ local DraggerClass = newClass("DraggerControl", "Control", "TooltipHost", functi
self.forceTooltip = forceTooltip
self.cursorX = 0
self.cursorY = 0
-end)
+ return self
+end
function DraggerClass:SetImage(path)
if path then
diff --git a/src/Classes/DropDownControl.lua b/src/Classes/DropDownControl.lua
index cc7d47161f..9a38178e85 100644
--- a/src/Classes/DropDownControl.lua
+++ b/src/Classes/DropDownControl.lua
@@ -49,8 +49,9 @@ local DropDownClass = newClass("DropDownControl", "Control", "ControlHost", "Too
self.enableDroppedWidth = false
-- Set by the parent control. Activates the auto width of the box component.
self.enableChangeBoxWidth = false
- -- self.tag = "-"
-end)
+ -- self.tag = "-"
+ return self
+end
-- maps the actual dropdown row index (after eventual filtering) to the original (unfiltered) list index
function DropDownClass:DropIndexToListIndex(dropIndex)
diff --git a/src/Classes/DropDownControl.lua.rej b/src/Classes/DropDownControl.lua.rej
new file mode 100644
index 0000000000..01f02a4a4d
--- /dev/null
+++ b/src/Classes/DropDownControl.lua.rej
@@ -0,0 +1,30 @@
+diff a/src/Classes/DropDownControl.lua b/src/Classes/DropDownControl.lua (rejected hunks)
+@@ -8,11 +8,14 @@ local m_min = math.min
+ local m_max = math.max
+ local m_floor = math.floor
+
+-local DropDownClass = newClass("DropDownControl", "Control", "ControlHost", "TooltipHost", "SearchHost", function(self, anchor, rect, list, selFunc, tooltipText, ignoreSearchOrder)
+- self.Control(anchor, rect)
+- self.ControlHost()
+- self.TooltipHost(tooltipText)
+- self.SearchHost(
++---@class DropDownControl: Control, ControlHost, TooltipHost, SearchHost
++local DropDownClass = newClass("DropDownControl", "Control", "ControlHost", "TooltipHost", "SearchHost")
++
++function DropDownClass:DropDownControl(anchor, rect, list, selFunc, tooltipText, ignoreSearchOrder)
++ self:Control(anchor, rect)
++ self:ControlHost()
++ self:TooltipHost(tooltipText)
++ self:SearchHost(
+ -- list to filter
+ function()
+ return self.list
+@@ -31,7 +34,7 @@ local DropDownClass = newClass("DropDownControl", "Control", "ControlHost", "Too
+ end,
+ ignoreSearchOrder
+ )
+- self.controls.scrollBar = new("ScrollBarControl", {"TOPRIGHT",self,"TOPRIGHT"}, {-1, 0, 18, 0}, (self.height - 4) * 4)
++ self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({"TOPRIGHT",self,"TOPRIGHT"}, {-1, 0, 18, 0}, (self.height - 4) * 4)
+ self.controls.scrollBar.height = function()
+ return self.dropHeight + 2
+ end
diff --git a/src/Classes/EditControl.lua b/src/Classes/EditControl.lua
index dd81738884..1024f53699 100644
--- a/src/Classes/EditControl.lua
+++ b/src/Classes/EditControl.lua
@@ -36,11 +36,15 @@ local function newlineCount(str)
end
end
-local EditClass = newClass("EditControl", "ControlHost", "Control", "UndoHandler", "TooltipHost", function(self, anchor, rect, init, prompt, filter, limit, changeFunc, lineHeight, allowZoom, clearable)
- self.ControlHost()
- self.Control(anchor, rect)
- self.UndoHandler()
- self.TooltipHost()
+---@class EditControl: ControlHost, Control, UndoHandler, TooltipHost
+---@field inactiveText (fun(buf: string?): string)|string
+local EditClass = newClass("EditControl", "ControlHost", "Control", "UndoHandler", "TooltipHost")
+
+function EditClass:EditControl(anchor, rect, init, prompt, filter, limit, changeFunc, lineHeight, allowZoom, clearable)
+ self:ControlHost()
+ self:Control(anchor, rect)
+ self:UndoHandler()
+ self:TooltipHost()
self:SetText(init or "")
self.prompt = prompt
self.filter = filter or (main.unicode and "%c" or "^%w%p ")
@@ -91,7 +95,8 @@ local EditClass = newClass("EditControl", "ControlHost", "Control", "UndoHandler
self.controls.scrollBarV.shown = false
end
self.protected = false
-end)
+ return self
+end
function EditClass:SetText(text, notify)
self.buf = tostring(text)
@@ -297,7 +302,8 @@ function EditClass:Draw(viewPort, noTooltip)
else
SetDrawColor(self.inactiveCol)
if self.inactiveText then
- local inactiveText = type(inactiveText) == "string" and self.inactiveText or self.inactiveText(self.buf)
+ local inactiveText = type(self.inactiveText) == "string" and self.inactiveText or self.inactiveText(self.buf)
+ ---@cast inactiveText string
DrawString(-self.controls.scrollBarH.offset, -self.controls.scrollBarV.offset, "LEFT", textHeight, self.font, inactiveText)
elseif self.protected then
DrawString(-self.controls.scrollBarH.offset, -self.controls.scrollBarV.offset, "LEFT", textHeight, self.font, string.rep(protected_replace, #self.buf))
diff --git a/src/Classes/EditControl.lua.rej b/src/Classes/EditControl.lua.rej
new file mode 100644
index 0000000000..d630cf5534
--- /dev/null
+++ b/src/Classes/EditControl.lua.rej
@@ -0,0 +1,31 @@
+diff a/src/Classes/EditControl.lua b/src/Classes/EditControl.lua (rejected hunks)
+@@ -64,24 +68,24 @@ local EditClass = newClass("EditControl", "ControlHost", "Control", "UndoHandler
+ if self.filter == "%D" or self.filter == "^%-%d" then
+ -- Add +/- buttons for integer number edits
+ self.isNumeric = true
+- self.controls.buttonDown = new("ButtonControl", {"RIGHT",self,"RIGHT"}, {-2, 0, buttonSize, buttonSize}, "-", function()
++ self.controls.buttonDown = new("ButtonControl"):ButtonControl({"RIGHT",self,"RIGHT"}, {-2, 0, buttonSize, buttonSize}, "-", function()
+ self:OnKeyUp("DOWN")
+ end)
+- self.controls.buttonUp = new("ButtonControl", {"RIGHT",self.controls.buttonDown,"LEFT"}, {-1, 0, buttonSize, buttonSize}, "+", function()
++ self.controls.buttonUp = new("ButtonControl"):ButtonControl({"RIGHT",self.controls.buttonDown,"LEFT"}, {-1, 0, buttonSize, buttonSize}, "+", function()
+ self:OnKeyUp("UP")
+ end)
+ elseif clearable then
+- self.controls.buttonClear = new("ButtonControl", {"RIGHT",self,"RIGHT"}, {-2, 0, buttonSize, buttonSize}, "x", function()
++ self.controls.buttonClear = new("ButtonControl"):ButtonControl({"RIGHT",self,"RIGHT"}, {-2, 0, buttonSize, buttonSize}, "x", function()
+ self:SetText("", true)
+ end)
+ self.controls.buttonClear.shown = function() return #self.buf > 0 and self:IsMouseInBounds() end
+ end
+- self.controls.scrollBarH = new("ScrollBarControl", {"BOTTOMLEFT",self,"BOTTOMLEFT"}, {1, -1, 0, 14}, 60, "HORIZONTAL", true)
++ self.controls.scrollBarH = new("ScrollBarControl"):ScrollBarControl({"BOTTOMLEFT",self,"BOTTOMLEFT"}, {1, -1, 0, 14}, 60, "HORIZONTAL", true)
+ self.controls.scrollBarH.width = function()
+ local width, height = self:GetSize()
+ return width - (self.controls.scrollBarV.enabled and 16 or 2)
+ end
+- self.controls.scrollBarV = new("ScrollBarControl", {"TOPRIGHT",self,"TOPRIGHT"}, {-1, 1, 14, 0}, (lineHeight or 0) * 3, "VERTICAL", true)
++ self.controls.scrollBarV = new("ScrollBarControl"):ScrollBarControl({"TOPRIGHT",self,"TOPRIGHT"}, {-1, 1, 14, 0}, (lineHeight or 0) * 3, "VERTICAL", true)
+ self.controls.scrollBarV.height = function()
+ local width, height = self:GetSize()
+ return height - (self.controls.scrollBarH.enabled and 16 or 2)
diff --git a/src/Classes/ExtBuildListControl.lua b/src/Classes/ExtBuildListControl.lua
index fb6070ba69..c00323a3a2 100644
--- a/src/Classes/ExtBuildListControl.lua
+++ b/src/Classes/ExtBuildListControl.lua
@@ -10,36 +10,39 @@ local m_max = math.max
local m_min = math.min
local dkjson = require "dkjson"
-local ExtBuildListControlClass = newClass("ExtBuildListControl", "ControlHost", "Control",
- function(self, anchor, rect, providers)
- self.Control(anchor, rect)
- self.ControlHost()
- self:SelectControl()
-
- self.rowHeight = 200
- self.scroll = "VERTICAL"
- self.forceTooltip = false
- self.font = "VAR"
- self.importButtons = {}
- self.previewButtons = {}
- self.inTransition = false
- self.contentHeight = 0
- self.tabs = {}
- self.activeListProvider = nil
- self.buildProviders = providers
- self.buildProvidersList = {}
- self.providerMaxLength = 150
- for _, provider in ipairs(self.buildProviders) do
- self.providerMaxLength = m_max(self.providerMaxLength, DrawStringWidth(16, self.font, provider.name) + 30)
- t_insert(self.buildProvidersList, provider.name)
- end
- end)
+---@class ExtBuildListControl: ControlHost, Control
+local ExtBuildListControlClass = newClass("ExtBuildListControl", "ControlHost", "Control")
+
+function ExtBuildListControlClass:ExtBuildListControl(anchor, rect, providers)
+ self:Control(anchor, rect)
+ self:ControlHost()
+ self:SelectControl()
+
+ self.rowHeight = 200
+ self.scroll = "VERTICAL"
+ self.forceTooltip = false
+ self.font = "VAR"
+ self.importButtons = {}
+ self.previewButtons = {}
+ self.inTransition = false
+ self.contentHeight = 0
+ self.tabs = {}
+ self.activeListProvider = nil
+ self.buildProviders = providers
+ self.buildProvidersList = {}
+ self.providerMaxLength = 150
+ for _, provider in ipairs(self.buildProviders) do
+ self.providerMaxLength = m_max(self.providerMaxLength, DrawStringWidth(16, self.font, provider.name) + 30)
+ t_insert(self.buildProvidersList, provider.name)
+ end
+ return self
+end
function ExtBuildListControlClass:Init(providerName)
wipeTable(self.controls)
wipeTable(self.tabs)
- self.controls.sort = new("DropDownControl", { "TOP", self, "TOP" }, { 0, -20, self.providerMaxLength, 20 },
+ self.controls.sort = new("DropDownControl"):DropDownControl({ "TOP", self, "TOP" }, { 0, -20, self.providerMaxLength, 20 },
self.buildProvidersList, function(index, value)
self:Init(value)
end)
@@ -72,7 +75,7 @@ function ExtBuildListControlClass:Init(providerName)
if lastControl then
anchor = { "LEFT", lastControl, "RIGHT" }
end
- local button = new("ButtonControl", anchor, { 0, lastControl and 0 or -20, stringWidth + 10, 20 }, title, function()
+ local button = new("ButtonControl"):ButtonControl(anchor, { 0, lastControl and 0 or -20, stringWidth + 10, 20 }, title, function()
if self.activeListProvider:GetActiveList() == title then
return
end
@@ -105,7 +108,7 @@ function ExtBuildListControlClass:Init(providerName)
return (self.width() - self.controls.sort.width()) / 2
end
- self.controls.scrollBarV = new("ScrollBarControl", { "RIGHT", self, "RIGHT" }, { -1, 0, self.scroll and 16 or 0, 0 },
+ self.controls.scrollBarV = new("ScrollBarControl"):ScrollBarControl({ "RIGHT", self, "RIGHT" }, { -1, 0, self.scroll and 16 or 0, 0 },
80, "VERTICAL") {
-- y = function()
-- return (self.scrollH and -8 or 0)
@@ -120,7 +123,7 @@ function ExtBuildListControlClass:Init(providerName)
end
if self.activeListProvider:GetPageUrl() then
- self.controls.all = new("ButtonControl", { "BOTTOM", self, "BOTTOM" }, { 0, 1, self.width, 20 }, "See All",
+ self.controls.all = new("ButtonControl"):ButtonControl({ "BOTTOM", self, "BOTTOM" }, { 0, 1, self.width, 20 }, "See All",
function()
local url = self.activeListProvider:GetPageUrl()
if url then
@@ -407,14 +410,14 @@ function ExtBuildListControlClass:Draw(viewPort, noTooltip)
local relativeHeight = currentHeight + 10 - self.controls.scrollBarV.offset
if relativeHeight > y and relativeHeight < self.height() + y - 10 then
if build.buildLink then
- local importButton = new("ButtonControl", nil, { x, currentHeight - self.controls.scrollBarV.offset, 45, 20 }, "Import", function()
+ local importButton = new("ButtonControl"):ButtonControl(nil, { x, currentHeight - self.controls.scrollBarV.offset, 45, 20 }, "Import", function()
self:importBuild(build)
end)
t_insert(self.controls, importButton)
end
if build.previewLink then
- local previewButton = new("ButtonControl", nil, { x + 50, currentHeight - self.controls.scrollBarV.offset, 60, 20 }, "Preview", function()
+ local previewButton = new("ButtonControl"):ButtonControl(nil, { x + 50, currentHeight - self.controls.scrollBarV.offset, 60, 20 }, "Preview", function()
OpenURL(build.previewLink)
end)
t_insert(self.controls, previewButton)
diff --git a/src/Classes/ExtBuildListProvider.lua b/src/Classes/ExtBuildListProvider.lua
index 2b0904ce86..546dc8b32c 100644
--- a/src/Classes/ExtBuildListProvider.lua
+++ b/src/Classes/ExtBuildListProvider.lua
@@ -10,14 +10,16 @@
-- .buildList [Needs to be filled in :GetBuilds with current list. buildName and buildLink fields are required.]
-- .statusMsg [This can be used to print status message on the screen. Builds will not be listed if it has a value other than nil.]
-local ExtBuildListProviderClass = newClass("ExtBuildListProvider",
- function(self, listTitles)
- self.listTitles = listTitles
- self.buildList = {}
- self.activeList = nil
- self.statusMsg = nil
- end
-)
+---@class ExtBuildListProvider
+local ExtBuildListProviderClass = newClass("ExtBuildListProvider")
+
+function ExtBuildListProviderClass:ExtBuildListProvider(listTitles)
+ self.listTitles = listTitles
+ self.buildList = {}
+ self.activeList = nil
+ self.statusMsg = nil
+ return self
+end
function ExtBuildListProviderClass:GetPageUrl()
return nil
diff --git a/src/Classes/FolderListControl.lua b/src/Classes/FolderListControl.lua
index ce4e6114b9..38d27a615e 100644
--- a/src/Classes/FolderListControl.lua
+++ b/src/Classes/FolderListControl.lua
@@ -21,7 +21,8 @@ local FolderListClass = newClass("FolderListControl", "ListControl", function(se
end
end)
self:BuildList()
-end)
+ return self
+end
function FolderListClass:SortList()
if not self.list then return end
diff --git a/src/Classes/FolderListControl.lua.rej b/src/Classes/FolderListControl.lua.rej
new file mode 100644
index 0000000000..1950dd613b
--- /dev/null
+++ b/src/Classes/FolderListControl.lua.rej
@@ -0,0 +1,21 @@
+diff a/src/Classes/FolderListControl.lua b/src/Classes/FolderListControl.lua (rejected hunks)
+@@ -6,13 +6,16 @@
+ local ipairs = ipairs
+ local t_insert = table.insert
+
+-local FolderListClass = newClass("FolderListControl", "ListControl", function(self, anchor, rect, subPath, onChange)
+- self.ListControl(anchor, rect, 16, "VERTICAL", false, { })
++---@class FolderListControl: ListControl
++local FolderListClass = newClass("FolderListControl", "ListControl")
++
++function FolderListClass:FolderListControl(anchor, rect, subPath, onChange)
++ self:ListControl(anchor, rect, 16, "VERTICAL", false, { })
+ self.subPath = subPath or ""
+ self.sortMode = "NAME"
+ self.onChangeCallback = onChange
+
+- self.controls.path = new("PathControl", {"BOTTOM",self,"TOP"}, {0, -2, self.width, 24}, main.buildPath, self.subPath, function(newSubPath)
++ self.controls.path = new("PathControl"):PathControl({"BOTTOM",self,"TOP"}, {0, -2, self.width, 24}, main.buildPath, self.subPath, function(newSubPath)
+ self.subPath = newSubPath
+ self:BuildList()
+ self.selIndex = nil
diff --git a/src/Classes/GemSelectControl.lua.rej b/src/Classes/GemSelectControl.lua.rej
new file mode 100644
index 0000000000..db31c90a24
--- /dev/null
+++ b/src/Classes/GemSelectControl.lua.rej
@@ -0,0 +1,34 @@
+diff a/src/Classes/GemSelectControl.lua b/src/Classes/GemSelectControl.lua (rejected hunks)
+@@ -15,9 +15,19 @@ local gemTooltip = LoadModule("Classes/GemTooltip")
+ local toolTipText = "Prefix tag searches with a colon and exclude tags with a dash. e.g. :fire:lightning:-cold:area"
+ local imbuedTooltipText = "\"Socketed in\" item must be set in order to add an imbued support.\nOnly one imbued support is allowed per item."
+
+-local GemSelectClass = newClass("GemSelectControl", "EditControl", function(self, anchor, rect, skillsTab, index, changeFunc, forceTooltip, imbued)
+- self.EditControl(anchor, rect, nil, nil, "^ %a':-")
+- self.controls.scrollBar = new("ScrollBarControl", { "TOPRIGHT", self, "TOPRIGHT" }, {-1, 0, 18, 0}, (self.height - 4) * 4)
++---@class GemSelectControl: EditControl
++local GemSelectClass = newClass("GemSelectControl", "EditControl")
++
++---@param anchor ControlAnchor
++---@param rect ControlRect
++---@param skillsTab SkillsTab
++---@param index integer
++---@param changeFunc fun(...)
++---@param forceTooltip boolean
++---@param imbued boolean
++function GemSelectClass:GemSelectControl(anchor, rect, skillsTab, index, changeFunc, forceTooltip, imbued)
++ self:EditControl(anchor, rect, nil, nil, "^ %a':-")
++ self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({ "TOPRIGHT", self, "TOPRIGHT" }, {-1, 0, 18, 0}, (self.height - 4) * 4)
+ self.controls.scrollBar.y = function()
+ local width, height = self:GetSize()
+ return height + 1
+@@ -54,7 +64,8 @@ local GemSelectClass = newClass("GemSelectControl", "EditControl", function(self
+ }
+ self.imbuedSelect = imbued
+ self.dpsBuildFlag = false
+-end)
++ return self
++end
+
+ function GemSelectClass:CalcOutputWithThisGem(calcFunc, gemData, useFullDPS)
+ local gemList = self.skillsTab.displayGroup.gemList
diff --git a/src/Classes/ImportTab.lua b/src/Classes/ImportTab.lua
index 0ca1eda976..1fd1a3dd74 100644
--- a/src/Classes/ImportTab.lua
+++ b/src/Classes/ImportTab.lua
@@ -160,12 +160,12 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
end
local exportWebsitesList = getExportSitesFromImportList()
- self.controls.exportFrom = new("DropDownControl", { "LEFT", self.controls.generateCodeCopy,"RIGHT"}, {8, 0, 120, 20}, exportWebsitesList, function(_, selectedWebsite)
+ self.controls.exportFrom = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.generateCodeCopy, "RIGHT" }, { 8, 0, 120, 20 }, exportWebsitesList, function(_, selectedWebsite)
main.lastExportWebsite = selectedWebsite.id
self.exportWebsiteSelected = selectedWebsite.id
end)
self.controls.exportFrom:SelByValue(self.exportWebsiteSelected or main.lastExportWebsite or "Pastebin", "id")
- self.controls.generateCodeByLink = new("ButtonControl", { "LEFT", self.controls.exportFrom, "RIGHT"}, {8, 0, 100, 20}, "Share", function()
+ self.controls.generateCodeByLink = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.exportFrom, "RIGHT" }, { 8, 0, 100, 20 }, "Share", function()
local exportWebsite = exportWebsitesList[self.controls.exportFrom.selIndex]
local subScriptId = buildSites.UploadBuild(self.controls.generateCodeOut.buf, exportWebsite)
if subScriptId then
@@ -197,8 +197,8 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
end
return #self.controls.generateCodeOut.buf > 0
end
- self.controls.generateCodeNote = new("LabelControl", {"TOPLEFT",self.controls.generateCodeOut,"BOTTOMLEFT"}, {0, 4, 0, 14}, "^7Note: this code can be very long; you can use 'Share' to shrink it.")
- self.controls.importCodeHeader = new("LabelControl", {"TOPLEFT",self.controls.generateCodeNote,"BOTTOMLEFT"}, {0, 26, 0, 16}, "^7To import a build, enter URL or code here:")
+ self.controls.generateCodeNote = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.generateCodeOut,"BOTTOMLEFT"}, {0, 4, 0, 14}, "^7Note: this code can be very long; you can use 'Share' to shrink it.")
+ self.controls.importCodeHeader = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.generateCodeNote,"BOTTOMLEFT"}, {0, 26, 0, 16}, "^7To import a build, enter URL or code here:")
local importCodeHandle = function (buf)
self.importCodeSite = nil
@@ -296,21 +296,21 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
end
end
- self.controls.importCodeIn = new("EditControl", {"TOPLEFT",self.controls.importCodeHeader,"BOTTOMLEFT"}, {0, 4, 328, 20}, "", nil, nil, nil, importCodeHandle, nil, nil, true)
+ self.controls.importCodeIn = new("EditControl"):EditControl({"TOPLEFT",self.controls.importCodeHeader,"BOTTOMLEFT"}, {0, 4, 328, 20}, "", nil, nil, nil, importCodeHandle, nil, nil, true)
self.controls.importCodeIn.enterFunc = function()
if self.importCodeValid then
self.controls.importCodeGo.onClick()
end
end
- self.controls.importCodeState = new("LabelControl", {"LEFT",self.controls.importCodeIn,"RIGHT"}, {8, 0, 0, 16})
+ self.controls.importCodeState = new("LabelControl"):LabelControl({"LEFT",self.controls.importCodeIn,"RIGHT"}, {8, 0, 0, 16})
self.controls.importCodeState.label = function()
return self.importCodeDetail or ""
end
- self.controls.importCodeMode = new("DropDownControl", {"TOPLEFT",self.controls.importCodeIn,"BOTTOMLEFT"}, {0, 4, 200, 20}, { "Import to this build", "Import to a new build", "Import as comparison" })
+ self.controls.importCodeMode = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.importCodeIn,"BOTTOMLEFT"}, {0, 4, 200, 20}, { "Import to this build", "Import to a new build", "Import as comparison" })
self.controls.importCodeMode.enabled = function()
return (self.build.dbFileName or self.controls.importCodeMode.selIndex == 3) and self.importCodeValid
end
- self.controls.importCodeGo = new("ButtonControl", {"LEFT",self.controls.importCodeMode,"RIGHT"}, {8, 0, 160, 20}, "Import", function()
+ self.controls.importCodeGo = new("ButtonControl"):ButtonControl({"LEFT",self.controls.importCodeMode,"RIGHT"}, {8, 0, 160, 20}, "Import", function()
if self.importCodeSite and not self.importCodeXML then
self.importCodeFetching = true
local selectedWebsite = buildSites.websiteList[self.importCodeSite]
@@ -1168,7 +1168,7 @@ function ImportTabClass:ImportItem(itemData, slotName)
return
end
- local item = new("Item")
+ local item = new("Item"):Item()
-- Determine rarity, display name and base type of the item
item.rarity = rarityMap[itemData.frameType]
diff --git a/src/Classes/ImportTab.lua.rej b/src/Classes/ImportTab.lua.rej
new file mode 100644
index 0000000000..451f88a434
--- /dev/null
+++ b/src/Classes/ImportTab.lua.rej
@@ -0,0 +1,328 @@
+diff a/src/Classes/ImportTab.lua b/src/Classes/ImportTab.lua (rejected hunks)
+@@ -76,19 +76,19 @@ local function addOAuthControls(self)
+ local rowSpacing = 6
+
+
+- self.controls.charImportStatusLabel = new("LabelControl", { "TOPLEFT", self.controls.sectionOauthCharImport, "TOPLEFT" },
++ self.controls.charImportStatusLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.sectionOauthCharImport, "TOPLEFT" },
+ { labelSpacing, 14, 200, 16 }, function()
+ return "^7Character import status: " .. charImportStatus()
+ end)
+
+- self.controls.logoutApiButton = new("ButtonControl", { "TOPLEFT", self.controls.charImportStatusLabel, "TOPRIGHT" },
++ self.controls.logoutApiButton = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.charImportStatusLabel, "TOPRIGHT" },
+ { labelSpacing, 0, 170, 16 }, "^7Logout from Path of Exile API", function()
+ main.api:ResetDetails()
+ main:SaveSettings()
+ end)
+ self.controls.logoutApiButton.shown = function() return self.usingOauth and self.isAuthorized() end
+
+- self.controls.characterImportAnchor = new("Control", { "TOPLEFT", self.controls.sectionOauthCharImport, "TOPLEFT" },
++ self.controls.characterImportAnchor = new("Control"):Control({ "TOPLEFT", self.controls.sectionOauthCharImport, "TOPLEFT" },
+ { labelSpacing, 40, 200, 16 })
+ self.controls.sectionOauthCharImport.height = function()
+ return self.isAuthorized() and 200 or 60
+@@ -160,7 +160,7 @@ local function addOAuthControls(self)
+ main.api:DownloadCharacterList(realm.realmCode, onResponse)
+ end
+
+- self.controls.authenticateButton = new("ButtonControl", { "TOPLEFT", self.controls.characterImportAnchor, "TOPLEFT" },
++ self.controls.authenticateButton = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.characterImportAnchor, "TOPLEFT" },
+ { 0, 0, 200, 16 }, "^7Authorize with Path of Exile", function()
+ main.api:FetchAuthToken(function(errCode)
+ if errCode then
+@@ -182,20 +182,20 @@ local function addOAuthControls(self)
+ end
+
+ -- Stage: select realm, league, character, and import data
+- self.controls.charSelectHeader = new("LabelControl", { "TOPLEFT", self.controls.sectionOauthCharImport, "TOPLEFT" },
++ self.controls.charSelectHeader = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.sectionOauthCharImport, "TOPLEFT" },
+ { labelSpacing, 40, 200, 16 }, "^7Choose character to import data from:")
+ self.controls.charSelectHeader.shown = function()
+ return self.usingOauth and self.isAuthorized()
+ end
+
+- self.controls.oauthErrorLabel = new("LabelControl", { "TOPRIGHT", self.controls.sectionOauthCharImport, "TOPRIGHT" },
++ self.controls.oauthErrorLabel = new("LabelControl"):LabelControl({ "TOPRIGHT", self.controls.sectionOauthCharImport, "TOPRIGHT" },
+ { -8, 40, 0, 18 })
+ self.controls.oauthErrorLabel.label = function()
+ local text = self.oauthErrCode and string.format("%sError: %s", colorCodes.NEGATIVE, self.oauthErrCode) or ""
+ return text
+ end
+
+- self.controls.accountRealm = new("DropDownControl", { "TOPLEFT", self.controls.charSelectHeader, "BOTTOMLEFT" },
++ self.controls.accountRealm = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.charSelectHeader, "BOTTOMLEFT" },
+ { 0, rowSpacing, 60, 20 }, realmList, function()
+ setLeaguesFromCharList()
+ end)
+@@ -208,7 +208,7 @@ local function addOAuthControls(self)
+ end
+ return "Fetch Characters"
+ end
+- self.controls.accountRealmFetchButton = new("ButtonControl", { "LEFT", self.controls.accountRealm, "RIGHT" },
++ self.controls.accountRealmFetchButton = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.accountRealm, "RIGHT" },
+ { labelSpacing, 0, 130, 20 }, fetchTextFunc, fetchCharacters)
+ self.controls.accountRealmFetchButton.enabled = fetchButtonEnabled
+
+@@ -223,12 +223,12 @@ local function addOAuthControls(self)
+ end
+ end
+
+- self.controls.charSelectLeagueLabel = new("LabelControl", { "TOPLEFT", self.controls.accountRealm, "BOTTOMLEFT" },
++ self.controls.charSelectLeagueLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.accountRealm, "BOTTOMLEFT" },
+ { 0, rowSpacing, 0, 14 }, "^7League:")
+- self.controls.charSelectLeague = new("DropDownControl", { "LEFT", self.controls.charSelectLeagueLabel, "RIGHT" },
++ self.controls.charSelectLeague = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.charSelectLeagueLabel, "RIGHT" },
+ { labelSpacing, 0, 150, 18 }, nil, onLeagueChange)
+ -- character select
+- self.controls.charSelect = new("DropDownControl", { "TOPLEFT", self.controls.charSelectLeagueLabel, "BOTTOMLEFT" },
++ self.controls.charSelect = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.charSelectLeagueLabel, "BOTTOMLEFT" },
+ { 0, rowSpacing, 400, 18 }, nil)
+ self.controls.charSelect.enabled = function()
+ return self.usingOauth and self.isAuthorized()
+@@ -243,9 +243,9 @@ local function addOAuthControls(self)
+ main.lastCharacterHash = common.sha1(charName)
+ self.lastCharacterHash = common.sha1(charName)
+ end
+- self.controls.charImportHeader = new("LabelControl", { "TOPLEFT", self.controls.charSelect, "BOTTOMLEFT" },
++ self.controls.charImportHeader = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.charSelect, "BOTTOMLEFT" },
+ { 0, rowSpacing, 200, 16 }, "^7Import:")
+- self.controls.charImportTree = new("ButtonControl", { "LEFT", self.controls.charImportHeader, "RIGHT" },
++ self.controls.charImportTree = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.charImportHeader, "RIGHT" },
+ { labelSpacing, 0, 170, 20 }, "Passive Tree and Jewels", function()
+ local realm = self.controls.accountRealm:GetSelValue()
+ local league = self.controls.charSelectLeague:GetSelValue()
+@@ -280,9 +280,9 @@ local function addOAuthControls(self)
+ self.controls.charImportTree.enabled = function()
+ return self.usingOauth and self.isAuthorized() and self.controls.charSelect:GetSelValue()
+ end
+- self.controls.charImportTreeClearJewels = new("CheckBoxControl", { "LEFT", self.controls.charImportTree, "RIGHT" },
++ self.controls.charImportTreeClearJewels = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.charImportTree, "RIGHT" },
+ { 90, 0, 18 }, "Delete jewels:", nil, "Delete all equipped jewels when importing.", true)
+- self.controls.charImportItems = new("ButtonControl", { "TOPLEFT", self.controls.charImportTree, "BOTTOMLEFT" },
++ self.controls.charImportItems = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.charImportTree, "BOTTOMLEFT" },
+ { 0, rowSpacing, 110, 20 }, "Items and Skills", function()
+ local realm = self.controls.accountRealm:GetSelValue()
+ local league = self.controls.charSelectLeague:GetSelValue()
+@@ -311,33 +311,32 @@ local function addOAuthControls(self)
+ self.controls.charImportItems.enabled = function()
+ return self.usingOauth and self.isAuthorized() and self.controls.charSelect:GetSelValue()
+ end
+- self.controls.charImportItemsClearSkills = new("CheckBoxControl", { "LEFT", self.controls.charImportItems, "RIGHT" },
++ self.controls.charImportItemsClearSkills = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.charImportItems, "RIGHT" },
+ { 85, 0, 18 }, "Delete skills:", nil, "Delete all existing skills when importing.", true)
+- self.controls.charImportItemsClearItems = new("CheckBoxControl", { "LEFT", self.controls.charImportItems, "RIGHT" },
++ self.controls.charImportItemsClearItems = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.charImportItems, "RIGHT" },
+ { 220, 0, 18 }, "Delete equipment:", nil, "Delete all equipped items when importing.", true)
+- self.controls.charImportItemsIgnoreWeaponSwap = new("CheckBoxControl", { "LEFT", self.controls.charImportItems,
++ self.controls.charImportItemsIgnoreWeaponSwap = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.charImportItems,
+ "RIGHT" }, { 380, 0, 18 }, "Ignore weapon swap:", nil, "Ignore items and skills in weapon swap.", false)
+ end
+ local function addAccountNameControls(self)
+ self.charImportMode = "GETACCOUNTNAME"
+ self.charImportStatus = "Idle"
+- self.controls.siteCharImportStatusLabel = new("LabelControl", { "TOPLEFT", self.controls.sectionCharSiteImport, "TOPLEFT" },
++ self.controls.siteCharImportStatusLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.sectionCharSiteImport, "TOPLEFT" },
+ { 6, 14, 200, 16 }, function()
+ return "^7Character import status: " .. self.charImportStatus
+ end)
+
+ -- Stage: input account name
+- self.controls.siteAccountNameHeader = new("LabelControl", { "TOPLEFT", self.controls.sectionCharSiteImport, "TOPLEFT" },
++ self.controls.siteAccountNameHeader = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.sectionCharSiteImport, "TOPLEFT" },
+ { 6, 40, 250, 16 }, "^7To start importing a character, enter the character's account name:")
+ self.controls.siteAccountNameHeader.shown = function()
+ return self.charImportMode == "GETACCOUNTNAME"
+ end
+
+- self.controls.siteAccountRealm = new("DropDownControl",
+- { "TOPLEFT", self.controls.siteAccountNameHeader, "BOTTOMLEFT" },
++ self.controls.siteAccountRealm = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.siteAccountNameHeader, "BOTTOMLEFT" },
+ { 0, 4, 60, 20 }, realmList)
+ self.controls.siteAccountRealm:SelByValue(main.lastRealm or "PC", "id")
+- self.controls.siteAccountName = new("EditControl", { "LEFT", self.controls.siteAccountRealm, "RIGHT" }, { 8, 0, 200, 20 },
++ self.controls.siteAccountName = new("EditControl"):EditControl({ "LEFT", self.controls.siteAccountRealm, "RIGHT" }, { 8, 0, 200, 20 },
+ main.lastAccountName or "", nil, "%c", nil, nil, nil, nil, true)
+ self.controls.siteAccountName.pasteFilter = function(text)
+ return text:gsub(".", function(c)
+@@ -360,7 +359,7 @@ local function addAccountNameControls(self)
+ return a:lower() < b:lower()
+ end)
+ end -- don't load the list many times
+- self.controls.siteAccountNameGo = new("ButtonControl", { "LEFT", self.controls.siteAccountName, "RIGHT" }, { 8, 0, 60, 20 },
++ self.controls.siteAccountNameGo = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.siteAccountName, "RIGHT" }, { 8, 0, 60, 20 },
+ "Start", function()
+ local realm = self.controls.siteAccountRealm:GetSelValue()
+ self:DownloadSiteCharacterList(realm)
+@@ -375,14 +374,14 @@ local function addAccountNameControls(self)
+ end
+ end
+
+- self.controls.siteAccountHistory = new("DropDownControl", { "LEFT", self.controls.siteAccountNameGo, "RIGHT" },
++ self.controls.siteAccountHistory = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.siteAccountNameGo, "RIGHT" },
+ { 8, 0, 200, 20 }, historyList, function()
+ self.controls.siteAccountName.buf = self.controls.siteAccountHistory.list[self.controls.siteAccountHistory.selIndex]
+ end)
+ self.controls.siteAccountHistory:SelByValue(main.lastAccountName)
+ self.controls.siteAccountHistory:CheckDroppedWidth(true)
+
+- self.controls.siteRemoveAccount = new("ButtonControl", { "LEFT", self.controls.siteAccountHistory, "RIGHT" }, { 8, 0, 20, 20 },
++ self.controls.siteRemoveAccount = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.siteAccountHistory, "RIGHT" }, { 8, 0, 20, 20 },
+ "X", function()
+ local accountName = self.controls.siteAccountHistory.list[self.controls.siteAccountHistory.selIndex]
+ if (accountName ~= nil) then
+@@ -397,37 +396,36 @@ local function addAccountNameControls(self)
+ tooltip:AddLine(16, "^7Removes account from the dropdown list")
+ end
+
+- self.controls.siteAccountNameMissingDiscriminator = new("LabelControl",
+- { "TOPLEFT", self.controls.siteAccountName, "BOTTOMLEFT" }, { 0, 8, 0, 16 }, "^1Missing discriminator e.g. #1234")
++ self.controls.siteAccountNameMissingDiscriminator = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.siteAccountName, "BOTTOMLEFT" }, { 0, 8, 0, 16 }, "^1Missing discriminator e.g. #1234")
+ self.controls.siteAccountNameMissingDiscriminator.shown = function()
+ return not self.controls.siteAccountName.buf:match("[#%-]%d%d%d%d$") and self.controls.siteAccountName.buf ~= ""
+ end
+
+- self.controls.siteAccountNameUnicode = new("LabelControl", { "TOPLEFT", self.controls.siteAccountRealm, "BOTTOMLEFT" },
++ self.controls.siteAccountNameUnicode = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.siteAccountRealm, "BOTTOMLEFT" },
+ { 0, 34, 0, 14 },
+ "^7Note: if the account name contains non-ASCII characters it must be pasted into the textbox,\nnot typed manually.")
+
+ -- Stage: select character and import data
+- self.controls.siteCharSelectHeader = new("LabelControl", { "TOPLEFT", self.controls.sectionCharSiteImport, "TOPLEFT" },
++ self.controls.siteCharSelectHeader = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.sectionCharSiteImport, "TOPLEFT" },
+ { 6, 40, 200, 16 }, "^7Choose character to import data from:")
+ self.controls.siteCharSelectHeader.shown = function()
+ return self.charImportMode == "SELECTCHAR" or self.charImportMode == "IMPORTING"
+ end
+- self.controls.siteCharSelectLeagueLabel = new("LabelControl", { "TOPLEFT", self.controls.siteCharSelectHeader, "BOTTOMLEFT" },
++ self.controls.siteCharSelectLeagueLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.siteCharSelectHeader, "BOTTOMLEFT" },
+ { 0, 6, 0, 14 }, "^7League:")
+- self.controls.siteCharSelectLeague = new("DropDownControl", { "LEFT", self.controls.siteCharSelectLeagueLabel, "RIGHT" },
++ self.controls.siteCharSelectLeague = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.siteCharSelectLeagueLabel, "RIGHT" },
+ { 4, 0, 150, 18 }, nil, function(index, value)
+ local realm = self.controls.siteAccountRealm:GetSelValue()
+ self:BuildCharacterList(realm.realmCode, value.league, self.lastCharList, self.controls.siteCharSelect)
+ end)
+- self.controls.siteCharSelect = new("DropDownControl", { "TOPLEFT", self.controls.siteCharSelectHeader, "BOTTOMLEFT" },
++ self.controls.siteCharSelect = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.siteCharSelectHeader, "BOTTOMLEFT" },
+ { 0, 24, 400, 18 })
+ self.controls.siteCharSelect.enabled = function()
+ return self.charImportMode == "SELECTCHAR"
+ end
+- self.controls.siteCharImportHeader = new("LabelControl", { "TOPLEFT", self.controls.siteCharSelect, "BOTTOMLEFT" },
++ self.controls.siteCharImportHeader = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.siteCharSelect, "BOTTOMLEFT" },
+ { 0, 16, 200, 16 }, "^7Import:")
+- self.controls.siteCharImportTree = new("ButtonControl", { "LEFT", self.controls.siteCharImportHeader, "RIGHT" },
++ self.controls.siteCharImportTree = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.siteCharImportHeader, "RIGHT" },
+ { 8, 0, 170, 20 }, "Passive Tree and Jewels", function()
+ local realm = self.controls.siteAccountRealm:GetSelValue()
+ if self.build.spec:CountAllocNodes() > 0 then
+@@ -443,9 +441,9 @@ local function addAccountNameControls(self)
+ self.controls.siteCharImportTree.enabled = function()
+ return self.charImportMode == "SELECTCHAR"
+ end
+- self.controls.siteCharImportTreeClearJewels = new("CheckBoxControl", { "LEFT", self.controls.siteCharImportTree, "RIGHT" },
++ self.controls.siteCharImportTreeClearJewels = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.siteCharImportTree, "RIGHT" },
+ { 90, 0, 18 }, "Delete jewels:", nil, "Delete all equipped jewels when importing.", true)
+- self.controls.siteCharImportItems = new("ButtonControl", { "LEFT", self.controls.siteCharImportTree, "LEFT" },
++ self.controls.siteCharImportItems = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.siteCharImportTree, "LEFT" },
+ { 0, 36, 110, 20 }, "Items and Skills", function()
+ local realm = self.controls.siteAccountRealm:GetSelValue()
+ self:DownloadItems(realm)
+@@ -454,64 +452,66 @@ local function addAccountNameControls(self)
+ self.controls.siteCharImportItems.enabled = function()
+ return self.charImportMode == "SELECTCHAR"
+ end
+- self.controls.siteCharImportItemsClearSkills = new("CheckBoxControl", { "LEFT", self.controls.siteCharImportItems, "RIGHT" },
++ self.controls.siteCharImportItemsClearSkills = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.siteCharImportItems, "RIGHT" },
+ { 85, 0, 18 }, "Delete skills:", nil, "Delete all existing skills when importing.", true)
+- self.controls.siteCharImportItemsClearItems = new("CheckBoxControl", { "LEFT", self.controls.siteCharImportItems, "RIGHT" },
++ self.controls.siteCharImportItemsClearItems = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.siteCharImportItems, "RIGHT" },
+ { 220, 0, 18 }, "Delete equipment:", nil, "Delete all equipped items when importing.", true)
+- self.controls.siteCharImportItemsIgnoreWeaponSwap = new("CheckBoxControl", { "LEFT", self.controls.siteCharImportItems,
++ self.controls.siteCharImportItemsIgnoreWeaponSwap = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.siteCharImportItems,
+ "RIGHT" }, { 380, 0, 18 }, "Ignore weapon swap:", nil, "Ignore items and skills in weapon swap.", false)
+- self.controls.siteCharBanditNote = new("LabelControl", { "TOPLEFT", self.controls.siteCharImportHeader, "BOTTOMLEFT" },
++ self.controls.siteCharBanditNote = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.siteCharImportHeader, "BOTTOMLEFT" },
+ { 0, 50, 200, 14 },
+ "^7Tip: After you finish importing a character, make sure you update the bandit choice,\nas it can only be imported by logging in above.")
+
+- self.controls.siteCharClose = new("ButtonControl", { "TOPLEFT", self.controls.siteCharImportHeader, "BOTTOMLEFT" },
++ self.controls.siteCharClose = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.siteCharImportHeader, "BOTTOMLEFT" },
+ { 0, 90, 60, 20 }, "Close", function()
+ self.charImportMode = "GETACCOUNTNAME"
+ self.charImportStatus = "Idle"
+ end)
+ end
+
+-local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(self, build)
+- self.ControlHost()
+- self.Control()
++---@class ImportTab: ControlHost, Control
++local ImportTabClass = newClass("ImportTab", "ControlHost", "Control")
++
++---@param build Build
++function ImportTabClass:ImportTab(build)
++ self:ControlHost()
++ self:Control()
+
+ self.build = build
+
+ if not main.api then
+- main.api = new("PoEAPI", main.lastToken, main.lastRefreshToken, main.tokenExpiry)
++ main.api = new("PoEAPI"):PoEAPI(main.lastToken, main.lastRefreshToken, main.tokenExpiry)
+ end
+
+
+- self.controls.sectionOauthCharImport = new("SectionControl", { "TOPLEFT", self, "TOPLEFT" }, { 10, 18, 650, 200 },
++ self.controls.sectionOauthCharImport = new("SectionControl"):SectionControl({ "TOPLEFT", self, "TOPLEFT" }, { 10, 18, 650, 200 },
+ "Import From Your Account")
+
+ addOAuthControls(self)
+
+- self.controls.sectionCharSiteImport = new("SectionControl",
+- { "TOPLEFT", self.controls.sectionOauthCharImport, "BOTTOMLEFT" },
++ self.controls.sectionCharSiteImport = new("SectionControl"):SectionControl({ "TOPLEFT", self.controls.sectionOauthCharImport, "BOTTOMLEFT" },
+ { 0, 18, 650, 250 },
+ "Import By Account Name")
+ addAccountNameControls(self)
+
+
+ -- Build import/export
+- self.controls.sectionBuild = new("SectionControl",
+- { "TOPLEFT", self.controls.sectionCharSiteImport, "BOTTOMLEFT", true },
++ self.controls.sectionBuild = new("SectionControl"):SectionControl({ "TOPLEFT", self.controls.sectionCharSiteImport, "BOTTOMLEFT", true },
+ { 0, 18, 650, 182 }, "Build Sharing")
+- self.controls.generateCodeLabel = new("LabelControl", { "TOPLEFT", self.controls.sectionBuild, "TOPLEFT" },
++ self.controls.generateCodeLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.sectionBuild, "TOPLEFT" },
+ { 6, 14, 0, 16 }, "^7Generate a code to share this build with other Path of Building users:")
+- self.controls.generateCode = new("ButtonControl", {"LEFT",self.controls.generateCodeLabel,"RIGHT"}, {4, 0, 80, 20}, "Generate", function()
++ self.controls.generateCode = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.generateCodeLabel, "RIGHT" }, { 4, 0, 80, 20 }, "Generate", function()
+ self.controls.generateCodeOut:SetText(common.base64.encode(Deflate(self.build:SaveDB("code"))):gsub("+","-"):gsub("/","_"))
+ end)
+- self.controls.enablePartyExportBuffs = new("CheckBoxControl", {"LEFT",self.controls.generateCode,"RIGHT"}, {100, 0, 18}, "Export Support", function(state)
++ self.controls.enablePartyExportBuffs = new("CheckBoxControl"):CheckBoxControl({"LEFT",self.controls.generateCode,"RIGHT"}, {100, 0, 18}, "Export Support", function(state)
+ self.build.partyTab.enableExportBuffs = state
+ self.build.buildFlag = true
+ end, "This is for party play, to export support character, it enables the exporting of auras, curses and modifiers to the enemy", false)
+- self.controls.generateCodeOut = new("EditControl", {"TOPLEFT",self.controls.generateCodeLabel,"BOTTOMLEFT"}, {0, 8, 250, 20}, "", "Code", "%Z")
++ self.controls.generateCodeOut = new("EditControl"):EditControl({"TOPLEFT",self.controls.generateCodeLabel,"BOTTOMLEFT"}, {0, 8, 250, 20}, "", "Code", "%Z")
+ self.controls.generateCodeOut.enabled = function()
+ return #self.controls.generateCodeOut.buf > 0
+ end
+- self.controls.generateCodeCopy = new("ButtonControl", {"LEFT",self.controls.generateCodeOut,"RIGHT"}, {8, 0, 60, 20}, "Copy", function()
++ self.controls.generateCodeCopy = new("ButtonControl"):ButtonControl({"LEFT",self.controls.generateCodeOut,"RIGHT"}, {8, 0, 60, 20}, "Copy", function()
+ Copy(self.controls.generateCodeOut.buf)
+ self.controls.generateCodeOut:SetText("")
+ end)
+@@ -726,8 +726,8 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
+ end
+ end)
+ end
+-
+-end)
++ return self
++end
+
+ -- attempt to fetch the last realm's character list once per instance, if there
+ -- is a last realm saved
diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua
index affafee709..708417861b 100644
--- a/src/Classes/Item.lua
+++ b/src/Classes/Item.lua
@@ -2117,7 +2117,7 @@ function ItemClass:BuildModList()
if not self.base then
return
end
- local baseList = new("ModList")
+ local baseList = new("ModList"):ModList()
if self.base.weapon then
self.weaponData = { }
elseif self.base.armour then
diff --git a/src/Classes/Item.lua.rej b/src/Classes/Item.lua.rej
new file mode 100644
index 0000000000..57f8871ec2
--- /dev/null
+++ b/src/Classes/Item.lua.rej
@@ -0,0 +1,28 @@
+diff a/src/Classes/Item.lua b/src/Classes/Item.lua (rejected hunks)
+@@ -88,11 +88,15 @@ end
+
+ local influenceInfo = itemLib.influenceInfo.all
+
+-local ItemClass = newClass("Item", function(self, raw, rarity, highQuality)
++---@class Item
++local ItemClass = newClass("Item")
++
++function ItemClass:Item(raw, rarity, highQuality)
+ if raw then
+ self:ParseRaw(sanitiseText(raw), rarity, highQuality)
+ end
+-end)
++ return self
++end
+
+ -- Reset all influence keys to false
+ function ItemClass:ResetInfluence()
+@@ -2180,7 +2184,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
+ if slotNum ~= 1 then
+ slotName = slotName:gsub("1", tostring(slotNum))
+ end
+- local modList = new("ModList")
++ local modList = new("ModList"):ModList()
+ for _, baseMod in ipairs(baseList) do
+ local mod = copyTable(baseMod)
+ local add = true
diff --git a/src/Classes/ItemDBControl.lua b/src/Classes/ItemDBControl.lua
index 0e3c8231e9..72095c1fb8 100644
--- a/src/Classes/ItemDBControl.lua
+++ b/src/Classes/ItemDBControl.lua
@@ -10,8 +10,11 @@ local m_max = math.max
local m_floor = math.floor
-local ItemDBClass = newClass("ItemDBControl", "ListControl", function(self, anchor, rect, itemsTab, db, dbType)
- self.ListControl(anchor, rect, 16, "VERTICAL", false)
+---@class ItemDBControl: ListControl
+local ItemDBClass = newClass("ItemDBControl", "ListControl")
+
+function ItemDBClass:ItemDBControl(anchor, rect, itemsTab, db, dbType)
+ self:ListControl(anchor, rect, 16, "VERTICAL", false)
self.itemsTab = itemsTab
self.db = db
self.dbType = dbType
@@ -333,7 +336,7 @@ end
function ItemDBClass:OnSelClick(index, item, doubleClick)
if IsKeyDown("CTRL") then
-- Add item
- local newItem = new("Item", item.raw)
+ local newItem = new("Item"):Item(item.raw)
newItem:NormaliseQuality()
self.itemsTab:AddItem(newItem, true)
diff --git a/src/Classes/ItemDBControl.lua.rej b/src/Classes/ItemDBControl.lua.rej
new file mode 100644
index 0000000000..d300657eb1
--- /dev/null
+++ b/src/Classes/ItemDBControl.lua.rej
@@ -0,0 +1,47 @@
+diff a/src/Classes/ItemDBControl.lua b/src/Classes/ItemDBControl.lua (rejected hunks)
+@@ -28,35 +31,36 @@ local ItemDBClass = newClass("ItemDBControl", "ListControl", function(self, anch
+ self.typeList = { "Any type", "Armour", "Jewellery", "One Handed Melee", "Two Handed Melee" }
+ self.slotList = { "Any slot", "Weapon 1", "Weapon 2", "Helmet", "Body Armour", "Gloves", "Boots", "Amulet", "Ring", "Belt", "Jewel", "Flask", "Graft 1", "Graft 2" }
+ local baseY = dbType == "RARE" and -22 or -62
+- self.controls.slot = new("DropDownControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, baseY, 179, 18}, self.slotList, function(index, value)
++ self.controls.slot = new("DropDownControl"):DropDownControl({"BOTTOMLEFT",self,"TOPLEFT"}, {0, baseY, 179, 18}, self.slotList, function(index, value)
+ self.listBuildFlag = true
+ end)
+- self.controls.type = new("DropDownControl", {"LEFT",self.controls.slot,"RIGHT"}, {2, 0, 179, 18}, self.typeList, function(index, value)
++ self.controls.type = new("DropDownControl"):DropDownControl({"LEFT",self.controls.slot,"RIGHT"}, {2, 0, 179, 18}, self.typeList, function(index, value)
+ self.listBuildFlag = true
+ end)
+ if dbType == "UNIQUE" then
+- self.controls.sort = new("DropDownControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, baseY + 20, 179, 18}, self.sortDropList, function(index, value)
++ self.controls.sort = new("DropDownControl"):DropDownControl({"BOTTOMLEFT",self,"TOPLEFT"}, {0, baseY + 20, 179, 18}, self.sortDropList, function(index, value)
+ self:SetSortMode(value.sortMode)
+ end)
+- self.controls.league = new("DropDownControl", {"LEFT",self.controls.sort,"RIGHT"}, {2, 0, 179, 18}, self.leagueList, function(index, value)
++ self.controls.league = new("DropDownControl"):DropDownControl({"LEFT",self.controls.sort,"RIGHT"}, {2, 0, 179, 18}, self.leagueList, function(index, value)
+ self.listBuildFlag = true
+ end)
+- self.controls.requirement = new("DropDownControl", {"LEFT",self.controls.sort,"BOTTOMLEFT"}, {0, 11, 179, 18}, { "Any requirements", "Current level", "Current attributes", "Current useable" }, function(index, value)
++ self.controls.requirement = new("DropDownControl"):DropDownControl({"LEFT",self.controls.sort,"BOTTOMLEFT"}, {0, 11, 179, 18}, { "Any requirements", "Current level", "Current attributes", "Current useable" }, function(index, value)
+ self.listBuildFlag = true
+ end)
+- self.controls.obtainable = new("DropDownControl", {"LEFT",self.controls.requirement,"RIGHT"}, {2, 0, 179, 18}, { "Obtainable", "Any source", "Unobtainable", "Vendor Recipe", "Upgraded", "Boss Item", "Corruption"}, function(index, value)
++ self.controls.obtainable = new("DropDownControl"):DropDownControl({"LEFT",self.controls.requirement,"RIGHT"}, {2, 0, 179, 18}, { "Obtainable", "Any source", "Unobtainable", "Vendor Recipe", "Upgraded", "Boss Item", "Corruption"}, function(index, value)
+ self.listBuildFlag = true
+ end)
+ end
+- self.controls.search = new("EditControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 258, 18}, "", "Search", "%c", 100, function()
++ self.controls.search = new("EditControl"):EditControl({"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 258, 18}, "", "Search", "%c", 100, function()
+ self.listBuildFlag = true
+ end, nil, nil, true)
+- self.controls.searchMode = new("DropDownControl", {"LEFT",self.controls.search,"RIGHT"}, {2, 0, 100, 18}, { "Anywhere", "Names", "Modifiers" }, function(index, value)
++ self.controls.searchMode = new("DropDownControl"):DropDownControl({"LEFT",self.controls.search,"RIGHT"}, {2, 0, 100, 18}, { "Anywhere", "Names", "Modifiers" }, function(index, value)
+ self.listBuildFlag = true
+ end)
+ self:BuildSortOrder()
+ self.listBuildFlag = true
+-end)
++ return self
++end
+
+ function ItemDBClass:LoadLeaguesAndTypes()
+ local leagueFlag = { }
diff --git a/src/Classes/ItemListControl.lua b/src/Classes/ItemListControl.lua
index ac03df2b1f..aaa03631da 100644
--- a/src/Classes/ItemListControl.lua
+++ b/src/Classes/ItemListControl.lua
@@ -146,7 +146,7 @@ end
function ItemListClass:ReceiveDrag(type, value, source)
if type == "Item" then
- local newItem = new("Item", value.raw)
+ local newItem = new("Item"):Item(value.raw)
newItem:NormaliseQuality()
self.itemsTab:AddItem(newItem, true, self.selDragIndex)
self.itemsTab:PopulateSlots()
diff --git a/src/Classes/ItemListControl.lua.rej b/src/Classes/ItemListControl.lua.rej
new file mode 100644
index 0000000000..e67ef7d28e
--- /dev/null
+++ b/src/Classes/ItemListControl.lua.rej
@@ -0,0 +1,65 @@
+diff a/src/Classes/ItemListControl.lua b/src/Classes/ItemListControl.lua (rejected hunks)
+@@ -7,20 +7,23 @@ local pairs = pairs
+ local ipairs = ipairs
+ local t_insert = table.insert
+
+-local ItemListClass = newClass("ItemListControl", "ListControl", function(self, anchor, rect, itemsTab, forceTooltip)
+- self.ListControl(anchor, rect, 16, "VERTICAL", true, itemsTab.itemOrderList, forceTooltip)
++---@class ItemListControl: ListControl
++local ItemListClass = newClass("ItemListControl", "ListControl")
++
++function ItemListClass:ItemListControl(anchor, rect, itemsTab, forceTooltip)
++ self:ListControl(anchor, rect, 16, "VERTICAL", true, itemsTab.itemOrderList, forceTooltip)
+ self.itemsTab = itemsTab
+ self.defaultText = "^x7F7F7FThis is the list of items that have been added to this build.\nYou can add items to this list by dragging them from\none of the other lists, or by clicking 'Add to build' when\nviewing an item."
+ self.dragTargetList = { }
+- self.controls.loadoutFilter = new("DropDownControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 110, 18}, nil, function()
++ self.controls.loadoutFilter = new("DropDownControl"):DropDownControl({"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 110, 18}, nil, function()
+ self:UpdateList()
+ end)
+ self.controls.loadoutFilter.enableDroppedWidth = true
+- self.controls.sort = new("ButtonControl", {"LEFT",self.controls.loadoutFilter,"RIGHT"}, {4, 0, 42, 18}, "Sort", function()
++ self.controls.sort = new("ButtonControl"):ButtonControl({"LEFT",self.controls.loadoutFilter,"RIGHT"}, {4, 0, 42, 18}, "Sort", function()
+ itemsTab:SortItemList()
+ self:UpdateList()
+ end)
+- self.controls.deleteUnused = new("ButtonControl", {"LEFT",self.controls.sort,"RIGHT"}, {4, 0, 84, 18}, "Del Unused", function()
++ self.controls.deleteUnused = new("ButtonControl"):ButtonControl({"LEFT",self.controls.sort,"RIGHT"}, {4, 0, 84, 18}, "Del Unused", function()
+ local delList = {}
+ for _, itemId in pairs(itemsTab.itemOrderList) do
+ if not itemsTab:GetEquippedSlotForItem(itemsTab.items[itemId]) and not self:FindEquippedAbyssJewel(itemId, false) and not self:FindSocketedJewel(itemId, false) then
+@@ -43,7 +46,7 @@ local ItemListClass = newClass("ItemListControl", "ListControl", function(self,
+ self.controls.deleteUnused.enabled = function()
+ return #self.list > 0
+ end
+- self.controls.deleteAll = new("ButtonControl", {"LEFT",self.controls.deleteUnused,"RIGHT"}, {4, 0, 58, 18}, "Del All", function()
++ self.controls.deleteAll = new("ButtonControl"):ButtonControl({"LEFT",self.controls.deleteUnused,"RIGHT"}, {4, 0, 58, 18}, "Del All", function()
+ main:OpenConfirmPopup("Delete All", "Are you sure you want to delete all items in this build?", "Delete", function()
+ for _, slot in pairs(itemsTab.slots) do
+ slot:SetSelItemId(0)
+@@ -66,13 +69,14 @@ local ItemListClass = newClass("ItemListControl", "ListControl", function(self,
+ self.controls.deleteAll.enabled = function()
+ return #self.list > 0
+ end
+- self.controls.delete = new("ButtonControl", {"LEFT",self.controls.deleteAll,"RIGHT"}, {4, 0, 50, 18}, "Delete", function()
++ self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT",self.controls.deleteAll,"RIGHT"}, {4, 0, 50, 18}, "Delete", function()
+ self:OnSelDelete(self.selIndex, self.selValue)
+ end)
+ self.controls.delete.enabled = function()
+ return self.selValue ~= nil
+ end
+-end)
++ return self
++end
+
+ function ItemListClass:UpdateLoadoutList()
+ local list = { "Any Loadout", "Current Loadout", "Unused Items" }
+@@ -316,7 +320,7 @@ function ItemListClass:OnSelClick(index, itemId, doubleClick)
+ -- disallow dragging since if the cursor is outside the selection after
+ -- the second click, the item will be stuck onto the cursor
+ self.selDragging = false
+- local newItem = new("Item", item:BuildRaw())
++ local newItem = new("Item"):Item(item:BuildRaw())
+ newItem.id = item.id
+ self.itemsTab:SetDisplayItem(newItem)
+ return false
diff --git a/src/Classes/ItemSetListControl.lua.rej b/src/Classes/ItemSetListControl.lua.rej
new file mode 100644
index 0000000000..105a44e247
--- /dev/null
+++ b/src/Classes/ItemSetListControl.lua.rej
@@ -0,0 +1,76 @@
+diff a/src/Classes/ItemSetListControl.lua b/src/Classes/ItemSetListControl.lua (rejected hunks)
+@@ -8,10 +8,13 @@ local t_remove = table.remove
+ local m_max = math.max
+ local s_format = string.format
+
+-local ItemSetListClass = newClass("ItemSetListControl", "ListControl", function(self, anchor, rect, itemsTab)
+- self.ListControl(anchor, rect, 16, "VERTICAL", true, itemsTab.itemSetOrderList)
++---@class ItemSetListControl: ListControl
++local ItemSetListClass = newClass("ItemSetListControl", "ListControl")
++
++function ItemSetListClass:ItemSetListControl(anchor, rect, itemsTab)
++ self:ListControl(anchor, rect, 16, "VERTICAL", true, itemsTab.itemSetOrderList)
+ self.itemsTab = itemsTab
+- self.controls.copy = new("ButtonControl", {"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
++ self.controls.copy = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
+ local newSet = copyTable(itemsTab.itemSets[self.selValue])
+ newSet.id = 1
+ while itemsTab.itemSets[newSet.id] do
+@@ -23,31 +26,32 @@ local ItemSetListClass = newClass("ItemSetListControl", "ListControl", function(
+ self.controls.copy.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.delete = new("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
++ self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
+ self:OnSelDelete(self.selIndex, self.selValue)
+ end)
+ self.controls.delete.enabled = function()
+ return self.selValue ~= nil and #self.list > 1
+ end
+- self.controls.rename = new("ButtonControl", {"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
++ self.controls.rename = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
+ self:RenameSet(itemsTab.itemSets[self.selValue])
+ end)
+ self.controls.rename.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.new = new("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
++ self.controls.new = new("ButtonControl"):ButtonControl({"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
+ local newSet = itemsTab:NewItemSet()
+ self:RenameSet(newSet, true)
+ end)
+-end)
++ return self
++end
+
+ function ItemSetListClass:RenameSet(itemSet, addOnName)
+ local controls = { }
+- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter name for this item set:")
+- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, itemSet.title, nil, nil, 100, function(buf)
++ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this item set:")
++ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, itemSet.title, nil, nil, 100, function(buf)
+ controls.save.enabled = buf:match("%S")
+ end)
+- controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function()
+ itemSet.title = controls.edit.buf
+ self.itemsTab.modFlag = true
+ if addOnName then
+@@ -60,7 +64,7 @@ function ItemSetListClass:RenameSet(itemSet, addOnName)
+ main:ClosePopup()
+ end)
+ controls.save.enabled = false
+- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
++ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
+ if addOnName then
+ self.itemsTab.itemSets[itemSet.id] = nil
+ end
+@@ -95,7 +99,7 @@ function ItemSetListClass:ReceiveDrag(type, value, source)
+ local itemSet = self.itemsTab:NewItemSet()
+ itemSet.title = value.title
+ for slotName, item in pairs(value.slots) do
+- local newItem = new("Item", item.raw)
++ local newItem = new("Item"):Item(item.raw)
+ newItem:NormaliseQuality()
+ self.itemsTab:AddItem(newItem, true)
+ itemSet[slotName].selItemId = newItem.id
diff --git a/src/Classes/ItemSlotControl.lua b/src/Classes/ItemSlotControl.lua
index c8ca3e3338..261f049bb1 100644
--- a/src/Classes/ItemSlotControl.lua
+++ b/src/Classes/ItemSlotControl.lua
@@ -8,8 +8,11 @@ local t_insert = table.insert
local m_min = math.min
local itemSlotHelper = LoadModule("Modules/ItemSlotHelper")
-local ItemSlotClass = newClass("ItemSlotControl", "DropDownControl", function(self, anchor, x, y, itemsTab, slotName, slotLabel, nodeId)
- self.DropDownControl(anchor, {x, y, 310, 20}, { }, function(index, value)
+---@class ItemSlotControl
+local ItemSlotClass = newClass("ItemSlotControl", "DropDownControl")
+
+function ItemSlotClass:ItemSlotControl(anchor, x, y, itemsTab, slotName, slotLabel, nodeId)
+ self:DropDownControl(anchor, { x, y, 310, 20 }, {}, function(index, value)
if self.items[index] ~= self.selItemId then
self:SetSelItemId(self.items[index])
itemsTab:PopulateSlots()
@@ -30,7 +33,7 @@ local ItemSlotClass = newClass("ItemSlotControl", "DropDownControl", function(se
self.slotName = slotName
self.slotNum = tonumber(slotName:match("%d+$") or slotName:match("%d+"))
if slotName:match("Flask") then
- self.controls.activate = new("CheckBoxControl", {"RIGHT",self,"LEFT"}, {-2, 0, 20}, nil, function(state)
+ self.controls.activate = new("CheckBoxControl"):CheckBoxControl({"RIGHT",self,"LEFT"}, {-2, 0, 20}, nil, function(state)
self.active = state
itemsTab.activeItemSet[self.slotName].active = state
itemsTab:AddUndoState()
@@ -69,7 +72,8 @@ local ItemSlotClass = newClass("ItemSlotControl", "DropDownControl", function(se
end
self.label = slotLabel or slotName
self.nodeId = nodeId
-end)
+ return self
+end
function ItemSlotClass:SetSelItemId(selItemId)
if self.nodeId then
@@ -123,7 +127,7 @@ function ItemSlotClass:ReceiveDrag(type, value, source)
if value.id and self.itemsTab.items[value.id] then
self:SetSelItemId(value.id)
else
- local newItem = new("Item", value.raw)
+ local newItem = new("Item"):Item(value.raw)
newItem:NormaliseQuality()
self.itemsTab:AddItem(newItem, true)
self:SetSelItemId(newItem.id)
diff --git a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua
index 797acf629c..179d13bdf6 100644
--- a/src/Classes/ItemsTab.lua
+++ b/src/Classes/ItemsTab.lua
@@ -161,10 +161,10 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
self.showStatDifferences = true
-- PoB Trader class initialization
- self.tradeQuery = new("TradeQuery", self)
+ self.tradeQuery = new("TradeQuery"):TradeQuery(self)
-- Set selector
- self.controls.setSelect = new("DropDownControl", {"TOPLEFT",self,"TOPLEFT"}, {96, 8, 216, 20}, nil, function(index, value)
+ self.controls.setSelect = new("DropDownControl"):DropDownControl({"TOPLEFT",self,"TOPLEFT"}, {96, 8, 216, 20}, nil, function(index, value)
self:SetActiveItemSet(self.itemSetOrderList[index])
self:AddUndoState()
end)
@@ -178,13 +178,13 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
self:AddItemSetTooltip(tooltip, self.itemSets[self.itemSetOrderList[index]])
end
end
- self.controls.setLabel = new("LabelControl", {"RIGHT",self.controls.setSelect,"LEFT"}, {-2, 0, 0, 16}, "^7Item set:")
- self.controls.setManage = new("ButtonControl", {"LEFT",self.controls.setSelect,"RIGHT"}, {4, 0, 90, 20}, "Manage...", function()
+ self.controls.setLabel = new("LabelControl"):LabelControl({"RIGHT",self.controls.setSelect,"LEFT"}, {-2, 0, 0, 16}, "^7Item set:")
+ self.controls.setManage = new("ButtonControl"):ButtonControl({"LEFT",self.controls.setSelect,"RIGHT"}, {4, 0, 90, 20}, "Manage...", function()
self:OpenItemSetManagePopup()
end)
-- Price Items
- self.controls.priceDisplayItem = new("ButtonControl", {"TOPLEFT",self,"TOPLEFT"}, {96, 32, 310, 20}, "Trade for these items", function()
+ self.controls.priceDisplayItem = new("ButtonControl"):ButtonControl({"TOPLEFT",self,"TOPLEFT"}, {96, 32, 310, 20}, "Trade for these items", function()
self.tradeQuery:PriceItem()
end)
self.controls.priceDisplayItem.tooltipFunc = function(tooltip)
@@ -258,7 +258,7 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
end
-- Passive tree dropdown controls
- self.controls.specSelect = new("DropDownControl", {"TOPLEFT",prevSlot,"BOTTOMLEFT"}, {0, 8, 216, 20}, nil, function(index, value)
+ self.controls.specSelect = new("DropDownControl"):DropDownControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, {0, 8, 216, 20}, nil, function(index, value)
if self.build.treeTab.specList[index] then
self.build.modFlag = true
self.build.treeTab:SetActiveSpec(index)
@@ -268,10 +268,10 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
return #self.controls.specSelect.list > 1
end
prevSlot = self.controls.specSelect
- self.controls.specButton = new("ButtonControl", {"LEFT",prevSlot,"RIGHT"}, {4, 0, 90, 20}, "Manage...", function()
+ self.controls.specButton = new("ButtonControl"):ButtonControl({"LEFT",prevSlot,"RIGHT"}, {4, 0, 90, 20}, "Manage...", function()
self.build.treeTab:OpenSpecManagePopup()
end)
- self.controls.specLabel = new("LabelControl", {"RIGHT",prevSlot,"LEFT"}, {-2, 0, 0, 16}, "^7Passive tree:")
+ self.controls.specLabel = new("LabelControl"):LabelControl({"RIGHT",prevSlot,"LEFT"}, {-2, 0, 0, 16}, "^7Passive tree:")
self.sockets = { }
local socketOrder = { }
@@ -284,12 +284,12 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
return a.id < b.id
end)
for _, node in ipairs(socketOrder) do
- local socketControl = new("ItemSlotControl", {"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, "Jewel "..node.id, "Socket", node.id)
+ local socketControl = new("ItemSlotControl"):ItemSlotControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, "Jewel "..node.id, "Socket", node.id)
self.sockets[node.id] = socketControl
addSlot(socketControl)
end
- self.controls.slotHeader = new("LabelControl", {"BOTTOMLEFT",self.slotAnchor,"TOPLEFT"}, {0, -4, 0, 16}, "^7Equipped items:")
- self.controls.weaponSwap1 = new("ButtonControl", {"BOTTOMRIGHT",self.slotAnchor,"TOPRIGHT"}, {-20, -2, 18, 18}, "I", function()
+ self.controls.slotHeader = new("LabelControl"):LabelControl({"BOTTOMLEFT",self.slotAnchor,"TOPLEFT"}, {0, -4, 0, 16}, "^7Equipped items:")
+ self.controls.weaponSwap1 = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self.slotAnchor,"TOPRIGHT"}, {-20, -2, 18, 18}, "I", function()
if self.activeItemSet.useSecondWeaponSet then
self.activeItemSet.useSecondWeaponSet = false
self:AddUndoState()
@@ -309,7 +309,7 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
self.controls.weaponSwap1.locked = function()
return not self.activeItemSet.useSecondWeaponSet
end
- self.controls.weaponSwap2 = new("ButtonControl", {"BOTTOMRIGHT",self.slotAnchor,"TOPRIGHT"}, {0, -2, 18, 18}, "II", function()
+ self.controls.weaponSwap2 = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self.slotAnchor,"TOPRIGHT"}, {0, -2, 18, 18}, "II", function()
if not self.activeItemSet.useSecondWeaponSet then
self.activeItemSet.useSecondWeaponSet = true
self:AddUndoState()
@@ -398,30 +398,29 @@ drag it onto the slot. This will also add it to
your build if it's from the unique/template list.
If there's 2 slots an item can go in,
holding Shift will put it in the second.]])
- self.controls.sharedItemList = new("SharedItemListControl", {"TOPLEFT",self.controls.craftDisplayItem, "BOTTOMLEFT"}, {0, 232, 340, 308}, self, true)
+ self.controls.sharedItemList = new("SharedItemListControl"):SharedItemListControl({"TOPLEFT",self.controls.craftDisplayItem, "BOTTOMLEFT"}, {0, 232, 340, 308}, self, true)
-- Display item
- self.displayItemTooltip = new("Tooltip")
+ self.displayItemTooltip = new("Tooltip"):Tooltip()
self.displayItemTooltip.maxWidth = 458
- self.anchorDisplayItem = new("Control", {"TOPLEFT",main.portraitMode and self.controls.setManage or self.controls.itemList,"TOPRIGHT"}, {20, main.portraitMode and 0 or -20, 0, 0})
+ self.anchorDisplayItem = new("Control"):Control({"TOPLEFT",main.portraitMode and self.controls.setManage or self.controls.itemList,"TOPRIGHT"}, {20, main.portraitMode and 0 or -20, 0, 0})
self.anchorDisplayItem.shown = function()
return self.displayItem ~= nil
end
- self.controls.addDisplayItem = new("ButtonControl", {"TOPLEFT",self.anchorDisplayItem,"TOPLEFT"}, {0, 0, 100, 20}, "", function()
+ self.controls.addDisplayItem = new("ButtonControl"):ButtonControl({"TOPLEFT",self.anchorDisplayItem,"TOPLEFT"}, {0, 0, 100, 20}, "", function()
self:AddDisplayItem()
end)
self.controls.addDisplayItem.label = function()
return self.items[self.displayItem.id] and "Save" or "Add to build"
end
- self.controls.editDisplayItem = new("ButtonControl", {"LEFT",self.controls.addDisplayItem,"RIGHT"}, {8, 0, 60, 20}, "Edit...", function()
+ self.controls.editDisplayItem = new("ButtonControl"):ButtonControl({"LEFT",self.controls.addDisplayItem,"RIGHT"}, {8, 0, 60, 20}, "Edit...", function()
self:EditDisplayItemText()
end)
- self.controls.removeDisplayItem = new("ButtonControl", {"LEFT",self.controls.editDisplayItem,"RIGHT"}, {8, 0, 60, 20}, "Cancel", function()
+ self.controls.removeDisplayItem = new("ButtonControl"):ButtonControl({"LEFT",self.controls.editDisplayItem,"RIGHT"}, {8, 0, 60, 20}, "Cancel", function()
self:SetDisplayItem()
end)
- self.controls.displayItemBuySimilar = new("ButtonControl",
- { "LEFT", self.controls.removeDisplayItem, "RIGHT", true },
+ self.controls.displayItemBuySimilar = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.removeDisplayItem, "RIGHT", true },
{ 8, 0, 100, 20 }, "Buy similar", function()
local itemSlot = self:GetComparisonSlotNameForItem(self.displayItem)
buySimilar.openPopup(self.displayItem, itemSlot, self.build)
@@ -660,10 +659,10 @@ holding Shift will put it in the second.]])
end
-- Section: Cluster Jewel
- self.controls.displayItemSectionClusterJewel = new("Control", {"TOPLEFT",self.controls.displayItemSectionCatalyst,"BOTTOMLEFT"}, {0, 0, 0, function()
+ self.controls.displayItemSectionClusterJewel = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionCatalyst,"BOTTOMLEFT"}, {0, 0, 0, function()
return self.controls.displayItemClusterJewelSkill:IsShown() and 52 or 0
end})
- self.controls.displayItemClusterJewelSkill = new("DropDownControl", {"TOPLEFT",self.controls.displayItemSectionClusterJewel,"TOPLEFT"}, {0, 0, 300, 20}, { }, function(index, value)
+ self.controls.displayItemClusterJewelSkill = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemSectionClusterJewel,"TOPLEFT"}, {0, 0, 300, 20}, { }, function(index, value)
self.displayItem.clusterJewelSkill = value.skillId
self:CraftClusterJewel()
end) {
@@ -923,7 +922,7 @@ holding Shift will put it in the second.]])
drop.shown = function()
return self.displayItem and self.displayItem.crafted and i <= self.displayItem.affixLimit
end
- slider = new("SliderControl", {"TOPLEFT",drop,"BOTTOMLEFT"}, {0, 2, 300, 16}, function(val)
+ slider = new("SliderControl"):SliderControl({"TOPLEFT",drop,"BOTTOMLEFT"}, {0, 2, 300, 16}, function(val)
local affix = self.displayItem[drop.outputTable][drop.outputIndex]
local index, range = slider:GetDivVal()
affix.modId = drop.list[drop.selIndex].modList[index]
@@ -1073,7 +1072,8 @@ holding Shift will put it in the second.]])
self:PopulateSlots()
self.lastSlot = self.slots[baseSlots[#baseSlots]]
-end)
+ return self
+end
function ItemsTabClass:Load(xml, dbFileName)
self.activeItemSetId = 0
@@ -1082,7 +1082,7 @@ function ItemsTabClass:Load(xml, dbFileName)
self.tradeQuery.statSortSelectionList = { }
for _, node in ipairs(xml) do
if node.elem == "Item" then
- local item = new("Item", "")
+ local item = new("Item"):Item("")
item.id = tonumber(node.attrib.id)
item.variant = tonumber(node.attrib.variant)
if node.attrib.variantAlt then
@@ -1515,7 +1515,7 @@ function ItemsTabClass:EquipItemInSet(item, itemSetId)
slotName = slotName .. " Swap"
end
if not item.id or not self.items[item.id] then
- item = new("Item", item.raw)
+ item = new("Item"):Item(item.raw)
self:AddItem(item, true)
end
local altSlot = slotName:gsub("1","2")
@@ -2163,9 +2163,9 @@ function ItemsTabClass:UpdateCustomControls()
local line = itemLib.formatModLine(modLine)
if line then
if not self.controls["displayItemCustomModifierRemove"..i] then
- self.controls["displayItemCustomModifierRemove"..i] = new("ButtonControl", {"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, {0, i * 22 + 4, 70, 20}, "^7Remove")
- self.controls["displayItemCustomModifier"..i] = new("LabelControl", {"LEFT",self.controls["displayItemCustomModifierRemove"..i],"RIGHT"}, {65, 0, 0, 16})
- self.controls["displayItemCustomModifierLabel"..i] = new("LabelControl", {"LEFT",self.controls["displayItemCustomModifierRemove"..i],"RIGHT"}, {5, 0, 0, 16})
+ self.controls["displayItemCustomModifierRemove"..i] = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, {0, i * 22 + 4, 70, 20}, "^7Remove")
+ self.controls["displayItemCustomModifier"..i] = new("LabelControl"):LabelControl({"LEFT",self.controls["displayItemCustomModifierRemove"..i],"RIGHT"}, {65, 0, 0, 16})
+ self.controls["displayItemCustomModifierLabel"..i] = new("LabelControl"):LabelControl({"LEFT",self.controls["displayItemCustomModifierRemove"..i],"RIGHT"}, {5, 0, 0, 16})
end
self.controls["displayItemCustomModifierRemove"..i].shown = true
local label = itemLib.formatModLine(modLine)
@@ -2383,11 +2383,11 @@ end
-- Opens the item set manager
function ItemsTabClass:OpenItemSetManagePopup()
local controls = { }
- controls.setList = new("ItemSetListControl", nil, {-155, 50, 300, 200}, self)
- controls.sharedList = new("SharedItemSetListControl", nil, {155, 50, 300, 200}, self)
+ controls.setList = new("ItemSetListControl"):ItemSetListControl(nil, {-155, 50, 300, 200}, self)
+ controls.sharedList = new("SharedItemSetListControl"):SharedItemSetListControl(nil, {155, 50, 300, 200}, self)
controls.setList.dragTargetList = { controls.sharedList }
controls.sharedList.dragTargetList = { controls.setList }
- controls.close = new("ButtonControl", nil, {0, 260, 90, 20}, "Done", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, {0, 260, 90, 20}, "Done", function()
main:ClosePopup()
end)
main:OpenPopup(630, 290, "Manage Item Sets", controls)
@@ -2397,7 +2397,7 @@ end
function ItemsTabClass:CraftItem()
local controls = { }
local function makeItem(base)
- local item = new("Item")
+ local item = new("Item"):Item()
item.name = base.name
item.base = base.base
item.baseName = base.name
@@ -2485,7 +2485,7 @@ function ItemsTabClass:CraftItem()
self:AddItemTooltip(tooltip, makeItem(value), nil, true)
end
end
- controls.save = new("ButtonControl", nil, {-45, 100, 80, 20}, "Create", function()
+ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 100, 80, 20}, "Create", function()
main:ClosePopup()
local item = makeItem(controls.base.list[controls.base.selIndex])
self:SetDisplayItem(item)
@@ -2496,7 +2496,7 @@ function ItemsTabClass:CraftItem()
self.lastCraftTypeSel = controls.type.selIndex
self.lastCraftBaseSel = controls.base.selIndex
end)
- controls.cancel = new("ButtonControl", nil, {45, 100, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 100, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(370, 130, "Craft Item", controls)
@@ -2513,8 +2513,8 @@ function ItemsTabClass:EditDisplayItemText(alsoAddItem)
return "Rarity: "..controls.rarity.list[controls.rarity.selIndex].rarity.."\n"..controls.edit.buf
end
end
- controls.rarity = new("DropDownControl", nil, {-190, 10, 100, 18}, rarityDropList)
- controls.edit = new("EditControl", nil, {0, 40, 480, 420}, "", nil, "^%C\t\n", nil, nil, 14)
+ controls.rarity = new("DropDownControl"):DropDownControl(nil, {-190, 10, 100, 18}, rarityDropList)
+ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 480, 420}, "", nil, "^%C\t\n", nil, nil, 14)
if self.displayItem then
controls.edit:SetText(self.displayItem:BuildRaw():gsub("Rarity: %w+\n",""))
controls.rarity:SelByValue(self.displayItem.rarity, "rarity")
@@ -2523,7 +2523,7 @@ function ItemsTabClass:EditDisplayItemText(alsoAddItem)
end
controls.edit.font = "FIXED"
controls.edit.pasteFilter = sanitiseText
- controls.save = new("ButtonControl", nil, {-45, 470, 80, 20}, self.displayItem and "Save" or "Create", function()
+ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 470, 80, 20}, self.displayItem and "Save" or "Create", function()
local id = self.displayItem and self.displayItem.id
self:CreateDisplayItemFromRaw(buildRaw(), not self.displayItem)
self.displayItem.id = id
@@ -2533,12 +2533,12 @@ function ItemsTabClass:EditDisplayItemText(alsoAddItem)
main:ClosePopup()
end, nil, true)
controls.save.enabled = function()
- local item = new("Item", buildRaw())
+ local item = new("Item"):Item(buildRaw())
return item.base ~= nil
end
controls.save.tooltipFunc = function(tooltip)
tooltip:Clear()
- local item = new("Item", buildRaw())
+ local item = new("Item"):Item(buildRaw())
if item.base then
self:AddItemTooltip(tooltip, item, nil, true)
else
@@ -2551,7 +2551,7 @@ function ItemsTabClass:EditDisplayItemText(alsoAddItem)
tooltip:AddLine(14, "Scholar's Platinum Kris of Joy")
end
end
- controls.cancel = new("ButtonControl", nil, {45, 470, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 470, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(500, 500, self.displayItem and "Edit Item Text" or "Create Custom Item from Text", controls, nil, "edit")
@@ -2583,7 +2583,7 @@ end
---@return table @The new item
function ItemsTabClass:anointItem(node)
self.anointEnchantSlot = self.anointEnchantSlot or 1
- local item = new("Item", self.displayItem:BuildRaw())
+ local item = new("Item"):Item(self.displayItem:BuildRaw())
item.id = self.displayItem.id
if #item.enchantModLines >= self.anointEnchantSlot then
t_remove(item.enchantModLines, self.anointEnchantSlot)
@@ -2676,7 +2676,7 @@ function ItemsTabClass:AnointDisplayItem(enchantSlot)
local width = saveLabelWidth()
return -(width + 90) / 2
end
- controls.save = new("ButtonControl", {"BOTTOMLEFT", nil, "BOTTOM" }, {saveLabelX, -4, saveLabelWidth, 20}, saveLabel, function()
+ controls.save = new("ButtonControl"):ButtonControl({"BOTTOMLEFT", nil, "BOTTOM" }, {saveLabelX, -4, saveLabelWidth, 20}, saveLabel, function()
self:SetDisplayItem(self:anointItem(controls.notableDB.selValue))
main:ClosePopup()
end)
@@ -2684,7 +2684,7 @@ function ItemsTabClass:AnointDisplayItem(enchantSlot)
tooltip:Clear()
self:AppendAnointTooltip(tooltip, controls.notableDB.selValue)
end
- controls.close = new("ButtonControl", {"TOPLEFT", controls.save, "TOPRIGHT" }, {10, 0, 80, 20}, "Cancel", function()
+ controls.close = new("ButtonControl"):ButtonControl({"TOPLEFT", controls.save, "TOPRIGHT" }, {10, 0, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(380, 448, "Anoint Item", controls)
@@ -3201,7 +3201,7 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
t_insert(sourceList, { label = "Custom", sourceId = "CUSTOM" })
buildMods(sourceList[1].sourceId)
local function addModifier()
- local item = new("Item", self.displayItem:BuildRaw())
+ local item = new("Item"):Item(self.displayItem:BuildRaw())
item.id = self.displayItem.id
local sourceId = sourceList[controls.source.selIndex].sourceId
if sourceId == "CUSTOM" then
@@ -3222,8 +3222,8 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
item:BuildAndParseRaw()
return item
end
- controls.sourceLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 20, 0, 16}, "^7Source:")
- controls.source = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 20, 150, 18}, sourceList, function(index, value)
+ controls.sourceLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 20, 0, 16}, "^7Source:")
+ controls.source = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 20, 150, 18}, sourceList, function(index, value)
buildMods(value.sourceId)
controls.modSelect:SetSel(1)
if controls.sort then
@@ -3231,18 +3231,18 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
end
end)
controls.source.enabled = #sourceList > 1
- controls.sortLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {350, 20, 0, 16}, "^7Sort by:")
+ controls.sortLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {350, 20, 0, 16}, "^7Sort by:")
controls.sortLabel.shown = function()
return sourceList[controls.source.selIndex].sourceId ~= "CUSTOM"
end
- controls.sort = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {355, 20, 240, 18}, sortList, function(index, value)
+ controls.sort = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {355, 20, 240, 18}, sortList, function(index, value)
applySort(value.stat, true)
end)
controls.sort.shown = function()
return sourceList[controls.source.selIndex].sourceId ~= "CUSTOM"
end
- controls.modSelectLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 45, 0, 16}, "^7Modifier:")
- controls.modSelect = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 600, 18}, modList)
+ controls.modSelectLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 45, 0, 16}, "^7Modifier:")
+ controls.modSelect = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 600, 18}, modList)
controls.modSelect.shown = function()
return sourceList[controls.source.selIndex].sourceId ~= "CUSTOM"
end
@@ -3255,11 +3255,11 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
self:AddModComparisonTooltip(tooltip, value.mod)
end
end
- controls.custom = new("EditControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 440, 18})
+ controls.custom = new("EditControl"):EditControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 440, 18})
controls.custom.shown = function()
return sourceList[controls.source.selIndex].sourceId == "CUSTOM"
end
- controls.save = new("ButtonControl", nil, {-45, 75, 80, 20}, "Add", function()
+ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 75, 80, 20}, "Add", function()
self:SetDisplayItem(addModifier())
main:ClosePopup()
end)
@@ -3267,7 +3267,7 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
tooltip:Clear()
self:AddItemTooltip(tooltip, addModifier())
end
- controls.close = new("ButtonControl", nil, {45, 75, 80, 20}, "Cancel", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, {45, 75, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(710, 105, "Add Modifier to Item", controls, "save", sourceList[controls.source.selIndex].sourceId == "CUSTOM" and "custom")
diff --git a/src/Classes/ItemsTab.lua.rej b/src/Classes/ItemsTab.lua.rej
new file mode 100644
index 0000000000..1b4f7c3371
--- /dev/null
+++ b/src/Classes/ItemsTab.lua.rej
@@ -0,0 +1,948 @@
+diff a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua (rejected hunks)
+@@ -78,14 +78,18 @@ local function buildModSortList()
+ return sortList, sortStats
+ end
+
+-local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Control", function(self, build)
+- self.UndoHandler()
+- self.ControlHost()
+- self.Control()
++---@class ItemsTab: UndoHandler, ControlHost, Control
++local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Control")
++
++---@param build Build
++function ItemsTabClass:ItemsTab(build)
++ self:UndoHandler()
++ self:ControlHost()
++ self:Control()
+
+ self.build = build
+
+- self.socketViewer = new("PassiveTreeView")
++ self.socketViewer = new("PassiveTreeView"):PassiveTreeView()
+
+ self.items = { }
+ self.itemOrderList = { }
+@@ -129,7 +133,7 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
+ self.slots = { }
+ self.orderedSlots = { }
+ self.slotOrder = { }
+- self.slotAnchor = new("Control", {"TOPLEFT",self,"TOPLEFT"}, {96, 76, 310, 0})
++ self.slotAnchor = new("Control"):Control({"TOPLEFT",self,"TOPLEFT"}, {96, 76, 310, 0})
+ local prevSlot = self.slotAnchor
+ local function addSlot(slot)
+ prevSlot = slot
+@@ -139,7 +143,7 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
+ t_insert(self.controls, slot)
+ end
+ for index, slotName in ipairs(baseSlots) do
+- local slot = new("ItemSlotControl", {"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName)
++ local slot = new("ItemSlotControl"):ItemSlotControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName)
+ addSlot(slot)
+ if slotName:match("Weapon") then
+ -- Add alternate weapon slot
+@@ -147,14 +151,14 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
+ slot.shown = function()
+ return not self.activeItemSet.useSecondWeaponSet
+ end
+- local swapSlot = new("ItemSlotControl", {"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Swap", slotName)
++ local swapSlot = new("ItemSlotControl"):ItemSlotControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Swap", slotName)
+ addSlot(swapSlot)
+ swapSlot.weaponSet = 2
+ swapSlot.shown = function()
+ return self.activeItemSet.useSecondWeaponSet
+ end
+ for i = 1, 6 do
+- local abyssal = new("ItemSlotControl", {"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Swap Abyssal Socket "..i, "Abyssal #"..i)
++ local abyssal = new("ItemSlotControl"):ItemSlotControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Swap Abyssal Socket "..i, "Abyssal #"..i)
+ addSlot(abyssal)
+ abyssal.parentSlot = swapSlot
+ abyssal.weaponSet = 2
+@@ -175,7 +179,7 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
+ if slotName == "Weapon 1" or slotName == "Weapon 2" or slotName == "Helmet" or slotName == "Gloves" or slotName == "Body Armour" or slotName == "Boots" or slotName == "Belt" then
+ -- Add Abyssal Socket slots
+ for i = 1, 6 do
+- local abyssal = new("ItemSlotControl", {"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Abyssal Socket "..i, "Abyssal #"..i)
++ local abyssal = new("ItemSlotControl"):ItemSlotControl({"TOPLEFT",prevSlot,"BOTTOMLEFT"}, 0, 2, self, slotName.." Abyssal Socket "..i, "Abyssal #"..i)
+ addSlot(abyssal)
+ abyssal.parentSlot = slot
+ if slotName:match("Weapon") then
+@@ -261,24 +265,24 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
+ self.controls.weaponSwap2.locked = function()
+ return self.activeItemSet.useSecondWeaponSet
+ end
+- self.controls.weaponSwapLabel = new("LabelControl", {"RIGHT",self.controls.weaponSwap1,"LEFT"}, {-4, 0, 0, 14}, "^7Weapon Set:")
++ self.controls.weaponSwapLabel = new("LabelControl"):LabelControl({"RIGHT",self.controls.weaponSwap1,"LEFT"}, {-4, 0, 0, 14}, "^7Weapon Set:")
+
+ -- All items list
+ if main.portraitMode then
+- self.controls.itemList = new("ItemListControl", {"TOPRIGHT",self.lastSlot,"BOTTOMRIGHT"}, {0, 0, 360, 308}, self, true)
++ self.controls.itemList = new("ItemListControl"):ItemListControl({"TOPRIGHT",self.lastSlot,"BOTTOMRIGHT"}, {0, 0, 360, 308}, self, true)
+ else
+- self.controls.itemList = new("ItemListControl", {"TOPLEFT",self.controls.setManage,"TOPRIGHT"}, {20, 20, 360, 308}, self, true)
++ self.controls.itemList = new("ItemListControl"):ItemListControl({"TOPLEFT",self.controls.setManage,"TOPRIGHT"}, {20, 20, 360, 308}, self, true)
+ end
+
+ -- Database selector
+- self.controls.selectDBLabel = new("LabelControl", {"TOPLEFT",self.controls.itemList,"BOTTOMLEFT"}, {0, 14, 0, 16}, "^7Import from:")
++ self.controls.selectDBLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.itemList,"BOTTOMLEFT"}, {0, 14, 0, 16}, "^7Import from:")
+ self.controls.selectDBLabel.shown = function()
+ return self.height < 980
+ end
+- self.controls.selectDB = new("DropDownControl", {"LEFT",self.controls.selectDBLabel,"RIGHT"}, {4, 0, 150, 18}, { "Uniques", "Rare Templates" })
++ self.controls.selectDB = new("DropDownControl"):DropDownControl({"LEFT",self.controls.selectDBLabel,"RIGHT"}, {4, 0, 150, 18}, { "Uniques", "Rare Templates" })
+
+ -- Unique database
+- self.controls.uniqueDB = new("ItemDBControl", {"TOPLEFT",self.controls.itemList,"BOTTOMLEFT"}, {0, 76, 360, function(c) return m_min(244, self.maxY - select(2, c:GetPos())) end}, self, main.uniqueDB, "UNIQUE")
++ self.controls.uniqueDB = new("ItemDBControl"):ItemDBControl({"TOPLEFT",self.controls.itemList,"BOTTOMLEFT"}, {0, 76, 360, function(c) return m_min(244, self.maxY - select(2, c:GetPos())) end}, self, main.uniqueDB, "UNIQUE")
+ self.controls.uniqueDB.y = function()
+ return self.controls.selectDBLabel:IsShown() and 118 or 96
+ end
+@@ -287,7 +291,7 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
+ end
+
+ -- Rare template database
+- self.controls.rareDB = new("ItemDBControl", {"TOPLEFT",self.controls.itemList,"BOTTOMLEFT"}, {0, 76, 360, function(c) return m_min(260, self.maxY - select(2, c:GetPos())) end}, self, main.rareDB, "RARE")
++ self.controls.rareDB = new("ItemDBControl"):ItemDBControl({"TOPLEFT",self.controls.itemList,"BOTTOMLEFT"}, {0, 76, 360, function(c) return m_min(260, self.maxY - select(2, c:GetPos())) end}, self, main.rareDB, "RARE")
+ self.controls.rareDB.y = function()
+ return self.controls.selectDBLabel:IsShown() and 78 or 396
+ end
+@@ -295,16 +299,16 @@ local ItemsTabClass = newClass("ItemsTab", "UndoHandler", "ControlHost", "Contro
+ return not self.controls.selectDBLabel:IsShown() or self.controls.selectDB.selIndex == 2
+ end
+ -- Create/import item
+- self.controls.craftDisplayItem = new("ButtonControl", {"TOPLEFT",main.portraitMode and self.controls.setManage or self.controls.itemList,"TOPRIGHT"}, {20, main.portraitMode and 0 or -20, 120, 20}, "Craft item...", function()
++ self.controls.craftDisplayItem = new("ButtonControl"):ButtonControl({"TOPLEFT",main.portraitMode and self.controls.setManage or self.controls.itemList,"TOPRIGHT"}, {20, main.portraitMode and 0 or -20, 120, 20}, "Craft item...", function()
+ self:CraftItem()
+ end)
+ self.controls.craftDisplayItem.shown = function()
+ return self.displayItem == nil
+ end
+- self.controls.newDisplayItem = new("ButtonControl", {"TOPLEFT",self.controls.craftDisplayItem,"TOPRIGHT"}, {8, 0, 120, 20}, "Create custom...", function()
++ self.controls.newDisplayItem = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.craftDisplayItem,"TOPRIGHT"}, {8, 0, 120, 20}, "Create custom...", function()
+ self:EditDisplayItemText()
+ end)
+- self.controls.displayItemTip = new("LabelControl", {"TOPLEFT",self.controls.craftDisplayItem,"BOTTOMLEFT"}, {0, 8, 100, 16},
++ self.controls.displayItemTip = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.craftDisplayItem,"BOTTOMLEFT"}, {0, 8, 100, 16},
+ [[^7Double-click an item from one of the lists,
+ or copy and paste an item from in game
+ (hover over the item and Ctrl+C) to view or edit
+@@ -350,7 +353,7 @@ holding Shift will put it in the second.]])
+ end
+ -- Section: Variant(s)
+
+- self.controls.displayItemSectionVariant = new("Control", {"TOPLEFT",self.controls.addDisplayItem,"BOTTOMLEFT"}, {0, 8, 0, function()
++ self.controls.displayItemSectionVariant = new("Control"):Control({"TOPLEFT",self.controls.addDisplayItem,"BOTTOMLEFT"}, {0, 8, 0, function()
+ if not self.displayItem then
+ return 0
+ end
+@@ -375,7 +378,7 @@ holding Shift will put it in the second.]])
+ (self.displayItem.hasAltVariant4 and 24 or 0) +
+ (self.displayItem.hasAltVariant5 and 24 or 0))
+ end})
+- self.controls.displayItemVersion = new("DropDownControl", {"TOPLEFT", self.controls.displayItemSectionVariant,"TOPLEFT"}, {0, 0, 300, 20}, nil, function(index, value)
++ self.controls.displayItemVersion = new("DropDownControl"):DropDownControl({"TOPLEFT", self.controls.displayItemSectionVariant,"TOPLEFT"}, {0, 0, 300, 20}, nil, function(index, value)
+ self.displayItem.selectedVersion = index
+ self.displayItem:NormaliseVariantSelections()
+ self.displayItem:BuildAndParseRaw()
+@@ -388,7 +391,7 @@ holding Shift will put it in the second.]])
+ return self.displayItem and self.displayItem.usesVariantGroups
+ and self.displayItem.versionList and #self.displayItem.versionList > 1
+ end
+- self.controls.displayItemVariant = new("DropDownControl", {"TOPLEFT", self.controls.displayItemSectionVariant,"TOPLEFT"}, {0, 0, 300, 20}, nil, function(index, value)
++ self.controls.displayItemVariant = new("DropDownControl"):DropDownControl({"TOPLEFT", self.controls.displayItemSectionVariant,"TOPLEFT"}, {0, 0, 300, 20}, nil, function(index, value)
+ self:SelectDisplayItemVariant(index, value, "variant", self.controls.displayItemVariant)
+ end)
+ self.controls.displayItemVariant.y = function()
+@@ -398,35 +401,35 @@ holding Shift will put it in the second.]])
+ self.controls.displayItemVariant.shown = function()
+ return self.displayItem.variantList and #self.displayItem.variantList > 1
+ end
+- self.controls.displayItemAltVariant = new("DropDownControl", {"TOPLEFT",self.controls.displayItemVariant,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
++ self.controls.displayItemAltVariant = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemVariant,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
+ self:SelectDisplayItemVariant(index, value, "variantAlt", self.controls.displayItemAltVariant)
+ end)
+ self.controls.displayItemAltVariant.maxDroppedWidth = 1000
+ self.controls.displayItemAltVariant.shown = function()
+ return self.displayItem.hasAltVariant
+ end
+- self.controls.displayItemAltVariant2 = new("DropDownControl", {"TOPLEFT",self.controls.displayItemAltVariant,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
++ self.controls.displayItemAltVariant2 = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemAltVariant,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
+ self:SelectDisplayItemVariant(index, value, "variantAlt2", self.controls.displayItemAltVariant2)
+ end)
+ self.controls.displayItemAltVariant2.maxDroppedWidth = 1000
+ self.controls.displayItemAltVariant2.shown = function()
+ return self.displayItem.hasAltVariant2
+ end
+- self.controls.displayItemAltVariant3 = new("DropDownControl", {"TOPLEFT",self.controls.displayItemAltVariant2,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
++ self.controls.displayItemAltVariant3 = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemAltVariant2,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
+ self:SelectDisplayItemVariant(index, value, "variantAlt3", self.controls.displayItemAltVariant3)
+ end)
+ self.controls.displayItemAltVariant3.maxDroppedWidth = 1000
+ self.controls.displayItemAltVariant3.shown = function()
+ return self.displayItem.hasAltVariant3
+ end
+- self.controls.displayItemAltVariant4 = new("DropDownControl", {"TOPLEFT",self.controls.displayItemAltVariant3,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
++ self.controls.displayItemAltVariant4 = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemAltVariant3,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
+ self:SelectDisplayItemVariant(index, value, "variantAlt4", self.controls.displayItemAltVariant4)
+ end)
+ self.controls.displayItemAltVariant4.maxDroppedWidth = 1000
+ self.controls.displayItemAltVariant4.shown = function()
+ return self.displayItem.hasAltVariant4
+ end
+- self.controls.displayItemAltVariant5 = new("DropDownControl", {"TOPLEFT",self.controls.displayItemAltVariant4,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
++ self.controls.displayItemAltVariant5 = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemAltVariant4,"BOTTOMLEFT"}, {0, 4, 300, 20}, nil, function(index, value)
+ self:SelectDisplayItemVariant(index, value, "variantAlt5", self.controls.displayItemAltVariant5)
+ end)
+ self.controls.displayItemAltVariant5.maxDroppedWidth = 1000
+@@ -452,11 +455,11 @@ holding Shift will put it in the second.]])
+ end
+
+ -- Section: Sockets and Links
+- self.controls.displayItemSectionSockets = new("Control", {"TOPLEFT",self.controls.displayItemSectionVariant,"BOTTOMLEFT"}, {0, 0, 0, function()
++ self.controls.displayItemSectionSockets = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionVariant,"BOTTOMLEFT"}, {0, 0, 0, function()
+ return self.displayItem and self.displayItem.selectableSocketCount > 0 and 28 or 0
+ end})
+ for i = 1, 6 do
+- local drop = new("DropDownControl", {"TOPLEFT",self.controls.displayItemSectionSockets,"TOPLEFT"}, {(i-1) * 64, 0, 36, 20}, socketDropList, function(index, value)
++ local drop = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemSectionSockets,"TOPLEFT"}, {(i-1) * 64, 0, 36, 20}, socketDropList, function(index, value)
+ self.displayItem.sockets[i].color = value.color
+ self.displayItem:BuildAndParseRaw()
+ self:UpdateDisplayItemTooltip()
+@@ -466,7 +469,7 @@ holding Shift will put it in the second.]])
+ end
+ self.controls["displayItemSocket"..i] = drop
+ if i < 6 then
+- local link = new("CheckBoxControl", {"LEFT",drop,"RIGHT"}, {4, 0, 20}, nil, function(state)
++ local link = new("CheckBoxControl"):CheckBoxControl({"LEFT",drop,"RIGHT"}, {4, 0, 20}, nil, function(state)
+ if state and self.displayItem.sockets[i].group ~= self.displayItem.sockets[i+1].group then
+ for s = i + 1, #self.displayItem.sockets do
+ self.displayItem.sockets[s].group = self.displayItem.sockets[s].group - 1
+@@ -485,7 +488,7 @@ holding Shift will put it in the second.]])
+ self.controls["displayItemLink"..i] = link
+ end
+ end
+- self.controls.displayItemAddSocket = new("ButtonControl", {"TOPLEFT",self.controls.displayItemSectionSockets,"TOPLEFT"}, {function() return (#self.displayItem.sockets - self.displayItem.abyssalSocketCount) * 64 - 12 end, 0, 20, 20}, "+", function()
++ self.controls.displayItemAddSocket = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemSectionSockets,"TOPLEFT"}, {function() return (#self.displayItem.sockets - self.displayItem.abyssalSocketCount) * 64 - 12 end, 0, 20, 20}, "+", function()
+ local insertIndex = #self.displayItem.sockets - self.displayItem.abyssalSocketCount + 1
+ t_insert(self.displayItem.sockets, insertIndex, {
+ color = self.displayItem.defaultSocketColor,
+@@ -503,28 +506,28 @@ holding Shift will put it in the second.]])
+ end
+
+ -- Section: Enchant / Anoint / Corrupt
+- self.controls.displayItemSectionEnchant = new("Control", {"TOPLEFT",self.controls.displayItemSectionSockets,"BOTTOMLEFT"}, {0, 0, 0, function()
++ self.controls.displayItemSectionEnchant = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionSockets,"BOTTOMLEFT"}, {0, 0, 0, function()
+ return (self.controls.displayItemEnchant:IsShown() or self.controls.displayItemEnchant2:IsShown() or self.controls.displayItemAnoint:IsShown() or self.controls.displayItemAnoint2:IsShown() or self.controls.displayItemCorrupt:IsShown() ) and 28 or 0
+ end})
+- self.controls.displayItemEnchant = new("ButtonControl", { "TOPLEFT", self.controls.displayItemSectionEnchant, "TOPLEFT" }, { 0, 0, 160, 20 }, "Change Enchantment...", function()
++ self.controls.displayItemEnchant = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.displayItemSectionEnchant, "TOPLEFT" }, { 0, 0, 160, 20 }, "Change Enchantment...", function()
+ self:EnchantDisplayItem(1)
+ end)
+ self.controls.displayItemEnchant.shown = function()
+ return self.displayItem and self.displayItem.enchantments
+ end
+- self.controls.displayItemEnchant2 = new("ButtonControl", { "TOPLEFT", self.controls.displayItemEnchant, "TOPRIGHT", true }, { 8, 0, 160, 20 }, "Change Enchantment 2...", function()
++ self.controls.displayItemEnchant2 = new("ButtonControl"):ButtonControl({ "TOPLEFT", self.controls.displayItemEnchant, "TOPRIGHT", true }, { 8, 0, 160, 20 }, "Change Enchantment 2...", function()
+ self:EnchantDisplayItem(2)
+ end)
+ self.controls.displayItemEnchant2.shown = function()
+ return self.displayItem and self.displayItem.enchantments and self.displayItem.canHaveTwoEnchants and #self.displayItem.enchantModLines > 0
+ end
+- self.controls.displayItemAnoint = new("ButtonControl", {"TOPLEFT",self.controls.displayItemEnchant2,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint...", function()
++ self.controls.displayItemAnoint = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemEnchant2,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint...", function()
+ self:AnointDisplayItem(1)
+ end)
+ self.controls.displayItemAnoint.shown = function()
+ return self.displayItem and isAnointable(self.displayItem)
+ end
+- self.controls.displayItemAnoint2 = new("ButtonControl", {"TOPLEFT",self.controls.displayItemAnoint,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint 2...", function()
++ self.controls.displayItemAnoint2 = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemAnoint,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint 2...", function()
+ self:AnointDisplayItem(2)
+ end)
+ self.controls.displayItemAnoint2.shown = function()
+@@ -533,7 +536,7 @@ holding Shift will put it in the second.]])
+ self.displayItem.canHaveTwoEnchants and
+ #self.displayItem.enchantModLines > 0
+ end
+- self.controls.displayItemAnoint3 = new("ButtonControl", {"TOPLEFT",self.controls.displayItemAnoint2,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint 3...", function()
++ self.controls.displayItemAnoint3 = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemAnoint2,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint 3...", function()
+ self:AnointDisplayItem(3)
+ end)
+ self.controls.displayItemAnoint3.shown = function()
+@@ -542,7 +545,7 @@ holding Shift will put it in the second.]])
+ self.displayItem.canHaveThreeEnchants and
+ #self.displayItem.enchantModLines > 1
+ end
+- self.controls.displayItemAnoint4 = new("ButtonControl", {"TOPLEFT",self.controls.displayItemAnoint3,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint 4...", function()
++ self.controls.displayItemAnoint4 = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemAnoint3,"TOPRIGHT",true}, {8, 0, 100, 20}, "Anoint 4...", function()
+ self:AnointDisplayItem(4)
+ end)
+ self.controls.displayItemAnoint4.shown = function()
+@@ -551,21 +554,21 @@ holding Shift will put it in the second.]])
+ self.displayItem.canHaveFourEnchants and
+ #self.displayItem.enchantModLines > 2
+ end
+- self.controls.displayItemCorrupt = new("ButtonControl", {"TOPLEFT",self.controls.displayItemAnoint4,"TOPRIGHT",true}, {8, 10, 100, 20}, "Corrupt...", function()
++ self.controls.displayItemCorrupt = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemAnoint4,"TOPRIGHT",true}, {8, 10, 100, 20}, "Corrupt...", function()
+ self:CorruptDisplayItem("Corrupted")
+ end)
+ self.controls.displayItemCorrupt.shown = function()
+ return self.displayItem and self.displayItem.corruptible
+ end
+ --[[
+- self.controls.displayItemScourge = new("ButtonControl", {"TOPLEFT",self.controls.displayItemCorrupt,"TOPRIGHT",true}, {8, 0, 100, 20}, "Scourge...", function()
++ self.controls.displayItemScourge = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemCorrupt,"TOPRIGHT",true}, {8, 0, 100, 20}, "Scourge...", function()
+ self:CorruptDisplayItem("Scourge")
+ end)
+ self.controls.displayItemScourge.shown = function()
+ return self.displayItem and self.displayItem.corruptible
+ end
+ --]]
+- self.controls.displayItemAddImplicit = new("ButtonControl", {"TOPLEFT",self.controls.displayItemCorrupt,"TOPRIGHT",true}, {8, 0, 120, 20}, "Add Implicit...", function()
++ self.controls.displayItemAddImplicit = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemCorrupt,"TOPRIGHT",true}, {8, 0, 120, 20}, "Add Implicit...", function()
+ self:AddImplicitToDisplayItem()
+ end)
+ self.controls.displayItemAddImplicit.shown = function()
+@@ -604,11 +607,11 @@ holding Shift will put it in the second.]])
+ self.displayItem:BuildAndParseRaw()
+ self:UpdateDisplayItemTooltip()
+ end
+- self.controls.displayItemSectionInfluence = new("Control", {"TOPLEFT",self.controls.displayItemSectionEnchant,"BOTTOMLEFT"}, {0, 0, 0, function()
++ self.controls.displayItemSectionInfluence = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionEnchant,"BOTTOMLEFT"}, {0, 0, 0, function()
+ return self.displayItem and self.displayItem.canBeInfluenced and 28 or 0
+ end})
+ local influenceTipText = table.concat(main:WrapString("Selecting an influence here will also allow the modifier dropdowns to contain influenced mods.", 16, 140), "\n")
+- self.controls.displayItemInfluence = new("DropDownControl", {"TOPLEFT",self.controls.displayItemSectionInfluence,"TOPRIGHT"}, {0, 0, 100, 20}, influenceDisplayList, function(index, value)
++ self.controls.displayItemInfluence = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemSectionInfluence,"TOPRIGHT"}, {0, 0, 100, 20}, influenceDisplayList, function(index, value)
+ local otherIndex = self.controls.displayItemInfluence2.selIndex
+ setDisplayItemInfluence({ index - 1, otherIndex - 1 })
+ end)
+@@ -616,7 +619,7 @@ holding Shift will put it in the second.]])
+ self.controls.displayItemInfluence.shown = function()
+ return self.displayItem and self.displayItem.canBeInfluenced
+ end
+- self.controls.displayItemInfluence2 = new("DropDownControl", {"TOPLEFT",self.controls.displayItemInfluence,"TOPRIGHT",true}, {8, 0, 100, 20}, influenceDisplayList, function(index, value)
++ self.controls.displayItemInfluence2 = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemInfluence,"TOPRIGHT",true}, {8, 0, 100, 20}, influenceDisplayList, function(index, value)
+ local otherIndex = self.controls.displayItemInfluence.selIndex
+ setDisplayItemInfluence({ index - 1, otherIndex - 1 })
+ end)
+@@ -626,15 +629,15 @@ holding Shift will put it in the second.]])
+ self.controls.displayItemInfluence2.tooltipText = influenceTipText
+
+ -- Section: Item Quality
+- self.controls.displayItemSectionQuality = new("Control", {"TOPLEFT",self.controls.displayItemSectionInfluence,"BOTTOMLEFT"}, {0, 0, 0, function()
++ self.controls.displayItemSectionQuality = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionInfluence,"BOTTOMLEFT"}, {0, 0, 0, function()
+ return (self.controls.displayItemQuality:IsShown() and self.controls.displayItemQualityEdit:IsShown()) and 28 or 0
+ end})
+- self.controls.displayItemQuality = new("LabelControl", { "TOPLEFT", self.controls.displayItemSectionQuality, "TOPRIGHT" }, { 0, 0, 0, 16 }, "^7Quality:")
++ self.controls.displayItemQuality = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.displayItemSectionQuality, "TOPRIGHT" }, { 0, 0, 0, 16 }, "^7Quality:")
+ self.controls.displayItemQuality.shown = function()
+ return self.displayItem and self.displayItem.quality and (self.displayItem.base.type ~= "Amulet" or self.displayItem.base.type ~= "Belt" or self.displayItem.base.type ~= "Jewel" or self.displayItem.base.type ~= "Quiver" or self.displayItem.base.type ~= "Ring" or self.displayItem.type ~= "Graft")
+ end
+
+- self.controls.displayItemQualityEdit = new("EditControl", {"LEFT",self.controls.displayItemQuality,"RIGHT"}, {2, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
++ self.controls.displayItemQualityEdit = new("EditControl"):EditControl({"LEFT",self.controls.displayItemQuality,"RIGHT"}, {2, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
+ self.displayItem.quality = tonumber(buf)
+ self.displayItem:BuildAndParseRaw()
+ self:UpdateDisplayItemTooltip()
+@@ -652,10 +655,10 @@ holding Shift will put it in the second.]])
+ end
+ end
+ -- Section: Catalysts
+- self.controls.displayItemSectionCatalyst = new("Control", {"TOPLEFT",self.controls.displayItemSectionQuality,"BOTTOMLEFT"}, {0, 0, 0, function()
++ self.controls.displayItemSectionCatalyst = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionQuality,"BOTTOMLEFT"}, {0, 0, 0, function()
+ return (self.controls.displayItemCatalyst:IsShown() or self.controls.displayItemCatalystQualityEdit:IsShown()) and 28 or 0
+ end})
+- self.controls.displayItemCatalyst = new("DropDownControl", {"TOPLEFT",self.controls.displayItemSectionCatalyst,"TOPRIGHT"}, {0, 0, 250, 20},
++ self.controls.displayItemCatalyst = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemSectionCatalyst,"TOPRIGHT"}, {0, 0, 250, 20},
+ {"Catalyst","Abrasive (Attack)","Accelerating (Speed)","Dextral (Suffix)","Fertile (Life & Mana)","Imbued (Caster)","Intrinsic (Attribute)","Noxious (Physical & Chaos Damage)",
+ "Prismatic (Resistance)","Sinistral (Prefix)","Tempering (Defense)","Turbulent (Elemental)","Unstable (Critical)"},
+ function(index, value)
+@@ -677,7 +680,7 @@ holding Shift will put it in the second.]])
+ self.controls.displayItemCatalyst.shown = function()
+ return self.displayItem and (self.displayItem.crafted or self.displayItem.hasModTags) and (self.displayItem.base.type == "Amulet" or self.displayItem.base.type == "Ring" or self.displayItem.base.type == "Belt")
+ end
+- self.controls.displayItemCatalystQualityEdit = new("EditControl", {"LEFT",self.controls.displayItemCatalyst,"RIGHT"}, {2, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
++ self.controls.displayItemCatalystQualityEdit = new("EditControl"):EditControl({"LEFT",self.controls.displayItemCatalyst,"RIGHT"}, {2, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
+ self.displayItem.catalystQuality = tonumber(buf)
+ if self.displayItem.crafted then
+ for i = 1, self.displayItem.affixLimit do
+@@ -706,27 +709,27 @@ holding Shift will put it in the second.]])
+ end
+ }
+
+- self.controls.displayItemClusterJewelNodeCountLabel = new("LabelControl", {"TOPLEFT",self.controls.displayItemClusterJewelSkill,"BOTTOMLEFT"}, {0, 7, 0, 14}, "^7Added Passives:")
+- self.controls.displayItemClusterJewelNodeCount = new("SliderControl", {"LEFT",self.controls.displayItemClusterJewelNodeCountLabel,"RIGHT"}, {2, 0, 150, 20}, function(val)
++ self.controls.displayItemClusterJewelNodeCountLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.displayItemClusterJewelSkill,"BOTTOMLEFT"}, {0, 7, 0, 14}, "^7Added Passives:")
++ self.controls.displayItemClusterJewelNodeCount = new("SliderControl"):SliderControl({"LEFT",self.controls.displayItemClusterJewelNodeCountLabel,"RIGHT"}, {2, 0, 150, 20}, function(val)
+ local divVal = self.controls.displayItemClusterJewelNodeCount:GetDivVal()
+ local clusterJewel = self.displayItem.clusterJewel
+ self.displayItem.clusterJewelNodeCount = round(val * (clusterJewel.maxNodes - clusterJewel.minNodes) + clusterJewel.minNodes)
+ self:CraftClusterJewel()
+ end)
+
+- self.controls.craftingSortingLabel = new("LabelControl", { "TOPLEFT", self.controls.displayItemSectionClusterJewel, "BOTTOMLEFT" }, { 0, 0, 0, 16 }, "^7Modifier sorting:")
++ self.controls.craftingSortingLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.displayItemSectionClusterJewel, "BOTTOMLEFT" }, { 0, 0, 0, 16 }, "^7Modifier sorting:")
+ self.controls.craftingSortingLabel.shown = function()
+ return self.displayItem and self.displayItem.crafted and
+ -- cluster jewels don't have good comparison support and sorting would be misleading
+ not (self.displayItem.base.type == "Jewel" and self.displayItem.base.subType == "Cluster")
+ end
+- self.controls.craftingSorting = new("DropDownControl", { "LEFT", self.controls.craftingSortingLabel, "RIGHT" }, { 4, 0, 200, 20 }, sortingOptions, function()
++ self.controls.craftingSorting = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.craftingSortingLabel, "RIGHT" }, { 4, 0, 200, 20 }, sortingOptions, function()
+ self:UpdateAffixControls()
+ end)
+
+ -- Section: Affix Selection
+ local maxModCount = 9
+- self.controls.displayItemSectionAffix = new("Control", { "TOPLEFT", self.controls.craftingSortingLabel, "BOTTOMLEFT", true }, { 0, function()
++ self.controls.displayItemSectionAffix = new("Control"):Control({ "TOPLEFT", self.controls.craftingSortingLabel, "BOTTOMLEFT", true }, { 0, function()
+ if self.controls.craftingSortingLabel.shown() then
+ return 8
+ else
+@@ -793,7 +796,7 @@ holding Shift will put it in the second.]])
+ end
+ return range
+ end
+- drop = new("DropDownControl", {"TOPLEFT",prev,"TOPLEFT"}, {i==1 and 40 or 0, 0, 418, 20}, nil, function(index, value)
++ drop = new("DropDownControl"):DropDownControl({"TOPLEFT",prev,"TOPLEFT"}, {i==1 and 40 or 0, 0, 418, 20}, nil, function(index, value)
+ local affix = { modId = "None", fractured = self.displayItem[drop.outputTable][drop.outputIndex].fractured }
+ if value.modId then
+ affix.modId = value.modId
+@@ -968,24 +971,24 @@ holding Shift will put it in the second.]])
+ end
+ drop.slider = slider
+ self.controls["displayItemAffix"..i] = drop
+- self.controls["displayItemAffixLabel"..i] = new("LabelControl", {"RIGHT",drop,"LEFT"}, {-4, 0, 0, 14}, function()
++ self.controls["displayItemAffixLabel"..i] = new("LabelControl"):LabelControl({"RIGHT",drop,"LEFT"}, {-4, 0, 0, 14}, function()
+ local ignoreModType = self.displayItem.rareLikeUnique and self.displayItem.rareLikeUnique.ignoreModType
+ return ignoreModType and "^7Explicit:"
+ or drop.outputTable == "prefixes" and "^7Prefix:"
+ or "^7Suffix:"
+ end)
+ self.controls["displayItemAffixRange"..i] = slider
+- self.controls["displayItemAffixRangeLabel"..i] = new("LabelControl", {"RIGHT",slider,"LEFT"}, {-4, 0, 0, 14}, function()
++ self.controls["displayItemAffixRangeLabel"..i] = new("LabelControl"):LabelControl({"RIGHT",slider,"LEFT"}, {-4, 0, 0, 14}, function()
+ return drop.selIndex > 1 and "^7Roll:" or "^x7F7F7FRoll:"
+ end)
+ end
+
+ -- Section: Custom modifiers
+ -- if either Custom or Crucible mod buttons are shown, create the control for the list of mods
+- self.controls.displayItemSectionCustom = new("Control", {"TOPLEFT",self.controls.displayItemSectionAffix,"BOTTOMLEFT",true}, {0, 0, 0, function()
++ self.controls.displayItemSectionCustom = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionAffix,"BOTTOMLEFT",true}, {0, 0, 0, function()
+ return (self.controls.displayItemAddCustom:IsShown() or self.controls.displayItemAddCrucible:IsShown()) and 28 + self.displayItem.customCount * 22 or 0
+ end})
+- self.controls.displayItemAddCustom = new("ButtonControl", {"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, {0, 0, 120, 20}, "Add modifier...", function()
++ self.controls.displayItemAddCustom = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, {0, 0, 120, 20}, "Add modifier...", function()
+ self:AddCustomModifierToDisplayItem()
+ end)
+ self.controls.displayItemAddCustom.shown = function()
+@@ -994,7 +997,7 @@ holding Shift will put it in the second.]])
+
+ -- Section: Crucible modifiers
+ -- if the Add modifier button is not shown, take its place, otherwise move it to the right of it
+- self.controls.displayItemAddCrucible = new("ButtonControl", {"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, {function()
++ self.controls.displayItemAddCrucible = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.displayItemSectionCustom,"TOPLEFT"}, {function()
+ return (self.controls.displayItemAddCustom:IsShown() and 128) or 0
+ end, 0, 150, 20}, "Add Crucible mod...", function()
+ self:AddCrucibleModifierToDisplayItem()
+@@ -1005,7 +1008,7 @@ holding Shift will put it in the second.]])
+
+ -- Section: Modifier Range
+ local labelFontSize = 14
+- self.controls.displayItemSectionRange = new("Control", { "TOPLEFT", self.controls.displayItemSectionCustom, "BOTTOMLEFT" }, { 0, 0, 0, function()
++ self.controls.displayItemSectionRange = new("Control"):Control({ "TOPLEFT", self.controls.displayItemSectionCustom, "BOTTOMLEFT" }, { 0, 0, 0, function()
+ if not self.displayItem or not self.displayItem.rangeLineList[1] then
+ return 0
+ end
+@@ -1022,7 +1025,7 @@ holding Shift will put it in the second.]])
+ end})
+ local foulbornIcon = NewImageHandle()
+ foulbornIcon:Load("Assets/breachicon.png")
+- self.controls.displayItemRangeLine = new("DropDownControl", {"TOPLEFT",self.controls.displayItemSectionRange,"TOPLEFT"}, {0, 0, 350, 18}, nil, function(index, value)
++ self.controls.displayItemRangeLine = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.displayItemSectionRange,"TOPLEFT"}, {0, 0, 350, 18}, nil, function(index, value)
+ self.controls.displayItemRangeSlider.val = self.displayItem.rangeLineList[index].range
+ end)
+ self.controls.displayItemRangeLine.shown = function()
+@@ -1031,7 +1034,7 @@ holding Shift will put it in the second.]])
+ local function getSelectedModLine()
+ return self.displayItem and self.displayItem.rangeLineList[self.controls.displayItemRangeLine.selIndex] or nil
+ end
+- local box = new("CheckBoxControl", { "LEFT", self.controls.displayItemRangeLine, "RIGHT", true }, { 0, 0, 18 }, nil)
++ local box = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.displayItemRangeLine, "RIGHT", true }, { 0, 0, 18 }, nil)
+ box.changeFunc = function(val)
+ local line = getSelectedModLine()
+ if line and line.modId and line.newModId then
+@@ -1068,7 +1071,7 @@ holding Shift will put it in the second.]])
+ end
+ end
+ self.controls.displayItemMutatedCheckbox = box
+- local slider = new("SliderControl", { "LEFT", self.controls.displayItemMutatedCheckbox, "RIGHT", true }, { 4, 0, 100, 18 }, function(val)
++ local slider = new("SliderControl"):SliderControl({ "LEFT", self.controls.displayItemMutatedCheckbox, "RIGHT", true }, { 4, 0, 100, 18 }, function(val)
+ local line = getSelectedModLine()
+ line.range = val
+ self.displayItem:BuildAndParseRaw()
+@@ -1093,7 +1096,7 @@ holding Shift will put it in the second.]])
+
+ -- layout: [box] <- [slider] <- text
+
+- local box = new("CheckBoxControl", { "TOPLEFT", baseControl, "TOPLEFT", true }, { 0, 0, 18 }, nil, function(val)
++ local box = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", baseControl, "TOPLEFT", true }, { 0, 0, 18 }, nil, function(val)
+ local line = self.displayItem and self.displayItem.rangeLineList[i]
+ if line and line.modId and line.newModId then
+ self.displayItem:MutateMod(line.modId, line.newModId, not line.mutated)
+@@ -1134,7 +1137,7 @@ holding Shift will put it in the second.]])
+
+ self.controls["displayItemStackedMutatedCheckbox" .. i] = box
+
+- local slider = new("SliderControl", { "LEFT", box, "RIGHT", true }, { 4, 0, 100, 18 }, function(val)
++ local slider = new("SliderControl"):SliderControl({ "LEFT", box, "RIGHT", true }, { 4, 0, 100, 18 }, function(val)
+ if self.displayItem and self.displayItem.rangeLineList[i] then
+ self.displayItem.rangeLineList[i].range = val
+ self.displayItem:BuildAndParseRaw()
+@@ -1156,7 +1159,7 @@ holding Shift will put it in the second.]])
+
+ self.controls["displayItemStackedRangeSlider" .. i] = slider
+
+- self.controls["displayItemStackedRangeLine" .. i] = new("LabelControl", { "LEFT", slider, "RIGHT", true }, { 4, -2, 350, labelFontSize }, function()
++ self.controls["displayItemStackedRangeLine" .. i] = new("LabelControl"):LabelControl({ "LEFT", slider, "RIGHT", true }, { 4, -2, 350, labelFontSize }, function()
+ local modLine = self.displayItem.rangeLineList[i]
+ if self.displayItem and modLine then
+ local colour = modLine.mutated and colorCodes.MUTATED or "^7"
+@@ -1172,11 +1175,11 @@ holding Shift will put it in the second.]])
+ end
+ end
+ -- Tooltip anchor
+- self.controls.displayItemTooltipAnchor = new("Control", {"TOPLEFT",self.controls.displayItemSectionRange,"BOTTOMLEFT"})
++ self.controls.displayItemTooltipAnchor = new("Control"):Control({"TOPLEFT",self.controls.displayItemSectionRange,"BOTTOMLEFT"})
+
+ -- Scroll bars
+- self.controls.scrollBarH = new("ScrollBarControl", nil, {0, 0, 0, 18}, 100, "HORIZONTAL", true)
+- self.controls.scrollBarV = new("ScrollBarControl", nil, {0, 0, 18, 0}, 100, "VERTICAL", true)
++ self.controls.scrollBarH = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 0, 18}, 100, "HORIZONTAL", true)
++ self.controls.scrollBarV = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 18, 0}, 100, "VERTICAL", true)
+
+ -- Initialise drag target lists
+ t_insert(self.controls.itemList.dragTargetList, self.controls.sharedItemList)
+@@ -1857,7 +1861,7 @@ end
+
+ -- Attempt to create a new item from the given item raw text and sets it as the new display item
+ function ItemsTabClass:CreateDisplayItemFromRaw(itemRaw, normalise)
+- local newItem = new("Item", itemRaw)
++ local newItem = new("Item"):Item(itemRaw)
+ if newItem.base then
+ if normalise then
+ self:CopyAnointsAndEldritchImplicits(newItem, main.migrateEldritchImplicits, false)
+@@ -2221,7 +2225,7 @@ function ItemsTabClass:UpdateAffixControl(control, item, affixType, outputTable,
+ if sortOption.stat and self.controls.craftingSortingLabel.shown() then
+ local calcFunc = self.build.calcsTab:GetMiscCalculator()
+ local slotName = self.displayItem:GetPrimarySlot()
+- local testSubject = new("Item", self.displayItem:BuildRaw())
++ local testSubject = new("Item"):Item(self.displayItem:BuildRaw())
+ local controlPowerCache = powerCache
+ if selAffix and selAffix ~= "None" then
+ testSubject[outputTable][outputIndex] = { modId = "None" }
+@@ -2260,7 +2264,7 @@ function ItemsTabClass:UpdateAffixControl(control, item, affixType, outputTable,
+ calcFunc({ repSlotName = slotName, repItem = testSubject }),
+ sortOption
+ )
+- testSubject = new("Item", originalItem)
++ testSubject = new("Item"):Item(originalItem)
+ else
+ for _, line in ipairs(mod) do
+ local rangedLine = itemLib.applyRange(line, main.defaultItemAffixQuality or 0.5, 1, 1)
+@@ -2407,7 +2411,7 @@ end
+
+ function ItemsTabClass:AddModComparisonTooltip(tooltip, mod)
+ local slotName = self.displayItem:GetPrimarySlot()
+- local newItem = new("Item", self.displayItem:BuildRaw())
++ local newItem = new("Item"):Item(self.displayItem:BuildRaw())
+
+ for _, subMod in ipairs(mod) do
+ t_insert(newItem.explicitModLines, { line = checkLineForAllocates(subMod, self.build.spec.nodes), modTags = mod.modTags, [mod.type] = true })
+@@ -2563,21 +2567,21 @@ function ItemsTabClass:CraftItem()
+ item:BuildAndParseRaw()
+ return item
+ end
+- controls.rarityLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {50, 20, 0, 16}, "Rarity:")
+- controls.rarity = new("DropDownControl", nil, {-80, 20, 100, 18}, rarityDropList)
++ controls.rarityLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {50, 20, 0, 16}, "Rarity:")
++ controls.rarity = new("DropDownControl"):DropDownControl(nil, {-80, 20, 100, 18}, rarityDropList)
+ controls.rarity.selIndex = self.lastCraftRaritySel or 3
+- controls.title = new("EditControl", nil, {70, 20, 190, 18}, "", "Name")
++ controls.title = new("EditControl"):EditControl(nil, {70, 20, 190, 18}, "", "Name")
+ controls.title.shown = function()
+ return controls.rarity.selIndex >= 3
+ end
+- controls.typeLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {50, 45, 0, 16}, "Type:")
+- controls.type = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {55, 45, 295, 18}, self.build.data.itemBaseTypeList, function(index, value)
++ controls.typeLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {50, 45, 0, 16}, "Type:")
++ controls.type = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {55, 45, 295, 18}, self.build.data.itemBaseTypeList, function(index, value)
+ controls.base.list = self.build.data.itemBaseLists[self.build.data.itemBaseTypeList[index]]
+ controls.base.selIndex = 1
+ end)
+ controls.type.selIndex = self.lastCraftTypeSel or 1
+- controls.baseLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {50, 70, 0, 16}, "Base:")
+- controls.base = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {55, 70, 200, 18}, self.build.data.itemBaseLists[self.build.data.itemBaseTypeList[controls.type.selIndex]])
++ controls.baseLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {50, 70, 0, 16}, "Base:")
++ controls.base = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {55, 70, 200, 18}, self.build.data.itemBaseLists[self.build.data.itemBaseTypeList[controls.type.selIndex]])
+ controls.base.selIndex = self.lastCraftBaseSel or 1
+ controls.base.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+@@ -2727,7 +2731,7 @@ function ItemsTabClass:EnchantDisplayItem(enchantSlot)
+ buildEnchantmentSourceList()
+ buildEnchantmentList()
+ local function enchantItem(idx, remove)
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ local index = idx or controls.enchantment.selIndex
+ item.id = self.displayItem.id
+ local entry = enchantmentList[index]
+@@ -2756,7 +2760,7 @@ function ItemsTabClass:EnchantDisplayItem(enchantSlot)
+ if entry.sortValues[stat] ~= nil then
+ return entry.sortValues[stat]
+ end
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ item.id = self.displayItem.id
+ local line = entry.line
+ local first, second = line:match("([^/]+)/([^/]+)")
+@@ -2813,8 +2817,8 @@ function ItemsTabClass:EnchantDisplayItem(enchantSlot)
+ end
+ end
+ if haveSkills then
+- controls.skillLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 20, 0, 16}, "^7Skill:")
+- controls.skill = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 20, 180, 18}, skillList, function(index, value)
++ controls.skillLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 20, 0, 16}, "^7Skill:")
++ controls.skill = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 20, 180, 18}, skillList, function(index, value)
+ buildEnchantmentSourceList()
+ buildEnchantmentList()
+ controls.enchantment:SetSel(1)
+@@ -2822,7 +2826,7 @@ function ItemsTabClass:EnchantDisplayItem(enchantSlot)
+ applySort(controls.sort.list[controls.sort.selIndex].stat, true)
+ end
+ end)
+- controls.allSkills = new("CheckBoxControl", {"TOPLEFT",nil,"TOPLEFT"}, {350, 20, 18}, "All skills:", function(state)
++ controls.allSkills = new("CheckBoxControl"):CheckBoxControl({"TOPLEFT",nil,"TOPLEFT"}, {350, 20, 18}, "All skills:", function(state)
+ buildSkillList(not state)
+ controls.skill:SetSel(1)
+ buildEnchantmentList()
+@@ -2837,33 +2841,33 @@ function ItemsTabClass:EnchantDisplayItem(enchantSlot)
+ controls.allSkills.enabled = false
+ end
+ end
+- controls.enchantmentSourceLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 45, 0, 16}, "^7Source:")
+- controls.enchantmentSource = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 180, 18}, enchantmentSourceList, function(index, value)
++ controls.enchantmentSourceLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 45, 0, 16}, "^7Source:")
++ controls.enchantmentSource = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 180, 18}, enchantmentSourceList, function(index, value)
+ buildEnchantmentList()
+ controls.enchantment:SetSel(m_min(controls.enchantment.selIndex, #enchantmentList))
+ if controls.sort then
+ applySort(controls.sort.list[controls.sort.selIndex].stat, true)
+ end
+ end)
+- controls.sortLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {350, 45, 0, 16}, "^7Sort by:")
+- controls.sort = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {355, 45, 240, 18}, sortList, function(index, value)
++ controls.sortLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {350, 45, 0, 16}, "^7Sort by:")
++ controls.sort = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {355, 45, 240, 18}, sortList, function(index, value)
+ applySort(value.stat, true)
+ end)
+- controls.enchantmentLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 70, 0, 16}, "^7Enchantment:")
+- controls.enchantment = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 70, 495, 18}, enchantmentList)
++ controls.enchantmentLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 70, 0, 16}, "^7Enchantment:")
++ controls.enchantment = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 70, 495, 18}, enchantmentList)
+ controls.enchantment.tooltipFunc = function(tooltip, mode, index)
+ tooltip:Clear()
+ self:AddItemTooltip(tooltip, enchantItem(index), nil, true)
+ end
+- controls.save = new("ButtonControl", nil, {-88, 100, 80, 20}, "Enchant", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-88, 100, 80, 20}, "Enchant", function()
+ self:SetDisplayItem(enchantItem())
+ main:ClosePopup()
+ end)
+- controls.remove = new("ButtonControl", nil, {0, 100, 80, 20}, "Remove", function()
++ controls.remove = new("ButtonControl"):ButtonControl(nil, {0, 100, 80, 20}, "Remove", function()
+ self:SetDisplayItem(enchantItem(nil, true))
+ main:ClosePopup()
+ end)
+- controls.close = new("ButtonControl", nil, {88, 100, 80, 20}, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl(nil, {88, 100, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ end)
+ main:OpenPopup(605, 130, "Enchant Item", controls)
+@@ -2979,7 +2983,7 @@ function ItemsTabClass:AnointDisplayItem(enchantSlot)
+ self.anointEnchantSlot = enchantSlot or 1
+
+ local controls = { }
+- controls.notableDB = new("NotableDBControl", {"TOPLEFT",nil,"TOPLEFT"}, {10, 60, 360, 360}, self, self.build.spec.tree.nodes, "ANOINT")
++ controls.notableDB = new("NotableDBControl"):NotableDBControl({"TOPLEFT",nil,"TOPLEFT"}, {10, 60, 360, 360}, self, self.build.spec.tree.nodes, "ANOINT")
+
+ local function saveLabel()
+ local node = controls.notableDB.selValue
+@@ -3066,7 +3070,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ if entry.sortValues[stat] ~= nil then
+ return entry.sortValues[stat]
+ end
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ item.id = self.displayItem.id
+ item.corrupted = true
+ local mod = entry.mod
+@@ -3134,7 +3138,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ if controls.implicit4 then controls.implicit4:UpdateSearch() end
+ end
+ local function corruptItem(addingImplicits)
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ item.id = self.displayItem.id
+ item.corrupted = true
+ -- either add implicits or roll ranges. if in the future it is possible
+@@ -3174,7 +3178,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ return item
+ end
+ if self.displayItem.rarity == "UNIQUE" or self.displayItem.rarity == "RELIC" then
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ local offset = 20
+ for i, mod in ipairs(item.explicitModLines) do
+ local modRange = mod.range or main.defaultItemAffixQuality
+@@ -3184,10 +3188,9 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ local lines = main:WrapString("^7" .. line, 16, 430)
+ return table.concat(lines, "\n"), #lines
+ end
+- controls["rollRangeValue" .. i] = new("LabelControl", { "TOPLEFT", nil, "TOPLEFT" },
++ controls["rollRangeValue" .. i] = new("LabelControl"):LabelControl({ "TOPLEFT", nil, "TOPLEFT" },
+ { 10, 10 + offset, 200, 16 }, "^71.00")
+- controls["rollRangeSlider" .. i] = new("SliderControl",
+- { "LEFT", controls["rollRangeValue" .. i], "RIGHT" }, { 5, 0, 80, 18 }, function(val)
++ controls["rollRangeSlider" .. i] = new("SliderControl"):SliderControl({ "LEFT", controls["rollRangeValue" .. i], "RIGHT" }, { 5, 0, 80, 18 }, function(val)
+ corruptedRanges[i] = 0.78 + round(0.44 * val, 2) -- 0.78-1.22
+ controls["rollRangeValue" .. i].label = "^7" .. string.format("%.2f", corruptedRanges[i])
+ controls["rollRangeLabel" .. i].label = formatLabel(corruptedRanges[i])
+@@ -3197,8 +3200,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ controls["rollRangeValue" .. i].label = "^7" .. string.format("%.2f", corruptedRanges[i])
+ local label, lineCount = formatLabel(corruptedRanges[i])
+ offset = offset + 16 * (lineCount - 1)
+- controls["rollRangeLabel" .. i] = new("LabelControl",
+- { "LEFT", controls["rollRangeSlider" .. i], "RIGHT" },
++ controls["rollRangeLabel" .. i] = new("LabelControl"):LabelControl({ "LEFT", controls["rollRangeSlider" .. i], "RIGHT" },
+ { 5, 0, 200, 16 }, label)
+ -- hide them by default as they are a secondary window
+ controls["rollRangeLabel" .. i].shown = false
+@@ -3218,7 +3220,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ end
+ controls.implicitCannotBeChangedLabel.shown = implicitNum > 0 and not canChangeImplicits
+ end
+- controls.implicits = new("ButtonControl", { "TOPLEFT", nil, "TOPLEFT" }, { 5, 5, 80, 20 }, "Implicits",
++ controls.implicits = new("ButtonControl"):ButtonControl({ "TOPLEFT", nil, "TOPLEFT" }, { 5, 5, 80, 20 }, "Implicits",
+ function()
+ local implicitNum = currentModType == "Corrupted" and 2 or 4
+ local canChangeImplicits = currentModType ~= "Corrupted" or not self.displayItem.implicitsCannotBeChanged
+@@ -3237,7 +3239,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ controls.implicits.shown = function()
+ return self.displayItem.rarity == "UNIQUE" or self.displayItem.rarity == "RELIC"
+ end
+- controls.rolls = new("ButtonControl", { "LEFT", controls.implicits, "RIGHT" }, { 5, 0, 80, 20 },
++ controls.rolls = new("ButtonControl"):ButtonControl({ "LEFT", controls.implicits, "RIGHT" }, { 5, 0, 80, 20 },
+ "Roll Ranges",
+ function()
+ setImplicitControlsShown(0, false)
+@@ -3255,9 +3257,9 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ controls.rolls.shown = function()
+ return self.displayItem.rarity == "UNIQUE" or self.displayItem.rarity == "RELIC"
+ end
+- controls.sourceLabel = new("LabelControl", { "TOPRIGHT", nil, "TOPLEFT" }, { 95, 30, 0, 16 },
++ controls.sourceLabel = new("LabelControl"):LabelControl({ "TOPRIGHT", nil, "TOPLEFT" }, { 95, 30, 0, 16 },
+ "^7Source:")
+- controls.source = new("DropDownControl", { "TOPLEFT", nil, "TOPLEFT" }, { 100, 30, 150, 18 },
++ controls.source = new("DropDownControl"):DropDownControl({ "TOPLEFT", nil, "TOPLEFT" }, { 100, 30, 150, 18 },
+ sourceList, function(index, value)
+ if value == "Scourge" then
+ currentModType = "ScourgeUpside"
+@@ -3285,19 +3287,19 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ controls.implicit4:SetSel(1)
+ end)
+ controls.source.enabled = #sourceList > 1
+- controls.sortLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {350, 20, 0, 16}, "^7Sort by:")
+- controls.sort = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {355, 20, 240, 18}, sortList, function(index, value)
++ controls.sortLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {350, 20, 0, 16}, "^7Sort by:")
++ controls.sort = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {355, 20, 240, 18}, sortList, function(index, value)
+ applySort(value.stat)
+ end)
+ local implicitRowSize = 20
+ local implicitYPos = 35
+- controls.implicitCannotBeChangedLabel = new("LabelControl", { "TOPLEFT", nil, "TOPLEFT" }, { 20, implicitYPos + implicitRowSize, 0, 20 }, "^7This Items Implicits Cannot Be Changed")
++ controls.implicitCannotBeChangedLabel = new("LabelControl"):LabelControl({ "TOPLEFT", nil, "TOPLEFT" }, { 20, implicitYPos + implicitRowSize, 0, 20 }, "^7This Items Implicits Cannot Be Changed")
+ controls.implicitCannotBeChangedLabel.shown = self.displayItem.implicitsCannotBeChanged
+ for i = 1, 4 do
+ local controlName = "implicit" .. i
+- controls[controlName .. "Label"] = new("LabelControl", { "TOPRIGHT", nil, "TOPLEFT" }, { 75, implicitYPos + i * implicitRowSize, 0, 16 },
++ controls[controlName .. "Label"] = new("LabelControl"):LabelControl({ "TOPRIGHT", nil, "TOPLEFT" }, { 75, implicitYPos + i * implicitRowSize, 0, 16 },
+ string.format("^7Implicit #%d:", i))
+- controls[controlName] = new("DropDownControl", { "TOPLEFT", nil, "TOPLEFT" }, { 80, implicitYPos + i * implicitRowSize, 440, 18 }, nil)
++ controls[controlName] = new("DropDownControl"):DropDownControl({ "TOPLEFT", nil, "TOPLEFT" }, { 80, implicitYPos + i * implicitRowSize, 440, 18 }, nil)
+ controls[controlName].tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ if mode ~= "OUT" and value and value.mod then
+@@ -3326,7 +3328,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ controls["implicit" .. i].selFunc()
+ end
+ end
+- controls.save = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, { -45, -4, 80, 20 }, modType, function()
++ controls.save = new("ButtonControl"):ButtonControl({ "BOTTOM", nil, "BOTTOM" }, { -45, -4, 80, 20 }, modType, function()
+ self:SetDisplayItem(corruptItem(controls.implicit1.shown))
+ main:ClosePopup()
+ end)
+@@ -3334,7 +3336,7 @@ function ItemsTabClass:CorruptDisplayItem(modType)
+ tooltip:Clear()
+ self:AddItemTooltip(tooltip, corruptItem(controls.implicit1.shown), nil, false)
+ end
+- controls.close = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, { 45, -4, 80, 20 }, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl({ "BOTTOM", nil, "BOTTOM" }, { 45, -4, 80, 20 }, "Cancel", function()
+ main:ClosePopup()
+ end)
+ main:OpenPopup(605, 103 + 20 * 2, modType .. " Item", controls)
+@@ -3358,7 +3360,7 @@ function ItemsTabClass:AddCustomModifierToDisplayItem()
+ if listMod.sortValues[stat] ~= nil then
+ return listMod.sortValues[stat]
+ end
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ item.id = self.displayItem.id
+ for _, line in ipairs(listMod.mod) do
+ t_insert(item.explicitModLines, { line = checkLineForAllocates(line, self.build.spec.nodes), modTags = listMod.mod.modTags, [listMod.type] = true })
+@@ -3708,7 +3710,7 @@ function ItemsTabClass:AddCrucibleModifierToDisplayItem()
+ end
+ end
+ local function addModifier()
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ item.id = self.displayItem.id
+ item.crucibleModLines = { }
+ local listMod = {
+@@ -3735,8 +3737,8 @@ function ItemsTabClass:AddCrucibleModifierToDisplayItem()
+ buildCrucibleMods()
+ local y = 45
+ for i = 1,5 do
+- controls["modSelectNode"..i.."Label"] = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, y, 0, 16}, "^7Node "..i..":")
+- controls["modSelectNode"..i] = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, y, 555, 18}, modList[i])
++ controls["modSelectNode"..i.."Label"] = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, y, 0, 16}, "^7Node "..i..":")
++ controls["modSelectNode"..i] = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, y, 555, 18}, modList[i])
+ controls["modSelectNode"..i].tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ if mode ~= "OUT" and value and value ~= "None" then
+@@ -3756,7 +3758,7 @@ function ItemsTabClass:AddCrucibleModifierToDisplayItem()
+ end
+ end
+ end
+- controls.save = new("ButtonControl", nil, {-45, 157, 80, 20}, "Add", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 157, 80, 20}, "Add", function()
+ self:SetDisplayItem(addModifier())
+ main:ClosePopup()
+ end)
+@@ -3764,7 +3766,7 @@ function ItemsTabClass:AddCrucibleModifierToDisplayItem()
+ tooltip:Clear()
+ self:AddItemTooltip(tooltip, addModifier())
+ end
+- controls.close = new("ButtonControl", nil, {45, 157, 80, 20}, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl(nil, {45, 157, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ end)
+ main:OpenPopup(710, 185, "Add Crucible Modifier to Item", controls, "save")
+@@ -3959,7 +3961,7 @@ function ItemsTabClass:AddImplicitToDisplayItem()
+ if listMod.sortValues[stat] ~= nil then
+ return listMod.sortValues[stat]
+ end
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ item.id = self.displayItem.id
+ applyCandidateMod(item, listMod)
+ item:BuildAndParseRaw()
+@@ -4039,7 +4041,7 @@ function ItemsTabClass:AddImplicitToDisplayItem()
+ end
+ end
+ local function addModifier()
+- local item = new("Item", self.displayItem:BuildRaw())
++ local item = new("Item"):Item(self.displayItem:BuildRaw())
+ item.id = self.displayItem.id
+ local sourceId = sourceList[controls.source.selIndex].sourceId
+ if sourceId == "CUSTOM" then
+@@ -4054,8 +4056,8 @@ function ItemsTabClass:AddImplicitToDisplayItem()
+ item:BuildAndParseRaw()
+ return item
+ end
+- controls.sourceLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 20, 0, 16}, "^7Source:")
+- controls.source = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 20, 150, 18}, sourceList, function(index, value)
++ controls.sourceLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 20, 0, 16}, "^7Source:")
++ controls.source = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 20, 150, 18}, sourceList, function(index, value)
+ if value.sourceId ~= "CUSTOM" then
+ controls.modSelectLabel.y = 70
+ buildMods(value.sourceId)
+@@ -4070,18 +4072,18 @@ function ItemsTabClass:AddImplicitToDisplayItem()
+ end
+ end)
+ controls.source.enabled = #sourceList > 1
+- controls.sortLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {350, 20, 0, 16}, "^7Sort by:")
++ controls.sortLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {350, 20, 0, 16}, "^7Sort by:")
+ controls.sortLabel.shown = function()
+ return sourceList[controls.source.selIndex].sourceId ~= "CUSTOM"
+ end
+- controls.sort = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {355, 20, 240, 18}, sortList, function(index, value)
++ controls.sort = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {355, 20, 240, 18}, sortList, function(index, value)
+ applySort(value.stat, true)
+ end)
+ controls.sort.shown = function()
+ return sourceList[controls.source.selIndex].sourceId ~= "CUSTOM"
+ end
+- controls.modGroupSelectLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 45, 0, 16}, "^7Type:")
+- controls.modGroupSelect = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 600, 18}, modGroups, function(index, value)
++ controls.modGroupSelectLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 45, 0, 16}, "^7Type:")
++ controls.modGroupSelect = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 600, 18}, modGroups, function(index, value)
+ controls.modSelect.list = modList[value.modListIndex]
+ controls.modSelect:SetSel(1)
+ end)
+@@ -4103,8 +4105,8 @@ function ItemsTabClass:AddImplicitToDisplayItem()
+ self:AddModComparisonTooltip(tooltip, value.mod)
+ end
+ end
+- controls.modSelectLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {95, 70, 0, 16}, "^7Modifier:")
+- controls.modSelect = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 70, 600, 18}, sourceList[controls.source.selIndex].sourceId ~= "CUSTOM" and modList[modGroups[1].modListIndex] or { })
++ controls.modSelectLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {95, 70, 0, 16}, "^7Modifier:")
++ controls.modSelect = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 70, 600, 18}, sourceList[controls.source.selIndex].sourceId ~= "CUSTOM" and modList[modGroups[1].modListIndex] or { })
+ controls.modSelect.shown = function()
+ return sourceList[controls.source.selIndex].sourceId ~= "CUSTOM"
+ end
+@@ -4117,11 +4119,11 @@ function ItemsTabClass:AddImplicitToDisplayItem()
+ self:AddModComparisonTooltip(tooltip, value.mod)
+ end
+ end
+- controls.custom = new("EditControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 440, 18})
++ controls.custom = new("EditControl"):EditControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 45, 440, 18})
+ controls.custom.shown = function()
+ return sourceList[controls.source.selIndex].sourceId == "CUSTOM"
+ end
+- controls.save = new("ButtonControl", nil, {-45, 100, 80, 20}, "Add", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 100, 80, 20}, "Add", function()
+ self:SetDisplayItem(addModifier())
+ main:ClosePopup()
+ end)
+@@ -4129,7 +4131,7 @@ function ItemsTabClass:AddImplicitToDisplayItem()
+ tooltip:Clear()
+ self:AddItemTooltip(tooltip, addModifier())
+ end
+- controls.close = new("ButtonControl", nil, {45, 100, 80, 20}, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl(nil, {45, 100, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ end)
+ main:OpenPopup(710, 130, "Add Implicit to Item", controls, "save", sourceList[controls.source.selIndex].sourceId == "CUSTOM" and "custom")
+@@ -4768,7 +4770,7 @@ function ItemsTabClass:AddItemTooltip(tooltip, item, slot, dbMode, maxWidth)
+ (#itemSkills > 1 and "s" or "") .. ".")
+ for i, itemSkill in ipairs(itemSkills) do
+ if not tooltip.childTooltips[i] then
+- tooltip.childTooltips[i] = new("Tooltip")
++ tooltip.childTooltips[i] = new("Tooltip"):Tooltip()
+ end
+ -- find gem since the item data only contains the skill id
+ local skill = data.skills[itemSkill.skillId]
diff --git a/src/Classes/LabelControl.lua b/src/Classes/LabelControl.lua
index 2f799ece2d..afedc6fdf3 100644
--- a/src/Classes/LabelControl.lua
+++ b/src/Classes/LabelControl.lua
@@ -3,13 +3,20 @@
-- Class: Label Control
-- Simple text label.
--
-local LabelClass = newClass("LabelControl", "Control", function(self, anchor, rect, label)
- self.Control(anchor, rect)
+---@class LabelControl: Control
+local LabelClass = newClass("LabelControl", "Control")
+
+---@param anchor? ControlAnchor
+---@param rect? ControlRect
+---@param label string
+function LabelClass:LabelControl(anchor, rect, label)
+ self:Control(anchor, rect)
self.label = label
self.width = function()
return DrawStringWidth(self:GetProperty("height"), "VAR", self:GetProperty("label"))
end
-end)
+ return self
+end
function LabelClass:Draw()
local x, y = self:GetPos()
diff --git a/src/Classes/ListControl.lua b/src/Classes/ListControl.lua
index 34dd0e7f41..7527b4cd96 100644
--- a/src/Classes/ListControl.lua
+++ b/src/Classes/ListControl.lua
@@ -30,16 +30,19 @@ local m_min = math.min
local m_max = math.max
local m_floor = math.floor
-local ListClass = newClass("ListControl", "Control", "ControlHost", function(self, anchor, rect, rowHeight, scroll, isMutable, list, forceTooltip)
- self.Control(anchor, rect)
- self.ControlHost()
+---@class ListControl: Control, ControlHost
+local ListClass = newClass("ListControl", "Control", "ControlHost")
+
+function ListClass:ListControl(anchor, rect, rowHeight, scroll, isMutable, list, forceTooltip)
+ self:Control(anchor, rect)
+ self:ControlHost()
self.rowHeight = rowHeight
self.scroll = scroll
self.isMutable = isMutable
self.list = list or { }
self.forceTooltip = forceTooltip
self.colList = { { } }
- self.tooltip = new("Tooltip")
+ self.tooltip = new("Tooltip"):Tooltip()
self.font = "VAR"
if self.scroll then
if self.scroll == "HORIZONTAL" then
@@ -48,7 +51,7 @@ local ListClass = newClass("ListControl", "Control", "ControlHost", function(sel
self.scrollH = false
end
end
- self.controls.scrollBarH = new("ScrollBarControl", {"BOTTOM",self,"BOTTOM"}, {-8, -1, 0, self.scroll and 16 or 0}, rowHeight * 2, "HORIZONTAL") {
+ self.controls.scrollBarH = new("ScrollBarControl"):ScrollBarControl({"BOTTOM",self,"BOTTOM"}, {-8, -1, 0, self.scroll and 16 or 0}, rowHeight * 2, "HORIZONTAL") {
shown = function()
return self.scrollH
end,
@@ -57,7 +60,7 @@ local ListClass = newClass("ListControl", "Control", "ControlHost", function(sel
return width - 18
end
}
- self.controls.scrollBarV = new("ScrollBarControl", {"RIGHT",self,"RIGHT"}, {-1, 0, self.scroll and 16 or 0, 0}, rowHeight * 2, "VERTICAL") {
+ self.controls.scrollBarV = new("ScrollBarControl"):ScrollBarControl({"RIGHT",self,"RIGHT"}, {-1, 0, self.scroll and 16 or 0, 0}, rowHeight * 2, "VERTICAL") {
y = function()
return (self.scrollH and -8 or 0)
end,
@@ -71,7 +74,9 @@ local ListClass = newClass("ListControl", "Control", "ControlHost", function(sel
self.controls.scrollBarV.shown = false
end
self.labelPositionOffset = {0, 0}
-end)
+ return self
+end
+
function ListClass:SelectIndex(index)
self.selValue = self.list[index]
diff --git a/src/Classes/MinionListControl.lua.rej b/src/Classes/MinionListControl.lua.rej
new file mode 100644
index 0000000000..868199b696
--- /dev/null
+++ b/src/Classes/MinionListControl.lua.rej
@@ -0,0 +1,40 @@
+diff a/src/Classes/MinionListControl.lua b/src/Classes/MinionListControl.lua (rejected hunks)
+@@ -8,14 +8,17 @@ local t_insert = table.insert
+ local t_remove = table.remove
+ local s_format = string.format
+
+-local MinionListClass = newClass("MinionListControl", "ListControl", function(self, anchor, rect, data, list, dest)
+- self.ListControl(anchor, rect, 16, "VERTICAL", not dest, list)
++---@class MinionListControl: ListControl
++local MinionListClass = newClass("MinionListControl", "ListControl")
++
++function MinionListClass:MinionListControl(anchor, rect, data, list, dest)
++ self:ListControl(anchor, rect, 16, "VERTICAL", not dest, list)
+ self.data = data
+ self.dest = dest
+ if dest then
+ self.dragTargetList = { dest }
+ self.label = "^7Available Spectres:"
+- self.controls.add = new("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Add", function()
++ self.controls.add = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Add", function()
+ self:AddSel()
+ end)
+ self.controls.add.enabled = function()
+@@ -23,14 +26,15 @@ local MinionListClass = newClass("MinionListControl", "ListControl", function(se
+ end
+ else
+ self.label = "^7Spectres in Build:"
+- self.controls.delete = new("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Remove", function()
++ self.controls.delete = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Remove", function()
+ self:OnSelDelete(self.selIndex, self.selValue)
+ end)
+ self.controls.delete.enabled = function()
+ return self.selValue ~= nil
+ end
+ end
+-end)
++ return self
++end
+
+ function MinionListClass:AddSel()
+ if self.dest and not isValueInArray(self.dest.list, self.selValue) then
diff --git a/src/Classes/MinionSearchListControl.lua.rej b/src/Classes/MinionSearchListControl.lua.rej
new file mode 100644
index 0000000000..116465ed88
--- /dev/null
+++ b/src/Classes/MinionSearchListControl.lua.rej
@@ -0,0 +1,35 @@
+diff a/src/Classes/MinionSearchListControl.lua b/src/Classes/MinionSearchListControl.lua (rejected hunks)
+@@ -8,16 +8,19 @@ local t_insert = table.insert
+ local t_remove = table.remove
+ local s_format = string.format
+
+-local MinionSearchListClass = newClass("MinionSearchListControl", "MinionListControl", function(self, anchor, rect, data, list, dest)
+- self.MinionListControl(anchor, rect, data, list, dest)
++---@class MinionSearchListControl: MinionListControl
++local MinionSearchListClass = newClass("MinionSearchListControl", "MinionListControl")
++
++function MinionSearchListClass:MinionSearchListControl(anchor, rect, data, list, dest)
++ self:MinionListControl(anchor, rect, data, list, dest)
+ self.unfilteredList = copyTable(list)
+ self.isMutable = false
+
+- self.controls.searchText = new("EditControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 203, 18}, "", "Search", "%c", 100, function(buf)
++ self.controls.searchText = new("EditControl"):EditControl({"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 203, 18}, "", "Search", "%c", 100, function(buf)
+ self:ListFilterChanged(buf, self.controls.searchModeDropDown.selIndex)
+ end, nil, nil, true)
+
+- self.controls.searchModeDropDown = new("DropDownControl", {"LEFT",self.controls.searchText,"RIGHT"}, {2, 0, 60, 18}, { "Names", "Skills", "Both"}, function(index, value)
++ self.controls.searchModeDropDown = new("DropDownControl"):DropDownControl({"LEFT",self.controls.searchText,"RIGHT"}, {2, 0, 60, 18}, { "Names", "Skills", "Both"}, function(index, value)
+ self:ListFilterChanged(self.controls.searchText.buf, index)
+ end)
+
+@@ -28,7 +31,8 @@ local MinionSearchListClass = newClass("MinionSearchListControl", "MinionListCon
+ self.controls.delete.y = self.controls.add.y - 20
+ end
+
+-end)
++ return self
++end
+
+ function MinionSearchListClass:DoesEntryMatchFilters(searchStr, minionId, filterMode)
+ if filterMode == 1 or filterMode == 3 then
diff --git a/src/Classes/ModDB.lua b/src/Classes/ModDB.lua
index 0fdba90fef..d9ccf0d772 100644
--- a/src/Classes/ModDB.lua
+++ b/src/Classes/ModDB.lua
@@ -17,10 +17,14 @@ local bor = OR64 -- bit.bor
local mod_createMod = modLib.createMod
-local ModDBClass = newClass("ModDB", "ModStore", function(self, parent)
- self.ModStore(parent)
+---@class ModDB: ModStore
+local ModDBClass = newClass("ModDB", "ModStore")
+
+function ModDBClass:ModDB(parent)
+ self:ModStore(parent)
self.mods = { }
-end)
+ return self
+end
function ModDBClass:AddMod(mod)
local name = mod.name
diff --git a/src/Classes/ModList.lua b/src/Classes/ModList.lua
index 7bbadba7d6..ff33169ad7 100644
--- a/src/Classes/ModList.lua
+++ b/src/Classes/ModList.lua
@@ -16,9 +16,13 @@ local bor = OR64 -- bit.bor
local mod_createMod = modLib.createMod
-local ModListClass = newClass("ModList", "ModStore", function(self, parent)
- self.ModStore(parent)
-end)
+---@class ModList: ModStore
+local ModListClass = newClass("ModList", "ModStore")
+
+function ModListClass:ModList(parent)
+ self:ModStore(parent)
+ return self
+end
function ModListClass:AddMod(mod)
t_insert(self, mod)
diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua
index 972c783749..c31acde6c8 100644
--- a/src/Classes/ModStore.lua
+++ b/src/Classes/ModStore.lua
@@ -27,12 +27,16 @@ local conditionName = setmetatable({ }, { __index = function(t, var)
return t[var]
end })
-local ModStoreClass = newClass("ModStore", function(self, parent)
+---@class ModStore
+local ModStoreClass = newClass("ModStore")
+
+function ModStoreClass:ModStore(parent)
self.parent = parent or false
self.actor = parent and parent.actor or { }
self.multipliers = { }
self.conditions = { }
-end)
+ return self
+end
local function getActor(self, actorType)
if actorType == "player" then
diff --git a/src/Classes/NotableDBControl.lua.rej b/src/Classes/NotableDBControl.lua.rej
new file mode 100644
index 0000000000..e6bc9b7704
--- /dev/null
+++ b/src/Classes/NotableDBControl.lua.rej
@@ -0,0 +1,38 @@
+diff a/src/Classes/NotableDBControl.lua b/src/Classes/NotableDBControl.lua (rejected hunks)
+@@ -19,8 +19,10 @@ local function IsAnointableNode(node)
+ end
+
+ ---@class NotableDBControl : ListControl
+-local NotableDBClass = newClass("NotableDBControl", "ListControl", function(self, anchor, rect, itemsTab, db, dbType)
+- self.ListControl(anchor, rect, 16, "VERTICAL", false)
++local NotableDBClass = newClass("NotableDBControl", "ListControl")
++
++function NotableDBClass:NotableDBControl(anchor, rect, itemsTab, db, dbType)
++ self:ListControl(anchor, rect, 16, "VERTICAL", false)
+ self.itemsTab = itemsTab
+ self.db = db
+ self.dbType = dbType
+@@ -32,18 +34,19 @@ local NotableDBClass = newClass("NotableDBControl", "ListControl", function(self
+ self.sortDropList = { }
+ self.sortOrder = { }
+ self.sortMode = "NAME"
+- self.controls.sort = new("DropDownControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, -22, 360, 18}, self.sortDropList, function(index, value)
++ self.controls.sort = new("DropDownControl"):DropDownControl({"BOTTOMLEFT",self,"TOPLEFT"}, {0, -22, 360, 18}, self.sortDropList, function(index, value)
+ self:SetSortMode(value.sortMode)
+ end)
+- self.controls.search = new("EditControl", {"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 258, 18}, "", "Search", "%c", 100, function()
++ self.controls.search = new("EditControl"):EditControl({"BOTTOMLEFT",self,"TOPLEFT"}, {0, -2, 258, 18}, "", "Search", "%c", 100, function()
+ self.listBuildFlag = true
+ end, nil, nil, true)
+- self.controls.searchMode = new("DropDownControl", {"LEFT",self.controls.search,"RIGHT"}, {2, 0, 100, 18}, { "Anywhere", "Names", "Modifiers" }, function(index, value)
++ self.controls.searchMode = new("DropDownControl"):DropDownControl({"LEFT",self.controls.search,"RIGHT"}, {2, 0, 100, 18}, { "Anywhere", "Names", "Modifiers" }, function(index, value)
+ self.listBuildFlag = true
+ end)
+ self:BuildSortOrder()
+ self.listBuildFlag = true
+-end)
++ return self
++end
+
+ ---@param node table @The notable node to check
+ ---@return boolean @Whether the notable matches the type and search filters.
diff --git a/src/Classes/NotesTab.lua b/src/Classes/NotesTab.lua
index a7dc1fcf8a..3dba394432 100644
--- a/src/Classes/NotesTab.lua
+++ b/src/Classes/NotesTab.lua
@@ -5,9 +5,13 @@
--
local t_insert = table.insert
-local NotesTabClass = newClass("NotesTab", "ControlHost", "Control", function(self, build)
- self.ControlHost()
- self.Control()
+---@class NotesTab: ControlHost, Control
+local NotesTabClass = newClass("NotesTab", "ControlHost", "Control")
+
+---@param build Build
+function NotesTabClass:NotesTab(build)
+ self:ControlHost()
+ self:Control()
self.build = build
diff --git a/src/Classes/NotesTab.lua.rej b/src/Classes/NotesTab.lua.rej
new file mode 100644
index 0000000000..ca7bb251c4
--- /dev/null
+++ b/src/Classes/NotesTab.lua.rej
@@ -0,0 +1,52 @@
+diff a/src/Classes/NotesTab.lua b/src/Classes/NotesTab.lua (rejected hunks)
+@@ -17,33 +21,34 @@ local NotesTabClass = newClass("NotesTab", "ControlHost", "Control", function(se
+ local notesDesc = [[^7You can use Ctrl +/- (or Ctrl+Scroll) to zoom in and out and Ctrl+0 to reset.
+ This field also supports different colors. Using the caret symbol (^) followed by a Hex code or a number (0-9) will set the color.
+ Below are some common color codes PoB uses: ]]
+- self.controls.notesDesc = new("LabelControl", {"TOPLEFT",self,"TOPLEFT"}, {8, 8, 150, 16}, notesDesc)
+- self.controls.normal = new("ButtonControl", {"TOPLEFT",self.controls.notesDesc,"TOPLEFT"}, {0, 48, 100, 18}, colorCodes.NORMAL.."NORMAL", function() self:SetColor(colorCodes.NORMAL) end)
+- self.controls.magic = new("ButtonControl", {"TOPLEFT",self.controls.normal,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.MAGIC.."MAGIC", function() self:SetColor(colorCodes.MAGIC) end)
+- self.controls.rare = new("ButtonControl", {"TOPLEFT",self.controls.magic,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.RARE.."RARE", function() self:SetColor(colorCodes.RARE) end)
+- self.controls.unique = new("ButtonControl", {"TOPLEFT",self.controls.rare,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.UNIQUE.."UNIQUE", function() self:SetColor(colorCodes.UNIQUE) end)
+- self.controls.fire = new("ButtonControl", {"TOPLEFT",self.controls.normal,"TOPLEFT"}, {0, 18, 100, 18}, colorCodes.FIRE.."FIRE", function() self:SetColor(colorCodes.FIRE) end)
+- self.controls.cold = new("ButtonControl", {"TOPLEFT",self.controls.fire,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.COLD.."COLD", function() self:SetColor(colorCodes.COLD) end)
+- self.controls.lightning = new("ButtonControl", {"TOPLEFT",self.controls.cold,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.LIGHTNING.."LIGHTNING", function() self:SetColor(colorCodes.LIGHTNING) end)
+- self.controls.chaos = new("ButtonControl", {"TOPLEFT",self.controls.lightning,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.CHAOS.."CHAOS", function() self:SetColor(colorCodes.CHAOS) end)
+- self.controls.strength = new("ButtonControl", {"TOPLEFT",self.controls.fire,"TOPLEFT"}, {0, 18, 100, 18}, colorCodes.STRENGTH.."STRENGTH", function() self:SetColor(colorCodes.STRENGTH) end)
+- self.controls.dexterity = new("ButtonControl", {"TOPLEFT",self.controls.strength,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.DEXTERITY.."DEXTERITY", function() self:SetColor(colorCodes.DEXTERITY) end)
+- self.controls.intelligence = new("ButtonControl", {"TOPLEFT",self.controls.dexterity,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.INTELLIGENCE.."INTELLIGENCE", function() self:SetColor(colorCodes.INTELLIGENCE) end)
+- self.controls.default = new("ButtonControl", {"TOPLEFT",self.controls.intelligence,"TOPLEFT"}, {120, 0, 100, 18}, "^7DEFAULT", function() self:SetColor("^7") end)
++ self.controls.notesDesc = new("LabelControl"):LabelControl({"TOPLEFT",self,"TOPLEFT"}, {8, 8, 150, 16}, notesDesc)
++ self.controls.normal = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.notesDesc,"TOPLEFT"}, {0, 48, 100, 18}, colorCodes.NORMAL.."NORMAL", function() self:SetColor(colorCodes.NORMAL) end)
++ self.controls.magic = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.normal,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.MAGIC.."MAGIC", function() self:SetColor(colorCodes.MAGIC) end)
++ self.controls.rare = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.magic,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.RARE.."RARE", function() self:SetColor(colorCodes.RARE) end)
++ self.controls.unique = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.rare,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.UNIQUE.."UNIQUE", function() self:SetColor(colorCodes.UNIQUE) end)
++ self.controls.fire = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.normal,"TOPLEFT"}, {0, 18, 100, 18}, colorCodes.FIRE.."FIRE", function() self:SetColor(colorCodes.FIRE) end)
++ self.controls.cold = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.fire,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.COLD.."COLD", function() self:SetColor(colorCodes.COLD) end)
++ self.controls.lightning = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.cold,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.LIGHTNING.."LIGHTNING", function() self:SetColor(colorCodes.LIGHTNING) end)
++ self.controls.chaos = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.lightning,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.CHAOS.."CHAOS", function() self:SetColor(colorCodes.CHAOS) end)
++ self.controls.strength = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.fire,"TOPLEFT"}, {0, 18, 100, 18}, colorCodes.STRENGTH.."STRENGTH", function() self:SetColor(colorCodes.STRENGTH) end)
++ self.controls.dexterity = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.strength,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.DEXTERITY.."DEXTERITY", function() self:SetColor(colorCodes.DEXTERITY) end)
++ self.controls.intelligence = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.dexterity,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.INTELLIGENCE.."INTELLIGENCE", function() self:SetColor(colorCodes.INTELLIGENCE) end)
++ self.controls.default = new("ButtonControl"):ButtonControl({"TOPLEFT",self.controls.intelligence,"TOPLEFT"}, {120, 0, 100, 18}, "^7DEFAULT", function() self:SetColor("^7") end)
+
+- self.controls.edit = new("EditControl", {"TOPLEFT",self.controls.fire,"TOPLEFT"}, {0, 48, 0, 0}, "", nil, "^%C\t\n", nil, nil, 16, true)
++ self.controls.edit = new("EditControl"):EditControl({"TOPLEFT",self.controls.fire,"TOPLEFT"}, {0, 48, 0, 0}, "", nil, "^%C\t\n", nil, nil, 16, true)
+ self.controls.edit.width = function()
+ return self.width - 16
+ end
+ self.controls.edit.height = function()
+ return self.height - 128
+ end
+- self.controls.toggleColorCodes = new("ButtonControl", {"TOPRIGHT",self,"TOPRIGHT"}, {-10, 70, 160, 20}, "Show Color Codes", function()
++ self.controls.toggleColorCodes = new("ButtonControl"):ButtonControl({"TOPRIGHT",self,"TOPRIGHT"}, {-10, 70, 160, 20}, "Show Color Codes", function()
+ self.showColorCodes = not self.showColorCodes
+ self:SetShowColorCodes(self.showColorCodes)
+ end)
+ self:SelectControl(self.controls.edit)
+-end)
++ return self
++end
+
+ function NotesTabClass:SetShowColorCodes(setting)
+ self.showColorCodes = setting
diff --git a/src/Classes/PartyTab.lua b/src/Classes/PartyTab.lua
index b0f7983713..6e41497b8b 100644
--- a/src/Classes/PartyTab.lua
+++ b/src/Classes/PartyTab.lua
@@ -9,15 +9,19 @@ local s_format = string.format
local t_insert = table.insert
local m_max = math.max
-local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(self, build)
- self.ControlHost()
- self.Control()
+---@class PartyTab: ControlHost, Control
+local PartyTabClass = newClass("PartyTab", "ControlHost", "Control")
+
+---@param build Build
+function PartyTabClass:PartyTab(build)
+ self:ControlHost()
+ self:Control()
self.build = build
- self.actor = { Aura = { }, Curse = { }, Warcry = { }, Link = { }, modDB = new("ModDB"), output = { } }
+ self.actor = { Aura = { }, Curse = { }, Warcry = { }, Link = { }, modDB = new("ModDB"):ModDB(), output = { } }
self.actor.modDB.actor = self.actor
- self.enemyModList = new("ModList")
+ self.enemyModList = new("ModList"):ModList()
self.buffExports = { }
self.enableExportBuffs = false
@@ -61,7 +65,7 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
All of these effects can be found in the Calcs tab]]
- self.controls.notesDesc = new("LabelControl", {"TOPLEFT",self,"TOPLEFT"}, {8, 8, 150, theme.stringHeight}, notesDesc)
+ self.controls.notesDesc = new("LabelControl"):LabelControl({"TOPLEFT",self,"TOPLEFT"}, {8, 8, 150, theme.stringHeight}, notesDesc)
self.controls.notesDesc.width = function()
local width = self.width / 2 - 16
if width ~= self.controls.notesDesc.lastWidth then
@@ -70,7 +74,7 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
end
return width
end
- self.controls.importCodeHeader = new("LabelControl", {"TOPLEFT",self.controls.notesDesc,"BOTTOMLEFT"}, {0, 32, 0, theme.stringHeight}, "^7Enter a build code/URL below:")
+ self.controls.importCodeHeader = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.notesDesc,"BOTTOMLEFT"}, {0, 32, 0, theme.stringHeight}, "^7Enter a build code/URL below:")
self.controls.importCodeHeader.y = function()
return theme.lineCounter(self.controls.notesDesc.label) + 4
end
@@ -270,7 +274,7 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
end
if partyDestinations[self.controls.importCodeDestination.selIndex] == "All" or partyDestinations[self.controls.importCodeDestination.selIndex] == "EnemyConditions" or partyDestinations[self.controls.importCodeDestination.selIndex] == "EnemyMods" then
wipeTable(self.enemyModList)
- self.enemyModList = new("ModList")
+ self.enemyModList = new("ModList"):ModList()
self:ParseBuffs(self.enemyModList, self.controls.enemyCond.buf, "EnemyConditions")
self:ParseBuffs(self.enemyModList, self.controls.enemyMods.buf, "EnemyMods", self.controls.simpleEnemyMods)
end
@@ -280,7 +284,7 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
end
end
- self.controls.importCodeIn = new("EditControl", {"TOPLEFT",self.controls.importCodeHeader,"BOTTOMLEFT"}, {0, 4, 328, theme.buttonHeight}, "", nil, nil, nil, importCodeHandle)
+ self.controls.importCodeIn = new("EditControl"):EditControl({"TOPLEFT",self.controls.importCodeHeader,"BOTTOMLEFT"}, {0, 4, 328, theme.buttonHeight}, "", nil, nil, nil, importCodeHandle)
self.controls.importCodeIn.width = function()
return (self.width > 880) and 328 or (self.width / 2 - 100)
end
@@ -289,13 +293,13 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.importCodeGo.onClick()
end
end
- self.controls.importCodeState = new("LabelControl", {"LEFT",self.controls.importCodeIn,"RIGHT"}, {8, 0, 0, theme.stringHeight})
+ self.controls.importCodeState = new("LabelControl"):LabelControl({"LEFT",self.controls.importCodeIn,"RIGHT"}, {8, 0, 0, theme.stringHeight})
self.controls.importCodeState.label = function()
return self.importCodeDetail or ""
end
- self.controls.importCodeDestination = new("DropDownControl", {"TOPLEFT",self.controls.importCodeIn,"BOTTOMLEFT"}, {0, 4, 160, theme.buttonHeight}, partyDestinations)
+ self.controls.importCodeDestination = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.importCodeIn,"BOTTOMLEFT"}, {0, 4, 160, theme.buttonHeight}, partyDestinations)
self.controls.importCodeDestination.tooltipText = "Destination for Import/clear\nCurrently Links Skills do not export"
- self.controls.importCodeGo = new("ButtonControl", {"LEFT",self.controls.importCodeDestination,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "Import", function()
+ self.controls.importCodeGo = new("ButtonControl"):ButtonControl({"LEFT",self.controls.importCodeDestination,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "Import", function()
local importCodeFetching = false
if self.importCodeSite and not self.importCodeXML then
self.importCodeFetching = true
@@ -323,7 +327,7 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.importCodeGo.onClick()
end
end
- self.controls.appendNotReplace = new("CheckBoxControl", {"LEFT",self.controls.importCodeGo,"RIGHT"}, {60, 0, theme.buttonHeight}, "Append", function(state)
+ self.controls.appendNotReplace = new("CheckBoxControl"):CheckBoxControl({"LEFT",self.controls.importCodeGo,"RIGHT"}, {60, 0, theme.buttonHeight}, "Append", function(state)
end, "This sets the import button to append to the current party lists instead of replacing them (curses will still replace)", false)
self.controls.appendNotReplace.x = function()
return (self.width > theme.widthThreshold1) and 60 or (-276)
@@ -332,36 +336,36 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
return (self.width > theme.widthThreshold1) and 0 or 24
end
- self.controls.clear = new("ButtonControl", {"LEFT",self.controls.appendNotReplace,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "Clear", function()
+ self.controls.clear = new("ButtonControl"):ButtonControl({"LEFT",self.controls.appendNotReplace,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "Clear", function()
clearInputText()
wipeTable(self.enemyModList)
- self.enemyModList = new("ModList")
+ self.enemyModList = new("ModList"):ModList()
self.build.buildFlag = true
end)
self.controls.clear.tooltipText = "^7Clears all the party tab imported data"
- self.controls.ShowAdvanceTools = new("CheckBoxControl", {"TOPLEFT",self.controls.importCodeDestination,"BOTTOMLEFT"}, {140, 4, theme.buttonHeight}, "^7Show Advanced Info", function(state)
+ self.controls.ShowAdvanceTools = new("CheckBoxControl"):CheckBoxControl({"TOPLEFT",self.controls.importCodeDestination,"BOTTOMLEFT"}, {140, 4, theme.buttonHeight}, "^7Show Advanced Info", function(state)
end, "This shows the advanced info like what stats each aura/curse etc are adding, as well as enables the ability to edit them without a re-export\nDo not edit any boxes unless you know what you are doing, use copy/paste or import instead", false)
self.controls.ShowAdvanceTools.y = function()
return (self.width > theme.widthThreshold1) and 4 or 28
end
- self.controls.removeEffects = new("ButtonControl", {"LEFT",self.controls.ShowAdvanceTools,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "Disable Party Effects", function()
+ self.controls.removeEffects = new("ButtonControl"):ButtonControl({"LEFT",self.controls.ShowAdvanceTools,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "Disable Party Effects", function()
wipeTable(self.actor)
wipeTable(self.enemyModList)
- self.actor = { Aura = {}, Curse = {}, Warcry = { }, Link = {}, modDB = new("ModDB"), output = { } }
+ self.actor = { Aura = {}, Curse = {}, Warcry = { }, Link = {}, modDB = new("ModDB"):ModDB(), output = { } }
self.actor.modDB.actor = self.actor
- self.enemyModList = new("ModList")
+ self.enemyModList = new("ModList"):ModList()
self.build.buildFlag = true
end)
self.controls.removeEffects.tooltipText = "^7Removes the effects of the supports, without removing the data\nUse \"rebuild all\" to apply the effects again"
- self.controls.rebuild = new("ButtonControl", {"LEFT",self.controls.removeEffects,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "^7Rebuild All", function()
+ self.controls.rebuild = new("ButtonControl"):ButtonControl({"LEFT",self.controls.removeEffects,"RIGHT"}, {8, 0, 160, theme.buttonHeight}, "^7Rebuild All", function()
wipeTable(self.actor)
wipeTable(self.enemyModList)
- self.actor = { Aura = {}, Curse = {}, Warcry = { }, Link = {}, modDB = new("ModDB"), output = { } }
+ self.actor = { Aura = {}, Curse = {}, Warcry = { }, Link = {}, modDB = new("ModDB"):ModDB(), output = { } }
self.actor.modDB.actor = self.actor
- self.enemyModList = new("ModList")
+ self.enemyModList = new("ModList"):ModList()
self:ParseBuffs(self.actor["modDB"], self.controls.editPartyMemberStats.buf, "PartyMemberStats", self.actor["output"])
self:ParseBuffs(self.actor["Aura"], self.controls.editAuras.buf, "Aura", self.controls.simpleAuras)
self:ParseBuffs(self.actor["Curse"], self.controls.editCurses.buf, "Curse", self.controls.simpleCurses)
@@ -379,11 +383,11 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
return (self.width > theme.widthThreshold1) and 0 or 24
end
- self.controls.editAurasLabel = new("LabelControl", {"TOPLEFT",self.controls.ShowAdvanceTools,"TOPLEFT"}, {-140, 40, 0, theme.stringHeight}, "^7Auras")
+ self.controls.editAurasLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.ShowAdvanceTools,"TOPLEFT"}, {-140, 40, 0, theme.stringHeight}, "^7Auras")
self.controls.editAurasLabel.y = function()
return 36 + ((self.width <= theme.widthThreshold1) and 24 or 0)
end
- self.controls.editAuras = new("EditControl", {"TOPLEFT",self.controls.editAurasLabel,"TOPLEFT"}, {0, 18, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
+ self.controls.editAuras = new("EditControl"):EditControl({"TOPLEFT",self.controls.editAurasLabel,"TOPLEFT"}, {0, 18, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
self.controls.editAuras.width = function()
return self.width / 2 - 16
end
@@ -394,16 +398,16 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.editAuras.shown = function()
return self.controls.ShowAdvanceTools.state
end
- self.controls.simpleAuras = new("LabelControl", {"TOPLEFT",self.controls.editAurasLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
+ self.controls.simpleAuras = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.editAurasLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
self.controls.simpleAuras.shown = function()
return not self.controls.ShowAdvanceTools.state
end
- self.controls.editWarcriesLabel = new("LabelControl", {"TOPLEFT",self.controls.editAurasLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Warcry Skills")
+ self.controls.editWarcriesLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.editAurasLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Warcry Skills")
self.controls.editWarcriesLabel.y = function()
return self.controls.ShowAdvanceTools.state and (self.controls.editAuras.height() + 8) or (theme.lineCounter(self.controls.simpleAuras.label) + 4)
end
- self.controls.editWarcries = new("EditControl", {"TOPLEFT",self.controls.editWarcriesLabel,"TOPLEFT"}, {0, 18, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
+ self.controls.editWarcries = new("EditControl"):EditControl({"TOPLEFT",self.controls.editWarcriesLabel,"TOPLEFT"}, {0, 18, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
self.controls.editWarcries.width = function()
return self.width / 2 - 16
end
@@ -413,16 +417,16 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.editWarcries.shown = function()
return self.controls.ShowAdvanceTools.state
end
- self.controls.simpleWarcries = new("LabelControl", {"TOPLEFT",self.controls.editWarcriesLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
+ self.controls.simpleWarcries = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.editWarcriesLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
self.controls.simpleWarcries.shown = function()
return not self.controls.ShowAdvanceTools.state
end
- self.controls.editLinksLabel = new("LabelControl", {"TOPLEFT",self.controls.editWarcriesLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Link Skills")
+ self.controls.editLinksLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.editWarcriesLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Link Skills")
self.controls.editLinksLabel.y = function()
return self.controls.ShowAdvanceTools.state and (self.controls.editWarcries.height() + 8) or (theme.lineCounter(self.controls.simpleWarcries.label) + 4)
end
- self.controls.editLinks = new("EditControl", {"TOPLEFT",self.controls.editLinksLabel,"TOPLEFT"}, {0, 18, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
+ self.controls.editLinks = new("EditControl"):EditControl({"TOPLEFT",self.controls.editLinksLabel,"TOPLEFT"}, {0, 18, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
self.controls.editLinks.width = function()
return self.width / 2 - 16
end
@@ -432,13 +436,13 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.editLinks.shown = function()
return self.controls.ShowAdvanceTools.state
end
- self.controls.simpleLinks = new("LabelControl", {"TOPLEFT",self.controls.editLinksLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
+ self.controls.simpleLinks = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.editLinksLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
self.controls.simpleLinks.shown = function()
return not self.controls.ShowAdvanceTools.state
end
- self.controls.editPartyMemberStatsLabel = new("LabelControl", {"TOPLEFT",self.controls.notesDesc,"TOPRIGHT"}, {8, 0, 0, theme.stringHeight}, "^7Party Member Stats")
- self.controls.editPartyMemberStats = new("EditControl", {"TOPLEFT",self.controls.editPartyMemberStatsLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
+ self.controls.editPartyMemberStatsLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.notesDesc,"TOPRIGHT"}, {8, 0, 0, theme.stringHeight}, "^7Party Member Stats")
+ self.controls.editPartyMemberStats = new("EditControl"):EditControl({"TOPLEFT",self.controls.editPartyMemberStatsLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
self.controls.editPartyMemberStats.width = function()
return self.width / 2 - 16
end
@@ -449,11 +453,11 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
return self.controls.ShowAdvanceTools.state
end
- self.controls.enemyCondLabel = new("LabelControl", {"TOPLEFT",self.controls.editPartyMemberStatsLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Enemy Conditions")
+ self.controls.enemyCondLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.editPartyMemberStatsLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Enemy Conditions")
self.controls.enemyCondLabel.y = function()
return self.controls.ShowAdvanceTools.state and (self.controls.editPartyMemberStats.height() + 8) or 4
end
- self.controls.enemyCond = new("EditControl", {"TOPLEFT",self.controls.enemyCondLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
+ self.controls.enemyCond = new("EditControl"):EditControl({"TOPLEFT",self.controls.enemyCondLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
self.controls.enemyCond.width = function()
return self.width / 2 - 16
end
@@ -463,16 +467,16 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.enemyCond.shown = function()
return self.controls.ShowAdvanceTools.state
end
- self.controls.simpleEnemyCond = new("LabelControl", {"TOPLEFT",self.controls.enemyCondLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "^7---------------------------\n")
+ self.controls.simpleEnemyCond = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.enemyCondLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "^7---------------------------\n")
self.controls.simpleEnemyCond.shown = function()
return not self.controls.ShowAdvanceTools.state
end
- self.controls.enemyModsLabel = new("LabelControl", {"TOPLEFT",self.controls.enemyCondLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Enemy Modifiers")
+ self.controls.enemyModsLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.enemyCondLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Enemy Modifiers")
self.controls.enemyModsLabel.y = function()
return self.controls.ShowAdvanceTools.state and (self.controls.enemyCond.height() + 8) or (theme.lineCounter(self.controls.simpleEnemyCond.label) + 4)
end
- self.controls.enemyMods = new("EditControl", {"TOPLEFT",self.controls.enemyModsLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
+ self.controls.enemyMods = new("EditControl"):EditControl({"TOPLEFT",self.controls.enemyModsLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
self.controls.enemyMods.width = function()
return self.width / 2 - 16
end
@@ -482,16 +486,16 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.enemyMods.shown = function()
return self.controls.ShowAdvanceTools.state
end
- self.controls.simpleEnemyMods = new("LabelControl", {"TOPLEFT",self.controls.enemyModsLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "\n")
+ self.controls.simpleEnemyMods = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.enemyModsLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "\n")
self.controls.simpleEnemyMods.shown = function()
return not self.controls.ShowAdvanceTools.state
end
- self.controls.editCursesLabel = new("LabelControl", {"TOPLEFT",self.controls.enemyModsLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Curses")
+ self.controls.editCursesLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.enemyModsLabel,"BOTTOMLEFT"}, {0, 8, 0, theme.stringHeight}, "^7Curses")
self.controls.editCursesLabel.y = function()
return self.controls.ShowAdvanceTools.state and (self.controls.enemyMods.height() + 8) or (theme.lineCounter(self.controls.simpleEnemyMods.label) + 4)
end
- self.controls.editCurses = new("EditControl", {"TOPLEFT",self.controls.editCursesLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
+ self.controls.editCurses = new("EditControl"):EditControl({"TOPLEFT",self.controls.editCursesLabel,"BOTTOMLEFT"}, {0, 2, 0, 0}, "", nil, "^%C\t\n", nil, nil, 14, true)
self.controls.editCurses.width = function()
return self.width / 2 - 16
end
@@ -501,12 +505,13 @@ local PartyTabClass = newClass("PartyTab", "ControlHost", "Control", function(se
self.controls.editCurses.shown = function()
return self.controls.ShowAdvanceTools.state
end
- self.controls.simpleCurses = new("LabelControl", {"TOPLEFT",self.controls.editCursesLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
+ self.controls.simpleCurses = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.editCursesLabel,"TOPLEFT"}, {0, 18, 0, theme.stringHeight}, "")
self.controls.simpleCurses.shown = function()
return not self.controls.ShowAdvanceTools.state
end
self:SelectControl(self.controls.editAuras)
-end)
+ return self
+end
function PartyTabClass:Load(xml, fileName)
for _, node in ipairs(xml) do
@@ -842,7 +847,7 @@ function PartyTabClass:ParseBuffs(list, buf, buffType, label)
end
if not listElement[currentName] then
listElement[currentName] = {
- modList = new("ModList"),
+ modList = new("ModList"):ModList(),
effectMult = currentEffect
}
if isMark then
@@ -851,7 +856,7 @@ function PartyTabClass:ParseBuffs(list, buf, buffType, label)
elseif listElement[currentName].effectMult ~= currentEffect then
if listElement[currentName].effectMult < currentEffect then
listElement[currentName] = {
- modList = new("ModList"),
+ modList = new("ModList"):ModList(),
effectMult = currentEffect
}
else
diff --git a/src/Classes/PassiveMasteryControl.lua b/src/Classes/PassiveMasteryControl.lua
index fb8b2f3580..a3f9e054ff 100644
--- a/src/Classes/PassiveMasteryControl.lua
+++ b/src/Classes/PassiveMasteryControl.lua
@@ -9,20 +9,23 @@ local m_min = math.min
local m_max = math.max
local m_floor = math.floor
---constructor
-local PassiveMasteryControlClass = newClass("PassiveMasteryControl", "ListControl", function(self, anchor, rect, list, treeTab, node, saveButton)
+---@class PassiveMasteryControl: ListControl
+local PassiveMasteryControlClass = newClass("PassiveMasteryControl", "ListControl")
+
+function PassiveMasteryControlClass:PassiveMasteryControl(anchor, rect, list, treeTab, node, saveButton)
self.list = list or { }
-- automagical width
for j=1,#list do
rect[3] = m_max(rect[3], DrawStringWidth(16, "VAR", list[j].label) + 5)
end
- self.ListControl(anchor, rect, 16, false, false, self.list)
+ self:ListControl(anchor, rect, 16, false, false, self.list)
self.treeTab = treeTab
self.treeView = treeTab.viewer
self.node = node
self.selIndex = nil
self.saveButton = saveButton
-end)
+ return self
+end
function PassiveMasteryControlClass:Draw(viewPort)
self.ListControl.Draw(self, viewPort)
diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua
index ffed6f6ff2..0622c668cb 100644
--- a/src/Classes/PassiveSpec.lua
+++ b/src/Classes/PassiveSpec.lua
@@ -2564,12 +2564,12 @@ end
--- Adds a line to or replaces a node given a line to add/replace with
--- @param node table The node to replace/add to
--- @param sd string The line being parsed and added
---- @param replacement boolean true to replace the node with the new mod, false to simply add it
+--- @param replacement? boolean true to replace the node with the new mod, false to simply add it
function PassiveSpecClass:NodeAdditionOrReplacementFromString(node,sd,replacement)
local addition = {}
addition.sd = {sd}
addition.mods = { }
- addition.modList = new("ModList")
+ addition.modList = new("ModList"):ModList()
addition.modKey = ""
local i = 1
while addition.sd[i] do
@@ -2640,7 +2640,7 @@ function PassiveSpecClass:NodeAdditionOrReplacementFromString(node,sd,replacemen
node.mods = tableConcat(node.mods, addition.mods)
node.modKey = node.modKey .. addition.modKey
end
- local modList = new("ModList")
+ local modList = new("ModList"):ModList()
modList:AddList(addition.modList)
if not replacement then
modList:AddList(node.modList)
diff --git a/src/Classes/PassiveSpec.lua.rej b/src/Classes/PassiveSpec.lua.rej
new file mode 100644
index 0000000000..24a536ef9f
--- /dev/null
+++ b/src/Classes/PassiveSpec.lua.rej
@@ -0,0 +1,34 @@
+diff a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua (rejected hunks)
+@@ -16,8 +16,11 @@ local b_rshift = bit.rshift
+ local band = bit.band
+ local bor = bit.bor
+
+-local PassiveSpecClass = newClass("PassiveSpec", "UndoHandler", function(self, build, treeVersion, convert)
+- self.UndoHandler()
++---@class PassiveSpec: UndoHandler
++local PassiveSpecClass = newClass("PassiveSpec", "UndoHandler")
++
++function PassiveSpecClass:PassiveSpec(build, treeVersion, convert)
++ self:UndoHandler()
+
+ self.build = build
+
+@@ -25,7 +28,8 @@ local PassiveSpecClass = newClass("PassiveSpec", "UndoHandler", function(self, b
+ self:Init(treeVersion, convert)
+
+ self:SelectClass(0)
+-end)
++ return self
++end
+
+ function PassiveSpecClass:Init(treeVersion, convert)
+ self.treeVersion = treeVersion
+@@ -1621,7 +1625,7 @@ function PassiveSpecClass:ReplaceNode(old, newNode)
+ old.name = newNode.name
+ old.mods = newNode.mods
+ old.modKey = newNode.modKey
+- old.modList = new("ModList")
++ old.modList = new("ModList"):ModList()
+ old.modList:AddList(newNode.modList)
+ old.sprites = newNode.sprites
+ old.effectSprites = newNode.effectSprites
diff --git a/src/Classes/PassiveSpecListControl.lua b/src/Classes/PassiveSpecListControl.lua
index 50b201044a..00d59aa910 100644
--- a/src/Classes/PassiveSpecListControl.lua
+++ b/src/Classes/PassiveSpecListControl.lua
@@ -63,7 +63,7 @@ function PassiveSpecListClass:RenameSpec(spec, popupTitle, addOnName)
main:ClosePopup()
end)
controls.save.enabled = false
- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
-- main:OpenPopup(370, 100, spec.title and "Rename" or "Set Name", controls, "save", "edit")
diff --git a/src/Classes/PassiveSpecListControl.lua.rej b/src/Classes/PassiveSpecListControl.lua.rej
new file mode 100644
index 0000000000..888924a70b
--- /dev/null
+++ b/src/Classes/PassiveSpecListControl.lua.rej
@@ -0,0 +1,65 @@
+diff a/src/Classes/PassiveSpecListControl.lua b/src/Classes/PassiveSpecListControl.lua (rejected hunks)
+@@ -7,11 +7,14 @@ local t_insert = table.insert
+ local t_remove = table.remove
+ local m_max = math.max
+
+-local PassiveSpecListClass = newClass("PassiveSpecListControl", "ListControl", function(self, anchor, rect, treeTab)
+- self.ListControl(anchor, rect, 16, "VERTICAL", true, treeTab.specList)
++---@class PassiveSpecListControl: ListControl
++local PassiveSpecListClass = newClass("PassiveSpecListControl", "ListControl")
++
++function PassiveSpecListClass:PassiveSpecListControl(anchor, rect, treeTab)
++ self:ListControl(anchor, rect, 16, "VERTICAL", true, treeTab.specList)
+ self.treeTab = treeTab
+- self.controls.copy = new("ButtonControl", {"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
+- local newSpec = new("PassiveSpec", treeTab.build, self.selValue.treeVersion)
++ self.controls.copy = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
++ local newSpec = new("PassiveSpec"):PassiveSpec(treeTab.build, self.selValue.treeVersion)
+ newSpec.title = self.selValue.title
+ newSpec.jewels = copyTable(self.selValue.jewels)
+ newSpec:RestoreUndoState(self.selValue:CreateUndoState())
+@@ -21,35 +24,36 @@ local PassiveSpecListClass = newClass("PassiveSpecListControl", "ListControl", f
+ self.controls.copy.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.delete = new("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
++ self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
+ self:OnSelDelete(self.selIndex, self.selValue)
+ end)
+ self.controls.delete.enabled = function()
+ return self.selValue ~= nil and #self.list > 1
+ end
+- self.controls.rename = new("ButtonControl", {"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
++ self.controls.rename = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
+ self:RenameSpec(self.selValue, "Rename Tree")
+ end)
+ self.controls.rename.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.new = new("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
+- local newSpec = new("PassiveSpec", treeTab.build, latestTreeVersion)
++ self.controls.new = new("ButtonControl"):ButtonControl({"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
++ local newSpec = new("PassiveSpec"):PassiveSpec(treeTab.build, latestTreeVersion)
+ newSpec:SelectClass(treeTab.build.spec.curClassId)
+ newSpec:SelectAscendClass(treeTab.build.spec.curAscendClassId)
+ newSpec:SelectSecondaryAscendClass(treeTab.build.spec.curSecondaryAscendClassId)
+ self:RenameSpec(newSpec, "New Tree", true)
+ end)
+ self:UpdateItemsTabPassiveTreeDropdown()
+-end)
++ return self
++end
+
+ function PassiveSpecListClass:RenameSpec(spec, title, addOnName)
+ local controls = { }
+- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter name for this passive tree:")
+- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, spec.title, nil, nil, 100, function(buf)
++ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this passive tree:")
++ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, spec.title, nil, nil, 100, function(buf)
+ controls.save.enabled = buf:match("%S")
+ end)
+- controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function()
+ spec.title = controls.edit.buf
+ self.treeTab.modFlag = true
+ if addOnName then
diff --git a/src/Classes/PassiveTree.lua.rej b/src/Classes/PassiveTree.lua.rej
new file mode 100644
index 0000000000..5001fcbfb7
--- /dev/null
+++ b/src/Classes/PassiveTree.lua.rej
@@ -0,0 +1,50 @@
+diff a/src/Classes/PassiveTree.lua b/src/Classes/PassiveTree.lua (rejected hunks)
+@@ -49,7 +49,29 @@ local function getFile(URL)
+ return #page > 0 and page
+ end
+
+-local PassiveTreeClass = newClass("PassiveTree", function(self, treeVersion)
++---@class PassiveTreeGroup
++---@field x number
++---@field y number
++---@field orbits integer[]
++---@field nodes string[]
++---@field background any
++---@field isProxy boolean?
++---@class PassiveTree
++---@field classes any[] A list of classes on the tree
++---@field alternate_ascendancies any[]?
++---@field tree "Default"|"DefaultAltAscendancies"
++---@field groups PassiveTreeGroup[]
++---@field nodes table<"root"|integer, any>
++---@field jewelSlots integer[]
++---@field min_x integer
++---@field min_y integer
++---@field max_x integer
++---@field max_y integer
++---@field constants table
++---@field points table
++local PassiveTreeClass = newClass("PassiveTree")
++
++function PassiveTreeClass:PassiveTree(treeVersion)
+ self.treeVersion = treeVersion
+ local versionNum = treeVersions[treeVersion].num
+
+@@ -764,14 +786,15 @@ local PassiveTreeClass = newClass("PassiveTree", function(self, treeVersion)
+ if treeVersion == latestTreeVersion then
+ buildTreeDependentUniques(self)
+ end
+-end)
++ return self
++end
+
+ function PassiveTreeClass:ProcessStats(node, startIndex)
+ startIndex = startIndex or 1
+ if startIndex == 1 then
+ node.modKey = ""
+ node.mods = { }
+- node.modList = new("ModList")
++ node.modList = new("ModList"):ModList()
+ end
+
+ if not node.sd then
diff --git a/src/Classes/PassiveTreeView.lua b/src/Classes/PassiveTreeView.lua
index 8c1aa57644..77f5440444 100644
--- a/src/Classes/PassiveTreeView.lua
+++ b/src/Classes/PassiveTreeView.lua
@@ -50,7 +50,8 @@ local PassiveTreeViewClass = newClass("PassiveTreeView", function(self)
self.searchStrResults = {}
self.showStatDifferences = true
self.hoverNode = nil
-end)
+ return self
+end
function PassiveTreeViewClass:Load(xml, fileName)
if xml.attrib.zoomLevel then
@@ -156,6 +157,7 @@ function PassiveTreeViewClass:GetCompareNodeColor(node, compareNode, spec, build
return nodeDefaultColor
end
+---@param build Build
function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
local spec = build.spec
local tree = spec.tree
diff --git a/src/Classes/PassiveTreeView.lua.rej b/src/Classes/PassiveTreeView.lua.rej
new file mode 100644
index 0000000000..4d695de861
--- /dev/null
+++ b/src/Classes/PassiveTreeView.lua.rej
@@ -0,0 +1,24 @@
+diff a/src/Classes/PassiveTreeView.lua b/src/Classes/PassiveTreeView.lua (rejected hunks)
+@@ -25,7 +25,10 @@ local function isAbyssConquered(node)
+ return conqueror and conqueror.type and conqueror.type:match("^abyss_")
+ end
+
+-local PassiveTreeViewClass = newClass("PassiveTreeView", function(self)
++---@class PassiveTreeView
++local PassiveTreeViewClass = newClass("PassiveTreeView")
++
++function PassiveTreeViewClass:PassiveTreeView()
+ self.ring = NewImageHandle()
+ self.ring:Load("Assets/ring.png", "CLAMP")
+ self.highlightRing = NewImageHandle()
+@@ -64,8 +67,8 @@ local PassiveTreeViewClass = newClass("PassiveTreeView", function(self)
+ self.kalguur2 = NewImageHandle()
+ self.kalguur2:Load("TreeData/PassiveSkillScreenKalguuranJewelCircle2.png", "CLAMP")
+
+- self.tooltip = new("Tooltip")
+- self.skillTooltip = new("Tooltip")
++ self.tooltip = new("Tooltip"):Tooltip()
++ self.skillTooltip = new("Tooltip"):Tooltip()
+
+ self.zoomLevel = 3
+ self.zoom = 1.2 ^ self.zoomLevel
diff --git a/src/Classes/PathControl.lua b/src/Classes/PathControl.lua
index 4d62bef272..af32ccbbb5 100644
--- a/src/Classes/PathControl.lua
+++ b/src/Classes/PathControl.lua
@@ -6,16 +6,20 @@
local ipairs = ipairs
local t_insert = table.insert
-local PathClass = newClass("PathControl", "Control", "ControlHost", "UndoHandler", function(self, anchor, rect, basePath, subPath, onChange)
- self.Control(anchor, rect)
- self.ControlHost()
- self.UndoHandler()
+---@class PathControl
+local PathClass = newClass("PathControl", "Control", "ControlHost", "UndoHandler")
+
+function PathClass:PathControl(anchor, rect, basePath, subPath, onChange)
+ self:Control(anchor, rect)
+ self:ControlHost()
+ self:UndoHandler()
self.basePath = basePath
self.baseName = basePath:match("([^/]+)/$") or "Base"
self:SetSubPath(subPath or "")
self:ResetUndo()
self.onChange = onChange
-end)
+ return self
+end
function PathClass:SetSubPath(subPath, noUndo)
if subPath == self.subPath then
@@ -33,7 +37,7 @@ function PathClass:SetSubPath(subPath, noUndo)
for index, folder in ipairs(self.folderList) do
local button = self.controls["folder"..i]
if not button then
- button = new("ButtonControl", {"LEFT",self,"LEFT"}, {0, 0, 0, self.height - 4})
+ button = new("ButtonControl"):ButtonControl({"LEFT",self,"LEFT"}, {0, 0, 0, self.height - 4})
self.controls["folder"..i] = button
end
button.shown = true
diff --git a/src/Classes/PoBArchivesProvider.lua b/src/Classes/PoBArchivesProvider.lua
index c2b6ab2a52..d2d694b774 100644
--- a/src/Classes/PoBArchivesProvider.lua
+++ b/src/Classes/PoBArchivesProvider.lua
@@ -9,17 +9,19 @@ local dkjson = require "dkjson"
local archivesUrl = 'https://pobarchives.com'
-local PoBArchivesProviderClass = newClass("PoBArchivesProvider", "ExtBuildListProvider",
- function(self, mode)
- if mode == "builds" then
- self.ExtBuildListProvider({"Trending", "Latest"})
- else
- self.ExtBuildListProvider({"Similar Builds"})
- end
- self.buildList = {}
- self.mode = mode
+---@class PoBArchivesProvider: ExtBuildListProvider
+local PoBArchivesProviderClass = newClass("PoBArchivesProvider", "ExtBuildListProvider")
+
+function PoBArchivesProviderClass:PoBArchivesProvider(mode)
+ if mode == "builds" then
+ self:ExtBuildListProvider({"Trending", "Latest"})
+ else
+ self:ExtBuildListProvider({"Similar Builds"})
end
-)
+ self.buildList = {}
+ self.mode = mode
+ return self
+end
function PoBArchivesProviderClass:GetApiUrl()
if self.importCode then
diff --git a/src/Classes/PoEAPI.lua.rej b/src/Classes/PoEAPI.lua.rej
new file mode 100644
index 0000000000..6fdabcee7e
--- /dev/null
+++ b/src/Classes/PoEAPI.lua.rej
@@ -0,0 +1,26 @@
+diff a/src/Classes/PoEAPI.lua b/src/Classes/PoEAPI.lua (rejected hunks)
+@@ -11,17 +11,21 @@ local scopesOAuth = {
+
+ local filename = "poe_api_response.json"
+
+-local PoEAPIClass = newClass("PoEAPI", function(self, authToken, refreshToken, tokenExpiry)
++---@class PoEAPI
++local PoEAPIClass = newClass("PoEAPI")
++
++function PoEAPIClass:PoEAPI(authToken, refreshToken, tokenExpiry)
+ self.retries = 0
+ self.authToken = authToken
+ self.refreshToken = refreshToken
+ self.tokenExpiry = tokenExpiry or 0
+ self.baseUrl = "https://api.pathofexile.com"
+- self.rateLimiter = new("TradeQueryRateLimiter")
++ self.rateLimiter = new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
+ self.tokenHasBeenValidated = false
+
+ self.ERROR_NO_AUTH = "No auth token"
+-end)
++ return self
++end
+
+ -- performs a basic check on the validity of the current login by refreshing the
+ -- token if necessary. if a refresh is attempted and fails, the login details
diff --git a/src/Classes/PopupDialog.lua b/src/Classes/PopupDialog.lua
index 223059def9..1e54e8c695 100644
--- a/src/Classes/PopupDialog.lua
+++ b/src/Classes/PopupDialog.lua
@@ -5,10 +5,13 @@
--
local m_floor = math.floor
-local PopupDialogClass = newClass("PopupDialog", "ControlHost", "Control", function(self, width, height, title, controls, enterControl, defaultControl,
+---@class PopupDialog: ControlHost, Control
+local PopupDialogClass = newClass("PopupDialog", "ControlHost", "Control")
+
+function PopupDialogClass:PopupDialog(width, height, title, controls, enterControl, defaultControl,
escapeControl, scrollBarFunc, resizeFunc)
- self.ControlHost()
- self.Control(nil, {0, 0, width, height})
+ self:ControlHost()
+ self:Control(nil, {0, 0, width, height})
self.x = function()
return m_floor((main.screenW - width) / 2)
end
@@ -35,7 +38,8 @@ local PopupDialogClass = newClass("PopupDialog", "ControlHost", "Control", funct
self.scrollBarFunc = scrollBarFunc
-- allow resizing of popup
self.resizeFunc = resizeFunc
-end)
+ return self
+end
function PopupDialogClass:Draw(viewPort)
local x, y = self:GetPos()
diff --git a/src/Classes/PowerReportListControl.lua b/src/Classes/PowerReportListControl.lua
index d33ed88456..0e8434129f 100644
--- a/src/Classes/PowerReportListControl.lua
+++ b/src/Classes/PowerReportListControl.lua
@@ -8,8 +8,11 @@ local t_insert = table.insert
local t_remove = table.remove
local t_sort = table.sort
-local PowerReportListClass = newClass("PowerReportListControl", "ListControl", function(self, anchor, rect, nodeSelectCallback)
- self.ListControl(anchor, rect, 16, "VERTICAL", false)
+---@class PowerReportListControl: ListControl
+local PowerReportListClass = newClass("PowerReportListControl", "ListControl")
+
+function PowerReportListClass:PowerReportListControl(anchor, rect, nodeSelectCallback)
+ self:ListControl(anchor, rect, 16, "VERTICAL", false)
local width = rect[3]
self.powerColumn = { width = width * 0.16, label = "", sortable = true }
@@ -26,7 +29,7 @@ local PowerReportListClass = newClass("PowerReportListControl", "ListControl", f
self.allocated = false
self.label = "Building Tree..."
- self.controls.filterSelect = new("DropDownControl", {"BOTTOMRIGHT", self, "TOPRIGHT"}, {0, -2, 200, 20},
+ self.controls.filterSelect = new("DropDownControl"):DropDownControl({"BOTTOMRIGHT", self, "TOPRIGHT"}, {0, -2, 200, 20},
{ "Show Unallocated", "Show Unallocated & Clusters", "Show Allocated" },
function(index, value)
self.showClusters = index == 2
diff --git a/src/Classes/PowerReportListControl.lua.rej b/src/Classes/PowerReportListControl.lua.rej
new file mode 100644
index 0000000000..b0ebce0248
--- /dev/null
+++ b/src/Classes/PowerReportListControl.lua.rej
@@ -0,0 +1,17 @@
+diff a/src/Classes/PowerReportListControl.lua b/src/Classes/PowerReportListControl.lua (rejected hunks)
+@@ -35,12 +38,13 @@ local PowerReportListClass = newClass("PowerReportListControl", "ListControl", f
+ self:ReList()
+ self:ReSort(3) -- Sort by power
+ end)
+- self.controls.masteryCheck = new("CheckBoxControl", {"RIGHT", self.controls.filterSelect, "LEFT"}, {-120, 0, 18}, "Show Masteries:", function(state)
++ self.controls.masteryCheck = new("CheckBoxControl"):CheckBoxControl({"RIGHT", self.controls.filterSelect, "LEFT"}, {-120, 0, 18}, "Show Masteries:", function(state)
+ self.showMasteries = state
+ self:ReList()
+ self:ReSort(3) -- Sort by power
+ end, nil, true)
+-end)
++ return self
++end
+
+ function PowerReportListClass:SetReport(stat, report)
+ self.powerColumn.label = stat and stat.label or ""
diff --git a/src/Classes/RectangleOutlineControl.lua b/src/Classes/RectangleOutlineControl.lua
index 8b8b0b9d47..d01a58d814 100644
--- a/src/Classes/RectangleOutlineControl.lua
+++ b/src/Classes/RectangleOutlineControl.lua
@@ -3,11 +3,15 @@
-- Class: RectangleOutline Control
-- Simple Outline Only Rectangle control
--
-local RectangleOutlineClass = newClass("RectangleOutlineControl", "Control", function(self, anchor, rect, colors, stroke)
- self.Control(anchor, rect)
+---@class RectangleOutlineControl: Control
+local RectangleOutlineClass = newClass("RectangleOutlineControl", "Control")
+
+function RectangleOutlineClass:RectangleOutlineControl(anchor, rect, colors, stroke)
+ self:Control(anchor, rect)
self.stroke = stroke or 1
self.colors = colors or { 1, 1, 1 }
-end)
+ return self
+end
function RectangleOutlineClass:Draw()
local x, y = self:GetPos()
diff --git a/src/Classes/ResizableEditControl.lua b/src/Classes/ResizableEditControl.lua
index 66a0402e3f..4f5145fc3b 100644
--- a/src/Classes/ResizableEditControl.lua
+++ b/src/Classes/ResizableEditControl.lua
@@ -6,14 +6,17 @@
local m_max = math.max
local m_min = math.min
-local ResizableEditClass = newClass("ResizableEditControl", "EditControl", function(self, anchor, rect, init, prompt, filter, limit, changeFunc, lineHeight, allowZoom, clearable)
- self.EditControl(anchor, rect, init, prompt, filter, limit, changeFunc, lineHeight, allowZoom, clearable)
+---@class ResizableEditControl: EditControl
+local ResizableEditClass = newClass("ResizableEditControl", "EditControl")
+
+function ResizableEditClass:ResizableEditControl(anchor, rect, init, prompt, filter, limit, changeFunc, lineHeight, allowZoom, clearable)
+ self:EditControl(anchor, rect, init, prompt, filter, limit, changeFunc, lineHeight, allowZoom, clearable)
local x, y, width, height, minWidth, minHeight, maxWidth, maxHeight = unpack(rect)
self.minHeight = minHeight or height
self.maxHeight = maxHeight or height
self.minWidth = minWidth or width
self.maxWidth = maxWidth or width
- self.controls.draggerHeight = new("DraggerControl", {"BOTTOMRIGHT", self, "BOTTOMRIGHT"}, {7, 7, 14, 14}, "//", nil, nil, function (position)
+ self.controls.draggerHeight = new("DraggerControl"):DraggerControl({"BOTTOMRIGHT", self, "BOTTOMRIGHT"}, {7, 7, 14, 14}, "//", nil, nil, function (position)
-- onRightClick
if (self.height ~= self.minHeight) or (self.width ~= self.minWidth) then
self:SetWidth(self.minWidth)
@@ -24,7 +27,9 @@ local ResizableEditClass = newClass("ResizableEditControl", "EditControl", funct
end
end)
self.protected = false
-end)
+ return self
+end
+
function ResizableEditClass:Draw(viewPort, noTooltip)
self:SetBoundedDrag(self)
self.EditControl:Draw(viewPort, noTooltip)
diff --git a/src/Classes/ScrollBarControl.lua b/src/Classes/ScrollBarControl.lua
index 7dfc416e9e..145fb94bfd 100644
--- a/src/Classes/ScrollBarControl.lua
+++ b/src/Classes/ScrollBarControl.lua
@@ -8,8 +8,11 @@ local m_max = math.max
local m_ceil = math.ceil
local m_floor = math.floor
-local ScrollBarClass = newClass("ScrollBarControl", "Control", function(self, anchor, rect, step, dir, autoHide)
- self.Control(anchor, rect)
+---@class ScrollBarControl: Control
+local ScrollBarClass = newClass("ScrollBarControl", "Control")
+
+function ScrollBarClass:ScrollBarControl(anchor, rect, step, dir, autoHide)
+ self:Control(anchor, rect)
self.step = step or self.width * 2
self.dir = dir or "VERTICAL"
self.offset = 0
@@ -19,7 +22,8 @@ local ScrollBarClass = newClass("ScrollBarControl", "Control", function(self, an
return self.enabled
end
end
-end)
+ return self
+end
function ScrollBarClass:SetContentDimension(conDim, viewDim)
self.conDim = conDim
diff --git a/src/Classes/SearchHost.lua.rej b/src/Classes/SearchHost.lua.rej
new file mode 100644
index 0000000000..9de4aefebe
--- /dev/null
+++ b/src/Classes/SearchHost.lua.rej
@@ -0,0 +1,21 @@
+diff a/src/Classes/SearchHost.lua b/src/Classes/SearchHost.lua (rejected hunks)
+@@ -4,13 +4,17 @@
+ -- Search host
+ --
+
+-local SearchHostClass = newClass("SearchHost", function(self, listAccessor, valueAccessor, ignoreOrder)
++---@class SearchHost
++local SearchHostClass = newClass("SearchHost")
++
++function SearchHostClass:SearchHost(listAccessor, valueAccessor, ignoreOrder)
+ self.searchListAccessor = listAccessor
+ self.valueAccessor = valueAccessor
+ self.searchTerm = ""
+ self.searchInfos = {}
+ self.ignoreOrder = ignoreOrder or false
+-end)
++ return self
++end
+
+ local function splitWords(s)
+ local words = {}
diff --git a/src/Classes/SectionControl.lua b/src/Classes/SectionControl.lua
index 45e1498d2e..e0acb6fd21 100644
--- a/src/Classes/SectionControl.lua
+++ b/src/Classes/SectionControl.lua
@@ -4,10 +4,14 @@
-- Section box with label
--
-local SectionClass = newClass("SectionControl", "Control", function(self, anchor, rect, label)
- self.Control(anchor, rect)
+---@class SectionControl: Control
+local SectionClass = newClass("SectionControl", "Control")
+
+function SectionClass:SectionControl(anchor, rect, label)
+ self:Control(anchor, rect)
self.label = label
-end)
+ return self
+end
function SectionClass:Draw()
local x, y = self:GetPos()
diff --git a/src/Classes/SharedItemListControl.lua b/src/Classes/SharedItemListControl.lua
index b7605b61dc..a4891b368f 100644
--- a/src/Classes/SharedItemListControl.lua
+++ b/src/Classes/SharedItemListControl.lua
@@ -7,19 +7,23 @@ local pairs = pairs
local t_insert = table.insert
local t_remove = table.remove
-local SharedItemListClass = newClass("SharedItemListControl", "ListControl", function(self, anchor, rect, itemsTab, forceTooltip)
- self.ListControl(anchor, rect, 16, "VERTICAL", true, main.sharedItemList, forceTooltip)
+---@class SharedItemListControl: ListControl
+local SharedItemListClass = newClass("SharedItemListControl", "ListControl")
+
+function SharedItemListClass:SharedItemListControl(anchor, rect, itemsTab, forceTooltip)
+ self:ListControl(anchor, rect, 16, "VERTICAL", true, main.sharedItemList, forceTooltip)
self.itemsTab = itemsTab
self.label = "^7Shared items:"
self.defaultText = "^x7F7F7FThis is a list of items that will be shared between all of\nyour builds.\nYou can add items to this list by dragging them from\none of the other lists."
self.dragTargetList = { }
- self.controls.delete = new("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Delete", function()
+ self.controls.delete = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Delete", function()
self:OnSelDelete(self.selIndex, self.selValue)
end)
self.controls.delete.enabled = function()
return self.selValue ~= nil
end
-end)
+ return self
+end
function SharedItemListClass:GetRowValue(column, index, item)
if column == 1 then
@@ -44,7 +48,7 @@ end
function SharedItemListClass:ReceiveDrag(type, value, source)
if type == "Item" then
local rawItem = { raw = value:BuildRaw() }
- local newItem = new("Item", rawItem.raw)
+ local newItem = new("Item"):Item(rawItem.raw)
if not value.id then
newItem:NormaliseQuality()
end
diff --git a/src/Classes/SharedItemSetListControl.lua b/src/Classes/SharedItemSetListControl.lua
index c24932a705..ba604874c7 100644
--- a/src/Classes/SharedItemSetListControl.lua
+++ b/src/Classes/SharedItemSetListControl.lua
@@ -8,37 +8,41 @@ local t_remove = table.remove
local m_max = math.max
local s_format = string.format
-local SharedItemSetListClass = newClass("SharedItemSetListControl", "ListControl", function(self, anchor, rect, itemsTab)
- self.ListControl(anchor, rect, 16, "VERTICAL", true, main.sharedItemSetList)
+---@class SharedItemSetListControl: ListControl
+local SharedItemSetListClass = newClass("SharedItemSetListControl", "ListControl")
+
+function SharedItemSetListClass:SharedItemSetListControl(anchor, rect, itemsTab)
+ self:ListControl(anchor, rect, 16, "VERTICAL", true, main.sharedItemSetList)
self.itemsTab = itemsTab
self.defaultText = "^x7F7F7FThis is a list of item sets that will be shared\nbetween all of your builds.\nYou can add sets to this list by dragging them\nfrom the build's set list."
- self.controls.delete = new("ButtonControl", {"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Delete", function()
+ self.controls.delete = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Delete", function()
self:OnSelDelete(self.selIndex, self.selValue)
end)
self.controls.delete.enabled = function()
return self.selValue ~= nil
end
- self.controls.rename = new("ButtonControl", {"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
+ self.controls.rename = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
self:RenameSet(self.selValue)
end)
self.controls.rename.enabled = function()
return self.selValue ~= nil
end
-end)
+ return self
+end
function SharedItemSetListClass:RenameSet(sharedItemSet)
local controls = { }
- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter name for this item set:")
- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, sharedItemSet.title, nil, nil, 100, function(buf)
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this item set:")
+ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, sharedItemSet.title, nil, nil, 100, function(buf)
controls.save.enabled = buf:match("%S")
end)
- controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function()
+ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function()
sharedItemSet.title = controls.edit.buf
self.itemsTab.modFlag = true
main:ClosePopup()
end)
controls.save.enabled = false
- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(370, 100, sharedItemSet.title and "Rename" or "Set Name", controls, "save", "edit")
@@ -82,7 +86,7 @@ function SharedItemSetListClass:ReceiveDrag(type, value, source)
if slot.selItemId ~= 0 then
local item = self.itemsTab.items[slot.selItemId]
local rawItem = { raw = item:BuildRaw() }
- local newItem = new("Item", rawItem.raw)
+ local newItem = new("Item"):Item(rawItem.raw)
if not value.id then
newItem:NormaliseQuality()
end
diff --git a/src/Classes/SkillListControl.lua b/src/Classes/SkillListControl.lua
index 891f4374b4..99a1af81c7 100644
--- a/src/Classes/SkillListControl.lua
+++ b/src/Classes/SkillListControl.lua
@@ -49,11 +49,11 @@ local SkillListClass = newClass("SkillListControl", "ListControl", function(self
self.controls.deleteAll.enabled = function()
return #self.list > 0
end
- self.controls.new = new("ButtonControl", {"RIGHT",self.controls.deleteAll,"LEFT"}, {-4, 0, 60, 18}, "New", function()
- local newGroup = {
- label = "",
- enabled = true,
- gemList = { }
+ self.controls.new = new("ButtonControl"):ButtonControl({"RIGHT",self.controls.deleteAll,"LEFT"}, {-4, 0, 60, 18}, "New", function()
+ local newGroup = {
+ label = "",
+ enabled = true,
+ gemList = { }
}
t_insert(self.list, newGroup)
self.selIndex = #self.list
@@ -66,7 +66,8 @@ local SkillListClass = newClass("SkillListControl", "ListControl", function(self
for k, x in pairs(slot_map) do
x.icon:Load(x.path)
end
-end)
+ return self
+end
function SkillListClass:GetRowValue(column, index, socketGroup)
if column == 1 then
diff --git a/src/Classes/SkillListControl.lua.rej b/src/Classes/SkillListControl.lua.rej
new file mode 100644
index 0000000000..ba97f60336
--- /dev/null
+++ b/src/Classes/SkillListControl.lua.rej
@@ -0,0 +1,26 @@
+diff a/src/Classes/SkillListControl.lua b/src/Classes/SkillListControl.lua (rejected hunks)
+@@ -26,17 +26,20 @@ local slot_map = {
+ ["Belt"] = { icon = NewImageHandle(), path = "Assets/icon_belt.png" },
+ }
+
+-local SkillListClass = newClass("SkillListControl", "ListControl", function(self, anchor, rect, skillsTab)
+- self.ListControl(anchor, rect, 16, "VERTICAL", true, skillsTab.socketGroupList)
++---@class SkillListControl: ListControl
++local SkillListClass = newClass("SkillListControl", "ListControl")
++
++function SkillListClass:SkillListControl(anchor, rect, skillsTab)
++ self:ListControl(anchor, rect, 16, "VERTICAL", true, skillsTab.socketGroupList)
+ self.skillsTab = skillsTab
+ self.label = "^7Socket Groups:"
+- self.controls.delete = new("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Delete", function()
++ self.controls.delete = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Delete", function()
+ self:OnSelDelete(self.selIndex, self.selValue)
+ end)
+ self.controls.delete.enabled = function()
+ return self.selValue ~= nil and self.selValue.source == nil
+ end
+- self.controls.deleteAll = new("ButtonControl", {"RIGHT",self.controls.delete,"LEFT"}, {-4, 0, 70, 18}, "Delete All", function()
++ self.controls.deleteAll = new("ButtonControl"):ButtonControl({"RIGHT",self.controls.delete,"LEFT"}, {-4, 0, 70, 18}, "Delete All", function()
+ main:OpenConfirmPopup("Delete All", "Are you sure you want to delete all socket groups in this build?", "Delete", function()
+ wipeTable(self.list)
+ skillsTab:RebuildImbuedSupportBySlot()
diff --git a/src/Classes/SkillSetListControl.lua.rej b/src/Classes/SkillSetListControl.lua.rej
new file mode 100644
index 0000000000..a8319aa910
--- /dev/null
+++ b/src/Classes/SkillSetListControl.lua.rej
@@ -0,0 +1,66 @@
+diff a/src/Classes/SkillSetListControl.lua b/src/Classes/SkillSetListControl.lua (rejected hunks)
+@@ -8,10 +8,13 @@ local t_remove = table.remove
+ local m_max = math.max
+ local s_format = string.format
+
+-local SkillSetListClass = newClass("SkillSetListControl", "ListControl", function(self, anchor, rect, skillsTab)
+- self.ListControl(anchor, rect, 16, "VERTICAL", true, skillsTab.skillSetOrderList)
++---@class SkillSetListControl: ListControl
++local SkillSetListClass = newClass("SkillSetListControl", "ListControl")
++
++function SkillSetListClass:SkillSetListControl(anchor, rect, skillsTab)
++ self:ListControl(anchor, rect, 16, "VERTICAL", true, skillsTab.skillSetOrderList)
+ self.skillsTab = skillsTab
+- self.controls.copy = new("ButtonControl", {"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
++ self.controls.copy = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self,"TOP"}, {2, -4, 60, 18}, "Copy", function()
+ local skillSet = skillsTab.skillSets[self.selValue]
+ local newSkillSet = copyTable(skillSet, true)
+ newSkillSet.socketGroupList = { }
+@@ -33,30 +36,31 @@ local SkillSetListClass = newClass("SkillSetListControl", "ListControl", functio
+ self.controls.copy.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.delete = new("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
++ self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT",self.controls.copy,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
+ self:OnSelDelete(self.selIndex, self.selValue)
+ end)
+ self.controls.delete.enabled = function()
+ return self.selValue ~= nil and #self.list > 1
+ end
+- self.controls.rename = new("ButtonControl", {"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
++ self.controls.rename = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self,"TOP"}, {-2, -4, 60, 18}, "Rename", function()
+ self:RenameSet(skillsTab.skillSets[self.selValue])
+ end)
+ self.controls.rename.enabled = function()
+ return self.selValue ~= nil
+ end
+- self.controls.new = new("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
++ self.controls.new = new("ButtonControl"):ButtonControl({"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
+ self:RenameSet(skillsTab:NewSkillSet(), true)
+ end)
+-end)
++ return self
++end
+
+ function SkillSetListClass:RenameSet(skillSet, addOnName)
+ local controls = { }
+- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter name for this skill set:")
+- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, skillSet.title, nil, nil, 100, function(buf)
++ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this skill set:")
++ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, skillSet.title, nil, nil, 100, function(buf)
+ controls.save.enabled = buf:match("%S")
+ end)
+- controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function()
+ skillSet.title = controls.edit.buf
+ self.skillsTab.modFlag = true
+ if addOnName then
+@@ -69,7 +73,7 @@ function SkillSetListClass:RenameSet(skillSet, addOnName)
+ main:ClosePopup()
+ end)
+ controls.save.enabled = false
+- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
++ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
+ if addOnName then
+ self.skillsTab.skillSets[skillSet.id] = nil
+ end
diff --git a/src/Classes/SkillsTab.lua b/src/Classes/SkillsTab.lua
index ac8688c0b4..4c32f5a5d3 100644
--- a/src/Classes/SkillsTab.lua
+++ b/src/Classes/SkillsTab.lua
@@ -77,10 +77,14 @@ local sortGemTypeList = {
{ label = "Effective Hit Pool", type = "TotalEHP" },
}
-local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Control", function(self, build)
- self.UndoHandler()
- self.ControlHost()
- self.Control()
+---@class SkillsTab: UndoHandler, ControlHost, Control
+local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Control")
+
+---@param build Build
+function SkillsTabClass:SkillsTab(build)
+ self:UndoHandler()
+ self:ControlHost()
+ self:Control()
self.build = build
@@ -264,7 +268,7 @@ will automatically apply to the skill.]]
end
-- Scroll bar
- self.controls.scrollBarH = new("ScrollBarControl", nil, {0, 0, 0, 18}, 100, "HORIZONTAL", true)
+ self.controls.scrollBarH = new("ScrollBarControl"):ScrollBarControl(nil, {0, 0, 0, 18}, 100, "HORIZONTAL", true)
-- Initialise skill sets
self.skillSets = { }
@@ -752,7 +756,7 @@ function SkillsTabClass:CreateGemSlot(index)
self.build.buildFlag = true
end
-- Delete gem
- slot.delete = new("ButtonControl", nil, {0, 0, 20, 20}, "x", function()
+ slot.delete = new("ButtonControl"):ButtonControl(nil, {0, 0, 20, 20}, "x", function()
return deleteGem()
end)
if index == 1 then
@@ -773,7 +777,7 @@ function SkillsTabClass:CreateGemSlot(index)
self.controls["gemSlot"..index.."Delete"] = slot.delete
-- Gem name specification
- slot.nameSpec = new("GemSelectControl", { "LEFT", slot.delete, "RIGHT" }, { 2, 0, 300, 20 }, self, index, function(gemId, addUndo, focusLost, bufMatchesGem)
+ slot.nameSpec = new("GemSelectControl"):GemSelectControl({ "LEFT", slot.delete, "RIGHT" }, { 2, 0, 300, 20 }, self, index, function(gemId, addUndo, focusLost, bufMatchesGem)
if not self.displayGroup then
return
end
@@ -1124,7 +1128,7 @@ function SkillsTabClass:CreateGemSlot(index)
self.controls["gemSlot"..index.."EnableGlobal1"] = slot.enableGlobal1
-- Enable global-effect skill 2
- slot.enableGlobal2 = new("CheckBoxControl", {"LEFT",slot.enableGlobal1,"RIGHT",true}, {0, 0, 20}, "", function(state)
+ slot.enableGlobal2 = new("CheckBoxControl"):CheckBoxControl({"LEFT",slot.enableGlobal1,"RIGHT",true}, {0, 0, 20}, "", function(state)
local gemInstance = self.displayGroup.gemList[index]
gemInstance.enableGlobal2 = state
self:AddUndoState()
@@ -1475,8 +1479,8 @@ end
-- Opens the skill set manager
function SkillsTabClass:OpenSkillSetManagePopup()
main:OpenPopup(370, 290, "Manage Skill Sets", {
- new("SkillSetListControl", nil, {0, 50, 350, 200}, self),
- new("ButtonControl", nil, {0, 260, 90, 20}, "Done", function()
+ new("SkillSetListControl"):SkillSetListControl(nil, {0, 50, 350, 200}, self),
+ new("ButtonControl"):ButtonControl(nil, {0, 260, 90, 20}, "Done", function()
main:ClosePopup()
end),
})
diff --git a/src/Classes/SkillsTab.lua.rej b/src/Classes/SkillsTab.lua.rej
new file mode 100644
index 0000000000..498b62159d
--- /dev/null
+++ b/src/Classes/SkillsTab.lua.rej
@@ -0,0 +1,249 @@
+diff a/src/Classes/SkillsTab.lua b/src/Classes/SkillsTab.lua (rejected hunks)
+@@ -92,7 +96,7 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ self.defaultGemQuality = main.defaultGemQuality
+
+ -- Set selector
+- self.controls.setSelect = new("DropDownControl", { "TOPLEFT", self, "TOPLEFT" }, { 76, 8, 210, 20 }, nil, function(index, value)
++ self.controls.setSelect = new("DropDownControl"):DropDownControl({ "TOPLEFT", self, "TOPLEFT" }, { 76, 8, 210, 20 }, nil, function(index, value)
+ self:SetActiveSkillSet(self.skillSetOrderList[index])
+ self:AddUndoState()
+ end)
+@@ -100,14 +104,14 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ self.controls.setSelect.enabled = function()
+ return #self.skillSetOrderList > 1
+ end
+- self.controls.setLabel = new("LabelControl", { "RIGHT", self.controls.setSelect, "LEFT" }, { -2, 0, 0, 16 }, "^7Skill set:")
+- self.controls.setManage = new("ButtonControl", { "LEFT", self.controls.setSelect, "RIGHT" }, { 4, 0, 90, 20 }, "Manage...", function()
++ self.controls.setLabel = new("LabelControl"):LabelControl({ "RIGHT", self.controls.setSelect, "LEFT" }, { -2, 0, 0, 16 }, "^7Skill set:")
++ self.controls.setManage = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.setSelect, "RIGHT" }, { 4, 0, 90, 20 }, "Manage...", function()
+ self:OpenSkillSetManagePopup()
+ end)
+
+ -- Socket group list
+- self.controls.groupList = new("SkillListControl", { "TOPLEFT", self, "TOPLEFT" }, { 20, 54, 360, 300 }, self)
+- self.controls.groupTip = new("LabelControl", { "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { 0, 8, 0, 14 },
++ self.controls.groupList = new("SkillListControl"):SkillListControl({ "TOPLEFT", self, "TOPLEFT" }, { 20, 54, 360, 300 }, self)
++ self.controls.groupTip = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { 0, 8, 0, 14 },
+ [[
+ ^7Usage Tips:
+ - You can copy/paste socket groups using Ctrl+C and Ctrl+V.
+@@ -120,14 +124,14 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ -- Gem options
+ local optionInputsX = 170
+ local optionInputsY = 45
+- self.controls.optionSection = new("SectionControl", { "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { 0, optionInputsY + 50, 360, 156 }, "Gem Options")
+- self.controls.sortGemsByDPS = new("CheckBoxControl", { "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 70, 20 }, "Sort gems by DPS:", function(state)
++ self.controls.optionSection = new("SectionControl"):SectionControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { 0, optionInputsY + 50, 360, 156 }, "Gem Options")
++ self.controls.sortGemsByDPS = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 70, 20 }, "Sort gems by DPS:", function(state)
+ self.sortGemsByDPS = state
+ end, nil, true)
+- self.controls.sortGemsByDPSFieldControl = new("DropDownControl", { "LEFT", self.controls.sortGemsByDPS, "RIGHT" }, { 10, 0, 140, 20 }, sortGemTypeList, function(index, value)
++ self.controls.sortGemsByDPSFieldControl = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.sortGemsByDPS, "RIGHT" }, { 10, 0, 140, 20 }, sortGemTypeList, function(index, value)
+ self.sortGemsByDPSField = value.type
+ end)
+- self.controls.defaultLevel = new("DropDownControl", { "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 94, 170, 20 }, defaultGemLevelList, function(index, value)
++ self.controls.defaultLevel = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 94, 170, 20 }, defaultGemLevelList, function(index, value)
+ self.defaultGemLevel = value.gemLevel
+ end)
+ self.controls.defaultLevel.tooltipFunc = function(tooltip, mode, index, value)
+@@ -136,36 +140,36 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ tooltip:AddLine(16, "^7" .. value.description)
+ end
+ end
+- self.controls.defaultLevelLabel = new("LabelControl", { "RIGHT", self.controls.defaultLevel, "LEFT" }, { -4, 0, 0, 16 }, "^7Default gem level:")
+- self.controls.defaultQuality = new("EditControl", { "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 118, 60, 20 }, nil, nil, "%D", 2, function(buf)
++ self.controls.defaultLevelLabel = new("LabelControl"):LabelControl({ "RIGHT", self.controls.defaultLevel, "LEFT" }, { -4, 0, 0, 16 }, "^7Default gem level:")
++ self.controls.defaultQuality = new("EditControl"):EditControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 118, 60, 20 }, nil, nil, "%D", 2, function(buf)
+ self.defaultGemQuality = m_min(tonumber(buf) or 0, 23)
+ end)
+- self.controls.defaultQualityLabel = new("LabelControl", { "RIGHT", self.controls.defaultQuality, "LEFT" }, { -4, 0, 0, 16 }, "^7Default gem quality:")
+- self.controls.showSupportGemTypes = new("DropDownControl", { "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 142, 170, 20 }, showSupportGemTypeList, function(index, value)
++ self.controls.defaultQualityLabel = new("LabelControl"):LabelControl({ "RIGHT", self.controls.defaultQuality, "LEFT" }, { -4, 0, 0, 16 }, "^7Default gem quality:")
++ self.controls.showSupportGemTypes = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 142, 170, 20 }, showSupportGemTypeList, function(index, value)
+ self.showSupportGemTypes = value.show
+ end)
+- self.controls.showSupportGemTypesLabel = new("LabelControl", { "RIGHT", self.controls.showSupportGemTypes, "LEFT" }, { -4, 0, 0, 16 }, "^7Show support gems:")
+- self.controls.showLegacyGems = new("CheckBoxControl", { "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 166, 20 }, "^7Show legacy gems:", function(state)
++ self.controls.showSupportGemTypesLabel = new("LabelControl"):LabelControl({ "RIGHT", self.controls.showSupportGemTypes, "LEFT" }, { -4, 0, 0, 16 }, "^7Show support gems:")
++ self.controls.showLegacyGems = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", self.controls.groupList, "BOTTOMLEFT" }, { optionInputsX, optionInputsY + 166, 20 }, "^7Show legacy gems:", function(state)
+ self.showLegacyGems = state
+ end)
+
+ -- Socket group details
+ if main.portraitMode then
+- self.anchorGroupDetail = new("Control", { "TOPLEFT", self.controls.optionSection, "BOTTOMLEFT" }, { 0, 20, 0, 0 })
++ self.anchorGroupDetail = new("Control"):Control({ "TOPLEFT", self.controls.optionSection, "BOTTOMLEFT" }, { 0, 20, 0, 0 })
+ else
+- self.anchorGroupDetail = new("Control", { "TOPLEFT", self.controls.groupList, "TOPRIGHT" }, { 20, 0, 0, 0 })
++ self.anchorGroupDetail = new("Control"):Control({ "TOPLEFT", self.controls.groupList, "TOPRIGHT" }, { 20, 0, 0, 0 })
+ end
+ self.anchorGroupDetail.shown = function()
+ return self.displayGroup ~= nil
+ end
+- self.controls.groupLabel = new("EditControl", { "TOPLEFT", self.anchorGroupDetail, "TOPLEFT" }, { 0, 0, 380, 20 }, nil, "Label", "%c", 50, function(buf)
++ self.controls.groupLabel = new("EditControl"):EditControl({ "TOPLEFT", self.anchorGroupDetail, "TOPLEFT" }, { 0, 0, 380, 20 }, nil, "Label", "%c", 50, function(buf)
+ self.displayGroup.label = buf
+ self:ProcessSocketGroup(self.displayGroup)
+ self:AddUndoState()
+ self.build.buildFlag = true
+ end)
+- self.controls.groupSlotLabel = new("LabelControl", { "TOPLEFT", self.anchorGroupDetail, "TOPLEFT" }, { 0, 30, 0, 16 }, "^7Socketed in:")
+- self.controls.groupSlot = new("DropDownControl", { "TOPLEFT", self.anchorGroupDetail, "TOPLEFT" }, { 85, 28, 130, 20 }, groupSlotDropList, function(index, value)
++ self.controls.groupSlotLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.anchorGroupDetail, "TOPLEFT" }, { 0, 30, 0, 16 }, "^7Socketed in:")
++ self.controls.groupSlot = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.anchorGroupDetail, "TOPLEFT" }, { 85, 28, 130, 20 }, groupSlotDropList, function(index, value)
+ -- maintain imbued support to new slot
+ if self.imbuedSupportBySlot[self.displayGroup.slot] and self.displayGroup.imbuedSupport then
+ if value.slotName and not self.imbuedSupportBySlot[value.slotName] then
+@@ -200,12 +204,12 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ self.controls.groupSlot.enabled = function()
+ return self.displayGroup.source == nil
+ end
+- self.controls.groupEnabled = new("CheckBoxControl", { "LEFT", self.controls.groupSlot, "RIGHT" }, { 70, 0, 20 }, "Enabled:", function(state)
++ self.controls.groupEnabled = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.groupSlot, "RIGHT" }, { 70, 0, 20 }, "Enabled:", function(state)
+ self.displayGroup.enabled = state
+ self:AddUndoState()
+ self.build.buildFlag = true
+ end)
+- self.controls.includeInFullDPS = new("CheckBoxControl", { "LEFT", self.controls.groupEnabled, "RIGHT" }, { 145, 0, 20 }, "Include in Full DPS:", function(state)
++ self.controls.includeInFullDPS = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.groupEnabled, "RIGHT" }, { 145, 0, 20 }, "Include in Full DPS:", function(state)
+ self.displayGroup.includeInFullDPS = state
+ self:AddUndoState()
+ self.build.buildFlag = true
+@@ -225,7 +229,7 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ end
+ return item, groupSlot
+ end
+- self.controls.socketsLabel = new("LabelControl", { "TOPLEFT", self.controls.groupSlotLabel, "BOTTOMLEFT" }, { 0, 8, 0, 16 }, function()
++ self.controls.socketsLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.groupSlotLabel, "BOTTOMLEFT" }, { 0, 8, 0, 16 }, function()
+ local item = getSelectedItem()
+ local socketLine = ""
+ if item and item.base and not item.base.socketLimit then
+@@ -239,7 +243,7 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ local item = getSelectedItem()
+ return not not item
+ end
+- self.controls.optimiseSockets = new("ButtonControl", { "LEFT", self.controls.socketsLabel, "RIGHT" }, { 4, 0, 120, 18 }, "^7Optimise Sockets", function()
++ self.controls.optimiseSockets = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.socketsLabel, "RIGHT" }, { 4, 0, 120, 18 }, "^7Optimise Sockets", function()
+ local item, groupSlot = getSelectedItem()
+ if not item or not groupSlot or not item.base then
+ return
+@@ -292,8 +296,8 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ -- buildFlag to true triggers the reload/run the CalcSetup to add on the support
+ -- the last var in the GemSelectControl init, the true, sets imbuedSelect to true which sets the level to 1 and support filtering
+ self.imbuedSupportBySlot = { }
+- self.controls.imbuedSupportLabel = new("LabelControl", { "TOPLEFT", self.controls.socketsLabel, "BOTTOMLEFT", true }, { 0, 8, 0, 16 }, colorCodes.CRAFTED .. "Imbued Support:")
+- self.controls.imbuedSupport = new("GemSelectControl", { "LEFT", self.controls.imbuedSupportLabel, "RIGHT" }, { 8, 0, 250, 20 }, self, 1, function(gemData, _, _, gemMatch, slotName)
++ self.controls.imbuedSupportLabel = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.socketsLabel, "BOTTOMLEFT", true }, { 0, 8, 0, 16 }, colorCodes.CRAFTED .. "Imbued Support:")
++ self.controls.imbuedSupport = new("GemSelectControl"):GemSelectControl({ "LEFT", self.controls.imbuedSupportLabel, "RIGHT" }, { 8, 0, 250, 20 }, self, 1, function(gemData, _, _, gemMatch, slotName)
+ local targetSlot = slotName or (self.displayGroup and self.displayGroup.slot)
+ if not targetSlot then
+ return
+@@ -332,7 +336,7 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ return self.displayGroup and not
+ self.displayGroup.source
+ end
+- self.controls.imbuedSupportClear = new("ButtonControl", { "LEFT", self.controls.imbuedSupportLabel, "RIGHT" }, { 260, 0, 20, 20}, "x", function()
++ self.controls.imbuedSupportClear = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.imbuedSupportLabel, "RIGHT" }, { 260, 0, 20, 20}, "x", function()
+ self.controls.imbuedSupport.gemId = nil
+ self.controls.imbuedSupport:SetText("")
+ self.controls.imbuedSupport:gemChangeFunc(nil)
+@@ -342,11 +346,11 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ end
+ self.controls.imbuedSupportClear.tooltipText = "Remove this imbued support."
+
+- self.controls.groupCountLabel = new("LabelControl", { "LEFT", self.controls.includeInFullDPS, "RIGHT" }, { 16, 0, 0, 16 }, "^7Count:")
++ self.controls.groupCountLabel = new("LabelControl"):LabelControl({ "LEFT", self.controls.includeInFullDPS, "RIGHT" }, { 16, 0, 0, 16 }, "^7Count:")
+ self.controls.groupCountLabel.shown = function()
+ return self.displayGroup.source ~= nil
+ end
+- self.controls.groupCount = new("EditControl", { "LEFT", self.controls.groupCountLabel, "RIGHT" }, { 4, 0, 60, 20 }, nil, nil, "%D", 2, function(buf)
++ self.controls.groupCount = new("EditControl"):EditControl({ "LEFT", self.controls.groupCountLabel, "RIGHT" }, { 4, 0, 60, 20 }, nil, nil, "%D", 2, function(buf)
+ self.displayGroup.groupCount = tonumber(buf) or 1
+ self:AddUndoState()
+ self.build.buildFlag = true
+@@ -354,7 +358,7 @@ local SkillsTabClass = newClass("SkillsTab", "UndoHandler", "ControlHost", "Cont
+ self.controls.groupCount.shown = function()
+ return self.displayGroup.source ~= nil
+ end
+- self.controls.sourceNote = new("LabelControl", { "TOPLEFT", self.controls.socketsLabel, "TOPLEFT" }, { 0, 30, 0, 16 })
++ self.controls.sourceNote = new("LabelControl"):LabelControl({ "TOPLEFT", self.controls.socketsLabel, "TOPLEFT" }, { 0, 30, 0, 16 })
+ self.controls.sourceNote.shown = function()
+ return self.displayGroup.source ~= nil
+ end
+@@ -400,15 +404,16 @@ will automatically apply to the skill.]]
+ self:SetActiveSkillSet(1)
+
+ -- Skill gem slots
+- self.anchorGemSlots = new("Control", { "TOPLEFT", self.controls.imbuedSupportLabel, "BOTTOMLEFT" }, { 0, 30, 0, 0 })
++ self.anchorGemSlots = new("Control"):Control({ "TOPLEFT", self.controls.imbuedSupportLabel, "BOTTOMLEFT" }, { 0, 30, 0, 0 })
+ self.gemSlots = {}
+ self:CreateGemSlot(1)
+- self.controls.gemNameHeader = new("LabelControl", {"BOTTOMLEFT", self.gemSlots[1].nameSpec, "TOPLEFT"}, {0, -2, 0, 16}, "^7Gem name:")
+- self.controls.gemLevelHeader = new("LabelControl", {"BOTTOMLEFT", self.gemSlots[1].level, "TOPLEFT"}, {0, -2, 0, 16}, "^7Level:")
+- self.controls.gemQualityHeader = new("LabelControl", {"BOTTOMLEFT", self.gemSlots[1].quality, "TOPLEFT"}, {0, -2, 0, 16}, "^7Quality:")
+- self.controls.gemEnableHeader = new("LabelControl", {"BOTTOMLEFT", self.gemSlots[1].enabled, "TOPLEFT"}, {-16, -2, 0, 16}, "^7Enabled:")
+- self.controls.gemCountHeader = new("LabelControl", {"BOTTOMLEFT", self.gemSlots[1].count, "TOPLEFT"}, {8, -2, 0, 16}, "^7Count:")
+-end)
++ self.controls.gemNameHeader = new("LabelControl"):LabelControl({"BOTTOMLEFT", self.gemSlots[1].nameSpec, "TOPLEFT"}, {0, -2, 0, 16}, "^7Gem name:")
++ self.controls.gemLevelHeader = new("LabelControl"):LabelControl({"BOTTOMLEFT", self.gemSlots[1].level, "TOPLEFT"}, {0, -2, 0, 16}, "^7Level:")
++ self.controls.gemQualityHeader = new("LabelControl"):LabelControl({"BOTTOMLEFT", self.gemSlots[1].quality, "TOPLEFT"}, {0, -2, 0, 16}, "^7Quality:")
++ self.controls.gemEnableHeader = new("LabelControl"):LabelControl({"BOTTOMLEFT", self.gemSlots[1].enabled, "TOPLEFT"}, {-16, -2, 0, 16}, "^7Enabled:")
++ self.controls.gemCountHeader = new("LabelControl"):LabelControl({"BOTTOMLEFT", self.gemSlots[1].count, "TOPLEFT"}, {8, -2, 0, 16}, "^7Count:")
++ return self
++end
+
+
+ function SkillsTabClass:LoadSkill(node, skillSetId)
+@@ -812,7 +817,7 @@ function SkillsTabClass:CreateGemSlot(index)
+ self.controls["gemSlot"..index.."Name"] = slot.nameSpec
+
+ -- Gem level
+- slot.level = new("EditControl", { "LEFT", slot.nameSpec, "RIGHT" }, { 2, 0, 60, 20 }, nil, nil, "%D", 2, function(buf)
++ slot.level = new("EditControl"):EditControl({ "LEFT", slot.nameSpec, "RIGHT" }, { 2, 0, 60, 20 }, nil, nil, "%D", 2, function(buf)
+ local gemInstance = self.displayGroup.gemList[index]
+ if not gemInstance then
+ gemInstance = { nameSpec = "", level = self.defaultGemLevel or 20, quality = self.defaultGemQuality or 0, enabled = true, enableGlobal1 = true, enableGlobal2 = true, count = 1, new = true }
+@@ -834,7 +839,7 @@ function SkillsTabClass:CreateGemSlot(index)
+ self.controls["gemSlot"..index.."Level"] = slot.level
+
+ -- Gem quality
+- slot.quality = new("EditControl", {"LEFT",slot.level,"RIGHT"}, {2, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
++ slot.quality = new("EditControl"):EditControl({"LEFT",slot.level,"RIGHT"}, {2, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
+ local gemInstance = self.displayGroup.gemList[index]
+ if not gemInstance then
+ gemInstance = { nameSpec = "", level = self.defaultGemLevel or 20, quality = self.defaultGemQuality or 0, enabled = true, enableGlobal1 = true, enableGlobal2 = true, count = 1, new = true }
+@@ -925,7 +930,7 @@ function SkillsTabClass:CreateGemSlot(index)
+ self.controls["gemSlot"..index.."Quality"] = slot.quality
+
+ -- Enable gem
+- slot.enabled = new("CheckBoxControl", {"LEFT",slot.quality,"RIGHT"}, {18, 0, 20}, nil, function(state)
++ slot.enabled = new("CheckBoxControl"):CheckBoxControl({"LEFT",slot.quality,"RIGHT"}, {18, 0, 20}, nil, function(state)
+ local gemInstance = self.displayGroup.gemList[index]
+ if not gemInstance then
+ gemInstance = { nameSpec = "", level = self.defaultGemLevel or 20, quality = self.defaultGemQuality or 0, enabled = true, enableGlobal1 = true, enableGlobal2 = true, count = 1, new = true }
+@@ -964,7 +969,7 @@ function SkillsTabClass:CreateGemSlot(index)
+ self.controls["gemSlot"..index.."Enable"] = slot.enabled
+
+ -- Count gem
+- slot.count = new("EditControl", {"LEFT",slot.enabled,"RIGHT"}, {18, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
++ slot.count = new("EditControl"):EditControl({"LEFT",slot.enabled,"RIGHT"}, {18, 0, 60, 20}, nil, nil, "%D", 2, function(buf)
+ local gemInstance = self.displayGroup.gemList[index]
+ if not gemInstance then
+ gemInstance = { nameSpec = "", level = self.defaultGemLevel or 20, quality = self.defaultGemQuality or 0, enabled = true, enableGlobal1 = true, count = 1, new = true }
+@@ -1005,14 +1010,14 @@ function SkillsTabClass:CreateGemSlot(index)
+ self.controls["gemSlot"..index.."Count"] = slot.count
+
+ -- Parser/calculator error message
+- slot.errMsg = new("LabelControl", {"LEFT",slot.count,"RIGHT"}, {2, 2, 0, 16}, function()
++ slot.errMsg = new("LabelControl"):LabelControl({"LEFT",slot.count,"RIGHT"}, {2, 2, 0, 16}, function()
+ local gemInstance = self.displayGroup and self.displayGroup.gemList[index]
+ return "^1"..(gemInstance and gemInstance.errMsg or "")
+ end)
+ self.controls["gemSlot"..index.."ErrMsg"] = slot.errMsg
+
+ -- Enable global-effect skill 1
+- slot.enableGlobal1 = new("CheckBoxControl", {"TOPLEFT",slot.delete,"BOTTOMLEFT"}, {0, 2, 20}, "", function(state)
++ slot.enableGlobal1 = new("CheckBoxControl"):CheckBoxControl({"TOPLEFT",slot.delete,"BOTTOMLEFT"}, {0, 2, 20}, "", function(state)
+ local gemInstance = self.displayGroup.gemList[index]
+ gemInstance.enableGlobal1 = state
+ self:AddUndoState()
diff --git a/src/Classes/SliderControl.lua b/src/Classes/SliderControl.lua
index 2c3048de48..89dba3e1fc 100644
--- a/src/Classes/SliderControl.lua
+++ b/src/Classes/SliderControl.lua
@@ -7,14 +7,18 @@ local m_min = math.min
local m_max = math.max
local m_ceil = math.ceil
-local SliderClass = newClass("SliderControl", "Control", "TooltipHost", function(self, anchor, rect, changeFunc, scrollWheelSpeedTbl)
- self.Control(anchor, rect)
- self.TooltipHost()
+---@class SliderControl: Control, TooltipHost
+local SliderClass = newClass("SliderControl", "Control", "TooltipHost")
+
+function SliderClass:SliderControl(anchor, rect, changeFunc, scrollWheelSpeedTbl)
+ self:Control(anchor, rect)
+ self:TooltipHost()
self.knobSize = self.height - 2
self.val = 0
self.changeFunc = changeFunc
self.scrollWheelSpeedTbl = scrollWheelSpeedTbl or { ["SHIFT"] = 0.25, ["CTRL"] = 0.01, ["DEFAULT"] = 0.05 }
-end)
+ return self
+end
function SliderClass:IsMouseOver()
if not self:IsShown() then
diff --git a/src/Classes/TextListControl.lua b/src/Classes/TextListControl.lua
index 7302a153b9..b9c7f726d5 100644
--- a/src/Classes/TextListControl.lua
+++ b/src/Classes/TextListControl.lua
@@ -3,10 +3,13 @@
-- Class: Text List
-- Simple list control for displaying a block of text
--
-local TextListClass = newClass("TextListControl", "Control", "ControlHost", function(self, anchor, rect, columns, list, sectionHeights)
- self.Control(anchor, rect)
- self.ControlHost()
- self.controls.scrollBar = new("ScrollBarControl", {"RIGHT",self,"RIGHT"}, {-1, 0, 18, 0}, 40)
+---@class TextListControl: Control, ControlHost
+local TextListClass = newClass("TextListControl", "Control", "ControlHost")
+
+function TextListClass:TextListControl(anchor, rect, columns, list, sectionHeights)
+ self:Control(anchor, rect)
+ self:ControlHost()
+ self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({"RIGHT",self,"RIGHT"}, {-1, 0, 18, 0}, 40)
self.controls.scrollBar.height = function()
local width, height = self:GetSize()
return height - 2
@@ -14,7 +17,8 @@ local TextListClass = newClass("TextListControl", "Control", "ControlHost", func
self.columns = columns or { { x = 0, align = "LEFT" } }
self.list = list or { }
self.sectionHeights = sectionHeights
-end)
+ return self
+end
function TextListClass:IsMouseOver()
if not self:IsShown() then
diff --git a/src/Classes/TimelessJewelListControl.lua b/src/Classes/TimelessJewelListControl.lua
index 5a55490875..131247178c 100644
--- a/src/Classes/TimelessJewelListControl.lua
+++ b/src/Classes/TimelessJewelListControl.lua
@@ -9,13 +9,17 @@ local m_min = math.min
local m_max = math.max
local t_concat = table.concat
-local TimelessJewelListControlClass = newClass("TimelessJewelListControl", "ListControl", function(self, anchor, rect, build)
+---@class TimelessJewelListControl: ListControl
+local TimelessJewelListControlClass = newClass("TimelessJewelListControl", "ListControl")
+
+function TimelessJewelListControlClass:TimelessJewelListControl(anchor, rect, build)
self.build = build
self.sharedList = self.build.timelessData.sharedResults or { }
self.list = self.build.timelessData.searchResults or { }
- self.ListControl(anchor, rect, 16, true, false, self.list)
+ self:ListControl(anchor, rect, 16, true, false, self.list)
self.selIndex = nil
-end)
+ return self
+end
function TimelessJewelListControlClass:Draw(viewPort, noTooltip)
self.noTooltip = noTooltip
@@ -227,7 +231,7 @@ Passives in radius are Conquered by the Templars
Historic
]]
end
- local item = new("Item", itemData)
+ local item = new("Item"):Item(itemData)
self.build.itemsTab:AddItem(item, true)
self.build.itemsTab:PopulateSlots()
self.list[index].label = "^xB2B2B2" .. self.list[index].label
diff --git a/src/Classes/TimelessJewelSocketControl.lua b/src/Classes/TimelessJewelSocketControl.lua
index 7ff6bcf0cf..3e841231df 100644
--- a/src/Classes/TimelessJewelSocketControl.lua
+++ b/src/Classes/TimelessJewelSocketControl.lua
@@ -6,11 +6,15 @@
local m_min = math.min
-local TimelessJewelSocketClass = newClass("TimelessJewelSocketControl", "DropDownControl", function(self, anchor, rect, list, selFunc, build, socketViewer)
- self.DropDownControl(anchor, rect, list, selFunc)
+---@class TimelessJewelSocketControl: DropDownControl
+local TimelessJewelSocketClass = newClass("TimelessJewelSocketControl", "DropDownControl")
+
+function TimelessJewelSocketClass:TimelessJewelSocketControl(anchor, rect, list, selFunc, build, socketViewer)
+ self:DropDownControl(anchor, rect, list, selFunc)
self.build = build
self.socketViewer = socketViewer
-end)
+ return self
+end
function TimelessJewelSocketClass:Draw(viewPort, noTooltip)
local x, y = self:GetPos()
diff --git a/src/Classes/Tooltip.lua.rej b/src/Classes/Tooltip.lua.rej
new file mode 100644
index 0000000000..fa600476a5
--- /dev/null
+++ b/src/Classes/Tooltip.lua.rej
@@ -0,0 +1,20 @@
+diff a/src/Classes/Tooltip.lua b/src/Classes/Tooltip.lua (rejected hunks)
+@@ -40,12 +40,16 @@ for _, recipeName in pairs(recipeNames) do
+ recipeImages[recipeName]:Load("TreeData/" .. recipeName .. ".png", "CLAMP")
+ end
+
+-local TooltipClass = newClass("Tooltip", function(self)
++---@class Tooltip
++local TooltipClass = newClass("Tooltip")
++
++function TooltipClass:Tooltip()
+ self.lines = { }
+ self.blocks = { }
+ self.childTooltips = nil
+ self:Clear()
+-end)
++ return self
++end
+
+ function TooltipClass:Clear(clearUpdateParams)
+ wipeTable(self.lines)
diff --git a/src/Classes/TooltipHost.lua b/src/Classes/TooltipHost.lua
index bd8db5231d..42a9c3e0e9 100644
--- a/src/Classes/TooltipHost.lua
+++ b/src/Classes/TooltipHost.lua
@@ -3,10 +3,14 @@
-- Class: Tooltip Host
-- Tooltip host
--
-local TooltipHostClass = newClass("TooltipHost", function(self, tooltipText)
- self.tooltip = new("Tooltip")
+---@class TooltipHost
+local TooltipHostClass = newClass("TooltipHost")
+
+function TooltipHostClass:TooltipHost(tooltipText)
+ self.tooltip = new("Tooltip"):Tooltip()
self.tooltipText = tooltipText
-end)
+ return self
+end
function TooltipHostClass:DrawTooltip(x, y, width, height, viewPort, ...)
if self.tooltipFunc then
diff --git a/src/Classes/TradeHelpers.lua b/src/Classes/TradeHelpers.lua
index 5057fe0b26..1891bc5e0e 100644
--- a/src/Classes/TradeHelpers.lua
+++ b/src/Classes/TradeHelpers.lua
@@ -526,7 +526,7 @@ end
-- with a preset changeFunc intended for mod values
function M.newPlainNumericEdit(anchor, rect, init, prompt, limit, integer, changeFunc)
local format = integer and "%D" or "^%d."
- local ctrl = new("EditControl", anchor, rect, init, prompt, format, limit, changeFunc)
+ local ctrl = new("EditControl"):EditControl(anchor, rect, init, prompt, format, limit, changeFunc)
-- Remove the +/- spinner buttons that "%D" filter triggers
ctrl.isNumeric = false
if ctrl.controls then
diff --git a/src/Classes/TradeQuery.lua b/src/Classes/TradeQuery.lua
index 261457739e..1382edf04d 100644
--- a/src/Classes/TradeQuery.lua
+++ b/src/Classes/TradeQuery.lua
@@ -198,7 +198,7 @@ end
-- Opens the item pricing popup
function TradeQueryClass:PriceItem()
- self.tradeQueryGenerator = new("TradeQueryGenerator", self)
+ self.tradeQueryGenerator = new("TradeQueryGenerator"):TradeQueryGenerator(self)
main.onFrameFuncs["TradeQueryGenerator"] = function()
self.tradeQueryGenerator:OnFrame()
end
@@ -215,7 +215,7 @@ function TradeQueryClass:PriceItem()
local itemSet = self.itemsTab.itemSets[itemSetId]
t_insert(newItemList, itemSet.title or "Default")
end
- self.controls.setSelect = new("DropDownControl", {"TOPLEFT", nil, "TOPLEFT"}, {pane_margins_horizontal, pane_margins_vertical, 188, row_height}, newItemList, function(index, value)
+ self.controls.setSelect = new("DropDownControl"):DropDownControl({"TOPLEFT", nil, "TOPLEFT"}, {pane_margins_horizontal, pane_margins_vertical, 188, row_height}, newItemList, function(index, value)
self.itemsTab:SetActiveItemSet(self.itemsTab.itemSetOrderList[index])
self.itemsTab:AddUndoState()
end)
@@ -312,7 +312,7 @@ on trade site to work on other leagues and realms)]]
-- Fetches Box
self.maxFetchPerSearchDefault = 2
- self.controls.fetchCountEdit = new("EditControl", {"TOPRIGHT", nil, "TOPRIGHT"}, {-12, 19, 150, row_height}, "", "Fetch Pages", "%D", 3, function(buf)
+ self.controls.fetchCountEdit = new("EditControl"):EditControl({"TOPRIGHT", nil, "TOPRIGHT"}, {-12, 19, 150, row_height}, "", "Fetch Pages", "%D", 3, function(buf)
self.maxFetchPages = m_min(m_max(tonumber(buf) or self.maxFetchPerSearchDefault, 1), 10)
self.tradeQueryRequests.maxFetchPerSearch = 10 * self.maxFetchPages
self.controls.fetchCountEdit.focusValue = self.maxFetchPages
@@ -336,7 +336,7 @@ on trade site to work on other leagues and realms)]]
self.statSortSelectionList = { }
initStatSortSelectionList(self.statSortSelectionList)
end
- self.controls.StatWeightMultipliersButton = new("ButtonControl", {"TOPRIGHT", self.controls.fetchCountEdit, "BOTTOMRIGHT"}, {0, row_vertical_padding, 150, row_height}, "^7Adjust search weights", function()
+ self.controls.StatWeightMultipliersButton = new("ButtonControl"):ButtonControl({"TOPRIGHT", self.controls.fetchCountEdit, "BOTTOMRIGHT"}, {0, row_vertical_padding, 150, row_height}, "^7Adjust search weights", function()
self.itemsTab.modFlag = true
self:SetStatWeights()
end)
@@ -361,7 +361,7 @@ on trade site to work on other leagues and realms)]]
self.sortModes.Price,
self.sortModes.Weight,
}
- self.controls.itemSortSelection = new("DropDownControl", {"TOPRIGHT", self.controls.StatWeightMultipliersButton, "TOPLEFT"}, {-8, 0, 170, row_height}, self.itemSortSelectionList, function(index, value)
+ self.controls.itemSortSelection = new("DropDownControl"):DropDownControl({"TOPRIGHT", self.controls.StatWeightMultipliersButton, "TOPLEFT"}, {-8, 0, 170, row_height}, self.itemSortSelectionList, function(index, value)
self.pbItemSortSelectionIndex = index
for row_idx, _ in pairs(self.resultTbl) do
self:UpdateControlsWithItems(row_idx)
@@ -525,7 +525,7 @@ Highest Weight - Displays the order retrieved from trade]]
end
end
- self.controls.otherTradesLabel = new("LabelControl", top_pane_alignment_ref, {0, (#slotTables+1)*(row_height + row_vertical_padding), 100, 16}, "^8Other trades:")
+ self.controls.otherTradesLabel = new("LabelControl"):LabelControl(top_pane_alignment_ref, {0, (#slotTables+1)*(row_height + row_vertical_padding), 100, 16}, "^8Other trades:")
self.controls.otherTradesLabel.shown = function()
return hideRowFunc(self, #slotTables+1)
end
@@ -630,7 +630,7 @@ function TradeQueryClass:SetStatWeights(previousSelectionList)
-- account for top gap, bottom button size and gap, and a gap before buttons
local listHeight = popupHeight - 45 - 30 - 10
- controls.ListControl = new("TradeStatWeightMultiplierListControl", { "TOPLEFT", nil, "TOPRIGHT" },
+ controls.ListControl = new("TradeStatWeightMultiplierListControl"):TradeStatWeightMultiplierListControl({ "TOPLEFT", nil, "TOPRIGHT" },
{ -410, 45, 400, listHeight }, statList, sliderController)
for _, stat in ipairs(data.powerStatList) do
@@ -647,8 +647,8 @@ function TradeQueryClass:SetStatWeights(previousSelectionList)
end
end
- controls.SliderLabel = new("LabelControl", { "TOPLEFT", nil, "TOPRIGHT" }, {-410, 20, 0, 16}, "^7"..statList[1].stat.label..":")
- controls.Slider = new("SliderControl", { "TOPLEFT", controls.SliderLabel, "TOPRIGHT" }, {20, 0, 150, 16}, function(value)
+ controls.SliderLabel = new("LabelControl"):LabelControl({ "TOPLEFT", nil, "TOPRIGHT" }, {-410, 20, 0, 16}, "^7"..statList[1].stat.label..":")
+ controls.Slider = new("SliderControl"):SliderControl({ "TOPLEFT", controls.SliderLabel, "TOPRIGHT" }, {20, 0, 150, 16}, function(value)
if value == 0 then
controls.SliderValue.label = "^7Disabled"
statList[sliderController.index].stat.weightMult = 0
@@ -659,7 +659,7 @@ function TradeQueryClass:SetStatWeights(previousSelectionList)
statList[sliderController.index].label = s_format("%.2f : ", 0.01 + value * 0.99)..statList[sliderController.index].stat.label
end
end)
- controls.SliderValue = new("LabelControl", { "TOPLEFT", controls.Slider, "TOPRIGHT" }, {20, 0, 0, 16}, "^7Disabled")
+ controls.SliderValue = new("LabelControl"):LabelControl({ "TOPLEFT", controls.Slider, "TOPRIGHT" }, {20, 0, 0, 16}, "^7Disabled")
controls.Slider.tooltip.realDraw = controls.Slider.tooltip.Draw
controls.Slider.tooltip.Draw = function(self, x, y, width, height, viewPort)
local sliderOffsetX = round(184 * (1 - controls.Slider.val))
@@ -685,7 +685,7 @@ function TradeQueryClass:SetStatWeights(previousSelectionList)
end
end
- controls.finalise = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, {-90, -10, 80, 20}, "Save", function()
+ controls.finalise = new("ButtonControl"):ButtonControl({ "BOTTOM", nil, "BOTTOM" }, {-90, -10, 80, 20}, "Save", function()
main:ClosePopup()
-- used in ItemsTab to save to xml under TradeSearchWeights node
@@ -703,13 +703,13 @@ function TradeQueryClass:SetStatWeights(previousSelectionList)
self:UpdateControlsWithItems(row_idx)
end
end)
- controls.cancel = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, { 0, -10, 80, 20 }, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl({ "BOTTOM", nil, "BOTTOM" }, { 0, -10, 80, 20 }, "Cancel", function()
if previousSelectionList and #previousSelectionList > 0 then
self.statSortSelectionList = copyTable(previousSelectionList, true)
end
main:ClosePopup()
end)
- controls.reset = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, { 90, -10, 80, 20 }, "Reset", function()
+ controls.reset = new("ButtonControl"):ButtonControl({ "BOTTOM", nil, "BOTTOM" }, { 90, -10, 80, 20 }, "Reset", function()
local previousSelection = { }
if isSameAsDefaultList(self.statSortSelectionList) then
previousSelection = copyTable(previousSelectionList, true)
@@ -846,7 +846,7 @@ function TradeQueryClass:UpdateDropdownList(row_idx)
local pb_index = self.sortedResultTbl[row_idx][result_index].index
local result = self.resultTbl[row_idx][pb_index]
local price = string.format(" %s(%d %s)", colorCodes["CURRENCY"], result.amount, result.currency)
- local item = new("Item", result.item_string)
+ local item = new("Item"):Item(result.item_string)
table.insert(dropdownLabels, colorCodes[item.rarity] .. item.name .. price)
end
self.controls["resultDropdown".. row_idx].selIndex = 1
@@ -985,7 +985,7 @@ end
function TradeQueryClass:FilterToSafeItems(itemEntries, slotName)
local itemsSafe = {}
for _, entry in ipairs(itemEntries) do
- local item = new("Item", entry.item_string)
+ local item = new("Item"):Item(entry.item_string)
if item.base and ((not slotName) or self.itemsTab:IsItemValidForSlot(item, slotName)) then
t_insert(itemsSafe, entry)
end
@@ -1187,14 +1187,14 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite
if not result then
return
end
- local item = new("Item", result.item_string)
+ local item = new("Item"):Item(result.item_string)
tooltip:Clear()
local tooltipSlot = slotTbl.selectedJewelNodeId and self.itemsTab.sockets[slotTbl.selectedJewelNodeId] or activeSlot
self.itemsTab:AddItemTooltip(tooltip, item, tooltipSlot)
tooltip:AddSeparator(10)
tooltip:AddLine(16, string.format("^7Price: %s %s", result.amount, result.currency))
end
- controls["importButton"..row_idx] = new("ButtonControl", { "TOPLEFT", controls["resultDropdown"..row_idx], "TOPRIGHT"}, {8, 0, 100, row_height}, "Import Item", function()
+ controls["importButton"..row_idx] = new("ButtonControl"):ButtonControl({ "TOPLEFT", controls["resultDropdown"..row_idx], "TOPRIGHT"}, {8, 0, 100, row_height}, "Import Item", function()
self.itemsTab:CreateDisplayItemFromRaw(self.resultTbl[row_idx][self.itemIndexTbl[row_idx]].item_string)
local item = self.itemsTab.displayItem
-- pass "true" to not auto equip it as we will have our own logic
@@ -1226,8 +1226,7 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite
return self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]].item_string ~= nil
end
-- Whisper so we can copy to clipboard
- controls["whisperButton" .. row_idx] = new("ButtonControl",
- { "TOPLEFT", controls["importButton" .. row_idx], "TOPRIGHT" }, { 8, 0, 155, row_height }, function()
+ controls["whisperButton" .. row_idx] = new("ButtonControl"):ButtonControl({ "TOPLEFT", controls["importButton" .. row_idx], "TOPRIGHT" }, { 8, 0, 155, row_height }, function()
local itemResult = self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]]
if not itemResult then return "" end
diff --git a/src/Classes/TradeQuery.lua.rej b/src/Classes/TradeQuery.lua.rej
new file mode 100644
index 0000000000..3dba05f3f7
--- /dev/null
+++ b/src/Classes/TradeQuery.lua.rej
@@ -0,0 +1,176 @@
+diff a/src/Classes/TradeQuery.lua b/src/Classes/TradeQuery.lua (rejected hunks)
+@@ -19,7 +19,10 @@ local s_format = string.format
+
+ local baseSlots = { "Weapon 1", "Weapon 2", "Weapon 1 Swap", "Weapon 2 Swap", "Helmet", "Body Armour", "Gloves", "Boots", "Amulet", "Ring 1", "Ring 2", "Ring 3", "Belt", "Flask 1", "Flask 2", "Flask 3", "Flask 4", "Flask 5" }
+
+-local TradeQueryClass = newClass("TradeQuery", function(self, itemsTab)
++---@class TradeQuery
++local TradeQueryClass = newClass("TradeQuery")
++
++function TradeQueryClass:TradeQuery(itemsTab)
+ self.itemsTab = itemsTab
+ self.itemsTab.leagueDropList = { }
+ self.totalPrice = { }
+@@ -56,15 +59,16 @@ local TradeQueryClass = newClass("TradeQuery", function(self, itemsTab)
+ -- last query for each row
+ self.lastQueries = {}
+
+- self.tradeQueryRequests = new("TradeQueryRequests")
++ self.tradeQueryRequests = new("TradeQueryRequests"):TradeQueryRequests()
+ if not main.api then
+- main.api = new("PoEAPI", main.lastToken, main.lastRefreshToken, main.tokenExpiry)
++ main.api = new("PoEAPI"):PoEAPI(main.lastToken, main.lastRefreshToken, main.tokenExpiry)
+ end
+
+ self.hostName = "https://www.pathofexile.com/"
+ -- www. optional
+ self.hostNamePattern = "h?t?t?p?s?:?/?/?w?w?w?%.?pathofexile%.com/"
+-end)
++ return self
++end
+
+
+
+@@ -323,7 +327,7 @@ function TradeQueryClass:PriceItem()
+ end
+ end)
+ end
+- self.controls.tradeAuthButton = new("ButtonControl", {"TOPLEFT", self.controls.setSelect, "TOPLEFT"}, {0, row_height + row_vertical_padding, 188, row_height}, self.loginStatus, function()
++ self.controls.tradeAuthButton = new("ButtonControl"):ButtonControl({"TOPLEFT", self.controls.setSelect, "TOPLEFT"}, {0, row_height + row_vertical_padding, 188, row_height}, self.loginStatus, function()
+ -- LOGIN
+ if not main.api.authToken then
+ main.api:FetchAuthToken(function()
+@@ -378,7 +382,7 @@ on trade site to work on other leagues and realms)]]
+ "Any (includes offline)"
+ }
+
+- self.controls.tradeTypeSelection = new("DropDownControl", { "TOPLEFT", self.controls.tradeAuthButton, "BOTTOMLEFT" },
++ self.controls.tradeTypeSelection = new("DropDownControl"):DropDownControl({ "TOPLEFT", self.controls.tradeAuthButton, "BOTTOMLEFT" },
+ { 0, row_vertical_padding, 188, row_height }, self.tradeTypes, function(index, value)
+ self.tradeTypeIndex = index
+ end)
+@@ -451,11 +455,11 @@ Lowest Price - Sorts from lowest to highest price of retrieved items
+ Highest Weight - Displays the order retrieved from trade]]
+ -- avoid calling selFunc to avoid updating controls before they are initialised
+ self.controls.itemSortSelection:SetSel(self.pbItemSortSelectionIndex, true)
+- self.controls.itemSortSelectionLabel = new("LabelControl", {"TOPRIGHT", self.controls.itemSortSelection, "TOPLEFT"}, {-4, 0, 56, 16}, "^7Sort By:")
++ self.controls.itemSortSelectionLabel = new("LabelControl"):LabelControl({"TOPRIGHT", self.controls.itemSortSelection, "TOPLEFT"}, {-4, 0, 56, 16}, "^7Sort By:")
+
+ -- Realm selection
+- self.controls.realmLabel = new("LabelControl", {"LEFT", self.controls.setSelect, "RIGHT"}, {18, 0, 20, row_height - 4}, "^7Realm:")
+- self.controls.realm = new("DropDownControl", {"LEFT", self.controls.realmLabel, "RIGHT"}, {6, 0, 150, row_height}, self.realmDropList, function(index, value)
++ self.controls.realmLabel = new("LabelControl"):LabelControl({"LEFT", self.controls.setSelect, "RIGHT"}, {18, 0, 20, row_height - 4}, "^7Realm:")
++ self.controls.realm = new("DropDownControl"):DropDownControl({"LEFT", self.controls.realmLabel, "RIGHT"}, {6, 0, 150, row_height}, self.realmDropList, function(index, value)
+ self.pbRealmIndex = index
+ if self.pbRealm ~= self.realmIds[value] then
+ self.pbRealm = self.realmIds[value]
+@@ -497,8 +501,8 @@ Highest Weight - Displays the order retrieved from trade]]
+ end
+
+ -- League selection
+- self.controls.leagueLabel = new("LabelControl", {"TOPRIGHT", self.controls.realmLabel, "TOPRIGHT"}, {0, row_height + row_vertical_padding, 20, row_height - 4}, "^7League:")
+- self.controls.league = new("DropDownControl", {"LEFT", self.controls.leagueLabel, "RIGHT"}, {6, 0, 150, row_height}, self.itemsTab.leagueDropList, function(index, value)
++ self.controls.leagueLabel = new("LabelControl"):LabelControl({"TOPRIGHT", self.controls.realmLabel, "TOPRIGHT"}, {0, row_height + row_vertical_padding, 20, row_height - 4}, "^7League:")
++ self.controls.league = new("DropDownControl"):DropDownControl({"LEFT", self.controls.leagueLabel, "RIGHT"}, {6, 0, 150, row_height}, self.itemsTab.leagueDropList, function(index, value)
+ self.pbLeagueIndex = index
+ self.pbLeague = value
+ end)
+@@ -554,7 +558,7 @@ Highest Weight - Displays the order retrieved from trade]]
+ t_insert(slotTables, { slotName = self.itemsTab.sockets[nodeId].label, nodeId = nodeId })
+ end
+
+- self.controls.sectionAnchor = new("LabelControl", {"LEFT", self.controls.tradeTypeSelection, "LEFT"}, {0, row_vertical_padding, 0, 0}, "")
++ self.controls.sectionAnchor = new("LabelControl"):LabelControl({"LEFT", self.controls.tradeTypeSelection, "LEFT"}, {0, row_vertical_padding, 0, 0}, "")
+ top_pane_alignment_ref = {"TOPLEFT", self.controls.sectionAnchor, "TOPLEFT"}
+ local scrollBarShown = #slotTables > 21 -- clipping starts beyond this
+ -- dynamically hide rows that are above or below the scrollBar
+@@ -615,15 +619,15 @@ Highest Weight - Displays the order retrieved from trade]]
+ self.pane_height = (row_height + row_vertical_padding) * effective_row_count + 3 * pane_margins_vertical + row_height / 2
+ local pane_width = 885 + (scrollBarShown and 25 or 0)
+
+- self.controls.scrollBar = new("ScrollBarControl", {"TOPRIGHT", self.controls["StatWeightMultipliersButton"],"TOPRIGHT"}, {0, 25, 18, 0}, 50, "VERTICAL", false)
++ self.controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({"TOPRIGHT", self.controls["StatWeightMultipliersButton"],"TOPRIGHT"}, {0, 25, 18, 0}, 50, "VERTICAL", false)
+ self.controls.scrollBar.shown = function() return scrollBarShown end
+
+- self.controls.fullPrice = new("LabelControl", {"BOTTOM", nil, "BOTTOM"}, {0, -row_height - pane_margins_vertical - row_vertical_padding, pane_width - 2 * pane_margins_horizontal, row_height}, "")
+- self.controls.close = new("ButtonControl", {"BOTTOM", nil, "BOTTOM"}, {0, -pane_margins_vertical, 90, row_height}, "Done", function()
++ self.controls.fullPrice = new("LabelControl"):LabelControl({"BOTTOM", nil, "BOTTOM"}, {0, -row_height - pane_margins_vertical - row_vertical_padding, pane_width - 2 * pane_margins_horizontal, row_height}, "")
++ self.controls.close = new("ButtonControl"):ButtonControl({"BOTTOM", nil, "BOTTOM"}, {0, -pane_margins_vertical, 90, row_height}, "Done", function()
+ main:ClosePopup()
+ end)
+
+- self.controls.pbNotice = new("LabelControl", {"BOTTOMRIGHT", nil, "BOTTOMRIGHT"}, {-row_height - pane_margins_vertical - row_vertical_padding, -pane_margins_vertical, 300, row_height}, "")
++ self.controls.pbNotice = new("LabelControl"):LabelControl({"BOTTOMRIGHT", nil, "BOTTOMRIGHT"}, {-row_height - pane_margins_vertical - row_vertical_padding, -pane_margins_vertical, 300, row_height}, "")
+
+ -- used in PopupDialog:Draw()
+ local function scrollBarFunc()
+@@ -835,7 +839,7 @@ function TradeQueryClass:GetResultEvaluation(row_idx, result_index, calcFunc, ba
+ }
+ table.sort(result.evaluation, function(a, b) return a.weight > b.weight end)
+ else
+- local item = new("Item", result.item_string)
++ local item = new("Item"):Item(result.item_string)
+
+ local output = self:ReduceOutput(calcFunc({ repSlotName = slotName, repItem = item }))
+ local weight = self.tradeQueryGenerator.WeightedRatioOutputs(baseOutput, output, self.statSortSelectionList)
+@@ -1015,8 +1019,8 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
+ return selectedNodeId and self.itemsTab.sockets[selectedNodeId] or activeSlot
+ end
+ local nameColor = slotTbl.unique and colorCodes.UNIQUE or "^7"
+- controls["name" .. row_idx] = new("LabelControl", top_pane_alignment_ref, { 0, row_idx * (row_height + row_vertical_padding), 135, row_height - 4 }, nameColor .. slotTbl.slotName)
+- controls["bestButton" .. row_idx] = new("ButtonControl", { "LEFT", controls["name" .. row_idx], "LEFT" }, { 135 + 8, 0, 80, row_height }, "Find best", function()
++ controls["name" .. row_idx] = new("LabelControl"):LabelControl(top_pane_alignment_ref, { 0, row_idx * (row_height + row_vertical_padding), 135, row_height - 4 }, nameColor .. slotTbl.slotName)
++ controls["bestButton" .. row_idx] = new("ButtonControl"):ButtonControl({ "LEFT", controls["name" .. row_idx], "LEFT" }, { 135 + 8, 0, 80, row_height }, "Find best", function()
+ self.tradeQueryGenerator:RequestQuery(activeSlot, { slotTbl = slotTbl, controls = controls, row_idx = row_idx }, self.statSortSelectionList, function(context, query, errMsg)
+ if errMsg then
+ self:SetNotice(context.controls.pbNotice, colorCodes.NEGATIVE .. errMsg)
+@@ -1047,7 +1051,7 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
+ -- replace eldritch mods or enchants if the user requested
+ -- so in TradeQueryGenerator
+ for i, _ in ipairs(itemsSafe) do
+- local item = new("Item", itemsSafe[i].item_string)
++ local item = new("Item"):Item(itemsSafe[i].item_string)
+ -- assume the user will add quality if they buy the item
+ item:NormaliseQuality()
+ if self.tradeQueryGenerator.lastIncludeEldritch == "Copy Current" or
+@@ -1095,7 +1099,7 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite
+ itemSlotHelper.DrawViewer(self.itemsTab, nodeId, viewerX, viewerY, boxSize, boxSize)
+ end
+ local pbURL
+- controls["uri"..row_idx] = new("EditControl", { "TOPLEFT", controls["bestButton"..row_idx], "TOPRIGHT"}, {8, 0, 514, row_height}, nil, nil, "^%C\t\n", nil, function(buf)
++ controls["uri"..row_idx] = new("EditControl"):EditControl({ "TOPLEFT", controls["bestButton"..row_idx], "TOPRIGHT"}, {8, 0, 514, row_height}, nil, nil, "^%C\t\n", nil, function(buf)
+ local subpath = buf:match(self.hostNamePattern .. "trade/search/(.+)$") or ""
+ local paths = {}
+ for path in subpath:gmatch("[^/]+") do
+@@ -1122,7 +1126,7 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite
+ tooltip:AddLine(16, "Control + click to open in web-browser")
+ end
+ end
+- controls["priceButton"..row_idx] = new("ButtonControl", { "TOPLEFT", controls["uri"..row_idx], "TOPRIGHT"}, {8, 0, 100, row_height}, "Price Item",
++ controls["priceButton"..row_idx] = new("ButtonControl"):ButtonControl({ "TOPLEFT", controls["uri"..row_idx], "TOPRIGHT"}, {8, 0, 100, row_height}, "Price Item",
+ function()
+ controls["priceButton"..row_idx].label = "Searching..."
+ local url = controls["uri" .. row_idx].buf
+@@ -1164,11 +1168,11 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite
+ local clampItemIndex = function(index)
+ return m_min(m_max(index or 1, 1), self.sortedResultTbl[row_idx] and #self.sortedResultTbl[row_idx] or 1)
+ end
+- controls["changeButton" .. row_idx] = new("ButtonControl", { "LEFT", controls["name" .. row_idx], "LEFT" }, { 135 + 8, 0, 80, row_height }, "<< Search", function()
++ controls["changeButton" .. row_idx] = new("ButtonControl"):ButtonControl({ "LEFT", controls["name" .. row_idx], "LEFT" }, { 135 + 8, 0, 80, row_height }, "<< Search", function()
+ self:ResetResultRow(row_idx)
+ end)
+ controls["changeButton"..row_idx].shown = function() return self.resultTbl[row_idx] end
+- controls["resultDropdown" .. row_idx] = new("DropDownControl", { "TOPLEFT", controls["changeButton" .. row_idx], "TOPRIGHT" }, { 8, 0, 351, row_height }, {}, function(index)
++ controls["resultDropdown" .. row_idx] = new("DropDownControl"):DropDownControl({ "TOPLEFT", controls["changeButton" .. row_idx], "TOPRIGHT" }, { 8, 0, 351, row_height }, {}, function(index)
+ self.itemIndexTbl[row_idx] = self.sortedResultTbl[row_idx][index].index
+ self:SetFetchResultReturn(row_idx, self.itemIndexTbl[row_idx])
+ end)
+@@ -1225,7 +1229,7 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite
+ local selected_result_index = self.itemIndexTbl[row_idx]
+ local item_string = self.resultTbl[row_idx][selected_result_index].item_string
+ if selected_result_index and item_string then
+- local item = new("Item", item_string)
++ local item = new("Item"):Item(item_string)
+ local tooltipSlot = slotTbl.selectedJewelNodeId and self.itemsTab.sockets[slotTbl.selectedJewelNodeId] or activeSlot
+ self.itemsTab:AddItemTooltip(tooltip, item, tooltipSlot, true)
+ addMegalomaniacCompareToTooltipIfApplicable(tooltip, selected_result_index)
diff --git a/src/Classes/TradeQueryGenerator.lua b/src/Classes/TradeQueryGenerator.lua
index 415a668a0f..cb26c1a21c 100644
--- a/src/Classes/TradeQueryGenerator.lua
+++ b/src/Classes/TradeQueryGenerator.lua
@@ -111,7 +111,10 @@ local function logToFile(...)
ConPrintf(...)
end
-local TradeQueryGeneratorClass = newClass("TradeQueryGenerator", function(self, queryTab)
+---@class TradeQueryGenerator
+local TradeQueryGeneratorClass = newClass("TradeQueryGenerator")
+
+function TradeQueryGeneratorClass:TradeQueryGenerator(queryTab)
self:InitMods()
self.queryTab = queryTab
self.itemsTab = queryTab.itemsTab
@@ -868,7 +871,7 @@ Implicits: 0]]
-- Open progress tracking blocker popup
local controls = { }
- controls.progressText = new("LabelControl", {"TOP",nil,"TOP"}, {0, 30, 0, 16}, string.format("Calculating Mod Weights..."))
+ controls.progressText = new("LabelControl"):LabelControl({"TOP",nil,"TOP"}, {0, 30, 0, 16}, string.format("Calculating Mod Weights..."))
self.calcContext.popup = main:OpenPopup(280, 65, "Please Wait", controls)
end
@@ -1332,7 +1335,7 @@ Remove: anoints are completely ignored, and removed from items.]]
local _, lastItemY = lastItemAnchor:GetPos()
local _, lastItemH = lastItemAnchor:GetSize()
- controls.modSelectorHeaderAnchor = new("Control", { "TOPLEFT", nil, "TOPLEFT" },
+ controls.modSelectorHeaderAnchor = new("Control"):Control({ "TOPLEFT", nil, "TOPLEFT" },
-- position right below last item, centered horizontally
{ (popupWidth - totalWidth) / 2, lastItemH + lastItemY, 0, 0 },
"")
@@ -1390,7 +1393,7 @@ Remove: anoints are completely ignored, and removed from items.]]
-- mod filter dropdown and aux controls
for i = 1, maxSelectors do
-- dropdown which lists all mods that fit
- local dropdown = new("DropDownControl", { "TOPLEFT", lastItemAnchor, "BOTTOMLEFT" },
+ local dropdown = new("DropDownControl"):DropDownControl({ "TOPLEFT", lastItemAnchor, "BOTTOMLEFT" },
{ 0, 4, totalWidth, 20 }, nil,
function(idx, val)
if idx == 1 then
@@ -1418,7 +1421,7 @@ Remove: anoints are completely ignored, and removed from items.]]
controls["modSelectorMin" .. i] = minimumBox
-- button which removes the mod row
- local clearButton = new("ButtonControl", { "LEFT", minimumBox, "RIGHT" }, { xSpacing, 0, buttonSize, buttonSize },
+ local clearButton = new("ButtonControl"):ButtonControl({ "LEFT", minimumBox, "RIGHT" }, { xSpacing, 0, buttonSize, buttonSize },
"x", function()
table.remove(selectedMods, i)
setModSelectors(controls)
diff --git a/src/Classes/TradeQueryGenerator.lua.rej b/src/Classes/TradeQueryGenerator.lua.rej
new file mode 100644
index 0000000000..59cbc99fd6
--- /dev/null
+++ b/src/Classes/TradeQueryGenerator.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Classes/TradeQueryGenerator.lua b/src/Classes/TradeQueryGenerator.lua (rejected hunks)
+@@ -83,7 +83,7 @@ local function canModSpawnForItemCategory(mod, category)
+ end
+ end
+ -- mock item
+- local itemClass = new("Item")
++ local itemClass = new("Item"):Item()
+ local itemObj = {}
+ -- add all influences to fake item
+ for _, curInfluenceInfo in ipairs(itemLib.influenceInfo.all) do
diff --git a/src/Classes/TradeQueryRateLimiter.lua b/src/Classes/TradeQueryRateLimiter.lua
index c96b5c9068..896b86cc8c 100644
--- a/src/Classes/TradeQueryRateLimiter.lua
+++ b/src/Classes/TradeQueryRateLimiter.lua
@@ -6,7 +6,9 @@
--
---@class TradeQueryRateLimiter
-local TradeQueryRateLimiterClass = newClass("TradeQueryRateLimiter", function(self)
+local TradeQueryRateLimiterClass = newClass("TradeQueryRateLimiter")
+
+function TradeQueryRateLimiterClass:TradeQueryRateLimiter()
-- policies_sample = {
-- -- label: policy
-- ["trade-search-request-limit"] = {
diff --git a/src/Classes/TradeQueryRateLimiter.lua.rej b/src/Classes/TradeQueryRateLimiter.lua.rej
new file mode 100644
index 0000000000..2237082e9e
--- /dev/null
+++ b/src/Classes/TradeQueryRateLimiter.lua.rej
@@ -0,0 +1,11 @@
+diff a/src/Classes/TradeQueryRateLimiter.lua b/src/Classes/TradeQueryRateLimiter.lua (rejected hunks)
+@@ -56,7 +58,8 @@ local TradeQueryRateLimiterClass = newClass("TradeQueryRateLimiter", function(se
+ ["character-list-request-limit"] = {},
+ ["character-request-limit"] = {}
+ }
+-end)
++ return self
++end
+
+ function TradeQueryRateLimiterClass:GetPolicyName(key)
+ return self.policyNames[key]
diff --git a/src/Classes/TradeQueryRequests.lua.rej b/src/Classes/TradeQueryRequests.lua.rej
new file mode 100644
index 0000000000..742e002c9c
--- /dev/null
+++ b/src/Classes/TradeQueryRequests.lua.rej
@@ -0,0 +1,25 @@
+diff a/src/Classes/TradeQueryRequests.lua b/src/Classes/TradeQueryRequests.lua (rejected hunks)
+@@ -8,17 +8,19 @@ local dkjson = require "dkjson"
+ local utils = LoadModule("Modules/Utils")
+
+ ---@class TradeQueryRequests
+-local TradeQueryRequestsClass = newClass("TradeQueryRequests", function(self, rateLimiter)
++local TradeQueryRequestsClass = newClass("TradeQueryRequests")
++
++function TradeQueryRequestsClass:TradeQueryRequests(rateLimiter)
+ self.maxFetchPerSearch = 10
+- self.tradeQuery = tradeQuery
+- self.rateLimiter = rateLimiter or new("TradeQueryRateLimiter")
++ self.rateLimiter = rateLimiter or new("TradeQueryRateLimiter"):TradeQueryRateLimiter()
+ self.requestQueue = {
+ ["search"] = {},
+ ["fetch"] = {},
+ }
+ self.hostName = "https://www.pathofexile.com/"
+ self.hostNamePattern = "h?t?t?p?s?:?/?/?w?w?w?%.?pathofexile%.com/"
+-end)
++ return self
++end
+
+ ---Main routine for processing request queue
+ --- @param onRateLimit fun(integer)?
diff --git a/src/Classes/TradeStatWeightMultiplierListControl.lua b/src/Classes/TradeStatWeightMultiplierListControl.lua
index f0260d89de..3be20855b1 100644
--- a/src/Classes/TradeStatWeightMultiplierListControl.lua
+++ b/src/Classes/TradeStatWeightMultiplierListControl.lua
@@ -4,12 +4,16 @@
-- Specialized UI element for listing and modifying Trade Stat Weight Multipliers.
--
-local TradeStatWeightMultiplierListControlClass = newClass("TradeStatWeightMultiplierListControl", "ListControl", function(self, anchor, rect, list, indexController)
+---@class TradeStatWeightMultiplierListControl: ListControl
+local TradeStatWeightMultiplierListControlClass = newClass("TradeStatWeightMultiplierListControl", "ListControl")
+
+function TradeStatWeightMultiplierListControlClass:TradeStatWeightMultiplierListControl(anchor, rect, list, indexController)
self.list = list
self.indexController = indexController
- self.ListControl(anchor, rect, 16, true, false, self.list)
+ self:ListControl(anchor, rect, 16, true, false, self.list)
self.selIndex = nil
-end)
+ return self
+end
function TradeStatWeightMultiplierListControlClass:Draw(viewPort, noTooltip)
self.noTooltip = noTooltip
diff --git a/src/Classes/TreeTab.lua b/src/Classes/TreeTab.lua
index b6df152ddc..fed700c636 100644
--- a/src/Classes/TreeTab.lua
+++ b/src/Classes/TreeTab.lua
@@ -115,7 +115,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
end
-- Compare checkbox
- self.controls.compareCheck = new("CheckBoxControl", { "LEFT", self.controls.specSelect, "RIGHT" }, { 74, 0, 20 }, "Compare:", function(state)
+ self.controls.compareCheck = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.specSelect, "RIGHT" }, { 74, 0, 20 }, "Compare:", function(state)
self.isComparing = state
self:SetCompareSpec(self.activeCompareSpec)
self.controls.compareSelect.shown = state
@@ -127,7 +127,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
end)
-- Compare tree dropdown
- self.controls.compareSelect = new("DropDownControl", { "LEFT", self.controls.compareCheck, "RIGHT" }, { 8, 0, 190, 20 }, nil, function(index, value)
+ self.controls.compareSelect = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.compareCheck, "RIGHT" }, { 8, 0, 190, 20 }, nil, function(index, value)
if self.specList[index] then
self:SetCompareSpec(index)
else
@@ -177,7 +177,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
self.controls.versionSelect.selIndex = #self.treeVersions
-- Tree Search Textbox
- self.controls.treeSearch = new("EditControl", { "LEFT", self.controls.versionSelect, "RIGHT" }, { 8, 0, main.portraitMode and 200 or 300, 20 }, "", "Search", "%c", 100, function(buf)
+ self.controls.treeSearch = new("EditControl"):EditControl({ "LEFT", self.controls.versionSelect, "RIGHT" }, { 8, 0, main.portraitMode and 200 or 300, 20 }, "", "Search", "%c", 100, function(buf)
self.viewer.searchStr = buf
self.searchFlag = buf ~= self.viewer.searchStrSaved
end, nil, nil, true)
@@ -201,7 +201,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
end)
-- Control for setting max node depth to limit calculation time of the heat map
- self.controls.nodePowerMaxDepthSelect = new("DropDownControl", { "LEFT", self.controls.treeHeatMap, "RIGHT" }, { 8, 0, 55, 20 }, { "All", 5, 10, 15, "Custom" }, function(index, value)
+ self.controls.nodePowerMaxDepthSelect = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.treeHeatMap, "RIGHT" }, { 8, 0, 55, 20 }, { "All", 5, 10, 15, "Custom" }, function(index, value)
-- Show custom value control and resize/move elements
self.isCustomMaxDepth = value == "Custom"
if self.isCustomMaxDepth then
@@ -234,7 +234,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
self.controls.nodePowerMaxDepthSelect.tooltipText = "Limit of Node distance to search (lower = faster)"
-- Control for setting max node depth by custom value
- self.controls.nodePowerMaxDepthCustom = new("EditControl", { "LEFT", self.controls.nodePowerMaxDepthSelect, "RIGHT" }, { 8, 0, 70, 20 }, "0", nil, "%D", nil, function(value)
+ self.controls.nodePowerMaxDepthCustom = new("EditControl"):EditControl({ "LEFT", self.controls.nodePowerMaxDepthSelect, "RIGHT" }, { 8, 0, 70, 20 }, "0", nil, "%D", nil, function(value)
self.build.calcsTab.nodePowerMaxDepth = tonumber(value)
-- If the heat map is shown, recalculate it with new value
@@ -245,7 +245,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
self.controls.nodePowerMaxDepthCustom.shown = false
-- Control for selecting the power stat to sort by (Defense, DPS, etc)
- self.controls.treeHeatMapStatSelect = new("DropDownControl", { "LEFT", self.controls.nodePowerMaxDepthSelect, "RIGHT" }, { 8, 0, 150, 20 }, nil, function(index, value)
+ self.controls.treeHeatMapStatSelect = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.nodePowerMaxDepthSelect, "RIGHT" }, { 8, 0, 150, 20 }, nil, function(index, value)
self:SetPowerCalc(value)
end)
self.controls.treeHeatMap.tooltipText = function()
@@ -261,14 +261,14 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
end
-- Show/Hide Power Report Button
- self.controls.powerReport = new("ButtonControl", { "LEFT", self.controls.treeHeatMapStatSelect, "RIGHT" }, { 8, 0, 150, 20 },
+ self.controls.powerReport = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.treeHeatMapStatSelect, "RIGHT" }, { 8, 0, 150, 20 },
function() return self.controls.powerReportList.shown and "Hide Power Report" or "Show Power Report" end, function()
self.controls.powerReportList.shown = not self.controls.powerReportList.shown
end)
-- Power Report List
local yPos = self.controls.treeHeatMap.y == 0 and self.controls.specSelect.height + 4 or self.controls.specSelect.height * 2 + 8
- self.controls.powerReportList = new("PowerReportListControl", { "TOPLEFT", self.controls.specSelect, "BOTTOMLEFT" }, { 0, yPos, 700, 170 }, function(selectedNode)
+ self.controls.powerReportList = new("PowerReportListControl"):PowerReportListControl({ "TOPLEFT", self.controls.specSelect, "BOTTOMLEFT" }, { 0, yPos, 700, 170 }, function(selectedNode)
-- this code is called by the list control when the user "selects" one of the passives in the list.
-- we use this to set a flag which causes the next Draw() to recenter the passive tree on the desired node.
if selectedNode.x then
@@ -489,7 +489,7 @@ function TreeTabClass:Load(xml, dbFileName)
self.specList = { }
if xml.elem == "Spec" then
-- Import single spec from old build
- self.specList[1] = new("PassiveSpec", self.build, defaultTreeVersion)
+ self.specList[1] = new("PassiveSpec"):PassiveSpec(self.build, defaultTreeVersion)
self.specList[1]:Load(xml, dbFileName)
self.activeSpec = 1
self.build.spec = self.specList[1]
@@ -502,14 +502,14 @@ function TreeTabClass:Load(xml, dbFileName)
main:OpenMessagePopup("Unknown Passive Tree Version", "The build you are trying to load uses an unrecognised version of the passive skill tree.\nYou may need to update the program before loading this build.")
return true
end
- local newSpec = new("PassiveSpec", self.build, node.attrib.treeVersion or defaultTreeVersion)
+ local newSpec = new("PassiveSpec"):PassiveSpec(self.build, node.attrib.treeVersion or defaultTreeVersion)
newSpec:Load(node, dbFileName)
t_insert(self.specList, newSpec)
end
end
end
if not self.specList[1] then
- self.specList[1] = new("PassiveSpec", self.build, latestTreeVersion)
+ self.specList[1] = new("PassiveSpec"):PassiveSpec(self.build, latestTreeVersion)
end
self:SetActiveSpec(tonumber(xml.attrib.activeSpec) or 1)
end
@@ -675,13 +675,13 @@ end
function TreeTabClass:OpenVersionConvertAllPopup(version)
local controls = { }
- controls.warningLabel = new("LabelControl", nil, {0, 20, 0, 16}, "^7Warning: some or all of the passives may be de-allocated due to changes in the tree.\n\n" ..
+ controls.warningLabel = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Warning: some or all of the passives may be de-allocated due to changes in the tree.\n\n" ..
"Convert will replace all trees that are not Version "..treeVersions[version].display..".\nThis action cannot be undone.\n")
- controls.convert = new("ButtonControl", nil, {-58, 105, 100, 20}, "Convert", function()
+ controls.convert = new("ButtonControl"):ButtonControl(nil, {-58, 105, 100, 20}, "Convert", function()
self:ConvertAllToVersion(version)
main:ClosePopup()
end)
- controls.cancel = new("ButtonControl", nil, {58, 105, 100, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {58, 105, 100, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(570, 140, "Convert all to Version "..treeVersions[version].display, controls, "convert", "edit")
@@ -692,7 +692,7 @@ function TreeTabClass:OpenImportPopup()
local controls = { }
local function decodePoePlannerTreeLink(treeLink)
-- treeVersion is not known at this point. We need to decode the URL to get it.
- local tmpSpec = new("PassiveSpec", self.build, latestTreeVersion)
+ local tmpSpec = new("PassiveSpec"):PassiveSpec(self.build, latestTreeVersion)
local newTreeVersion_or_errMsg = tmpSpec:DecodePoePlannerURL(treeLink, true)
-- Check for an error message
if string.find(newTreeVersion_or_errMsg, "Invalid") then
@@ -701,7 +701,7 @@ function TreeTabClass:OpenImportPopup()
end
-- 20230908. We always create a new Spec()
- local newSpec = new("PassiveSpec", self.build, newTreeVersion_or_errMsg)
+ local newSpec = new("PassiveSpec"):PassiveSpec(self.build, newTreeVersion_or_errMsg)
newSpec.title = controls.name.buf
newSpec:DecodePoePlannerURL(treeLink, false) --DecodePoePlannerURL was used above and URL proven correct.
t_insert(self.specList, newSpec)
@@ -808,7 +808,7 @@ function TreeTabClass:OpenImportPopup()
end
end)
controls.import.enabled = false
- controls.cancel = new("ButtonControl", nil, {45, 85, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 85, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(580, 115, "Import Tree", controls, "import", "name")
@@ -818,9 +818,9 @@ function TreeTabClass:OpenExportPopup()
local treeLink = self.build.spec:EncodeURL(treeVersions[self.build.spec.treeVersion].url)
local popup
local controls = { }
- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "Passive tree link:")
- controls.edit = new("EditControl", nil, {0, 40, 350, 18}, treeLink, nil, "%Z")
- controls.shrink = new("ButtonControl", nil, {-90, 70, 140, 20}, "Shrink with PoEURL", function()
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "Passive tree link:")
+ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 18}, treeLink, nil, "%Z")
+ controls.shrink = new("ButtonControl"):ButtonControl(nil, {-90, 70, 140, 20}, "Shrink with PoEURL", function()
controls.shrink.enabled = false
controls.shrink.label = "Shrinking..."
launch:DownloadPage("http://poeurl.com/shrink.php?url="..treeLink, function(response, errMsg)
@@ -834,10 +834,10 @@ function TreeTabClass:OpenExportPopup()
end
end)
end)
- controls.copy = new("ButtonControl", nil, {30, 70, 80, 20}, "Copy", function()
+ controls.copy = new("ButtonControl"):ButtonControl(nil, {30, 70, 80, 20}, "Copy", function()
Copy(treeLink)
end)
- controls.done = new("ButtonControl", nil, {120, 70, 80, 20}, "Done", function()
+ controls.done = new("ButtonControl"):ButtonControl(nil, {120, 70, 80, 20}, "Done", function()
main:ClosePopup()
end)
popup = main:OpenPopup(380, 100, "Export Tree", controls, "done", "edit")
@@ -1043,7 +1043,7 @@ function TreeTabClass:BuildPowerReportList(currentStat)
end
function TreeTabClass:FindTimelessJewel()
- local socketViewer = new("PassiveTreeView")
+ local socketViewer = new("PassiveTreeView"):PassiveTreeView()
local treeData = self.build.spec.tree
local legionNodes = treeData.legion.nodes
local legionAdditions = treeData.legion.additions
@@ -1473,8 +1473,8 @@ function TreeTabClass:FindTimelessJewel()
end
local socketFilterAdditionalDistanceMAX = 10
- controls.socketFilterAdditionalDistanceLabel = new("LabelControl", {"LEFT", controls.socketFilter, "RIGHT"}, {10, 0, 0, 16}, "^7Node Distance:")
- controls.socketFilterAdditionalDistance = new("SliderControl", {"LEFT", controls.socketFilterAdditionalDistanceLabel, "RIGHT"}, {10, 0, 66, 18}, function(value)
+ controls.socketFilterAdditionalDistanceLabel = new("LabelControl"):LabelControl({"LEFT", controls.socketFilter, "RIGHT"}, {10, 0, 0, 16}, "^7Node Distance:")
+ controls.socketFilterAdditionalDistance = new("SliderControl"):SliderControl({"LEFT", controls.socketFilterAdditionalDistanceLabel, "RIGHT"}, {10, 0, 66, 18}, function(value)
timelessData.socketFilterDistance = m_floor(value * socketFilterAdditionalDistanceMAX + 0.01)
controls.socketFilterAdditionalDistanceValue.label = s_format("^7%d", timelessData.socketFilterDistance)
end, { ["SHIFT"] = 1, ["CTRL"] = 1 / (socketFilterAdditionalDistanceMAX * 2), ["DEFAULT"] = 1 / socketFilterAdditionalDistanceMAX })
@@ -1493,7 +1493,7 @@ function TreeTabClass:FindTimelessJewel()
end
return controls.socketFilterAdditionalDistance.tooltip.realDraw(self, x, y, width, height, viewPort)
end
- controls.socketFilterAdditionalDistanceValue = new("LabelControl", {"LEFT", controls.socketFilterAdditionalDistance, "RIGHT"}, {5, 0, 0, 16}, "^70")
+ controls.socketFilterAdditionalDistanceValue = new("LabelControl"):LabelControl({"LEFT", controls.socketFilterAdditionalDistance, "RIGHT"}, {5, 0, 0, 16}, "^70")
controls.socketFilterAdditionalDistance:SetVal((timelessData.socketFilterDistance or 0) / socketFilterAdditionalDistanceMAX)
controls.socketFilterAdditionalDistanceLabel.shown = timelessData.socketFilter
controls.socketFilterAdditionalDistance.shown = timelessData.socketFilter
@@ -1519,7 +1519,7 @@ function TreeTabClass:FindTimelessJewel()
end
end
end
- controls.nodeSliderValue = new("LabelControl", {"LEFT", controls.nodeSlider, "RIGHT"}, {5, 0, 0, 16}, "^71.000")
+ controls.nodeSliderValue = new("LabelControl"):LabelControl({"LEFT", controls.nodeSlider, "RIGHT"}, {5, 0, 0, 16}, "^71.000")
controls.nodeSlider.tooltip.realDraw = controls.nodeSlider.tooltip.Draw
controls.nodeSlider.tooltip.Draw = function(self, x, y, width, height, viewPort)
local sliderOffsetX = round(184 * (1 - controls.nodeSlider.val))
@@ -1548,7 +1548,7 @@ function TreeTabClass:FindTimelessJewel()
end
end
end
- controls.nodeSlider2Value = new("LabelControl", {"LEFT", controls.nodeSlider2, "RIGHT"}, {5, 0, 0, 16}, "^71.000")
+ controls.nodeSlider2Value = new("LabelControl"):LabelControl({"LEFT", controls.nodeSlider2, "RIGHT"}, {5, 0, 0, 16}, "^71.000")
controls.nodeSlider2.tooltip.realDraw = controls.nodeSlider2.tooltip.Draw
controls.nodeSlider2.tooltip.Draw = function(self, x, y, width, height, viewPort)
local sliderOffsetX = round(184 * (1 - controls.nodeSlider2.val))
diff --git a/src/Classes/TreeTab.lua.rej b/src/Classes/TreeTab.lua.rej
new file mode 100644
index 0000000000..776b8bc18c
--- /dev/null
+++ b/src/Classes/TreeTab.lua.rej
@@ -0,0 +1,653 @@
+diff a/src/Classes/TreeTab.lua b/src/Classes/TreeTab.lua (rejected hunks)
+@@ -19,24 +19,28 @@ local s_gsub = string.gsub
+ local s_byte = string.byte
+ local dkjson = require "dkjson"
+
+-local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+- self.ControlHost()
++---@class TreeTab: ControlHost
++local TreeTabClass = newClass("TreeTab", "ControlHost")
++
++---@param build Build
++function TreeTabClass:TreeTab(build)
++ self:ControlHost()
+
+ self.build = build
+ self.isComparing = false;
+ self.isCustomMaxDepth = false;
+
+- self.viewer = new("PassiveTreeView")
++ self.viewer = new("PassiveTreeView"):PassiveTreeView()
+
+ self.specList = { }
+- self.specList[1] = new("PassiveSpec", build, latestTreeVersion)
++ self.specList[1] = new("PassiveSpec"):PassiveSpec(build, latestTreeVersion)
+ self:SetActiveSpec(1)
+ self:SetCompareSpec(1)
+
+- self.anchorControls = new("Control", nil, {0, 0, 0, 20})
++ self.anchorControls = new("Control"):Control(nil, {0, 0, 0, 20})
+
+ -- Tree list dropdown
+- self.controls.specSelect = new("DropDownControl", { "LEFT",self.anchorControls,"RIGHT" }, { 0, 0, 190, 20 }, nil, function(index, value)
++ self.controls.specSelect = new("DropDownControl"):DropDownControl({ "LEFT",self.anchorControls,"RIGHT" }, { 0, 0, 190, 20 }, nil, function(index, value)
+ if self.specList[index] then
+ self.build.modFlag = true
+ self:SetActiveSpec(index)
+@@ -126,18 +130,18 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+ self.controls.compareSelect.maxDroppedWidth = 1000
+ self.controls.compareSelect.enableDroppedWidth = true
+ self.controls.compareSelect.enableChangeBoxWidth = true
+- self.controls.reset = new("ButtonControl", { "LEFT", self.controls.compareCheck, "RIGHT" }, { 8, 0, 145, 20 }, "Reset Tree/Tattoos", function()
++ self.controls.reset = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.compareCheck, "RIGHT" }, { 8, 0, 145, 20 }, "Reset Tree/Tattoos", function()
+ local controls = { }
+ local buttonY = 65
+- controls.warningLabel = new("LabelControl", nil, { 0, 30, 0, 16 }, "^7Warning: resetting your passive tree or removing all tattoos cannot be undone.\n")
+- controls.reset = new("ButtonControl", nil, { -130, buttonY, 100, 20 }, "Reset Tree", function()
++ controls.warningLabel = new("LabelControl"):LabelControl(nil, { 0, 30, 0, 16 }, "^7Warning: resetting your passive tree or removing all tattoos cannot be undone.\n")
++ controls.reset = new("ButtonControl"):ButtonControl(nil, { -130, buttonY, 100, 20 }, "Reset Tree", function()
+ self.build.spec:ResetNodes()
+ self.build.spec:BuildAllDependsAndPaths()
+ self.build.spec:AddUndoState()
+ self.build.buildFlag = true
+ main:ClosePopup()
+ end)
+- controls.removeTattoo = new("ButtonControl", nil, { 0, buttonY, 144, 20 }, "Remove All Tattoos", function()
++ controls.removeTattoo = new("ButtonControl"):ButtonControl(nil, { 0, buttonY, 144, 20 }, "Remove All Tattoos", function()
+ for id, node in pairs(self.build.spec.hashOverrides) do --hashOverrides will contain only the nodes that have been tattoo-ed
+ if node.isTattoo then
+ self:RemoveTattooFromNode(self.build.spec.nodes[id])
+@@ -147,7 +151,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+ self.build.buildFlag = true
+ main:ClosePopup()
+ end)
+- controls.cancel = new("ButtonControl", nil, { 130, buttonY, 100, 20 }, "Cancel", function()
++ controls.cancel = new("ButtonControl"):ButtonControl(nil, { 130, buttonY, 100, 20 }, "Cancel", function()
+ main:ClosePopup()
+ end)
+ main:OpenPopup(570, 100, "Reset Tree/Tattoos", controls, nil, "edit", "cancel")
+@@ -162,8 +166,8 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+ }
+ t_insert(self.treeVersions, value)
+ end
+- self.controls.versionText = new("LabelControl", { "LEFT", self.controls.reset, "RIGHT" }, { 8, 0, 0, 16 }, "^7Version:")
+- self.controls.versionSelect = new("DropDownControl", { "LEFT", self.controls.versionText, "RIGHT" }, { 8, 0, 100, 20 }, self.treeVersions, function(index, selected)
++ self.controls.versionText = new("LabelControl"):LabelControl({ "LEFT", self.controls.reset, "RIGHT" }, { 8, 0, 0, 16 }, "^7Version:")
++ self.controls.versionSelect = new("DropDownControl"):DropDownControl({ "LEFT", self.controls.versionText, "RIGHT" }, { 8, 0, 100, 20 }, self.treeVersions, function(index, selected)
+ if selected.value ~= self.build.spec.treeVersion then
+ self:OpenVersionConvertPopup(selected.value, true)
+ end
+@@ -184,7 +188,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+ -- table holding all realm/league pairs. (allLeagues[realm] = [league.id,...])
+ self.tradeLeaguesList = {}
+ -- Find Timeless Jewel Button
+- self.controls.findTimelessJewel = new("ButtonControl", { "LEFT", self.controls.treeSearch, "RIGHT" }, { 8, 0, 150, 20 }, "Find Timeless Jewel", function()
++ self.controls.findTimelessJewel = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.treeSearch, "RIGHT" }, { 8, 0, 150, 20 }, "Find Timeless Jewel", function()
+ self:FindTimelessJewel()
+ end)
+
+@@ -192,7 +196,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+ self.defaultTattoo = { }
+
+ -- Show Node Power Checkbox
+- self.controls.treeHeatMap = new("CheckBoxControl", { "LEFT", self.controls.findTimelessJewel, "RIGHT" }, { 130, 0, 20 }, "Show Node Power:", function(state)
++ self.controls.treeHeatMap = new("CheckBoxControl"):CheckBoxControl({ "LEFT", self.controls.findTimelessJewel, "RIGHT" }, { 130, 0, 20 }, "Show Node Power:", function(state)
+ self.viewer.showHeatMap = state
+ self.controls.treeHeatMapStatSelect.shown = state
+
+@@ -319,7 +323,7 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+ end
+ end
+
+- self.controls.specConvertText = new("LabelControl", { "BOTTOMLEFT", self.controls.specSelect, "TOPLEFT" }, { 0, -14, 0, 16 }, "^7This is an older tree version, which may not be fully compatible with the current game version.")
++ self.controls.specConvertText = new("LabelControl"):LabelControl({ "BOTTOMLEFT", self.controls.specSelect, "TOPLEFT" }, { 0, -14, 0, 16 }, "^7This is an older tree version, which may not be fully compatible with the current game version.")
+ self.controls.specConvertText.shown = function()
+ return self.showConvert
+ end
+@@ -332,16 +336,17 @@ local TreeTabClass = newClass("TreeTab", "ControlHost", function(self, build)
+ local function buildConvertAllButtonLabel()
+ return colorCodes.POSITIVE.."Convert all trees to "..treeVersions[getLatestTreeVersion()].display
+ end
+- self.controls.specConvert = new("ButtonControl", { "LEFT", self.controls.specConvertText, "RIGHT" }, { 8, 0, function() return DrawStringWidth(16, "VAR", buildConvertButtonLabel()) + 20 end, 20 }, buildConvertButtonLabel, function()
++ self.controls.specConvert = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.specConvertText, "RIGHT" }, { 8, 0, function() return DrawStringWidth(16, "VAR", buildConvertButtonLabel()) + 20 end, 20 }, buildConvertButtonLabel, function()
+ self:ConvertToVersion(getLatestTreeVersion(), false, true)
+ end)
+- self.controls.specConvertAll = new("ButtonControl", { "LEFT", self.controls.specConvert, "RIGHT" }, { 8, 0, function() return DrawStringWidth(16, "VAR", buildConvertAllButtonLabel()) + 20 end, 20 }, buildConvertAllButtonLabel, function()
++ self.controls.specConvertAll = new("ButtonControl"):ButtonControl({ "LEFT", self.controls.specConvert, "RIGHT" }, { 8, 0, function() return DrawStringWidth(16, "VAR", buildConvertAllButtonLabel()) + 20 end, 20 }, buildConvertAllButtonLabel, function()
+ self:OpenVersionConvertAllPopup(getLatestTreeVersion())
+ end)
+ self.jumpToNode = false
+ self.jumpToX = 0
+ self.jumpToY = 0
+-end)
++ return self
++end
+
+ function TreeTabClass:RemoveTattooFromNode(node)
+ self.build.spec.tree.nodes[node.id].isTattoo = false
+@@ -592,7 +597,7 @@ function TreeTabClass:ConvertToVersion(version, remove, success, ignoreTreeSubTy
+ version = version..treeSubTypeCapture
+ end
+ end
+- local newSpec = new("PassiveSpec", self.build, version)
++ local newSpec = new("PassiveSpec"):PassiveSpec(self.build, version)
+ newSpec.title = self.build.spec.title
+ newSpec.jewels = copyTable(self.build.spec.jewels)
+ newSpec:RestoreUndoState(self.build.spec:CreateUndoState(), version)
+@@ -628,19 +633,19 @@ end
+
+ function TreeTabClass:OpenSpecManagePopup()
+ local importTree =
+- new("ButtonControl", nil, {-99, 259, 90, 20}, "Import Tree", function()
++ new("ButtonControl"):ButtonControl(nil, {-99, 259, 90, 20}, "Import Tree", function()
+ self:OpenImportPopup()
+ end)
+ local exportTree =
+- new("ButtonControl", {"LEFT", importTree, "RIGHT"}, {8, 0, 90, 20}, "Export Tree", function()
++ new("ButtonControl"):ButtonControl({"LEFT", importTree, "RIGHT"}, {8, 0, 90, 20}, "Export Tree", function()
+ self:OpenExportPopup()
+ end)
+
+ main:OpenPopup(370, 290, "Manage Passive Trees", {
+- new("PassiveSpecListControl", nil, {0, 50, 350, 200}, self),
++ new("PassiveSpecListControl"):PassiveSpecListControl(nil, {0, 50, 350, 200}, self),
+ importTree,
+ exportTree,
+- new("ButtonControl", {"LEFT", exportTree, "RIGHT"}, {8, 0, 90, 20}, "Done", function()
++ new("ButtonControl"):ButtonControl({"LEFT", exportTree, "RIGHT"}, {8, 0, 90, 20}, "Done", function()
+ main:ClosePopup()
+ end),
+ })
+@@ -648,17 +653,17 @@ end
+
+ function TreeTabClass:OpenVersionConvertPopup(version, ignoreTreeSubType)
+ local controls = { }
+- controls.warningLabel = new("LabelControl", nil, {0, 20, 0, 16}, "^7Warning: some or all of the passives may be de-allocated due to changes in the tree.\n\n" ..
++ controls.warningLabel = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Warning: some or all of the passives may be de-allocated due to changes in the tree.\n\n" ..
+ "Convert will replace your current tree.\nCopy + Convert will backup your current tree.\n")
+- controls.convert = new("ButtonControl", nil, {-125, 105, 100, 20}, "Convert", function()
++ controls.convert = new("ButtonControl"):ButtonControl(nil, {-125, 105, 100, 20}, "Convert", function()
+ self:ConvertToVersion(version, true, false, ignoreTreeSubType)
+ main:ClosePopup()
+ end)
+- controls.convertCopy = new("ButtonControl", nil, {0, 105, 125, 20}, "Copy + Convert", function()
++ controls.convertCopy = new("ButtonControl"):ButtonControl(nil, {0, 105, 125, 20}, "Copy + Convert", function()
+ self:ConvertToVersion(version, false, false, ignoreTreeSubType)
+ main:ClosePopup()
+ end)
+- controls.cancel = new("ButtonControl", nil, {125, 105, 100, 20}, "Cancel", function()
++ controls.cancel = new("ButtonControl"):ButtonControl(nil, {125, 105, 100, 20}, "Cancel", function()
+ self.controls.versionSelect:SelByValue(self.build.spec.treeVersion, 'value')
+ main:ClosePopup()
+ end)
+@@ -709,7 +714,7 @@ function TreeTabClass:OpenImportPopup()
+ -- newTreeVersion is passed in as an output of validateTreeVersion(). It will always be a valid tree version text string
+ -- 20230908. We always create a new Spec()
+ ConPrintf("Tree version: " .. newTreeVersion)
+- local newSpec = new("PassiveSpec", self.build, newTreeVersion)
++ local newSpec = new("PassiveSpec"):PassiveSpec(self.build, newTreeVersion)
+ newSpec.title = controls.name.buf
+ local errMsg = newSpec:DecodeURL(treeLink)
+ if errMsg then
+@@ -740,18 +745,18 @@ function TreeTabClass:OpenImportPopup()
+ return latestTreeVersion .. (alternateType and ("_" .. alternateType:gsub("-", "_")) or "")
+ end
+
+- controls.nameLabel = new("LabelControl", nil, {-180, 20, 0, 16}, "Enter name for this passive tree:")
+- controls.name = new("EditControl", nil, {100, 20, 350, 18}, "", nil, nil, nil, function(buf)
++ controls.nameLabel = new("LabelControl"):LabelControl(nil, {-180, 20, 0, 16}, "Enter name for this passive tree:")
++ controls.name = new("EditControl"):EditControl(nil, {100, 20, 350, 18}, "", nil, nil, nil, function(buf)
+ controls.msg.label = ""
+ controls.import.enabled = buf:match("%S") and controls.edit.buf:match("%S")
+ end)
+- controls.editLabel = new("LabelControl", nil, {-150, 45, 0, 16}, "Enter passive tree link:")
+- controls.edit = new("EditControl", nil, {100, 45, 350, 18}, "", nil, nil, nil, function(buf)
++ controls.editLabel = new("LabelControl"):LabelControl(nil, {-150, 45, 0, 16}, "Enter passive tree link:")
++ controls.edit = new("EditControl"):EditControl(nil, {100, 45, 350, 18}, "", nil, nil, nil, function(buf)
+ controls.msg.label = ""
+ controls.import.enabled = buf:match("%S") and controls.name.buf:match("%S")
+ end)
+- controls.msg = new("LabelControl", nil, {0, 65, 0, 16}, "")
+- controls.import = new("ButtonControl", nil, {-45, 85, 80, 20}, "Import", function()
++ controls.msg = new("LabelControl"):LabelControl(nil, {0, 65, 0, 16}, "")
++ controls.import = new("ButtonControl"):ButtonControl(nil, {-45, 85, 80, 20}, "Import", function()
+ local treeLink = controls.edit.buf
+ if #treeLink == 0 then
+ return
+@@ -900,7 +905,7 @@ function TreeTabClass:ModifyNodePopup(selectedNode)
+ end
+ end
+ for idx, desc in ipairs(wrapTable) do
+- controls[idx] = new("LabelControl", {"TOPLEFT", controls[idx-1] or controls.modSelect,"TOPLEFT"}, {0, 20, 600, 16}, "^7"..desc)
++ controls[idx] = new("LabelControl"):LabelControl({"TOPLEFT", controls[idx-1] or controls.modSelect,"TOPLEFT"}, {0, 20, 600, 16}, "^7"..desc)
+ totalHeight = totalHeight + 20
+ end
+ main.popups[1].height = totalHeight + 75
+@@ -912,8 +917,8 @@ function TreeTabClass:ModifyNodePopup(selectedNode)
+ end
+
+ buildMods(selectedNode)
+- controls.modSelectLabel = new("LabelControl", {"TOPRIGHT",nil,"TOPLEFT"}, {170, 25, 0, 16}, "^7Modifier:")
+- controls.modSelect = new("DropDownControl", {"TOPLEFT",nil,"TOPLEFT"}, {175, 25, 250, 18}, modGroups, function(idx) constructUI(modGroups[idx]) end)
++ controls.modSelectLabel = new("LabelControl"):LabelControl({"TOPRIGHT",nil,"TOPLEFT"}, {170, 25, 0, 16}, "^7Modifier:")
++ controls.modSelect = new("DropDownControl"):DropDownControl({"TOPLEFT",nil,"TOPLEFT"}, {175, 25, 250, 18}, modGroups, function(idx) constructUI(modGroups[idx]) end)
+ controls.modSelect.selIndex = self.defaultTattoo[nodeName] or 1
+ controls.modSelect.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+@@ -923,7 +928,7 @@ function TreeTabClass:ModifyNodePopup(selectedNode)
+ end
+ end
+ end
+- controls.save = new("ButtonControl", nil, {-90, 75, 80, 20}, "Add", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-90, 75, 80, 20}, "Add", function()
+ addModifier(selectedNode)
+ self.build.spec:AddUndoState()
+ self.modFlag = true
+@@ -931,7 +936,7 @@ function TreeTabClass:ModifyNodePopup(selectedNode)
+ self.defaultTattoo[nodeName] = controls.modSelect.selIndex
+ main:ClosePopup()
+ end)
+- controls.reset = new("ButtonControl", nil, {0, 75, 80, 20}, "Reset Node", function()
++ controls.reset = new("ButtonControl"):ButtonControl(nil, {0, 75, 80, 20}, "Reset Node", function()
+ self:RemoveTattooFromNode(selectedNode)
+ self.build.spec:AddUndoState()
+ self.modFlag = true
+@@ -939,7 +944,7 @@ function TreeTabClass:ModifyNodePopup(selectedNode)
+ self.defaultTattoo[nodeName] = nil
+ main:ClosePopup()
+ end)
+- controls.close = new("ButtonControl", nil, {90, 75, 80, 20}, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl(nil, {90, 75, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ end)
+
+@@ -976,13 +981,13 @@ function TreeTabClass:ModifyNodePopup(selectedNode)
+ end
+ return count
+ end
+- controls.totalTattoos = new("ButtonControl", nil, { 0, 95, 145, 20 }, "^7Tattoo Count: ".. getTattooCount() .."/50", function() return end)
++ controls.totalTattoos = new("ButtonControl"):ButtonControl(nil, { 0, 95, 145, 20 }, "^7Tattoo Count: ".. getTattooCount() .."/50", function() return end)
+ controls.totalTattoos.tooltipFunc = function(tooltip, mode, index, value) getTattooCount(tooltip) end
+ main:OpenPopup(600, 105, "Replace Modifier of Node", controls, "save")
+ constructUI(modGroups[self.defaultTattoo[nodeName] or 1])
+
+ -- Show Legacy Tattoos
+- controls.showLegacyTattoo = new("CheckBoxControl", { "LEFT", controls.totalTattoos, "RIGHT" }, { 195, 0, 20 }, "Show Legacy Tattoos:", function(state)
++ controls.showLegacyTattoo = new("CheckBoxControl"):CheckBoxControl({ "LEFT", controls.totalTattoos, "RIGHT" }, { 195, 0, 20 }, "Show Legacy Tattoos:", function(state)
+ self.showLegacyTattoo = state
+ buildMods(selectedNode)
+ end)
+@@ -1024,13 +1029,13 @@ function TreeTabClass:OpenMasteryPopup(node, viewPort)
+ --Check to make sure that the effects list has a potential mod to apply to a mastery
+ if not (next(effects) == nil) then
+ local passiveMasteryControlHeight = (#effects + 1) * 14 + 2
+- controls.close = new("ButtonControl", nil, {0, 30 + passiveMasteryControlHeight, 90, 20}, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl(nil, {0, 30 + passiveMasteryControlHeight, 90, 20}, "Cancel", function()
+ node.sd = cachedSd
+ node.allMasteryOptions = cachedAllMasteryOption
+ self.build.spec.tree:ProcessStats(node)
+ main:ClosePopup()
+ end)
+- controls.effect = new("PassiveMasteryControl", {"TOPLEFT",nil,"TOPLEFT"}, {6, 25, 0, passiveMasteryControlHeight}, effects, self, node, controls.save)
++ controls.effect = new("PassiveMasteryControl"):PassiveMasteryControl({"TOPLEFT",nil,"TOPLEFT"}, {6, 25, 0, passiveMasteryControlHeight}, effects, self, node, controls.save)
+ main:OpenPopup(controls.effect.width + 12, controls.effect.height + 60, node.name, controls, nil, nil, "close")
+ end
+ end
+@@ -1504,13 +1509,13 @@ function TreeTabClass:FindTimelessJewel()
+ self.build.modFlag = true
+ end
+
+- controls.devotionSelectLabel = new("LabelControl", {"TOPRIGHT", nil, "TOPLEFT"}, {920, 25, 0, 16}, "^7Devotion modifiers:")
++ controls.devotionSelectLabel = new("LabelControl"):LabelControl({"TOPRIGHT", nil, "TOPLEFT"}, {920, 25, 0, 16}, "^7Devotion modifiers:")
+ controls.devotionSelectLabel.shown = timelessData.jewelType.id == 4
+- controls.devotionSelect1 = new("DropDownControl", {"TOP", controls.devotionSelectLabel, "BOTTOM"}, {0, 8, 200, 18}, devotionVariants, function(index, value)
++ controls.devotionSelect1 = new("DropDownControl"):DropDownControl({"TOP", controls.devotionSelectLabel, "BOTTOM"}, {0, 8, 200, 18}, devotionVariants, function(index, value)
+ timelessData.devotionVariant1 = index
+ end)
+ controls.devotionSelect1.selIndex = timelessData.devotionVariant1
+- controls.devotionSelect2 = new("DropDownControl", {"TOP", controls.devotionSelect1, "BOTTOM"}, {0, 7, 200, 18}, devotionVariants, function(index, value)
++ controls.devotionSelect2 = new("DropDownControl"):DropDownControl({"TOP", controls.devotionSelect1, "BOTTOM"}, {0, 7, 200, 18}, devotionVariants, function(index, value)
+ timelessData.devotionVariant2 = index
+ end)
+ controls.devotionSelect2.selIndex = timelessData.devotionVariant2
+@@ -1526,7 +1531,7 @@ function TreeTabClass:FindTimelessJewel()
+ local clearProtected
+ self.allocatedNodesInRadiusCount = 0
+
+- controls.jewelSelect = new("DropDownControl", {"TOPLEFT", nil, "TOPLEFT"}, {520, 25, 200, rowHeight}, jewelTypes, function(index, value)
++ controls.jewelSelect = new("DropDownControl"):DropDownControl({"TOPLEFT", nil, "TOPLEFT"}, {520, 25, 200, rowHeight}, jewelTypes, function(index, value)
+ timelessData.jewelType = value
+ controls.devotionSelectLabel.shown = value.id == 4 -- Militant Faith
+ controls.abyssAscendancyLabel.shown = value.id == 11
+@@ -1545,15 +1550,15 @@ function TreeTabClass:FindTimelessJewel()
+ end
+ end)
+ controls.jewelSelect.selIndex = timelessData.jewelType.id
+- controls.jewelSelectLabel = new("LabelControl", {"RIGHT", controls.jewelSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Jewel Type:")
++ controls.jewelSelectLabel = new("LabelControl"):LabelControl({"RIGHT", controls.jewelSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Jewel Type:")
+
+
+- controls.conquerorSelect = new("DropDownControl", {"TOPLEFT", controls.jewelSelect, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, conquerorTypes[timelessData.jewelType.id], function(index, value)
++ controls.conquerorSelect = new("DropDownControl"):DropDownControl({"TOPLEFT", controls.jewelSelect, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, conquerorTypes[timelessData.jewelType.id], function(index, value)
+ timelessData.conquerorType = value
+ self.build.modFlag = true
+ end)
+ controls.conquerorSelect.selIndex = timelessData.conquerorType.id
+- controls.conquerorSelectLabel = new("LabelControl", {"RIGHT", controls.conquerorSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Conqueror:")
++ controls.conquerorSelectLabel = new("LabelControl"):LabelControl({"RIGHT", controls.conquerorSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Conqueror:")
+
+ setAllocatedNodes = function()
+ if timelessData.jewelSocket.id == -1 or not treeData.nodes[timelessData.jewelSocket.id] then
+@@ -1588,7 +1593,7 @@ function TreeTabClass:FindTimelessJewel()
+ end
+
+
+- controls.socketSelect = new("TimelessJewelSocketControl", {"TOPLEFT", controls.conquerorSelect, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, jewelSockets, function(index, value)
++ controls.socketSelect = new("TimelessJewelSocketControl"):TimelessJewelSocketControl({"TOPLEFT", controls.conquerorSelect, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, jewelSockets, function(index, value)
+ timelessData.jewelSocket = value
+ setAllocatedNodes() -- reset list when changing sockets
+ self.build.modFlag = true
+@@ -1600,7 +1605,7 @@ function TreeTabClass:FindTimelessJewel()
+ break
+ end
+ end
+- controls.socketSelectLabel = new("LabelControl", {"RIGHT", controls.socketSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Jewel Socket:")
++ controls.socketSelectLabel = new("LabelControl"):LabelControl({"RIGHT", controls.socketSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Jewel Socket:")
+
+ clearProtected = function()
+ protectedNodesCount = 0
+@@ -1612,7 +1617,7 @@ function TreeTabClass:FindTimelessJewel()
+ end
+ end
+
+- controls.socketFilter = new("CheckBoxControl", {"TOPLEFT", controls.socketSelect, "BOTTOMLEFT"}, {0, rowSpacing, rowHeight}, nil, function(value)
++ controls.socketFilter = new("CheckBoxControl"):CheckBoxControl({"TOPLEFT", controls.socketSelect, "BOTTOMLEFT"}, {0, rowSpacing, rowHeight}, nil, function(value)
+ timelessData.socketFilter = value
+ self.build.modFlag = true
+ controls.socketFilterAdditionalDistanceLabel.shown = value
+@@ -1626,7 +1631,7 @@ function TreeTabClass:FindTimelessJewel()
+ clearProtected()
+ end
+ end)
+- controls.socketFilterLabel = new("LabelControl", {"RIGHT", controls.socketFilter, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Filter Nodes:")
++ controls.socketFilterLabel = new("LabelControl"):LabelControl({"RIGHT", controls.socketFilter, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Filter Nodes:")
+ controls.socketFilter.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ tooltip:AddLine(16, "^7Enable this option to exclude nodes that you do not have allocated on your active passive skill tree.")
+@@ -1635,7 +1640,7 @@ function TreeTabClass:FindTimelessJewel()
+ controls.socketFilter.state = timelessData.socketFilter
+
+ -- Protect notables that must not be replaced by Militant Faith or Reclaimed Malevolence.
+- controls.protectAllocatedLabel = new("LabelControl", { "TOPLEFT", nil, "TOPLEFT" }, {
++ controls.protectAllocatedLabel = new("LabelControl"):LabelControl({ "TOPLEFT", nil, "TOPLEFT" }, {
+ 15,
+ function()
+ return timelessData.jewelType.id == 11 and 85 or 25
+@@ -1643,17 +1648,17 @@ function TreeTabClass:FindTimelessJewel()
+ 0,
+ 16,
+ }, "^7Protect allocated nodes from changing:")
+- controls.protectAllocatedSelect = new("DropDownControl", { "TOPLEFT", controls.protectAllocatedLabel, "BOTTOMLEFT" }, { 0, 8, 200, 18 }, nil, nil)
+- controls.protectAllocatedButtonAdd = new("ButtonControl", { "LEFT", controls.protectAllocatedSelect, "RIGHT" }, { 5, 0, 44, 18 }, "Add", function()
++ controls.protectAllocatedSelect = new("DropDownControl"):DropDownControl({ "TOPLEFT", controls.protectAllocatedLabel, "BOTTOMLEFT" }, { 0, 8, 200, 18 }, nil, nil)
++ controls.protectAllocatedButtonAdd = new("ButtonControl"):ButtonControl({ "LEFT", controls.protectAllocatedSelect, "RIGHT" }, { 5, 0, 44, 18 }, "Add", function()
+ local selValue = controls.protectAllocatedSelect:GetSelValue()
+ local nodeName = selValue and selValue.label
+ if nodeName and not controls["protected:"..nodeName] then
+ protectedNodesCount = protectedNodesCount + 1
+ t_insert(protectedNodes, nodeName)
+- controls["protected:"..nodeName] = new("LabelControl", { "TOPLEFT", controls.protectAllocatedSelect, "BOTTOMLEFT" }, { 0, 16 * protectedNodesCount - 10, 0, 16 }, "^7"..nodeName)
++ controls["protected:"..nodeName] = new("LabelControl"):LabelControl({ "TOPLEFT", controls.protectAllocatedSelect, "BOTTOMLEFT" }, { 0, 16 * protectedNodesCount - 10, 0, 16 }, "^7"..nodeName)
+ end
+ end)
+- controls.protectAllocatedButtonClear = new("ButtonControl", { "LEFT", controls.protectAllocatedButtonAdd, "RIGHT" }, { 5, 0, 44, 18 }, "Clear", function()
++ controls.protectAllocatedButtonClear = new("ButtonControl"):ButtonControl({ "LEFT", controls.protectAllocatedButtonAdd, "RIGHT" }, { 5, 0, 44, 18 }, "Clear", function()
+ clearProtected()
+ end)
+ -- set shown and list on load
+@@ -1664,9 +1669,9 @@ function TreeTabClass:FindTimelessJewel()
+
+ -- This requirement is separate from ordinary node weights and remains above
+ -- the protection list so adding protected nodes does not move the selector.
+- controls.abyssAscendancyLabel = new("LabelControl", {"TOPLEFT", nil, "TOPLEFT"}, {15, 25, 0, 16}, "^7Required ascendancy outcome:")
++ controls.abyssAscendancyLabel = new("LabelControl"):LabelControl({"TOPLEFT", nil, "TOPLEFT"}, {15, 25, 0, 16}, "^7Required ascendancy outcome:")
+ controls.abyssAscendancyLabel.shown = timelessData.jewelType.id == 11
+- controls.abyssAscendancySelect = new("DropDownControl", {"TOPLEFT", controls.abyssAscendancyLabel, "BOTTOMLEFT"}, {0, 8, 200, 18}, abyssAscendancyOptions, function(index, value)
++ controls.abyssAscendancySelect = new("DropDownControl"):DropDownControl({"TOPLEFT", controls.abyssAscendancyLabel, "BOTTOMLEFT"}, {0, 8, 200, 18}, abyssAscendancyOptions, function(index, value)
+ local searchLines = { }
+ for _, searchRow in ipairs(searchListTbl) do
+ if not searchRow[1]:match("^abyss_special_ascendancy_notable_") then
+@@ -1741,11 +1746,11 @@ function TreeTabClass:FindTimelessJewel()
+ local scrollWheelSpeedTbl2 = { ["SHIFT"] = 0.2, ["CTRL"] = 0.002, ["DEFAULT"] = 0.02 }
+
+ local nodeSliderStatLabel = "None"
+- controls.nodeSlider = new("SliderControl", {"TOPLEFT", controls.socketFilter, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value)
++ controls.nodeSlider = new("SliderControl"):SliderControl({"TOPLEFT", controls.socketFilter, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value)
+ controls.nodeSliderValue.label = s_format("^7%.3f", value * 10)
+ parseSearchList(1, controls.searchListFallback and controls.searchListFallback.shown or false)
+ end, scrollWheelSpeedTbl)
+- controls.nodeSliderLabel = new("LabelControl", {"RIGHT", controls.nodeSlider, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Primary Node Weight:")
++ controls.nodeSliderLabel = new("LabelControl"):LabelControl({"RIGHT", controls.nodeSlider, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Primary Node Weight:")
+ controls.nodeSlider.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ if not controls.nodeSlider.dragging then
+@@ -1770,11 +1775,11 @@ function TreeTabClass:FindTimelessJewel()
+ controls.nodeSlider:SetVal(0.1)
+
+ local nodeSlider2StatLabel = "None"
+- controls.nodeSlider2 = new("SliderControl", {"TOPLEFT", controls.nodeSlider, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value)
++ controls.nodeSlider2 = new("SliderControl"):SliderControl({"TOPLEFT", controls.nodeSlider, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value)
+ controls.nodeSlider2Value.label = s_format("^7%.3f", value * 10)
+ parseSearchList(1, controls.searchListFallback and controls.searchListFallback.shown or false)
+ end, scrollWheelSpeedTbl)
+- controls.nodeSlider2Label = new("LabelControl", {"RIGHT", controls.nodeSlider2, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Secondary Node Weight:")
++ controls.nodeSlider2Label = new("LabelControl"):LabelControl({"RIGHT", controls.nodeSlider2, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Secondary Node Weight:")
+ controls.nodeSlider2.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ if not controls.nodeSlider2.dragging then
+@@ -1798,7 +1803,7 @@ function TreeTabClass:FindTimelessJewel()
+ end
+ controls.nodeSlider2:SetVal(0.1)
+
+- controls.nodeSlider3 = new("SliderControl", {"TOPLEFT", controls.nodeSlider2, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value)
++ controls.nodeSlider3 = new("SliderControl"):SliderControl({"TOPLEFT", controls.nodeSlider2, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value)
+ if value == 1 then
+ controls.nodeSlider3Value.label = "^7Required"
+ else
+@@ -1806,14 +1811,14 @@ function TreeTabClass:FindTimelessJewel()
+ end
+ parseSearchList(1, controls.searchListFallback and controls.searchListFallback.shown or false)
+ end, scrollWheelSpeedTbl2)
+- controls.nodeSlider3Label = new("LabelControl", {"RIGHT", controls.nodeSlider3, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Minimum Node Weight:")
++ controls.nodeSlider3Label = new("LabelControl"):LabelControl({"RIGHT", controls.nodeSlider3, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Minimum Node Weight:")
+ controls.nodeSlider3.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ if not controls.nodeSlider3.dragging then
+ tooltip:AddLine(16, "^7Seeds that do not meet the minimum weight threshold for a desired node are excluded from the search results.")
+ end
+ end
+- controls.nodeSlider3Value = new("LabelControl", {"LEFT", controls.nodeSlider3, "RIGHT"}, {5, 0, 0, 16}, "^70")
++ controls.nodeSlider3Value = new("LabelControl"):LabelControl({"LEFT", controls.nodeSlider3, "RIGHT"}, {5, 0, 0, 16}, "^70")
+ controls.nodeSlider3.tooltip.realDraw = controls.nodeSlider3.tooltip.Draw
+ controls.nodeSlider3.tooltip.Draw = function(self, x, y, width, height, viewPort)
+ local sliderOffsetX = round(184 * (1 - controls.nodeSlider3.val))
+@@ -1861,7 +1866,7 @@ function TreeTabClass:FindTimelessJewel()
+ statCount == 1 and t_concat(legionPassive.sd, " + ") or legionPassive.sd[1] or "None",
+ legionPassive.sd[2] or "None"
+ end
+- controls.nodeSelect = new("DropDownControl", {"TOPLEFT", controls.nodeSlider3, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, modData, function(index, value)
++ controls.nodeSelect = new("DropDownControl"):DropDownControl({"TOPLEFT", controls.nodeSlider3, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, modData, function(index, value)
+ nodeSliderStatLabel = "None"
+ nodeSlider2StatLabel = "None"
+ if value.id then
+@@ -1916,7 +1921,7 @@ function TreeTabClass:FindTimelessJewel()
+ self.build.modFlag = true
+ end
+ end)
+- controls.nodeSelectLabel = new("LabelControl", {"RIGHT", controls.nodeSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Search for Node:")
++ controls.nodeSelectLabel = new("LabelControl"):LabelControl({"RIGHT", controls.nodeSelect, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Search for Node:")
+ controls.nodeSelect.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ if mode ~= "OUT" and value.descriptions then
+@@ -2104,12 +2109,12 @@ function TreeTabClass:FindTimelessJewel()
+ })
+ end
+ end
+- controls.fallbackWeightsList = new("DropDownControl", {"TOPLEFT", controls.nodeSelect, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, fallbackWeightsList, function(index)
++ controls.fallbackWeightsList = new("DropDownControl"):DropDownControl({"TOPLEFT", controls.nodeSelect, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, fallbackWeightsList, function(index)
+ timelessData.fallbackWeightMode.idx = index
+ end)
+- controls.fallbackWeightsLabel = new("LabelControl", {"RIGHT", controls.fallbackWeightsList, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Fallback Weight Mode:")
++ controls.fallbackWeightsLabel = new("LabelControl"):LabelControl({"RIGHT", controls.fallbackWeightsList, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Fallback Weight Mode:")
+ controls.fallbackWeightsList.selIndex = timelessData.fallbackWeightMode.idx or 1
+- controls.fallbackWeightsButton = new("ButtonControl", {"LEFT", controls.fallbackWeightsList, "RIGHT"}, {5, 0, 66, 18}, "Generate", function()
++ controls.fallbackWeightsButton = new("ButtonControl"):ButtonControl({"LEFT", controls.fallbackWeightsList, "RIGHT"}, {5, 0, 66, 18}, "Generate", function()
+ setupFallbackWeights()
+ controls.searchListFallbackButton.label = "^4Fallback Nodes"
+ end)
+@@ -2117,12 +2122,12 @@ function TreeTabClass:FindTimelessJewel()
+ tooltip:Clear()
+ tooltip:AddLine(16, "^7Click this button to generate new fallback node weights, replacing your old ones.")
+ end
+- controls.totalMinimumWeight = new("EditControl", {"TOPLEFT", controls.fallbackWeightsList, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, "", nil, "%D", nil, function(val)
++ controls.totalMinimumWeight = new("EditControl"):EditControl({"TOPLEFT", controls.fallbackWeightsList, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, "", nil, "%D", nil, function(val)
+ local num = tonumber(val)
+ timelessData.totalMinimumWeight = num or nil
+ self.build.modFlag = true
+ end)
+- controls.totalMinimumWeightLabel = new("LabelControl", {"RIGHT", controls.totalMinimumWeight, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Total Minimum Weight:")
++ controls.totalMinimumWeightLabel = new("LabelControl"):LabelControl({"RIGHT", controls.totalMinimumWeight, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Total Minimum Weight:")
+ controls.totalMinimumWeight.tooltipFunc = function(tooltip, mode, index, value)
+ tooltip:Clear()
+ tooltip:AddLine(16, "^7Optional: Only show results where total weight meets or exceeds this value.")
+@@ -2133,7 +2138,7 @@ function TreeTabClass:FindTimelessJewel()
+ local buttonHeight = 20
+ local edgePadding = 12
+ local listYOffset = -(buttonHeight + edgePadding * 2)
+- controls.searchList = new("EditControl", { "BOTTOMLEFT", nil, "BOTTOMLEFT" },
++ controls.searchList = new("EditControl"):EditControl({ "BOTTOMLEFT", nil, "BOTTOMLEFT" },
+ { edgePadding, listYOffset, listWidth, listHeight }, timelessData.searchList, nil,
+ "^%C\t\n", nil, function(value)
+ timelessData.searchList = value
+@@ -2144,7 +2149,7 @@ function TreeTabClass:FindTimelessJewel()
+ controls.searchList.enabled = true
+ controls.searchList:SetText(timelessData.searchList and timelessData.searchList or "")
+
+- controls.searchListFallback = new("EditControl", { "BOTTOMLEFT", nil, "BOTTOMLEFT" },
++ controls.searchListFallback = new("EditControl"):EditControl({ "BOTTOMLEFT", nil, "BOTTOMLEFT" },
+ { edgePadding, listYOffset, listWidth, listHeight },
+ timelessData.searchListFallback, nil, "^%C\t\n", nil, function(value)
+ timelessData.searchListFallback = value
+@@ -2155,7 +2160,7 @@ function TreeTabClass:FindTimelessJewel()
+ controls.searchListFallback.enabled = false
+ controls.searchListFallback:SetText(timelessData.searchListFallback and timelessData.searchListFallback or "")
+
+- controls.searchListButton = new("ButtonControl",
++ controls.searchListButton = new("ButtonControl"):ButtonControl(
+ { "BOTTOMLEFT", nil, "BOTTOMLEFT" },
+ { edgePadding, listYOffset - listHeight - rowSpacing, 106, buttonHeight }, "^7Desired Nodes", function()
+ if controls.searchListFallback.shown then
+@@ -2174,7 +2179,7 @@ function TreeTabClass:FindTimelessJewel()
+ end
+ controls.searchListButton.locked = function() return controls.searchList.shown end
+
+- controls.searchListFallbackButton = new("ButtonControl", {"LEFT", controls.searchListButton, "RIGHT"}, {5, 0, 110, buttonHeight}, "^7Fallback Nodes", function()
++ controls.searchListFallbackButton = new("ButtonControl"):ButtonControl({"LEFT", controls.searchListButton, "RIGHT"}, {5, 0, 110, buttonHeight}, "^7Fallback Nodes", function()
+ controls.searchList.shown = false
+ controls.searchList.enabled = false
+ controls.searchListFallback.shown = true
+@@ -2191,11 +2196,11 @@ function TreeTabClass:FindTimelessJewel()
+ end
+ controls.searchListFallbackButton.locked = function() return controls.searchListFallback.shown end
+
+- controls.searchResults = new("TimelessJewelListControl", { "BOTTOMLEFT", nil, "BOTTOMLEFT" },
++ controls.searchResults = new("TimelessJewelListControl"):TimelessJewelListControl({ "BOTTOMLEFT", nil, "BOTTOMLEFT" },
+ { edgePadding*2 + listWidth, -(buttonHeight + edgePadding * 2), listWidth, listHeight }, self.build)
+- self.tradeQueryRequests = new("TradeQueryRequests")
+- controls.msg = new("LabelControl", nil, { -280, 5, 0, 20 }, "")
+- controls.searchTradeButton = new("ButtonControl", { "BOTTOMRIGHT", controls.searchResults, "TOPRIGHT" }, { 0, -rowSpacing, 170, buttonHeight }, "Open Trade URL", function()
++ self.tradeQueryRequests = new("TradeQueryRequests"):TradeQueryRequests()
++ controls.msg = new("LabelControl"):LabelControl(nil, { -280, 5, 0, 20 }, "")
++ controls.searchTradeButton = new("ButtonControl"):ButtonControl({ "BOTTOMRIGHT", controls.searchResults, "TOPRIGHT" }, { 0, -rowSpacing, 170, buttonHeight }, "Open Trade URL", function()
+ local seedTrades = {}
+ local startRow, endRow
+ if controls.searchResults.highlightIndex and not controls.searchMore.state then
+@@ -2318,17 +2323,17 @@ function TreeTabClass:FindTimelessJewel()
+ tooltip:AddLine(16, "^7After selecting a row You can also shift+click on another row to select a range of rows to search.")
+ end
+
+- controls.searchTradeLeagueSelect = new("DropDownControl", { "RIGHT", controls.searchTradeButton, "LEFT" },
++ controls.searchTradeLeagueSelect = new("DropDownControl"):DropDownControl({ "RIGHT", controls.searchTradeButton, "LEFT" },
+ { -labelSpacing, 0, 140, buttonHeight }, nil, function(idx, val)
+ self.timelessJewelLeagueSelect = val
+ end)
+- controls.searchTradeLeagueLabel = new("LabelControl", { "TOPRIGHT", controls.searchTradeLeagueSelect, "TOPLEFT" },
++ controls.searchTradeLeagueLabel = new("LabelControl"):LabelControl({ "TOPRIGHT", controls.searchTradeLeagueSelect, "TOPLEFT" },
+ { -labelSpacing, 0, 0, labelHeight }, "^7League:")
+ -- Realm selection
+ self.realmList = {
+ "PC", "Sony", "Xbox"
+ }
+- controls.realmSelection = new("DropDownControl", { "BOTTOMLEFT", controls.searchTradeLeagueSelect, "TOPLEFT" },
++ controls.realmSelection = new("DropDownControl"):DropDownControl({ "BOTTOMLEFT", controls.searchTradeLeagueSelect, "TOPLEFT" },
+ { 0, -rowSpacing, 50, buttonHeight }, self.realmList, nil)
+ local function updateLeagues()
+ local currentRealmId = controls.realmSelection:GetSelValue():lower()
+@@ -2382,7 +2387,7 @@ function TreeTabClass:FindTimelessJewel()
+ -- manually call the function because when initialising, because the
+ -- function does not get called when the selection index stays the same
+ controls.realmSelection.selFunc(controls.realmSelection.selIndex)
+- controls.realmLabel = new("LabelControl", { "TOPRIGHT", controls.realmSelection, "TOPLEFT" },
++ controls.realmLabel = new("LabelControl"):LabelControl({ "TOPRIGHT", controls.realmSelection, "TOPLEFT" },
+ { -labelSpacing, 0, 0, labelHeight }, "^7Realm:")
+
+ -- Buyout selection
+@@ -2393,7 +2398,7 @@ function TreeTabClass:FindTimelessJewel()
+ "In person (online)",
+ "Any (includes offline)"
+ }
+- controls.tradeTypeSelection = new("DropDownControl", { "BOTTOMRIGHT", controls.searchTradeButton, "TOPRIGHT" },
++ controls.tradeTypeSelection = new("DropDownControl"):DropDownControl({ "BOTTOMRIGHT", controls.searchTradeButton, "TOPRIGHT" },
+ { 0, -rowSpacing, 205, buttonHeight }, tradeTypes, function(index, value)
+ self.tradeTypeIndex = index
+ end)
+@@ -2402,7 +2407,7 @@ function TreeTabClass:FindTimelessJewel()
+ controls.tradeTypeSelection:SetSel(self.tradeTypeIndex)
+
+ -- Checkbox to search a lot at once, or just a few
+- controls.searchMore = new("CheckBoxControl", { "BOTTOMRIGHT", controls.tradeTypeSelection, "TOPRIGHT" },
++ controls.searchMore = new("CheckBoxControl"):CheckBoxControl({ "BOTTOMRIGHT", controls.tradeTypeSelection, "TOPRIGHT" },
+ { 0, -rowSpacing, 19 }, nil, function(state)
+ self.lastSearchMore = state
+ end,
+@@ -2412,7 +2417,7 @@ function TreeTabClass:FindTimelessJewel()
+ if self.lastSearchMore then
+ controls.searchMore.state = self.lastSearchMore
+ end
+- controls.searchMoreLabel = new("LabelControl", { "RIGHT", controls.searchMore, "LEFT" },
++ controls.searchMoreLabel = new("LabelControl"):LabelControl({ "RIGHT", controls.searchMore, "LEFT" },
+ { -labelSpacing, 0, 0, labelHeight }, "^7Search Maximum Amount:")
+
+ -- Helper function to search a single socket
+@@ -2780,7 +2785,7 @@ function TreeTabClass:FindTimelessJewel()
+ local buttonDivider = 10
+ local buttonWidth = 80
+ -- reset button anchored to middle of panel and other buttons anchored to it
+- controls.resetButton = new("ButtonControl", {"BOTTOMLEFT", nil, "BOTTOMLEFT"}, {panelWidth / 2 - buttonWidth/2, -edgePadding, buttonWidth, buttonHeight}, "Reset", function()
++ controls.resetButton = new("ButtonControl"):ButtonControl({"BOTTOMLEFT", nil, "BOTTOMLEFT"}, {panelWidth / 2 - buttonWidth/2, -edgePadding, buttonWidth, buttonHeight}, "Reset", function()
+ updateSearchList("", true)
+ updateSearchList("", false)
+ controls.abyssAscendancySelect.selIndex = 1
+@@ -2788,10 +2793,10 @@ function TreeTabClass:FindTimelessJewel()
+ controls.searchTradeButton.enabled = false
+ clearProtected()
+ end)
+- controls.closeButton = new("ButtonControl", {"LEFT", controls.resetButton, "RIGHT"}, {buttonDivider, 0, buttonWidth, buttonHeight}, "Cancel", function()
++ controls.closeButton = new("ButtonControl"):ButtonControl({"LEFT", controls.resetButton, "RIGHT"}, {buttonDivider, 0, buttonWidth, buttonHeight}, "Cancel", function()
+ main:ClosePopup()
+ end)
+- controls.searchButton = new("ButtonControl", {"RIGHT", controls.resetButton, "LEFT"}, {-buttonDivider, 0, buttonWidth, buttonHeight}, "Search", function()
++ controls.searchButton = new("ButtonControl"):ButtonControl({"RIGHT", controls.resetButton, "LEFT"}, {-buttonDivider, 0, buttonWidth, buttonHeight}, "Search", function()
+ if timelessData.jewelSocket.id == -1 then
+ wipeTable(timelessData.searchResults)
+ wipeTable(timelessData.sharedResults)
diff --git a/src/Classes/UndoHandler.lua b/src/Classes/UndoHandler.lua
index 6759de6cf0..4e6674808f 100644
--- a/src/Classes/UndoHandler.lua
+++ b/src/Classes/UndoHandler.lua
@@ -9,10 +9,16 @@
local t_insert = table.insert
local t_remove = table.remove
-local UndoHandlerClass = newClass("UndoHandler", function(self)
+---@class UndoHandler
+---@field CreateUndoState fun() Must be manually defined. Creates a state that can be restored
+---@field RestoreUndoState fun(state: any) Must be manually defined. Restores a state created by calling CreateUndoState()
+local UndoHandlerClass = newClass("UndoHandler")
+
+function UndoHandlerClass:UndoHandler()
self.undo = { }
self.redo = { }
-end)
+ return self
+end
-- Initialises the undo/redo buffers
-- Should be called after the current state is first loaded/initialised
@@ -24,6 +30,7 @@ end
-- Adds a new undo state to the undo buffer, and also clears the redo buffer
-- Should be called after the user makes a change to the current state
+---@param noClearRedo boolean?
function UndoHandlerClass:AddUndoState(noClearRedo)
t_insert(self.undo, 1, self:CreateUndoState())
self.undo[102] = nil
diff --git a/src/Data/Bases/amulet.lua.rej b/src/Data/Bases/amulet.lua.rej
new file mode 100644
index 0000000000..504bd03bf9
--- /dev/null
+++ b/src/Data/Bases/amulet.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/amulet.lua b/src/Data/Bases/amulet.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+
+ itemBases["Paua Amulet"] = {
+ type = "Amulet",
+@@ -1627,3 +1626,4 @@ itemBases["Monkey Paw Talisman (Frenzy)"] = {
+ "Every fell beast, every creature, had to die.\"",
+ },
+ }
++end
diff --git a/src/Data/Bases/axe.lua.rej b/src/Data/Bases/axe.lua.rej
new file mode 100644
index 0000000000..a4187447d4
--- /dev/null
+++ b/src/Data/Bases/axe.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/axe.lua b/src/Data/Bases/axe.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Rusted Hatchet"] = {
+ type = "One Handed Axe",
+ socketLimit = 3,
+@@ -508,3 +507,4 @@ itemBases["Apex Cleaver"] = {
+ weapon = { PhysicalMin = 78, PhysicalMax = 121, CritChanceBase = 5, AttackRateBase = 1.35, Range = 13, },
+ req = { level = 70, str = 139, dex = 65, },
+ }
++end
diff --git a/src/Data/Bases/belt.lua.rej b/src/Data/Bases/belt.lua.rej
new file mode 100644
index 0000000000..c767c984f1
--- /dev/null
+++ b/src/Data/Bases/belt.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/belt.lua b/src/Data/Bases/belt.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Rustic Sash"] = {
+ type = "Belt",
+ tags = { belt = true, default = true, },
+@@ -129,3 +128,4 @@ itemBases["Golden Obi"] = {
+ implicitIds = { "ItemFoundRarityIncreaseImplicitDemigodsBelt1", },
+ req = { },
+ }
++end
diff --git a/src/Data/Bases/body.lua.rej b/src/Data/Bases/body.lua.rej
new file mode 100644
index 0000000000..59ee575d10
--- /dev/null
+++ b/src/Data/Bases/body.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/body.lua b/src/Data/Bases/body.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+
+ itemBases["Plate Vest"] = {
+ type = "Body Armour",
+@@ -1258,3 +1257,4 @@ itemBases["Golden Mantle"] = {
+ armour = { ArmourBaseMin = 75, ArmourBaseMax = 86, EvasionBaseMin = 75, EvasionBaseMax = 86, EnergyShieldBaseMin = 17, EnergyShieldBaseMax = 19, },
+ req = { level = 20, str = 8, dex = 8, int = 8, },
+ }
++end
diff --git a/src/Data/Bases/boots.lua b/src/Data/Bases/boots.lua
index dfc0740fc9..2d09547181 100644
--- a/src/Data/Bases/boots.lua
+++ b/src/Data/Bases/boots.lua
@@ -1960,3 +1960,4 @@ itemBases["Golden Caligae"] = {
armour = { },
req = { level = 12, },
}
+end
diff --git a/src/Data/Bases/boots.lua.rej b/src/Data/Bases/boots.lua.rej
new file mode 100644
index 0000000000..1da84fa721
--- /dev/null
+++ b/src/Data/Bases/boots.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Data/Bases/boots.lua b/src/Data/Bases/boots.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+
+ itemBases["Iron Greaves"] = {
+ type = "Boots",
diff --git a/src/Data/Bases/bow.lua.rej b/src/Data/Bases/bow.lua.rej
new file mode 100644
index 0000000000..6b8bc8587e
--- /dev/null
+++ b/src/Data/Bases/bow.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/bow.lua b/src/Data/Bases/bow.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Crude Bow"] = {
+ type = "Bow",
+ socketLimit = 6,
+@@ -293,3 +292,4 @@ itemBases["Ethereal Bow"] = {
+ weapon = { PhysicalMin = 5, PhysicalMax = 9, CritChanceBase = 6, AttackRateBase = 1.5, Range = 120, },
+ req = { dex = 14, },
+ }
++end
diff --git a/src/Data/Bases/claw.lua.rej b/src/Data/Bases/claw.lua.rej
new file mode 100644
index 0000000000..79804f4e6a
--- /dev/null
+++ b/src/Data/Bases/claw.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/claw.lua b/src/Data/Bases/claw.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Nailed Fist"] = {
+ type = "Claw",
+ socketLimit = 3,
+@@ -310,3 +309,4 @@ itemBases["Void Fangs"] = {
+ weapon = { PhysicalMin = 22, PhysicalMax = 41, CritChanceBase = 7, AttackRateBase = 1.6, Range = 11, },
+ req = { level = 70, dex = 113, int = 113, },
+ }
++end
diff --git a/src/Data/Bases/dagger.lua.rej b/src/Data/Bases/dagger.lua.rej
new file mode 100644
index 0000000000..b9cf3f4894
--- /dev/null
+++ b/src/Data/Bases/dagger.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/dagger.lua b/src/Data/Bases/dagger.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Glass Shank"] = {
+ type = "Dagger",
+ socketLimit = 3,
+@@ -371,3 +370,4 @@ itemBases["Infernal Blade"] = {
+ weapon = { PhysicalMin = 21, PhysicalMax = 85, CritChanceBase = 8.5, AttackRateBase = 1.45, Range = 10, },
+ req = { level = 70, dex = 121, int = 121, },
+ }
++end
diff --git a/src/Data/Bases/fishing.lua.rej b/src/Data/Bases/fishing.lua.rej
new file mode 100644
index 0000000000..4709ba8243
--- /dev/null
+++ b/src/Data/Bases/fishing.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/fishing.lua b/src/Data/Bases/fishing.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Fishing Rod"] = {
+ type = "Fishing Rod",
+ socketLimit = 4,
+@@ -10,3 +9,4 @@ itemBases["Fishing Rod"] = {
+ weapon = { PhysicalMin = 8, PhysicalMax = 15, CritChanceBase = 5, AttackRateBase = 1.2, Range = 13, },
+ req = { str = 8, dex = 8, },
+ }
++end
diff --git a/src/Data/Bases/flask.lua.rej b/src/Data/Bases/flask.lua.rej
new file mode 100644
index 0000000000..df058bfd2a
--- /dev/null
+++ b/src/Data/Bases/flask.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/flask.lua b/src/Data/Bases/flask.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Small Life Flask"] = {
+ type = "Flask",
+ subType = "Life",
+@@ -399,3 +398,4 @@ itemBases["Iron Flask"] = {
+ flask = { duration = 4, chargesUsed = 40, chargesMax = 60, buff = { "+200 to Ward" }, },
+ req = { level = 27, },
+ }
++end
diff --git a/src/Data/Bases/gloves.lua.rej b/src/Data/Bases/gloves.lua.rej
new file mode 100644
index 0000000000..7907d3e86a
--- /dev/null
+++ b/src/Data/Bases/gloves.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/gloves.lua b/src/Data/Bases/gloves.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+
+ itemBases["Iron Gauntlets"] = {
+ type = "Gloves",
+@@ -837,3 +836,4 @@ itemBases["Golden Bracers"] = {
+ armour = { },
+ req = { level = 12, },
+ }
++end
diff --git a/src/Data/Bases/helmet.lua b/src/Data/Bases/helmet.lua
index 486ea0281e..09ee01735f 100644
--- a/src/Data/Bases/helmet.lua
+++ b/src/Data/Bases/helmet.lua
@@ -2677,3 +2677,4 @@ itemBases["Golden Visage"] = {
armour = { },
req = { level = 12, },
}
+end
diff --git a/src/Data/Bases/helmet.lua.rej b/src/Data/Bases/helmet.lua.rej
new file mode 100644
index 0000000000..531eae43af
--- /dev/null
+++ b/src/Data/Bases/helmet.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Data/Bases/helmet.lua b/src/Data/Bases/helmet.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+
+ itemBases["Iron Hat"] = {
+ type = "Helmet",
diff --git a/src/Data/Bases/jewel.lua b/src/Data/Bases/jewel.lua
index 7f19b8c210..7c2674e775 100644
--- a/src/Data/Bases/jewel.lua
+++ b/src/Data/Bases/jewel.lua
@@ -64,3 +64,4 @@ itemBases["Timeless Jewel"] = {
implicitModTypes = { },
req = { },
}
+end
diff --git a/src/Data/Bases/jewel.lua.rej b/src/Data/Bases/jewel.lua.rej
new file mode 100644
index 0000000000..3a86e63cac
--- /dev/null
+++ b/src/Data/Bases/jewel.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Data/Bases/jewel.lua b/src/Data/Bases/jewel.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Crimson Jewel"] = {
+ type = "Jewel",
+ tags = { default = true, jewel = true, not_dex = true, not_for_sale = true, not_int = true, strjewel = true, },
diff --git a/src/Data/Bases/mace.lua.rej b/src/Data/Bases/mace.lua.rej
new file mode 100644
index 0000000000..04d192a963
--- /dev/null
+++ b/src/Data/Bases/mace.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/mace.lua b/src/Data/Bases/mace.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Driftwood Club"] = {
+ type = "One Handed Mace",
+ socketLimit = 3,
+@@ -895,3 +894,4 @@ itemBases["Impact Force Propagator"] = {
+ weapon = { PhysicalMin = 81, PhysicalMax = 135, CritChanceBase = 5, AttackRateBase = 1.15, Range = 13, },
+ req = { level = 70, str = 220, },
+ }
++end
diff --git a/src/Data/Bases/quiver.lua.rej b/src/Data/Bases/quiver.lua.rej
new file mode 100644
index 0000000000..c2f3181cf5
--- /dev/null
+++ b/src/Data/Bases/quiver.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/quiver.lua b/src/Data/Bases/quiver.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Cured Quiver"] = {
+ type = "Quiver",
+ hidden = true,
+@@ -267,3 +266,4 @@ itemBases["Artillery Quiver"] = {
+ implicitIds = { "SummonTotemCastSpeedImplicit1", },
+ req = { level = 74, },
+ }
++end
diff --git a/src/Data/Bases/ring.lua.rej b/src/Data/Bases/ring.lua.rej
new file mode 100644
index 0000000000..31f88faa8d
--- /dev/null
+++ b/src/Data/Bases/ring.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/ring.lua b/src/Data/Bases/ring.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+
+ itemBases["Iron Ring"] = {
+ type = "Ring",
+@@ -449,3 +448,4 @@ itemBases["Jet Ring"] = {
+ implicitIds = { "AllDefensesImplicitJetRing", },
+ req = { },
+ }
++end
diff --git a/src/Data/Bases/shield.lua b/src/Data/Bases/shield.lua
index 979171b0e5..f612834f6a 100644
--- a/src/Data/Bases/shield.lua
+++ b/src/Data/Bases/shield.lua
@@ -1,7 +1,6 @@
-- This file is automatically generated, do not edit!
-- Item data (c) Grinding Gear Games
-local itemBases = ...
-
+return function(itemBases)
itemBases["Splintered Tower Shield"] = {
type = "Shield",
diff --git a/src/Data/Bases/shield.lua.rej b/src/Data/Bases/shield.lua.rej
new file mode 100644
index 0000000000..aaa602682f
--- /dev/null
+++ b/src/Data/Bases/shield.lua.rej
@@ -0,0 +1,6 @@
+diff a/src/Data/Bases/shield.lua b/src/Data/Bases/shield.lua (rejected hunks)
+@@ -1164,3 +1163,4 @@ itemBases["Golden Flame"] = {
+ armour = { BlockChance = 20, MovementPenalty = 3, },
+ req = { level = 15, },
+ }
++end
diff --git a/src/Data/Bases/staff.lua.rej b/src/Data/Bases/staff.lua.rej
new file mode 100644
index 0000000000..b12e299fc2
--- /dev/null
+++ b/src/Data/Bases/staff.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/staff.lua b/src/Data/Bases/staff.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Gnarled Branch"] = {
+ type = "Staff",
+ socketLimit = 6,
+@@ -323,3 +322,4 @@ itemBases["Eventuality Rod"] = {
+ weapon = { PhysicalMin = 78, PhysicalMax = 144, CritChanceBase = 8.3, AttackRateBase = 1.25, Range = 13, },
+ req = { level = 70, str = 117, int = 117, },
+ }
++end
diff --git a/src/Data/Bases/sword.lua.rej b/src/Data/Bases/sword.lua.rej
new file mode 100644
index 0000000000..7cb3c38165
--- /dev/null
+++ b/src/Data/Bases/sword.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/sword.lua b/src/Data/Bases/sword.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+
+ itemBases["Rusted Sword"] = {
+ type = "One Handed Sword",
+@@ -959,3 +958,4 @@ itemBases["Energy Blade Two Handed"] = {
+ weapon = { PhysicalMin = 0, PhysicalMax = 0, CritChanceBase = 7, AttackRateBase = 1.6, Range = 13, },
+ req = { },
+ }
++end
diff --git a/src/Data/Bases/wand.lua.rej b/src/Data/Bases/wand.lua.rej
new file mode 100644
index 0000000000..edbf820885
--- /dev/null
+++ b/src/Data/Bases/wand.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Bases/wand.lua b/src/Data/Bases/wand.lua (rejected hunks)
+@@ -1,7 +1,6 @@
+ -- This file is automatically generated, do not edit!
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ itemBases["Driftwood Wand"] = {
+ type = "Wand",
+ socketLimit = 3,
+@@ -313,3 +312,4 @@ itemBases["Convening Wand"] = {
+ weapon = { PhysicalMin = 25, PhysicalMax = 47, CritChanceBase = 8, AttackRateBase = 1.5, Range = 120, },
+ req = { level = 50, int = 183, },
+ }
++end
diff --git a/src/Data/BossSkills.lua b/src/Data/BossSkills.lua
index 6bb77b7c4d..a82293b505 100644
--- a/src/Data/BossSkills.lua
+++ b/src/Data/BossSkills.lua
@@ -5,6 +5,7 @@
-- Boss Skill data (c) Grinding Gear Games
--
return {
+ bossSkills = {
["Atziri Flameblast"] = {
DamageType = "Spell",
DamageMultipliers = {
@@ -167,7 +168,9 @@ return {
},
tooltip = "Cannot be Blocked, Dodged, or Suppressed. \n It is three separate hits, and has a large DoT effect. Neither is taken into account here. \n i.e. Hits before death should be more than 3 to survive"
},
-},{
+ },
+
+ bossSkillsList = {
{ val = "None", label = "None" },
{ val = "Atziri Flameblast", label = "Atziri Flameblast" },
{ val = "Shaper Ball", label = "Shaper Ball" },
@@ -178,5 +181,5 @@ return {
{ val = "Exarch Ball", label = "Exarch Ball" },
{ val = "Eater Beam", label = "Eater Beam" },
{ val = "Maven Fireball", label = "Maven Fireball" },
- { val = "Maven Memory Game", label = "Maven Memory Game" }
-}
\ No newline at end of file
+ { val = "Maven Memory Game", label = "Maven Memory Game" } },
+}
diff --git a/src/Data/Bosses.lua b/src/Data/Bosses.lua
index 13f07d5cb2..66239e31f8 100644
--- a/src/Data/Bosses.lua
+++ b/src/Data/Bosses.lua
@@ -4,8 +4,7 @@
-- Boss Data
-- Boss data (c) Grinding Gear Games
--
-local bosses = ...
-
+local bosses = {}
bosses["Venarius"] = {
armourMult = 50,
evasionMult = 0,
@@ -121,3 +120,4 @@ bosses["Drox"] = {
evasionMult = 0,
isUber = false,
}
+return bosses
diff --git a/src/Data/Minions.lua.rej b/src/Data/Minions.lua.rej
new file mode 100644
index 0000000000..e8b2621cb7
--- /dev/null
+++ b/src/Data/Minions.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Minions.lua b/src/Data/Minions.lua (rejected hunks)
+@@ -4,8 +4,10 @@
+ -- Minion Data
+ -- Monster data (c) Grinding Gear Games
+ --
+-local minions, mod = ...
+
++return function(mod, flag)
++ ---@class MinionData
++ local minions = {}
+ minions["RaisedZombie"] = {
+ name = "Raised Zombie",
+ monsterTags = { "animal_claw_weapon", "fast_movement", "flesh_armour", "is_unarmed", "medium_height", "melee", "physical_affinity", "red_blood", "undead", "zombie", },
+@@ -1945,3 +1947,5 @@ minions["ShamblingUndead"] = {
+ -- set_item_drop_slots [set_item_drop_slots = 0]
+ },
+ }
++ return minions
++end
diff --git a/src/Data/Misc.lua.rej b/src/Data/Misc.lua.rej
new file mode 100644
index 0000000000..6ef183cbf6
--- /dev/null
+++ b/src/Data/Misc.lua.rej
@@ -0,0 +1,15 @@
+diff a/src/Data/Misc.lua b/src/Data/Misc.lua (rejected hunks)
+@@ -1,6 +1,7 @@
+ -- This file is automatically generated, do not edit!
+
+-local data = ...
++---@class MiscDataExport
++local data = {}
+ -- From DefaultMonsterStats.dat
+ data.monsterEvasionTable = { 67, 86, 104, 124, 144, 166, 188, 211, 234, 259, 285, 311, 339, 368, 397, 428, 460, 493, 527, 563, 600, 638, 677, 718, 760, 804, 849, 896, 944, 994, 1046, 1100, 1155, 1212, 1271, 1332, 1395, 1460, 1528, 1597, 1669, 1743, 1819, 1898, 1979, 2063, 2150, 2239, 2331, 2426, 2524, 2626, 2730, 2837, 2948, 3063, 3180, 3302, 3427, 3556, 3689, 3826, 3967, 4112, 4262, 4416, 4575, 4739, 4907, 5081, 5260, 5444, 5633, 5828, 6029, 6235, 6448, 6667, 6892, 7124, 7362, 7608, 7860, 8120, 8388, 8663, 8946, 9237, 9536, 9844, 10160, 10486, 10821, 11165, 11519, 11883, 12258, 12643, 13038, 13445, }
+ data.monsterAccuracyTable = { 14, 15, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 31, 32, 34, 35, 37, 39, 41, 43, 45, 47, 49, 52, 54, 57, 59, 62, 65, 68, 71, 74, 77, 81, 84, 88, 92, 96, 100, 105, 109, 114, 119, 124, 129, 135, 140, 146, 152, 159, 165, 172, 179, 187, 195, 203, 211, 220, 229, 238, 247, 257, 268, 279, 290, 301, 314, 326, 339, 352, 366, 381, 396, 412, 428, 444, 462, 480, 499, 518, 538, 559, 580, 603, 626, 650, 675, 701, 728, 755, 784, 814, 845, 877, 910, 945, 980, }
+@@ -473,3 +474,4 @@ data.mapLevelBossLifeMult = { [1] = 1.5, [2] = 1.52, [3] = 1.54, [4] = 1.56, [5]
+ data.mapLevelBossAilmentMult = { [1] = 0.81, [2] = 0.81, [3] = 0.81, [4] = 0.81, [5] = 0.81, [6] = 0.81, [7] = 0.81, [8] = 0.81, [9] = 0.81, [10] = 0.81, [11] = 0.81, [12] = 0.81, [13] = 0.81, [14] = 0.81, [15] = 0.81, [16] = 0.81, [17] = 0.81, [18] = 0.81, [19] = 0.81, [20] = 0.81, [21] = 0.81, [22] = 0.81, [23] = 0.81, [24] = 0.81, [25] = 0.81, [26] = 0.81, [27] = 0.81, [28] = 0.81, [29] = 0.81, [30] = 0.81, [31] = 0.81, [32] = 0.81, [33] = 0.81, [34] = 0.81, [35] = 0.81, [36] = 0.81, [37] = 0.81, [38] = 0.81, [39] = 0.81, [40] = 0.81, [41] = 0.81, [42] = 0.81, [43] = 0.81, [44] = 0.81, [45] = 0.81, [46] = 0.81, [47] = 0.81, [48] = 0.81, [49] = 0.81, [50] = 0.81, [51] = 0.8, [52] = 0.79, [53] = 0.78, [54] = 0.77, [55] = 0.76, [56] = 0.75, [57] = 0.74, [58] = 0.73, [59] = 0.72, [60] = 0.71, [61] = 0.7, [62] = 0.69, [63] = 0.68, [64] = 0.67, [65] = 0.66, [66] = 0.65, [67] = 0.64, [68] = 0.63, [69] = 0.59, [70] = 0.58, [71] = 0.57, [72] = 0.56, [73] = 0.55, [74] = 0.53, [75] = 0.52, [76] = 0.51, [77] = 0.5, [78] = 0.49, [79] = 0.48, [80] = 0.48, [81] = 0.47, [82] = 0.47, [83] = 0.47, [84] = 0.47, [85] = 0.47, [86] = 0.47, [87] = 0.47, [88] = 0.47, [89] = 0.47, [90] = 0.47, }
+ -- From VillageBalancePerLevelShared.dat
+ data.goldRespecPrices = { 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12, 14, 15, 17, 18, 20, 22, 24, 26, 28, 31, 34, 36, 39, 43, 46, 50, 54, 58, 62, 67, 72, 83, 90, 97, 105, 113, 121, 130, 151, 161, 171, 182, 209, 222, 237, 252, 267, 295, 313, 333, 354, 376, 427, 452, 482, 513, 546, 618, 656, 694, 733, 773, 816, 860, 892, 921, 1055, 1203, 1365, 1541, 1748, 1974, 2221, 2490, 2770, 3073, 3400, 3752, 4131, 4538, 4976, 5444, 5967, 6526, 7126, 7766, 8450, 9851, 11380, 13042, 14847, 16801, 18914, 21192, 23647, 26286, 29119, }
++return data
diff --git a/src/Data/ModCache.lua.rej b/src/Data/ModCache.lua.rej
new file mode 100644
index 0000000000..7c5192604c
--- /dev/null
+++ b/src/Data/ModCache.lua.rej
@@ -0,0 +1,13 @@
+diff a/src/Data/ModCache.lua b/src/Data/ModCache.lua (rejected hunks)
+@@ -1,4 +1,5 @@
+-local c=...c[" Wolf Alpha Talisman"]={nil," Wolf Alpha Talisman "}
++local c = {}
++c[" Wolf Alpha Talisman"]={nil," Wolf Alpha Talisman "}
+ c[" Wolf Alpha Talisman League: Talisman Standard"]={nil," Wolf Alpha Talisman League: Talisman Standard "}
+ c["(10-15)% increased Energy Shield Recharge Rate"]={nil,"(10-15)% increased Energy Shield Recharge Rate "}
+ c["(10-20)% increased Effect of Cold Ailments"]={nil,"(10-20)% increased Effect of Cold Ailments "}
+@@ -13173,3 +13174,4 @@ c["wielding a Bow, with a 1 second Cooldown 12% increased Cast Speed"]={nil,"wie
+ c["you consume a total of 8 Steel Shards"]={nil,"you consume a total of 8 Steel Shards "}
+ c["your maximum number of Crab Barriers"]={nil,"your maximum number of Crab Barriers "}
+ c["your maximum number of Power Charges"]={nil,"your maximum number of Power Charges "}
++return c
diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua
index 6e5decaed8..8bfd48b325 100644
--- a/src/Data/SkillStatMap.lua
+++ b/src/Data/SkillStatMap.lua
@@ -3,8 +3,7 @@
-- Stat to internal modifier mapping table for skills
-- Stat data (c) Grinding Gear Games
--
-local mod, flag, skill = ...
-
+return function(mod, flag, skill)
return {
--
-- Skill data modifiers
diff --git a/src/Data/SkillStatMap.lua.rej b/src/Data/SkillStatMap.lua.rej
new file mode 100644
index 0000000000..36306b9ea3
--- /dev/null
+++ b/src/Data/SkillStatMap.lua.rej
@@ -0,0 +1,6 @@
+diff a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua (rejected hunks)
+@@ -2372,3 +2371,4 @@ return {
+ -- Display only
+ },
+ }
++end
diff --git a/src/Data/Skills/act_dex.lua.rej b/src/Data/Skills/act_dex.lua.rej
new file mode 100644
index 0000000000..76f86f3475
--- /dev/null
+++ b/src/Data/Skills/act_dex.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/act_dex.lua b/src/Data/Skills/act_dex.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Active Dexterity skill gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["AlchemistsMark"] = {
+ name = "Alchemist's Mark",
+ baseTypeName = "Alchemist's Mark",
+@@ -18480,4 +18479,5 @@ skills["QuickstepHardMode"] = {
+ [9] = { cooldown = 10, levelRequirement = 1, storedUses = 1, },
+ [10] = { cooldown = 10, levelRequirement = 1, storedUses = 1, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Skills/act_int.lua.rej b/src/Data/Skills/act_int.lua.rej
new file mode 100644
index 0000000000..0013a82602
--- /dev/null
+++ b/src/Data/Skills/act_int.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/act_int.lua b/src/Data/Skills/act_int.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Active Intelligence skill gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["Arc"] = {
+ name = "Arc",
+ baseTypeName = "Arc",
+@@ -21483,4 +21482,5 @@ skills["Zealotry"] = {
+ [39] = { 19, 53, 33, cooldown = 1.2, levelRequirement = 99, manaReservationPercent = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, },
+ [40] = { 20, 54, 34, cooldown = 1.2, levelRequirement = 100, manaReservationPercent = 50, storedUses = 1, statInterpolation = { 1, 1, 1, }, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Skills/act_str.lua.rej b/src/Data/Skills/act_str.lua.rej
new file mode 100644
index 0000000000..c59d056df1
--- /dev/null
+++ b/src/Data/Skills/act_str.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/act_str.lua b/src/Data/Skills/act_str.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Active Strength skill gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["Absolution"] = {
+ name = "Absolution",
+ baseTypeName = "Absolution",
+@@ -13105,4 +13104,5 @@ skills["WarBanner"] = {
+ [39] = { 4, 8, 13, 13, cooldown = 1, levelRequirement = 99, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, cost = { Mana = 23, }, },
+ [40] = { 4, 8, 13, 14, cooldown = 1, levelRequirement = 100, storedUses = 1, statInterpolation = { 1, 1, 1, 1, }, cost = { Mana = 23, }, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Skills/minion.lua.rej b/src/Data/Skills/minion.lua.rej
new file mode 100644
index 0000000000..2e1887bbeb
--- /dev/null
+++ b/src/Data/Skills/minion.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/minion.lua b/src/Data/Skills/minion.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Minion active skills
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["ChaosElementalCascadeSummoned"] = {
+ name = "Cascade",
+ hidden = true,
+@@ -2346,4 +2345,5 @@ skills["MeleePartialChaos"] = {
+ levels = {
+ [1] = { 0, baseMultiplier = 0.75, levelRequirement = 1, statInterpolation = { 2, }, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Skills/other.lua.rej b/src/Data/Skills/other.lua.rej
new file mode 100644
index 0000000000..741b8a2cd1
--- /dev/null
+++ b/src/Data/Skills/other.lua.rej
@@ -0,0 +1,17 @@
+diff a/src/Data/Skills/other.lua b/src/Data/Skills/other.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Other active skills
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["RepeatingShockwave"] = {
+ name = "Abberath's Fury",
+ hidden = true,
+@@ -6144,3 +6143,5 @@ skills["EnemyExplode"] = {
+ [1] = { damageEffectiveness = 1, baseMultiplier = 1, levelRequirement = 1, }
+ }
+ }
++
++end
diff --git a/src/Data/Skills/spectre.lua.rej b/src/Data/Skills/spectre.lua.rej
new file mode 100644
index 0000000000..77f89e3ea0
--- /dev/null
+++ b/src/Data/Skills/spectre.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/spectre.lua b/src/Data/Skills/spectre.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Spectre active skills
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["AxisCasterGlacialCascade"] = {
+ name = "Glacial Cascade",
+ hidden = true,
+@@ -11884,4 +11883,5 @@ skills["VaalOverseerHeavyStrike"] = {
+ [1] = { baseMultiplier = 1.26, cooldown = 2, levelRequirement = 1, storedUses = 1, },
+ [2] = { baseMultiplier = 1.26, cooldown = 2, levelRequirement = 68, storedUses = 1, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Skills/sup_dex.lua.rej b/src/Data/Skills/sup_dex.lua.rej
new file mode 100644
index 0000000000..b81839eaec
--- /dev/null
+++ b/src/Data/Skills/sup_dex.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/sup_dex.lua b/src/Data/Skills/sup_dex.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Dexterity support gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["SupportAddedColdDamage"] = {
+ name = "Added Cold Damage",
+ description = "Supports any skill that hits enemies.",
+@@ -5050,4 +5049,5 @@ skills["SupportWitheringTouch"] = {
+ [39] = { 44, levelRequirement = 99, manaMultiplier = 30, statInterpolation = { 1, }, },
+ [40] = { 44, levelRequirement = 100, manaMultiplier = 30, statInterpolation = { 1, }, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Skills/sup_int.lua.rej b/src/Data/Skills/sup_int.lua.rej
new file mode 100644
index 0000000000..ff6ef8b7c7
--- /dev/null
+++ b/src/Data/Skills/sup_int.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/sup_int.lua b/src/Data/Skills/sup_int.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Intelligence support gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["SupportAddedChaosDamage"] = {
+ name = "Added Chaos Damage",
+ description = "Supports any skill that hits enemies.",
+@@ -7004,4 +7003,5 @@ skills["SupportVaalSacrifice"] = {
+ [14] = { 120, levelRequirement = 94, statInterpolation = { 1, }, },
+ [15] = { 125, levelRequirement = 95, statInterpolation = { 1, }, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Skills/sup_str.lua.rej b/src/Data/Skills/sup_str.lua.rej
new file mode 100644
index 0000000000..643936e7bd
--- /dev/null
+++ b/src/Data/Skills/sup_str.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua (rejected hunks)
+@@ -4,8 +4,7 @@
+ -- Strength support gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ skills["SupportAddedFireDamage"] = {
+ name = "Added Fire Damage",
+ description = "Supports any skill that hits enemies.",
+@@ -5545,4 +5544,5 @@ skills["SupportExpertRetaliation"] = {
+ [39] = { 107, 53, levelRequirement = 99, manaMultiplier = 30, statInterpolation = { 1, 1, }, },
+ [40] = { 108, 54, levelRequirement = 100, manaMultiplier = 30, statInterpolation = { 1, 1, }, },
+ },
+-}
+\ No newline at end of file
++}
++end
diff --git a/src/Data/Spectres.lua.rej b/src/Data/Spectres.lua.rej
new file mode 100644
index 0000000000..6f0cb56248
--- /dev/null
+++ b/src/Data/Spectres.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Data/Spectres.lua b/src/Data/Spectres.lua (rejected hunks)
+@@ -4,8 +4,10 @@
+ -- Spectre Data
+ -- Monster data (c) Grinding Gear Games
+ --
+-local minions, mod, flag = ...
+
++return function(mod, flag)
++ ---@class SpectreData
++ local minions = {}
+ -- Blackguard
+ minions["Metadata/Monsters/Axis/AxisCaster"] = {
+ name = "Blackguard Mage",
+@@ -7225,3 +7227,5 @@ minions["Metadata/Monsters/VaalMonsters/VaalOverseer"] = {
+ modList = {
+ },
+ }
++ return minions
++end
diff --git a/src/Export/Bases/amulet.txt.rej b/src/Export/Bases/amulet.txt.rej
new file mode 100644
index 0000000000..42418af62a
--- /dev/null
+++ b/src/Export/Bases/amulet.txt.rej
@@ -0,0 +1,18 @@
+diff a/src/Export/Bases/amulet.txt b/src/Export/Bases/amulet.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Amulet
+ #influenceBaseTag amulet
+
+@@ -20,4 +19,5 @@ local itemBases = ...
+ #base Metadata/Items/Amulets/Talismans/Talisman2_6_4 Avian Twins Talisman (Cold-To-Fire)
+ #base Metadata/Items/Amulets/Talismans/Talisman2_6_5 Avian Twins Talisman (Lightning-To-Cold)
+ #base Metadata/Items/Amulets/Talismans/Talisman3_6_1 Monkey Paw Talisman (Power)
+-#base Metadata/Items/Amulets/Talismans/Talisman3_6_2 Monkey Paw Talisman (Frenzy)
+\ No newline at end of file
++#base Metadata/Items/Amulets/Talismans/Talisman3_6_2 Monkey Paw Talisman (Frenzy)
++end
+\ No newline at end of file
diff --git a/src/Export/Bases/axe.txt.rej b/src/Export/Bases/axe.txt.rej
new file mode 100644
index 0000000000..7835534448
--- /dev/null
+++ b/src/Export/Bases/axe.txt.rej
@@ -0,0 +1,14 @@
+diff a/src/Export/Bases/axe.txt b/src/Export/Bases/axe.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type One Handed Axe
+ #influenceBaseTag axe
+ #socketLimit 3
+@@ -10,3 +9,4 @@ local itemBases = ...
+ #influenceBaseTag 2h_axe
+ #socketLimit 6
+ #baseMatch BaseType Metadata/Items/Weapons/TwoHandWeapons/TwoHandAxes/AbstractTwoHandAxe
++end
diff --git a/src/Export/Bases/belt.txt.rej b/src/Export/Bases/belt.txt.rej
new file mode 100644
index 0000000000..25e04428d6
--- /dev/null
+++ b/src/Export/Bases/belt.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/belt.txt b/src/Export/Bases/belt.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Belt
+ #influenceBaseTag belt
+ #baseMatch Metadata/Items/Belts/Belt%d+
+@@ -11,4 +10,5 @@ local itemBases = ...
+ #base Metadata/Items/Belts/BeltAbyss
+ #base Metadata/Items/Belts/BeltFaridun
+
+-#base Metadata/Items/Belts/BeltDemigods1
+\ No newline at end of file
++#base Metadata/Items/Belts/BeltDemigods1
++end
diff --git a/src/Export/Bases/body.txt.rej b/src/Export/Bases/body.txt.rej
new file mode 100644
index 0000000000..f822cec442
--- /dev/null
+++ b/src/Export/Bases/body.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/body.txt b/src/Export/Bases/body.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Body Armour
+ #influenceBaseTag body_armour
+ #socketLimit 6
+@@ -26,4 +25,5 @@ local itemBases = ...
+ #subType Armour/Evasion/Energy Shield
+ #baseMatch Metadata/Items/Armours/BodyArmours/BodyStrDexInt%d+
+ #forceHide true
+-#base Metadata/Items/Armours/BodyArmours/BodyDemigods1
+\ No newline at end of file
++#base Metadata/Items/Armours/BodyArmours/BodyDemigods1
++end
diff --git a/src/Export/Bases/boots.txt.rej b/src/Export/Bases/boots.txt.rej
new file mode 100644
index 0000000000..f4de6ba6a1
--- /dev/null
+++ b/src/Export/Bases/boots.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/boots.txt b/src/Export/Bases/boots.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Boots
+ #influenceBaseTag boots
+ #socketLimit 4
+@@ -40,4 +39,5 @@ local itemBases = ...
+ #baseMatch Metadata/Items/Armours/Boots/BootsExpedition%d+
+
+ #subType
+-#base Metadata/Items/Armours/Boots/BootsDemigods1
+\ No newline at end of file
++#base Metadata/Items/Armours/Boots/BootsDemigods1
++end
diff --git a/src/Export/Bases/bow.txt.rej b/src/Export/Bases/bow.txt.rej
new file mode 100644
index 0000000000..032bb1edd6
--- /dev/null
+++ b/src/Export/Bases/bow.txt.rej
@@ -0,0 +1,13 @@
+diff a/src/Export/Bases/bow.txt b/src/Export/Bases/bow.txt (rejected hunks)
+@@ -1,7 +1,7 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Bow
+ #influenceBaseTag bow
+ #socketLimit 6
+-#baseMatch BaseType Metadata/Items/Weapons/TwoHandWeapons/Bows/AbstractBow
+\ No newline at end of file
++#baseMatch BaseType Metadata/Items/Weapons/TwoHandWeapons/Bows/AbstractBow
++end
diff --git a/src/Export/Bases/claw.txt.rej b/src/Export/Bases/claw.txt.rej
new file mode 100644
index 0000000000..571ba24808
--- /dev/null
+++ b/src/Export/Bases/claw.txt.rej
@@ -0,0 +1,13 @@
+diff a/src/Export/Bases/claw.txt b/src/Export/Bases/claw.txt (rejected hunks)
+@@ -1,7 +1,7 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Claw
+ #influenceBaseTag claw
+ #socketLimit 3
+-#baseMatch BaseType Metadata/Items/Weapons/OneHandWeapons/Claws/AbstractClaw
+\ No newline at end of file
++#baseMatch BaseType Metadata/Items/Weapons/OneHandWeapons/Claws/AbstractClaw
++end
diff --git a/src/Export/Bases/dagger.txt.rej b/src/Export/Bases/dagger.txt.rej
new file mode 100644
index 0000000000..3fedab89b7
--- /dev/null
+++ b/src/Export/Bases/dagger.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/dagger.txt b/src/Export/Bases/dagger.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Dagger
+ #influenceBaseTag dagger
+ #socketLimit 3
+@@ -10,4 +9,5 @@ local itemBases = ...
+ #subType Rune Dagger
+ #influenceBaseTag rune_dagger
+ #socketLimit 3
+-#baseMatch BaseType Metadata/Items/Weapons/OneHandWeapons/Daggers/AbstractRuneDagger
+\ No newline at end of file
++#baseMatch BaseType Metadata/Items/Weapons/OneHandWeapons/Daggers/AbstractRuneDagger
++end
diff --git a/src/Export/Bases/fishing.txt.rej b/src/Export/Bases/fishing.txt.rej
new file mode 100644
index 0000000000..f12923d2d4
--- /dev/null
+++ b/src/Export/Bases/fishing.txt.rej
@@ -0,0 +1,11 @@
+diff a/src/Export/Bases/fishing.txt b/src/Export/Bases/fishing.txt (rejected hunks)
+@@ -1,7 +1,7 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Fishing Rod
+ #socketLimit 4
+ #forceShow true
+ #baseMatch Metadata/Items/Weapons/TwoHandWeapon/FishingRods/FishingRod
++end
diff --git a/src/Export/Bases/flask.txt.rej b/src/Export/Bases/flask.txt.rej
new file mode 100644
index 0000000000..3f4e2a4e6e
--- /dev/null
+++ b/src/Export/Bases/flask.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/flask.txt b/src/Export/Bases/flask.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Flask
+ #subType Life
+ #baseMatch Metadata/Items/Flasks/FlaskLife
+@@ -12,4 +11,5 @@ local itemBases = ...
+ #baseMatch Metadata/Items/Flasks/FlaskHybrid
+
+ #subType Utility
+-#baseMatch Metadata/Items/Flasks/FlaskUtility
+\ No newline at end of file
++#baseMatch Metadata/Items/Flasks/FlaskUtility
++end
diff --git a/src/Export/Bases/gloves.txt.rej b/src/Export/Bases/gloves.txt.rej
new file mode 100644
index 0000000000..0c6190a8a8
--- /dev/null
+++ b/src/Export/Bases/gloves.txt.rej
@@ -0,0 +1,14 @@
+diff a/src/Export/Bases/gloves.txt b/src/Export/Bases/gloves.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Gloves
+ #influenceBaseTag gloves
+ #socketLimit 4
+@@ -35,3 +34,4 @@ local itemBases = ...
+
+ #subType
+ #base Metadata/Items/Armours/Gloves/GlovesDemigods1
++end
diff --git a/src/Export/Bases/helmet.txt.rej b/src/Export/Bases/helmet.txt.rej
new file mode 100644
index 0000000000..e5d489e1ad
--- /dev/null
+++ b/src/Export/Bases/helmet.txt.rej
@@ -0,0 +1,14 @@
+diff a/src/Export/Bases/helmet.txt b/src/Export/Bases/helmet.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Helmet
+ #influenceBaseTag helmet
+ #socketLimit 4
+@@ -32,3 +31,4 @@ local itemBases = ...
+
+ #subType
+ #base Metadata/Items/Armours/Helmets/HelmetWreath1
++end
diff --git a/src/Export/Bases/jewel.txt b/src/Export/Bases/jewel.txt
index 61c1ae4321..2f1601a52a 100644
--- a/src/Export/Bases/jewel.txt
+++ b/src/Export/Bases/jewel.txt
@@ -1,6 +1,5 @@
-- Item data (c) Grinding Gear Games
-local itemBases = ...
-
+return function(itemBases)
#type Jewel
#base Metadata/Items/Jewels/JewelStr
#base Metadata/Items/Jewels/JewelDex
diff --git a/src/Export/Bases/jewel.txt.rej b/src/Export/Bases/jewel.txt.rej
new file mode 100644
index 0000000000..615cbda0a0
--- /dev/null
+++ b/src/Export/Bases/jewel.txt.rej
@@ -0,0 +1,9 @@
+diff a/src/Export/Bases/jewel.txt b/src/Export/Bases/jewel.txt (rejected hunks)
+@@ -25,4 +24,5 @@ local itemBases = ...
+ #subType Charm
+ #base Metadata/Items/AnimalCharms/StrAnimalCharm
+ #base Metadata/Items/AnimalCharms/DexAnimalCharm
+-#base Metadata/Items/AnimalCharms/IntAnimalCharm
+\ No newline at end of file
++#base Metadata/Items/AnimalCharms/IntAnimalCharm
++end
diff --git a/src/Export/Bases/mace.txt.rej b/src/Export/Bases/mace.txt.rej
new file mode 100644
index 0000000000..a4645e12fc
--- /dev/null
+++ b/src/Export/Bases/mace.txt.rej
@@ -0,0 +1,14 @@
+diff a/src/Export/Bases/mace.txt b/src/Export/Bases/mace.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type One Handed Mace
+ #influenceBaseTag mace
+ #socketLimit 3
+@@ -14,3 +13,4 @@ local itemBases = ...
+ #influenceBaseTag 2h_mace
+ #socketLimit 6
+ #baseMatch BaseType Metadata/Items/Weapons/TwoHandWeapons/TwoHandMaces/AbstractTwoHandMace
++end
diff --git a/src/Export/Bases/quiver.txt.rej b/src/Export/Bases/quiver.txt.rej
new file mode 100644
index 0000000000..d88d0835a4
--- /dev/null
+++ b/src/Export/Bases/quiver.txt.rej
@@ -0,0 +1,14 @@
+diff a/src/Export/Bases/quiver.txt b/src/Export/Bases/quiver.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Quiver
+ #influenceBaseTag quiver
+ #forceHide true
+@@ -12,3 +11,4 @@ local itemBases = ...
+ #baseMatch Metadata/Items/Quivers/Descent
+ #forceShow false
+ #baseMatch Metadata/Items/Quivers/QuiverAtlas%d+
++end
diff --git a/src/Export/Bases/ring.txt.rej b/src/Export/Bases/ring.txt.rej
new file mode 100644
index 0000000000..fbfe40a96d
--- /dev/null
+++ b/src/Export/Bases/ring.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/ring.txt b/src/Export/Bases/ring.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Ring
+ #influenceBaseTag ring
+
+@@ -19,4 +18,5 @@ local itemBases = ...
+
+ #base Metadata/Items/Rings/BreachRing
+ #base Metadata/Items/Rings/RingDemigods1
+-#base Metadata/Items/Rings/RingVictor1
+\ No newline at end of file
++#base Metadata/Items/Rings/RingVictor1
++end
diff --git a/src/Export/Bases/shield.txt.rej b/src/Export/Bases/shield.txt.rej
new file mode 100644
index 0000000000..36c30bcf93
--- /dev/null
+++ b/src/Export/Bases/shield.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/shield.txt b/src/Export/Bases/shield.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Shield
+ #influenceBaseTag shield
+ #socketLimit 3
+@@ -27,4 +26,5 @@ local itemBases = ...
+ #baseMatch Metadata/Items/Armours/Shields/ShieldDexInt%d+
+
+ #subType
+-#base Metadata/Items/Armours/Shields/ShieldDemigods
+\ No newline at end of file
++#base Metadata/Items/Armours/Shields/ShieldDemigods
++end
diff --git a/src/Export/Bases/staff.txt.rej b/src/Export/Bases/staff.txt.rej
new file mode 100644
index 0000000000..67fac69952
--- /dev/null
+++ b/src/Export/Bases/staff.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/staff.txt b/src/Export/Bases/staff.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Staff
+ #influenceBaseTag staff
+ #socketLimit 6
+@@ -10,4 +9,5 @@ local itemBases = ...
+ #subType Warstaff
+ #influenceBaseTag warstaff
+ #socketLimit 6
+-#baseMatch BaseType Metadata/Items/Weapons/TwoHandWeapons/Staves/AbstractWarstaff
+\ No newline at end of file
++#baseMatch BaseType Metadata/Items/Weapons/TwoHandWeapons/Staves/AbstractWarstaff
++end
diff --git a/src/Export/Bases/sword.txt.rej b/src/Export/Bases/sword.txt.rej
new file mode 100644
index 0000000000..6cf2c6ab19
--- /dev/null
+++ b/src/Export/Bases/sword.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/sword.txt b/src/Export/Bases/sword.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type One Handed Sword
+ #socketLimit 3
+ #influenceBaseTag sword
+@@ -26,4 +25,5 @@ local itemBases = ...
+
+ #forceHide true
+ #base Metadata/Items/Weapons/TwoHandWeapons/TwoHandSwords/StormBladeTwoHand
+-#forceHide false
+\ No newline at end of file
++#forceHide false
++end
diff --git a/src/Export/Bases/wand.txt.rej b/src/Export/Bases/wand.txt.rej
new file mode 100644
index 0000000000..3511cfbea8
--- /dev/null
+++ b/src/Export/Bases/wand.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Bases/wand.txt b/src/Export/Bases/wand.txt (rejected hunks)
+@@ -1,6 +1,5 @@
+ -- Item data (c) Grinding Gear Games
+-local itemBases = ...
+-
++return function(itemBases)
+ #type Wand
+ #influenceBaseTag wand
+ #socketLimit 3
+@@ -19,4 +18,5 @@ local itemBases = ...
+ #type Wand
+ #influenceBaseTag wand
+ #socketLimit 3
+-#base Metadata/Items/Weapons/OneHandWeapons/Wands/WandMinion2
+\ No newline at end of file
++#base Metadata/Items/Weapons/OneHandWeapons/Wands/WandMinion2
++end
diff --git a/src/Export/Classes/Dat64File.lua b/src/Export/Classes/Dat64File.lua
index 9ebb0b6e22..4d052f3423 100644
--- a/src/Export/Classes/Dat64File.lua
+++ b/src/Export/Classes/Dat64File.lua
@@ -84,7 +84,10 @@ local dataTypes = {
},
}
-local Dat64FileClass = newClass("Dat64File", function(self, name, raw)
+---@class Dat64File
+local Dat64FileClass = newClass("Dat64File")
+
+function Dat64FileClass:Dat64File(name, raw)
self.name = name:lower()
self.raw = raw
@@ -124,7 +127,8 @@ local Dat64FileClass = newClass("Dat64File", function(self, name, raw)
--ConPrintf("Loaded '%s': %d Rows at %d Bytes", self.name, self.rowCount, self.rowSize)
self:OnSpecChanged()
-end)
+ return self
+end
function Dat64FileClass:OnSpecChanged()
wipeTable(self.cols)
diff --git a/src/Export/Classes/DatFile.lua b/src/Export/Classes/DatFile.lua
index f63f80a92e..6bc843fe95 100644
--- a/src/Export/Classes/DatFile.lua
+++ b/src/Export/Classes/DatFile.lua
@@ -76,7 +76,10 @@ local dataTypes = {
},
}
-local DatFileClass = newClass("DatFile", function(self, name, raw)
+---@class DatFile
+local DatFileClass = newClass("DatFile")
+
+function DatFileClass:DatFile(name, raw)
self.name = name
self.raw = raw
@@ -116,7 +119,8 @@ local DatFileClass = newClass("DatFile", function(self, name, raw)
--ConPrintf("Loaded '%s': %d Rows at %d Bytes", self.name, self.rowCount, self.rowSize)
self:OnSpecChanged()
-end)
+ return self
+end
function DatFileClass:OnSpecChanged()
wipeTable(self.cols)
diff --git a/src/Export/Classes/DatListControl.lua b/src/Export/Classes/DatListControl.lua
index e1153982d9..a47aac70d7 100644
--- a/src/Export/Classes/DatListControl.lua
+++ b/src/Export/Classes/DatListControl.lua
@@ -3,12 +3,16 @@
-- Class: Dat List
-- Dat list control.
--
-local DatListClass = newClass("DatListControl", "ListControl", function(self, anchor, rect)
+---@class DatListControl: ListControl
+local DatListClass = newClass("DatListControl", "ListControl")
+
+function DatListClass:DatListControl(anchor, rect)
self.originalList = main.datFileList
self.searchBuf = ""
self.filteredList = self.originalList
- self.ListControl(anchor, rect, 14, "VERTICAL", false, self.filteredList)
-end)
+ self:ListControl(anchor, rect, 14, "VERTICAL", false, self.filteredList)
+ return self
+end
function DatListClass:BuildFilteredList()
local search = self.searchBuf:lower()
diff --git a/src/Export/Classes/GGPKData.lua b/src/Export/Classes/GGPKData.lua
index 88236939ea..f327739712 100644
--- a/src/Export/Classes/GGPKData.lua
+++ b/src/Export/Classes/GGPKData.lua
@@ -31,7 +31,10 @@ end
-- Path can be in any format recognized by the extractor at oozPath, ie,
-- a .ggpk file or a Steam Path of Exile directory
-local GGPKClass = newClass("GGPKData", function(self, path, datPath, reExport)
+---@class GGPKData
+local GGPKClass = newClass("GGPKData")
+
+function GGPKClass:GGPKData(path, datPath, reExport)
if datPath then
self.oozPath = datPath:match("\\$") and datPath or (datPath .. "\\")
else
diff --git a/src/Export/Classes/GGPKData.lua.rej b/src/Export/Classes/GGPKData.lua.rej
new file mode 100644
index 0000000000..7ccdcf85d7
--- /dev/null
+++ b/src/Export/Classes/GGPKData.lua.rej
@@ -0,0 +1,11 @@
+diff a/src/Export/Classes/GGPKData.lua b/src/Export/Classes/GGPKData.lua (rejected hunks)
+@@ -46,7 +49,8 @@ local GGPKClass = newClass("GGPKData", function(self, path, datPath, reExport)
+ self.ot = { }
+
+ self:AddDat64Files()
+-end)
++ return self
++end
+
+ function GGPKClass:CleanDir(reExport)
+ if reExport then
diff --git a/src/Export/Classes/GGPKSourceListControl.lua b/src/Export/Classes/GGPKSourceListControl.lua
index 90f01fd3ca..ab478c1f8e 100644
--- a/src/Export/Classes/GGPKSourceListControl.lua
+++ b/src/Export/Classes/GGPKSourceListControl.lua
@@ -3,46 +3,50 @@
-- Class: GGPK Source List
-- GGPK source list control.
--
-local GGPKSourceListClass = newClass("GGPKSourceListControl", "ListControl", function(self, anchor, rect)
- self.ListControl(anchor, rect, 16, false, false, main.datSources)
+---@class GGPKSourceListControl: ListControl
+local GGPKSourceListClass = newClass("GGPKSourceListControl", "ListControl")
+
+function GGPKSourceListClass:GGPKSourceListControl(anchor, rect)
+ self:ListControl(anchor, rect, 16, false, false, main.datSources)
self.colList = {
{ width = self.width * 0.25, label = "Name", sortable = true },
{ width = self.width * 0.75, label = "Spec File Path" },
}
self.colLabels = true
- self.controls.new = new("ButtonControl", {"BOTTOMLEFT",self,"TOP"}, {-62, -4, 60, 18}, "New", function()
+ self.controls.new = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self,"TOP"}, {-62, -4, 60, 18}, "New", function()
local datSource = {}
self:EditDATSource(datSource, true)
end)
- self.controls.delete = new("ButtonControl", {"LEFT",self.controls.new,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
+ self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT",self.controls.new,"RIGHT"}, {4, 0, 60, 18}, "Delete", function()
self:OnSelDelete(self.selIndex)
end)
self.controls.delete.enabled = function()
return self.selValue ~= nil and #self.list > 1
end
-end)
+ return self
+end
function GGPKSourceListClass:EditDATSource(datSource, newSource)
local controls = { }
- controls.labelLabel = new("LabelControl", nil, {-30, 20, 0, 16}, "^7Name:")
- controls.label = new("EditControl", nil, {85, 20, 180, 20}, datSource.label, nil, nil, nil, function(buf)
+ controls.labelLabel = new("LabelControl"):LabelControl(nil, {-30, 20, 0, 16}, "^7Name:")
+ controls.label = new("EditControl"):EditControl(nil, {85, 20, 180, 20}, datSource.label, nil, nil, nil, function(buf)
controls.save.enabled = (controls.dat.buf:match("%S") or controls.ggpk.buf:match("%S")) and buf:match("%S")
end)
- controls.ggpkLabel = new("LabelControl", nil, {0, 40, 0, 16}, "^7Source from GGPK/Steam PoE path:")
- controls.ggpk = new("EditControl", {"TOP",controls.ggpkLabel,"TOP"}, {0, 20, 350, 20}, datSource.ggpkPath, nil, nil, nil, function(buf)
+ controls.ggpkLabel = new("LabelControl"):LabelControl(nil, {0, 40, 0, 16}, "^7Source from GGPK/Steam PoE path:")
+ controls.ggpk = new("EditControl"):EditControl({"TOP",controls.ggpkLabel,"TOP"}, {0, 20, 350, 20}, datSource.ggpkPath, nil, nil, nil, function(buf)
controls.save.enabled = (buf:match("%S") or controls.dat.buf:match("%S")) and controls.label.buf:match("%S") and controls.spec.buf:match("%S")
end)
controls.ggpk.enabled = function() return not controls.dat.buf:match("%S") end
- controls.datLabel = new("LabelControl", {"TOP",controls.ggpk,"TOP"}, {0, 22, 0, 16}, "^7Source from DAT files:")
- controls.dat = new("EditControl", {"TOP",controls.datLabel,"TOP"}, {0, 20, 350, 20}, datSource.datFilePath, nil, nil, nil, function(buf)
+ controls.datLabel = new("LabelControl"):LabelControl({"TOP",controls.ggpk,"TOP"}, {0, 22, 0, 16}, "^7Source from DAT files:")
+ controls.dat = new("EditControl"):EditControl({"TOP",controls.datLabel,"TOP"}, {0, 20, 350, 20}, datSource.datFilePath, nil, nil, nil, function(buf)
controls.save.enabled = (buf:match("%S") or controls.ggpk.buf:match("%S")) and controls.label.buf:match("%S") and controls.spec.buf:match("%S")
end)
controls.dat.enabled = function() return not controls.ggpk.buf:match("%S") end
- controls.specLabel = new("LabelControl", {"TOP",controls.dat,"TOP"}, {0, 22, 0, 16}, "^7Spec File location:")
- controls.spec = new("EditControl", {"TOP",controls.specLabel,"TOP"}, {0, 20, 350, 20}, datSource.spec or "spec.lua", nil, nil, nil, function(buf)
+ controls.specLabel = new("LabelControl"):LabelControl({"TOP",controls.dat,"TOP"}, {0, 22, 0, 16}, "^7Spec File location:")
+ controls.spec = new("EditControl"):EditControl({"TOP",controls.specLabel,"TOP"}, {0, 20, 350, 20}, datSource.spec or "spec.lua", nil, nil, nil, function(buf)
controls.save.enabled = (controls.dat.buf:match("%S") or controls.ggpk.buf:match("%S")) and controls.label.buf:match("%S") and buf:match("%S")
end)
- controls.save = new("ButtonControl", {"TOP",controls.spec,"TOP"}, {-45, 22, 80, 20}, "Save", function()
+ controls.save = new("ButtonControl"):ButtonControl({"TOP",controls.spec,"TOP"}, {-45, 22, 80, 20}, "Save", function()
local reload = datSource.label == (main.datSource and main.datSource.label)
datSource.label = controls.label.buf
datSource.ggpkPath = controls.ggpk.buf or ""
@@ -59,7 +63,7 @@ function GGPKSourceListClass:EditDATSource(datSource, newSource)
main:ClosePopup()
end)
controls.save.enabled = false
- controls.cancel = new("ButtonControl", {"TOP",controls.spec,"TOP"}, {45, 22, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl({"TOP",controls.spec,"TOP"}, {45, 22, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(370, 200, datSource[1] and "Edit DAT Source" or "New DAT Source", controls, "save", "edit")
diff --git a/src/Export/Classes/RowListControl.lua b/src/Export/Classes/RowListControl.lua
index e108716069..46a70a93e2 100644
--- a/src/Export/Classes/RowListControl.lua
+++ b/src/Export/Classes/RowListControl.lua
@@ -6,11 +6,15 @@
local ipairs = ipairs
local t_insert = table.insert
-local RowListClass = newClass("RowListControl", "ListControl", function(self, anchor, rect)
- self.ListControl(anchor, rect, 14, "HORIZONTAL", false, { })
+---@class RowListControl: ListControl
+local RowListClass = newClass("RowListControl", "ListControl")
+
+function RowListClass:RowListControl(anchor, rect)
+ self:ListControl(anchor, rect, 14, "HORIZONTAL", false, { })
self.colLabels = true
self._autoSizeToggleState = {} -- internal toggle memory, not saved to spec
-end)
+ return self
+end
function RowListClass:BuildRows(filter)
wipeTable(self.list)
diff --git a/src/Export/Classes/ScriptListControl.lua b/src/Export/Classes/ScriptListControl.lua
index 048f02544c..c4bc132769 100644
--- a/src/Export/Classes/ScriptListControl.lua
+++ b/src/Export/Classes/ScriptListControl.lua
@@ -3,9 +3,13 @@
-- Class: Script List
-- Script list control.
--
-local ScriptListClass = newClass("ScriptListControl", "ListControl", function(self, anchor, rect)
- self.ListControl(anchor, rect, 16, "VERTICAL", false, main.scriptList)
-end)
+---@class ScriptListControl: ListControl
+local ScriptListClass = newClass("ScriptListControl", "ListControl")
+
+function ScriptListClass:ScriptListControl(anchor, rect)
+ self:ListControl(anchor, rect, 16, "VERTICAL", false, main.scriptList)
+ return self
+end
function ScriptListClass:GetRowValue(column, index, script)
if column == 1 then
diff --git a/src/Export/Classes/SpecColListControl.lua b/src/Export/Classes/SpecColListControl.lua
index 9371234e68..ca491dcf11 100644
--- a/src/Export/Classes/SpecColListControl.lua
+++ b/src/Export/Classes/SpecColListControl.lua
@@ -5,9 +5,13 @@
--
local t_remove = table.remove
-local SpecColListClass = newClass("SpecColListControl", "ListControl", function(self, anchor, rect)
- self.ListControl(anchor, rect, 14, "VERTICAL", true)
-end)
+---@class SpecColListControl: ListControl
+local SpecColListClass = newClass("SpecColListControl", "ListControl")
+
+function SpecColListClass:SpecColListControl(anchor, rect)
+ self:ListControl(anchor, rect, 14, "VERTICAL", true)
+ return self
+end
function SpecColListClass:GetRowValue(column, index, specCol)
if column == 1 then
diff --git a/src/Export/Enemies/BossSkills.txt b/src/Export/Enemies/BossSkills.txt
index 8c56f8111e..529a9aaa5e 100644
--- a/src/Export/Enemies/BossSkills.txt
+++ b/src/Export/Enemies/BossSkills.txt
@@ -4,6 +4,7 @@
-- Boss Skill data (c) Grinding Gear Games
--
return {
+ bossSkills = {
#boss Atziri Metadata/Monsters/Atziri/Atziri true true
#skill Flameblast AtziriFlameblastEmpowered, stages = 10,
#tooltip "The Uber variant has 10 ^xB97123Fire^7 penetration (Applied on Pinnacle And Uber)"
@@ -31,4 +32,9 @@ return {
#tooltip "Allocating Throw the Gauntlet increases Damage by a further 100% (Applied on Uber) and causes the fireball to have 30 ^xB97123Fire^7 penetration (Applied on Uber)"
#skill MemoryGame MavenMemoryGame, skillIndexUber = nil,
#tooltip "Cannot be Blocked, Dodged, or Suppressed. \n It is three separate hits, and has a large DoT effect. Neither is taken into account here. \n i.e. Hits before death should be more than 3 to survive"
-#skillList
\ No newline at end of file
+ },
+
+ bossSkillsList = {
+#skillList
+ },
+}
\ No newline at end of file
diff --git a/src/Export/Enemies/Bosses.txt b/src/Export/Enemies/Bosses.txt
index b742ecc932..3892b0e3db 100644
--- a/src/Export/Enemies/Bosses.txt
+++ b/src/Export/Enemies/Bosses.txt
@@ -3,8 +3,7 @@
-- Boss Data
-- Boss data (c) Grinding Gear Games
--
-local bosses = ...
-
+local bosses = {}
#boss Venarius SynthesisVenarius {Uber}
#boss EaterOfWorlds AtlasInvadersConsumeBoss {Uber}
#boss SearingExarch AtlasInvadersCleansingBoss {Uber}
@@ -31,4 +30,5 @@ local bosses = ...
#boss Baran AtlasExiles1
#boss Veritania AtlasExiles2
#boss AlHezmin AtlasExiles3
-#boss Drox AtlasExiles4
\ No newline at end of file
+#boss Drox AtlasExiles4
+return bosses
\ No newline at end of file
diff --git a/src/Export/Main.lua b/src/Export/Main.lua
index f6ef44f74a..3b463d7149 100644
--- a/src/Export/Main.lua
+++ b/src/Export/Main.lua
@@ -20,7 +20,7 @@ LoadModule("../Modules/Common.lua")
LoadModule("../Classes/ControlHost.lua")
-main = new("ControlHost")
+main = new("ControlHost"):ControlHost()
local classList = {
"UndoHandler",
@@ -53,10 +53,10 @@ local ourClassList = {
"GGPKData",
}
for _, className in ipairs(classList) do
- LoadModule("../Classes/"..className..".lua", launch, main)
+ LoadModule("../Classes/" .. className .. ".lua")
end
for _, className in ipairs(ourClassList) do
- LoadModule("Classes/"..className, launch, main)
+ LoadModule("Classes/" .. className)
end
local tempTable1 = { }
@@ -164,14 +164,14 @@ function main:Init()
self.colList = { }
- self.controls.shownLeagueLabel = new("LabelControl", nil, {10, 10, 100, 16}, "^7Data from:")
- self.controls.leagueLabel = new("LabelControl", {"LEFT", self.controls.shownLeagueLabel, "RIGHT"}, {10, 0, 100, 16}, function() return "^7" .. (self.leagueLabel or "Unknown") end)
- self.controls.addSource = new("ButtonControl", nil, {10, 30, 100, 18}, "Edit Sources...", function()
- self.OpenPathPopup()
+ self.controls.shownLeagueLabel = new("LabelControl"):LabelControl(nil, {10, 10, 100, 16}, "^7Data from:")
+ self.controls.leagueLabel = new("LabelControl"):LabelControl({"LEFT", self.controls.shownLeagueLabel, "RIGHT"}, {10, 0, 100, 16}, function() return "^7" .. (self.leagueLabel or "Unknown") end)
+ self.controls.addSource = new("ButtonControl"):ButtonControl(nil, {10, 30, 100, 18}, "Edit Sources...", function()
+ self:OpenPathPopup()
end)
self.datSources = self.datSources or { }
- self.controls.datSource = new("DropDownControl", nil, {10, 50, 250, 18}, self.datSources, function(_, value)
+ self.controls.datSource = new("DropDownControl"):DropDownControl(nil, {10, 50, 250, 18}, self.datSources, function(_, value)
self:LoadDatSource(value)
end, nil)
@@ -179,11 +179,11 @@ function main:Init()
self.controls.datSource:SelByValue(self.datSource.label, "label")
end
- self.controls.scripts = new("ButtonControl", nil, {160, 30, 100, 18}, "Scripts >>", function()
+ self.controls.scripts = new("ButtonControl"):ButtonControl(nil, {160, 30, 100, 18}, "Scripts >>", function()
self:SetCurrentDat()
end)
- self.controls.scriptAll = new("ButtonControl", nil, {270, 10, 140, 18}, "Run All", function()
+ self.controls.scriptAll = new("ButtonControl"):ButtonControl(nil, {270, 10, 140, 18}, "Run All", function()
do -- run stat desc first
local errMsg = PLoadModule("Scripts/".."statdesc"..".lua")
if errMsg then
@@ -240,14 +240,14 @@ function main:Init()
end
)
- self.controls.datSearch = new("EditControl", {"TOPLEFT", self.controls.datSource, "BOTTOMLEFT"}, {0, 2, 250, 18}, nil, "^7Search", nil, nil, function(buf)
+ self.controls.datSearch = new("EditControl"):EditControl({"TOPLEFT", self.controls.datSource, "BOTTOMLEFT"}, {0, 2, 250, 18}, nil, "^7Search", nil, nil, function(buf)
self.controls.datList.searchBuf = buf
self.controls.datList:BuildFilteredList()
end, nil, nil, true)
- self.controls.datList = new("DatListControl", {"TOPLEFT",self.controls.datSearch,"BOTTOMLEFT"}, {0, 2, 250, function() return self.screenH - 100 end})
+ self.controls.datList = new("DatListControl"):DatListControl({"TOPLEFT",self.controls.datSearch,"BOTTOMLEFT"}, {0, 2, 250, function() return self.screenH - 100 end})
- self.controls.specEditToggle = new("ButtonControl", nil, {270, 10, 100, 18}, function() return self.editSpec and "Done <<" or "Edit >>" end, function()
+ self.controls.specEditToggle = new("ButtonControl"):ButtonControl(nil, {270, 10, 100, 18}, function() return self.editSpec and "Done <<" or "Edit >>" end, function()
self.editSpec = not self.editSpec
if self.editSpec then
self:SetCurrentCol(1)
@@ -257,13 +257,13 @@ function main:Init()
return self.curDatFile
end
}
- self.controls.specColList = new("SpecColListControl", {"TOPLEFT",self.controls.specEditToggle,"BOTTOMLEFT"}, {0, 2, 200, 200}) {
+ self.controls.specColList = new("SpecColListControl"):SpecColListControl({"TOPLEFT",self.controls.specEditToggle,"BOTTOMLEFT"}, {0, 2, 200, 200}) {
shown = function()
return self.editSpec
end
}
- self.controls.colName = new("EditControl", {"TOPLEFT",self.controls.specColList,"TOPRIGHT"}, {10, 0, 150, 18}, nil, nil, nil, nil, function(buf)
+ self.controls.colName = new("EditControl"):EditControl({"TOPLEFT",self.controls.specColList,"TOPRIGHT"}, {10, 0, 150, 18}, nil, nil, nil, nil, function(buf)
self.curSpecCol.name = buf
self.curDatFile:OnSpecChanged()
self.controls.rowList:BuildColumns()
@@ -277,19 +277,19 @@ function main:Init()
end
}
- self.controls.colType = new("DropDownControl", {"TOPLEFT",self.controls.colName,"BOTTOMLEFT"}, {0, 4, 90, 18}, self.typeDrop, function(_, value)
+ self.controls.colType = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.colName,"BOTTOMLEFT"}, {0, 4, 90, 18}, self.typeDrop, function(_, value)
self.curSpecCol.type = value
self.curDatFile:OnSpecChanged()
self:UpdateCol()
end, "^7Field type in the dat file")
- self.controls.colIsList = new("CheckBoxControl", {"TOPLEFT",self.controls.colType,"BOTTOMLEFT"}, {30, 4, 18}, "List:", function(state)
+ self.controls.colIsList = new("CheckBoxControl"):CheckBoxControl({"TOPLEFT",self.controls.colType,"BOTTOMLEFT"}, {30, 4, 18}, "List:", function(state)
self.curSpecCol.list = state
self.curDatFile:OnSpecChanged()
self.controls.rowList:BuildColumns()
end)
- self.controls.colRefTo = new("EditControl", {"TOPLEFT",self.controls.colType,"BOTTOMLEFT"}, {0, 26, 150, 18}, nil, nil, nil, nil, function(buf)
+ self.controls.colRefTo = new("EditControl"):EditControl({"TOPLEFT",self.controls.colType,"BOTTOMLEFT"}, {0, 26, 150, 18}, nil, nil, nil, nil, function(buf)
self.curSpecCol.refTo = buf
self.curDatFile:OnSpecChanged()
end) {
@@ -299,7 +299,7 @@ function main:Init()
end
}
- self.controls.colWidth = new("EditControl", {"TOPLEFT",self.controls.colRefTo,"BOTTOMLEFT"}, {0, 4, 100, 18}, nil, nil, "%D", nil, function(buf)
+ self.controls.colWidth = new("EditControl"):EditControl({"TOPLEFT",self.controls.colRefTo,"BOTTOMLEFT"}, {0, 4, 100, 18}, nil, nil, "%D", nil, function(buf)
self.curSpecCol.width = m_max(tonumber(buf) or 150, 20)
self.controls.rowList:BuildColumns()
end) {
@@ -310,7 +310,7 @@ function main:Init()
end
}
- self.controls.enumBase = new("EditControl", {"TOPLEFT",self.controls.colWidth,"BOTTOMLEFT"}, {0, 4, 100, 18}, nil, nil, "%D", nil, function(buf)
+ self.controls.enumBase = new("EditControl"):EditControl({"TOPLEFT",self.controls.colWidth,"BOTTOMLEFT"}, {0, 4, 100, 18}, nil, nil, "%D", nil, function(buf)
self.curSpecCol.enumBase = tonumber(buf) or 0
self.curDatFile:OnSpecChanged()
end) {
@@ -321,14 +321,14 @@ function main:Init()
end
}
- self.controls.colDelete = new("ButtonControl", {"BOTTOMRIGHT",self.controls.colName,"TOPRIGHT"}, {0, -4, 18, 18}, "x", function()
+ self.controls.colDelete = new("ButtonControl"):ButtonControl({"BOTTOMRIGHT",self.controls.colName,"TOPRIGHT"}, {0, -4, 18, 18}, "x", function()
t_remove(self.curDatFile.spec, self.curSpecColIndex)
self.curDatFile:OnSpecChanged()
self.controls.rowList:BuildColumns()
self:SetCurrentCol()
end)
- self.controls.filter = new("EditControl", nil, {270, 0, 800, 18}, nil, "^8Filter") {
+ self.controls.filter = new("EditControl"):EditControl(nil, {270, 0, 800, 18}, nil, "^8Filter") {
y = function()
return self.editSpec and 240 or 30
end,
@@ -341,10 +341,10 @@ function main:Init()
end,
}
self.controls.filter.tooltipText = "Takes a Lua expression that returns true or false for a row.\nE.g. `Id:match(\"test\")` or for a key column, `Col and Col.Id:match(\"test\")`"
- self.controls.filterError = new("LabelControl", {"LEFT",self.controls.filter,"RIGHT"}, {4, 2, 0, 14}, "")
- self.controls.showRaw = new("LabelControl", {"LEFT",self.controls.filter,"RIGHT"}, {600, 2, 0, 14}, "^7Hold ALT to show raw data.")
+ self.controls.filterError = new("LabelControl"):LabelControl({"LEFT",self.controls.filter,"RIGHT"}, {4, 2, 0, 14}, "")
+ self.controls.showRaw = new("LabelControl"):LabelControl({"LEFT",self.controls.filter,"RIGHT"}, {600, 2, 0, 14}, "^7Hold ALT to show raw data.")
- self.controls.rowList = new("RowListControl", nil, {270, 0, 0, 0}) {
+ self.controls.rowList = new("RowListControl"):RowListControl(nil, {270, 0, 0, 0}) {
y = function()
return self.editSpec and 260 or 50
end,
@@ -359,7 +359,7 @@ function main:Init()
end
}
- self.controls.addCol = new("ButtonControl", {"LEFT",self.controls.specEditToggle,"RIGHT"}, {10, 0, 80, 18}, "Add", function()
+ self.controls.addCol = new("ButtonControl"):ButtonControl({"LEFT",self.controls.specEditToggle,"RIGHT"}, {10, 0, 80, 18}, "Add", function()
self:AddSpecCol()
end) {
shown = function()
@@ -399,8 +399,8 @@ end
function main:OpenPathPopup()
main:OpenPopup(370, 290, "Manage GGPK versions", {
- new("GGPKSourceListControl", nil, {0, 50, 350, 200}, self),
- new("ButtonControl", nil, {0, 260, 90, 20}, "Done", function()
+ new("GGPKSourceListControl"):GGPKSourceListControl(nil, {0, 50, 350, 200}, self),
+ new("ButtonControl"):ButtonControl(nil, {0, 260, 90, 20}, "Done", function()
main:ClosePopup()
end),
})
@@ -489,10 +489,10 @@ function main:InitGGPK()
local now = GetTime()
local ggpkPath = self.datSource.ggpkPath
if ggpkPath and ggpkPath ~= "" then
- self.ggpk = new("GGPKData", ggpkPath, nil, self.reExportGGPKData)
+ self.ggpk = new("GGPKData"):GGPKData(ggpkPath, nil, self.reExportGGPKData)
ConPrintf("GGPK: %d ms", GetTime() - now)
elseif self.datSource.datFilePath then
- self.ggpk = new("GGPKData", nil, self.datSource.datFilePath, self.reExportGGPKData)
+ self.ggpk = new("GGPKData"):GGPKData(nil, self.datSource.datFilePath, self.reExportGGPKData)
ConPrintf("GGPK: %d ms", GetTime() - now)
end
end
@@ -505,7 +505,7 @@ function main:LoadDatFiles()
ConPrintf("DAT find: %d ms", GetTime() - now)
now = GetTime()
end
- local datFile = new("DatFile", record.name:gsub("%.dat$",""), record.data)
+ local datFile = new("DatFile"):DatFile(record.name:gsub("%.dat$",""), record.data)
t_insert(self.datFileList, datFile)
self.datFileByName[datFile.name] = datFile
end
@@ -519,7 +519,7 @@ function main:LoadDat64Files()
ConPrintf("DAT64 find: %d ms", GetTime() - now)
now = GetTime()
end
- local datFile = new("Dat64File", record.name:gsub("%.datc64$",""), record.data)
+ local datFile = new("Dat64File"):Dat64File(record.name:gsub("%.datc64$",""), record.data)
t_insert(self.datFileList, datFile)
self.datFileByName[datFile.name] = datFile
end
@@ -777,7 +777,7 @@ function main:CopyFolder(srcName, dstName)
end
function main:OpenPopup(width, height, title, controls, enterControl, defaultControl, escapeControl, scrollBarFunc, resizeFunc)
- local popup = new("PopupDialog", width, height, title, controls, enterControl, defaultControl, escapeControl, scrollBarFunc, resizeFunc)
+ local popup = new("PopupDialog"):PopupDialog(width, height, title, controls, enterControl, defaultControl, escapeControl, scrollBarFunc, resizeFunc)
t_insert(self.popups, 1, popup)
return popup
end
@@ -790,10 +790,10 @@ function main:OpenMessagePopup(title, msg)
local controls = { }
local numMsgLines = 0
for line in string.gmatch(msg .. "\n", "([^\n]*)\n") do
- t_insert(controls, new("LabelControl", nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
+ t_insert(controls, new("LabelControl"):LabelControl(nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
numMsgLines = numMsgLines + 1
end
- controls.close = new("ButtonControl", nil, {0, 40 + numMsgLines * 16, 80, 20}, "Ok", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, {0, 40 + numMsgLines * 16, 80, 20}, "Ok", function()
main:ClosePopup()
end)
return self:OpenPopup(m_max(DrawStringWidth(16, "VAR", msg) + 30, 190), 70 + numMsgLines * 16, title, controls, "close")
@@ -803,15 +803,15 @@ function main:OpenConfirmPopup(title, msg, confirmLabel, onConfirm)
local controls = { }
local numMsgLines = 0
for line in string.gmatch(msg .. "\n", "([^\n]*)\n") do
- t_insert(controls, new("LabelControl", nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
+ t_insert(controls, new("LabelControl"):LabelControl(nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
numMsgLines = numMsgLines + 1
end
local confirmWidth = m_max(80, DrawStringWidth(16, "VAR", confirmLabel) + 10)
- controls.confirm = new("ButtonControl", nil, {-5 - m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, confirmLabel, function()
+ controls.confirm = new("ButtonControl"):ButtonControl(nil, {-5 - m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, confirmLabel, function()
main:ClosePopup()
onConfirm()
end)
- t_insert(controls, new("ButtonControl", nil, {5 + m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, "Cancel", function()
+ t_insert(controls, new("ButtonControl"):ButtonControl(nil, {5 + m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, "Cancel", function()
main:ClosePopup()
end))
return self:OpenPopup(m_max(DrawStringWidth(16, "VAR", msg) + 30, 190), 70 + numMsgLines * 16, title, controls, "confirm")
@@ -819,11 +819,11 @@ end
function main:OpenNewFolderPopup(path, onClose)
local controls = { }
- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter folder name:")
- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, nil, nil, "\\/:%*%?\"<>|%c", 100, function(buf)
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter folder name:")
+ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, nil, nil, "\\/:%*%?\"<>|%c", 100, function(buf)
controls.create.enabled = buf:match("%S")
end)
- controls.create = new("ButtonControl", nil, {-45, 70, 80, 20}, "Create", function()
+ controls.create = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Create", function()
local newFolderName = controls.edit.buf
local res, msg = MakeDir(path..newFolderName)
if not res then
@@ -836,7 +836,7 @@ function main:OpenNewFolderPopup(path, onClose)
main:ClosePopup()
end)
controls.create.enabled = false
- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
if onClose then
onClose()
end
diff --git a/src/Export/Main.lua.rej b/src/Export/Main.lua.rej
new file mode 100644
index 0000000000..2224cc062d
--- /dev/null
+++ b/src/Export/Main.lua.rej
@@ -0,0 +1,39 @@
+diff a/src/Export/Main.lua b/src/Export/Main.lua (rejected hunks)
+@@ -195,7 +195,7 @@ function main:Init()
+ end
+ }
+
+- self.controls.clearOutput = new("ButtonControl", nil, {1230, 10, 100, 18}, "Clear", function()
++ self.controls.clearOutput = new("ButtonControl"):ButtonControl(nil, {1230, 10, 100, 18}, "Clear", function()
+ wipeTable(self.scriptOutput)
+ end) {
+ shown = function()
+@@ -205,23 +205,23 @@ function main:Init()
+ return #self.scriptOutput > 0
+ end
+ }
+- self.controls.clearAutoClearOutput = new("CheckBoxControl", { "TOPLEFT", self.controls.clearOutput, "BOTTOMLEFT" }, { 120, 10, 20, 20 }, "Auto Clear Output:", function(state)
++ self.controls.clearAutoClearOutput = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", self.controls.clearOutput, "BOTTOMLEFT" }, { 120, 10, 20, 20 }, "Auto Clear Output:", function(state)
+ self.clearAutoClearOutput = state
+ end, nil, false)
+- self.controls.helpText = new("LabelControl", {"TOPLEFT",self.controls.clearOutput,"BOTTOMLEFT"}, {0, 42, 100, 16}, "Press Ctrl+F5 to re-export\ndata from the game")
++ self.controls.helpText = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.clearOutput,"BOTTOMLEFT"}, {0, 42, 100, 16}, "Press Ctrl+F5 to re-export\ndata from the game")
+
+- self.controls.scriptList = new("ScriptListControl", nil, {270, 35, 140, 400}) {
++ self.controls.scriptList = new("ScriptListControl"):ScriptListControl(nil, {270, 35, 140, 400}) {
+ shown = function()
+ return not self.curDatFile
+ end
+ }
+- self.controls.scriptOutput = new("TextListControl", nil, {420, 10, 800, 600}, nil, self.scriptOutput) {
++ self.controls.scriptOutput = new("TextListControl"):TextListControl(nil, {420, 10, 800, 600}, nil, self.scriptOutput) {
+ shown = function()
+ return not self.curDatFile
+ end
+ }
+
+- self.controls.copyScriptOutput = new("ButtonControl",{"TOPRIGHT", self.controls.scriptOutput, "BOTTOMRIGHT"},{0, 4, 80, 20},"Copy",function()
++ self.controls.copyScriptOutput = new("ButtonControl"):ButtonControl({"TOPRIGHT", self.controls.scriptOutput, "BOTTOMRIGHT"},{0, 4, 80, 20},"Copy",function()
+ local lines = {}
+ local textList = self.controls.scriptOutput.list or {} -- grab the actual list
+ for _, entry in ipairs(textList) do
diff --git a/src/Export/Minions/Minions.txt.rej b/src/Export/Minions/Minions.txt.rej
new file mode 100644
index 0000000000..2183e8552c
--- /dev/null
+++ b/src/Export/Minions/Minions.txt.rej
@@ -0,0 +1,23 @@
+diff a/src/Export/Minions/Minions.txt b/src/Export/Minions/Minions.txt (rejected hunks)
+@@ -3,8 +3,10 @@
+ -- Minion Data
+ -- Monster data (c) Grinding Gear Games
+ --
+-local minions, mod = ...
+
++return function(mod, flag)
++ ---@class MinionData
++ local minions = {}
+ #monster Metadata/Monsters/RaisedZombies/RaisedZombieStandard RaisedZombie
+ #limit ActiveZombieLimit
+ #emit
+@@ -265,4 +267,6 @@ minions["GuardianRelicAll"] = {
+
+ #monster Metadata/Monsters/RaisedZombies/RestlessDeadPlayerSummoned ShamblingUndead
+ #limit ShamblingUndeadLimit
+-#emit
+\ No newline at end of file
++#emit
++ return minions
++end
+\ No newline at end of file
diff --git a/src/Export/Minions/Spectres.txt.rej b/src/Export/Minions/Spectres.txt.rej
new file mode 100644
index 0000000000..926d6d992f
--- /dev/null
+++ b/src/Export/Minions/Spectres.txt.rej
@@ -0,0 +1,22 @@
+diff a/src/Export/Minions/Spectres.txt b/src/Export/Minions/Spectres.txt (rejected hunks)
+@@ -3,8 +3,10 @@
+ -- Spectre Data
+ -- Monster data (c) Grinding Gear Games
+ --
+-local minions, mod, flag = ...
+
++return function(mod, flag)
++ ---@class SpectreData
++ local minions = {}
+ -- Blackguard
+ #spectre Metadata/Monsters/Axis/AxisCaster
+ #spectre Metadata/Monsters/Axis/AxisCasterArc
+@@ -446,4 +448,6 @@ local minions, mod, flag = ...
+ #spectre Metadata/Monsters/FaridunLeague/FaridunWarlock/FaridunWarlockMid_
+ #spectre Metadata/Monsters/FaridunLeague/FaridunWarlock/FaridunWarlockHigh
+ -- Undead Vaal Commander
+-#spectre Metadata/Monsters/VaalMonsters/VaalOverseer
+\ No newline at end of file
++#spectre Metadata/Monsters/VaalMonsters/VaalOverseer
++ return minions
++end
diff --git a/src/Export/Scripts/bossData.lua b/src/Export/Scripts/bossData.lua
index cf3a4e03dd..3d7e58bd0e 100644
--- a/src/Export/Scripts/bossData.lua
+++ b/src/Export/Scripts/bossData.lua
@@ -554,13 +554,11 @@ end
end
-- #skillList
- directiveTable.skills.skillList = function(state, args, out)
- out:write('},{\n')
+directiveTable.skills.skillList = function(state, args, out)
out:write(' { val = "None", label = "None" }')
for _, skillName in pairs(state.skillList) do
out:write(',\n { val = "', skillName, '", label = "', skillName, '" }')
end
- out:write('\n}')
state.boss = nil
state.skillList = nil
end
diff --git a/src/Export/Scripts/minions.lua b/src/Export/Scripts/minions.lua
index ce4d82d25e..aa5ed7cbc2 100644
--- a/src/Export/Scripts/minions.lua
+++ b/src/Export/Scripts/minions.lua
@@ -15,7 +15,7 @@ local function makeSkillDataMod(dataKey, dataValue, ...)
return makeSkillMod("SkillData", "LIST", { key = dataKey, value = dataValue }, 0, 0, ...)
end
dofile("../Data/Global.lua")
-local skillStatMap = LoadModule("../Data/SkillStatMap.lua", makeSkillMod, makeFlagMod, makeSkillDataMod)
+local skillStatMap = LoadModule("../Data/SkillStatMap")(makeSkillMod, makeFlagMod, makeSkillDataMod)
local function tableToString(tbl, pre)
pre = pre or ""
diff --git a/src/Export/Scripts/miscdata.lua.rej b/src/Export/Scripts/miscdata.lua.rej
new file mode 100644
index 0000000000..48f86ab941
--- /dev/null
+++ b/src/Export/Scripts/miscdata.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Export/Scripts/miscdata.lua b/src/Export/Scripts/miscdata.lua (rejected hunks)
+@@ -2,7 +2,8 @@
+ local utils = LoadModule("../Modules/Utils")
+ local out = io.open("../Data/Misc.lua", "w")
+ out:write("-- This file is automatically generated, do not edit!\n\n")
+-out:write('local data = ...\n')
++out:write('---@class MiscDataExport\n')
++out:write('local data = {}\n')
+ local evasion = ""
+ local accuracy = ""
+ local life = ""
+@@ -141,6 +142,7 @@ for row in dat("VillageBalancePerLevelShared"):Rows() do
+ end
+ out:write('}\n')
+
++out:write('return data\n')
+ out:close()
+
+ local currencies = {}
diff --git a/src/Export/Skills/act_dex.txt.rej b/src/Export/Skills/act_dex.txt.rej
new file mode 100644
index 0000000000..a885ae216f
--- /dev/null
+++ b/src/Export/Skills/act_dex.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Skills/act_dex.txt b/src/Export/Skills/act_dex.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Active Dexterity skill gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill AlchemistsMark
+ #flags spell curse mark area duration
+ statMap = {
+@@ -3669,3 +3668,5 @@ local skills, mod, flag, skill = ...
+ #skill QuickstepHardMode
+ #flags movement travel
+ #mods
++
++end
diff --git a/src/Export/Skills/act_int.txt.rej b/src/Export/Skills/act_int.txt.rej
new file mode 100644
index 0000000000..7dd1ad1863
--- /dev/null
+++ b/src/Export/Skills/act_int.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Skills/act_int.txt b/src/Export/Skills/act_int.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Active Intelligence skill gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill Arc
+ #flags spell chaining
+ statMap = {
+@@ -4695,3 +4694,5 @@ local skills, mod, flag, skill = ...
+ },
+ #baseMod skill("radius", 40)
+ #mods
++
++end
diff --git a/src/Export/Skills/act_str.txt.rej b/src/Export/Skills/act_str.txt.rej
new file mode 100644
index 0000000000..032e592679
--- /dev/null
+++ b/src/Export/Skills/act_str.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Skills/act_str.txt b/src/Export/Skills/act_str.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Active Strength skill gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill Absolution
+ #flags spell minion duration area
+ minionList = {
+@@ -2495,3 +2494,5 @@ local skills, mod, flag, skill = ...
+ #baseMod mod("AuraEffect", "MORE", -100, 0, 0, { type = "Condition", var = "BannerPlanted", neg = true })
+ #baseMod flag("Condition:AffectedByPlacedBanner", { type = "Condition", var = "BannerPlanted" }, { type = "GlobalEffect", effectType = "Buff" })
+ #mods
++
++end
diff --git a/src/Export/Skills/glove.txt.rej b/src/Export/Skills/glove.txt.rej
new file mode 100644
index 0000000000..a95ffe2d2a
--- /dev/null
+++ b/src/Export/Skills/glove.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Skills/glove.txt b/src/Export/Skills/glove.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Glove enchantment skills
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill EnchantmentOfBladesOnHit
+ #flags spell projectile
+ fromItem = true,
+@@ -340,3 +339,5 @@ local skills, mod, flag, skill = ...
+ #flags spell projectile area
+ fromItem = true,
+ #mods
++
++end
diff --git a/src/Export/Skills/minion.txt.rej b/src/Export/Skills/minion.txt.rej
new file mode 100644
index 0000000000..644e2d13c9
--- /dev/null
+++ b/src/Export/Skills/minion.txt.rej
@@ -0,0 +1,20 @@
+diff a/src/Export/Skills/minion.txt b/src/Export/Skills/minion.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Minion active skills
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill ChaosElementalCascadeSummoned Cascade
+ #flags spell area
+ #mods
+@@ -486,4 +485,6 @@ skills["GuardianSentinelFireAura"] = {
+
+ #skill MeleePartialChaos
+ #flags attack melee
+-#mods
+\ No newline at end of file
++#mods
++
++end
diff --git a/src/Export/Skills/other.txt.rej b/src/Export/Skills/other.txt.rej
new file mode 100644
index 0000000000..528894fef2
--- /dev/null
+++ b/src/Export/Skills/other.txt.rej
@@ -0,0 +1,17 @@
+diff a/src/Export/Skills/other.txt b/src/Export/Skills/other.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Other active skills
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill RepeatingShockwave
+ #flags spell area
+ fromItem = true,
+@@ -1670,3 +1669,5 @@ skills["EnemyExplode"] = {
+ [1] = { damageEffectiveness = 1, baseMultiplier = 1, levelRequirement = 1, }
+ }
+ }
++
++end
diff --git a/src/Export/Skills/spectre.txt.rej b/src/Export/Skills/spectre.txt.rej
new file mode 100644
index 0000000000..05435771f8
--- /dev/null
+++ b/src/Export/Skills/spectre.txt.rej
@@ -0,0 +1,20 @@
+diff a/src/Export/Skills/spectre.txt b/src/Export/Skills/spectre.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Spectre active skills
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill AxisCasterGlacialCascade
+ #flags spell area
+ #baseMod skill("radius", 12)
+@@ -2299,4 +2298,6 @@ skills["LegionKaruiMeleeCombo2"] = {
+
+ #skill VaalOverseerHeavyStrike Heavy Strike
+ #flags attack melee
+-#mods
+\ No newline at end of file
++#mods
++
++end
diff --git a/src/Export/Skills/sup_dex.txt.rej b/src/Export/Skills/sup_dex.txt.rej
new file mode 100644
index 0000000000..40757d22bc
--- /dev/null
+++ b/src/Export/Skills/sup_dex.txt.rej
@@ -0,0 +1,20 @@
+diff a/src/Export/Skills/sup_dex.txt b/src/Export/Skills/sup_dex.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Dexterity support gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill SupportAddedColdDamage
+ #mods
+
+@@ -689,4 +688,6 @@ local skills, mod, flag, skill = ...
+ #mods
+
+ #skill SupportWitheringTouch
+-#mods
+\ No newline at end of file
++#mods
++
++end
diff --git a/src/Export/Skills/sup_int.txt.rej b/src/Export/Skills/sup_int.txt.rej
new file mode 100644
index 0000000000..e7480b0edb
--- /dev/null
+++ b/src/Export/Skills/sup_int.txt.rej
@@ -0,0 +1,20 @@
+diff a/src/Export/Skills/sup_int.txt b/src/Export/Skills/sup_int.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Intelligence support gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill SupportAddedChaosDamage
+ #mods
+
+@@ -1027,4 +1026,6 @@ local skills, mod, flag, skill = ...
+ mod("Speed", "MORE", nil, ModFlag.Cast),
+ },
+ },
+-#mods
+\ No newline at end of file
++#mods
++
++end
diff --git a/src/Export/Skills/sup_str.txt.rej b/src/Export/Skills/sup_str.txt.rej
new file mode 100644
index 0000000000..8f6ad188a9
--- /dev/null
+++ b/src/Export/Skills/sup_str.txt.rej
@@ -0,0 +1,20 @@
+diff a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt (rejected hunks)
+@@ -3,8 +3,7 @@
+ -- Strength support gems
+ -- Skill data (c) Grinding Gear Games
+ --
+-local skills, mod, flag, skill = ...
+-
++return function(skills, mod, flag, skill)
+ #skill SupportAddedFireDamage
+ #mods
+
+@@ -826,4 +825,6 @@ local skills, mod, flag, skill = ...
+ mod("CooldownRecovery", "MORE", nil),
+ },
+ },
+-#mods
+\ No newline at end of file
++#mods
++
++end
diff --git a/src/GameVersions.lua.rej b/src/GameVersions.lua.rej
new file mode 100644
index 0000000000..cbb97b934f
--- /dev/null
+++ b/src/GameVersions.lua.rej
@@ -0,0 +1,6 @@
+diff a/src/GameVersions.lua b/src/GameVersions.lua (rejected hunks)
+@@ -1,3 +1,4 @@
++---@diagnostic disable: lowercase-global
+ -- Game versions
+ ---Default target version for unknown builds and builds created before 3.0.0.
+ legacyTargetVersion = "2_6"
diff --git a/src/HeadlessWrapper.lua.rej b/src/HeadlessWrapper.lua.rej
new file mode 100644
index 0000000000..0c623c25ae
--- /dev/null
+++ b/src/HeadlessWrapper.lua.rej
@@ -0,0 +1,232 @@
+diff a/src/HeadlessWrapper.lua b/src/HeadlessWrapper.lua (rejected hunks)
+@@ -1,178 +1,26 @@
+ #@
++---@diagnostic disable: lowercase-global
+ -- This wrapper allows the program to run headless on any OS (in theory)
+ -- It can be run using a standard lua interpreter, although LuaJIT is preferable
+
++-- define global SimpleGraphic API functions. some of these have dummy function
++-- bodies intended for headless use.
++dofile("_SimpleGraphic.def.lua")
+
+-
+--- Callbacks
+-local callbackTable = { }
+-local mainObject
+-function runCallback(name, ...)
+- if callbackTable[name] then
+- return callbackTable[name](...)
+- elseif mainObject and mainObject[name] then
+- return mainObject[name](mainObject, ...)
+- end
+-end
+-function SetCallback(name, func)
+- callbackTable[name] = func
+-end
+-function GetCallback(name)
+- return callbackTable[name]
+-end
+-function SetMainObject(obj)
+- mainObject = obj
+-end
+-
+--- Image Handles
+-local imageHandleClass = { }
+-imageHandleClass.__index = imageHandleClass
+-function NewImageHandle()
+- return setmetatable({ }, imageHandleClass)
+-end
+-function imageHandleClass:Load(fileName, ...)
+- self.valid = true
+-end
+-function imageHandleClass:Unload()
+- self.valid = false
+-end
+-function imageHandleClass:IsValid()
+- return self.valid
+-end
+-function imageHandleClass:SetLoadingPriority(pri) end
+-function imageHandleClass:ImageSize()
+- return 1, 1
+-end
+-
+--- Rendering
+-function RenderInit(flag, ...) end
+-function GetScreenSize()
+- return 1920, 1080
+-end
+-function GetScreenScale()
+- return 1
+-end
+ function GetVirtualScreenSize()
+- return GetScreenSize()
+-end
+-function GetDPIScaleOverridePercent()
+- return 1
+-end
+-function SetDPIScaleOverridePercent(scale) end
+-function SetClearColor(r, g, b, a) end
+-function SetDrawLayer(layer, subLayer) end
+-function SetViewport(x, y, width, height) end
+-function SetDrawColor(r, g, b, a) end
+-function DrawImage(imgHandle, left, top, width, height, tcLeft, tcTop, tcRight, tcBottom) end
+-function DrawImageQuad(imageHandle, x1, y1, x2, y2, x3, y3, x4, y4, s1, t1, s2, t2, s3, t3, s4, t4) end
+-function DrawString(left, top, align, height, font, text) end
+-function DrawStringWidth(height, font, text)
+- return 1
+-end
+-function DrawStringCursorIndex(height, font, text, cursorX, cursorY)
+- return 0
+-end
+-function StripEscapes(text)
+- return text:gsub("%^%d",""):gsub("%^x%x%x%x%x%x%x","")
+-end
+-function GetAsyncCount()
+- return 0
++ return 1920, 1080
+ end
+
+--- Search Handles
+-function NewFileSearch() end
++-- Callbacks
++__callbackTable__ = { }
+
+--- General Functions
+-function SetWindowTitle(title) end
+-function GetCursorPos()
+- return 0, 0
+-end
+-function SetCursorPos(x, y) end
+-function ShowCursor(doShow) end
+-function IsKeyDown(keyName) end
+-function Copy(text) end
+-function Paste() end
+-function Deflate(data)
+- -- TODO: Might need this
+- return ""
+-end
+-function Inflate(data)
+- -- TODO: And this
+- return ""
+-end
+-function GetTime()
+- return 0
+-end
+-function GetScriptPath()
+- return ""
+-end
+-function GetRuntimePath()
+- return ""
+-end
+-function GetUserPath()
+- return ""
+-end
+-function MakeDir(path) end
+-function RemoveDir(path) end
+-function SetWorkDir(path) end
+-function GetWorkDir()
+- return ""
+-end
+-function LaunchSubScript(scriptText, funcList, subList, ...) end
+-function AbortSubScript(ssID) end
+-function IsSubScriptRunning(ssID) end
+-function LoadModule(fileName, ...)
+- if not fileName:match("%.lua") then
+- fileName = fileName .. ".lua"
+- end
+- local func, err = loadfile(fileName)
+- if func then
+- return func(...)
+- else
+- error("LoadModule() error loading '"..fileName.."': "..err)
+- end
+-end
+-function PLoadModule(fileName, ...)
+- if not fileName:match("%.lua") then
+- fileName = fileName .. ".lua"
+- end
+- local func, err = loadfile(fileName)
+- if func then
+- return PCall(func, ...)
+- else
+- error("PLoadModule() error loading '"..fileName.."': "..err)
+- end
+-end
+-function PCall(func, ...)
+- local ret = { pcall(func, ...) }
+- if ret[1] then
+- table.remove(ret, 1)
+- return nil, unpack(ret)
+- else
+- return ret[2]
++function runCallback(name, ...)
++ if __callbackTable__[name] then
++ return __callbackTable__[name](...)
++ elseif __mainObject__ and __mainObject__[name] then
++ return __mainObject__[name](__mainObject__, ...)
+ end
+ end
+-function ConPrintf(fmt, ...)
+- -- Optional
+- print(string.format(fmt, ...))
+-end
+-function ConPrintTable(tbl, noRecurse) end
+-function ConExecute(cmd) end
+-function ConClear() end
+-function SpawnProcess(cmdName, args) end
+-function OpenURL(url) end
+-function SetProfiling(isEnabled) end
+-function Restart() end
+-function Exit() end
+-function TakeScreenshot() end
+-
+----@return string? provider
+----@return string? version
+----@return number? status
+-function GetCloudProvider(fullPath)
+- return nil, nil, nil
+-end
+-
+
+ local l_require = require
+ function require(name)
+@@ -189,32 +37,32 @@ dofile("Launch.lua")
+ -- Prevents loading of ModCache
+ -- Allows running mod parsing related tests without pushing ModCache
+ -- The CI env var will be true when run from github workflows but should be false for other tools using the headless wrapper
+-mainObject.continuousIntegrationMode = os.getenv("CI")
++__mainObject__.continuousIntegrationMode = os.getenv("CI")
+
+ runCallback("OnInit")
+ runCallback("OnFrame") -- Need at least one frame for everything to initialise
+
+-if mainObject.promptMsg then
++if __mainObject__.promptMsg then
+ -- Something went wrong during startup
+- print(mainObject.promptMsg)
++ print(__mainObject__.promptMsg)
+ io.read("*l")
+ return
+ end
+
+ -- The build module; once a build is loaded, you can find all the good stuff in here
+-build = mainObject.main.modes["BUILD"]
++build = __mainObject__.main.modes["BUILD"]
+
+ -- Here's some helpful helper functions to help you get started
+ function newBuild()
+- mainObject.main:SetMode("BUILD", false, "Help, I'm stuck in Path of Building!")
++ __mainObject__.main:SetMode("BUILD", false, "Help, I'm stuck in Path of Building!")
+ runCallback("OnFrame")
+ end
+ function loadBuildFromXML(xmlText, name)
+- mainObject.main:SetMode("BUILD", false, name or "", xmlText)
++ __mainObject__.main:SetMode("BUILD", false, name or "", xmlText)
+ runCallback("OnFrame")
+ end
+ function loadBuildFromJSON(characterJSON)
+- mainObject.main:SetMode("BUILD", false, "")
++ __mainObject__.main:SetMode("BUILD", false, "")
+ runCallback("OnFrame")
+ -- characterJSON could, for example, be the response from the PoE API:
+ -- https://www.pathofexile.com/developer/docs/reference#characters-get
diff --git a/src/Launch.lua b/src/Launch.lua
index a0f9d64761..7a651f90f9 100644
--- a/src/Launch.lua
+++ b/src/Launch.lua
@@ -12,6 +12,7 @@ SetWindowTitle(APP_NAME)
ConExecute("set vid_mode 8")
ConExecute("set vid_resizable 3")
+---@diagnostic disable-next-line: lowercase-global
launch = { }
SetMainObject(launch)
jit.opt.start('maxtrace=4000','maxmcode=8192')
@@ -317,16 +318,15 @@ function launch:DownloadPage(url, callback, params)
}
end
end
-
function launch:ApplyUpdate(mode)
if mode == "basic" then
-- Need to revert to the basic environment to fully apply the update
- LoadModule("UpdateApply", "Update/opFile.txt")
+ LoadModule("UpdateApply")("Update/opFile.txt")
SpawnProcess(GetRuntimePath()..'/Update', 'UpdateApply.lua Update/opFileRuntime.txt')
Exit()
elseif mode == "normal" then
-- Update can be applied while normal environment is running
- LoadModule("UpdateApply", "Update/opFile.txt")
+ LoadModule("UpdateApply")("Update/opFile.txt")
Restart()
self.doRestart = "Updating..."
end
diff --git a/src/Modules/Build.lua b/src/Modules/Build.lua
index e8b9a48140..dcbc5ec525 100644
--- a/src/Modules/Build.lua
+++ b/src/Modules/Build.lua
@@ -587,7 +587,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
self.spec:SetWindowTitleWithBuildClass()
--[[
- local testTooltip = new("Tooltip")
+ local testTooltip = new("Tooltip"):Tooltip()
for _, item in pairs(main.uniqueDB.list) do
ConPrintf("%s", item.name)
self.itemsTab:AddItemTooltip(testTooltip, item)
@@ -1419,24 +1419,24 @@ end
function buildMode:OpenConversionPopup()
local controls = { }
local currentVersion = treeVersions[latestTreeVersion].display
- controls.note = new("LabelControl", nil, {0, 20, 0, 16}, colorCodes.TIP..[[
+ controls.note = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, colorCodes.TIP..[[
Info:^7 You are trying to load a build created for a version of Path of Exile that is
not supported by us. You will have to convert it to the current game version to load it.
To use a build newer than the current supported game version, you may have to update.
To use a build older than the current supported game version, we recommend loading it
in an older version of Path of Building Community instead.
]])
- controls.label = new("LabelControl", nil, {0, 110, 0, 16}, colorCodes.WARNING..[[
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 110, 0, 16}, colorCodes.WARNING..[[
Warning:^7 Converting a build to a different game version may have side effects.
For example, if the passive tree has changed, then some passives may be deallocated.
You should create a backup copy of the build before proceeding.
]])
- controls.convert = new("ButtonControl", nil, {-40, 170, 120, 20}, "Convert to ".. currentVersion, function()
+ controls.convert = new("ButtonControl"):ButtonControl(nil, {-40, 170, 120, 20}, "Convert to ".. currentVersion, function()
main:ClosePopup()
self:Shutdown()
self:Init(self.dbFileName, self.buildName, nil, true)
end)
- controls.cancel = new("ButtonControl", nil, {60, 170, 70, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {60, 170, 70, 20}, "Cancel", function()
main:ClosePopup()
self:CloseBuild()
end)
@@ -1450,13 +1450,13 @@ function buildMode:OpenSavePopup(mode)
["UPDATE"] = "before updating?",
}
local controls = { }
- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7This build has unsaved changes.\nDo you want to save them "..modeDesc[mode])
- controls.save = new("ButtonControl", nil, {-90, 70, 80, 20}, "Save", function()
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7This build has unsaved changes.\nDo you want to save them "..modeDesc[mode])
+ controls.save = new("ButtonControl"):ButtonControl(nil, {-90, 70, 80, 20}, "Save", function()
main:ClosePopup()
self.actionOnSave = mode
self:SaveDBFile()
end)
- controls.noSave = new("ButtonControl", nil, {0, 70, 80, 20}, "Don't Save", function()
+ controls.noSave = new("ButtonControl"):ButtonControl(nil, {0, 70, 80, 20}, "Don't Save", function()
main:ClosePopup()
if mode == "LIST" then
self:CloseBuild()
@@ -1466,7 +1466,7 @@ function buildMode:OpenSavePopup(mode)
launch:ApplyUpdate(launch.updateAvailable)
end
end)
- controls.close = new("ButtonControl", nil, {90, 70, 80, 20}, "Cancel", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, {90, 70, 80, 20}, "Cancel", function()
main:ClosePopup()
end)
main:OpenPopup(300, 100, "Save Changes", controls)
@@ -1896,7 +1896,7 @@ function buildMode:OpenSimilarPopup()
local buildProviders = {
{
name = "PoB Archives",
- impl = new("PoBArchivesProvider", "similar")
+ impl = new("PoBArchivesProvider"):PoBArchivesProvider("similar")
}
}
local width = 600
@@ -1904,7 +1904,7 @@ function buildMode:OpenSimilarPopup()
return main.screenH * 0.8
end
local padding = 50
- controls.similarBuildList = new("ExtBuildListControl", nil, {0, padding, width, height() - 2 * padding}, buildProviders)
+ controls.similarBuildList = new("ExtBuildListControl"):ExtBuildListControl(nil, {0, padding, width, height() - 2 * padding}, buildProviders)
controls.similarBuildList.shown = true
controls.similarBuildList.height = function()
return height() - 2 * padding
@@ -1917,7 +1917,7 @@ function buildMode:OpenSimilarPopup()
-- controls.similarBuildList.shown = not controls.similarBuildList:IsShown()
- controls.close = new("ButtonControl", nil, {0, height() - (padding + 20) / 2, 80, 20}, "Close", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, {0, height() - (padding + 20) / 2, 80, 20}, "Close", function()
main:ClosePopup()
end)
-- used in PopupDialog to dynamically size the popup
diff --git a/src/Modules/Build.lua.rej b/src/Modules/Build.lua.rej
new file mode 100644
index 0000000000..5be88b4e18
--- /dev/null
+++ b/src/Modules/Build.lua.rej
@@ -0,0 +1,402 @@
+diff a/src/Modules/Build.lua b/src/Modules/Build.lua (rejected hunks)
+@@ -15,7 +15,10 @@ local m_floor = math.floor
+ local m_abs = math.abs
+ local s_format = string.format
+
+-local buildMode = new("ControlHost")
++---@class Build: ControlHost
++---@field spec PassiveSpec added by TreeTab
++---@field powerBuilderCallback fun()
++local buildMode = new("ControlHost"):ControlHost()
+
+ local function InsertIfNew(t, val)
+ if (not t) then return end
+@@ -112,24 +115,24 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ self.secondaryAscendDropLegacySelection = nil
+ self.secondaryAscendDropEntryCount = nil
+
+- local miscTooltip = new("Tooltip")
++ local miscTooltip = new("Tooltip"):Tooltip()
+
+ -- Controls: top bar, left side
+- self.anchorTopBarLeft = new("Control", nil, {4, 4, 0, 20})
+- self.controls.back = new("ButtonControl", {"LEFT",self.anchorTopBarLeft,"RIGHT"}, {0, 0, 60, 20}, "<< Back", function()
++ self.anchorTopBarLeft = new("Control"):Control(nil, {4, 4, 0, 20})
++ self.controls.back = new("ButtonControl"):ButtonControl({"LEFT",self.anchorTopBarLeft,"RIGHT"}, {0, 0, 60, 20}, "<< Back", function()
+ if self.unsaved then
+ self:OpenSavePopup("LIST")
+ else
+ self:CloseBuild()
+ end
+ end)
+- self.controls.save = new("ButtonControl", {"LEFT",self.controls.back,"RIGHT"}, {8, 0, 50, 20}, "Save", function()
++ self.controls.save = new("ButtonControl"):ButtonControl({"LEFT",self.controls.back,"RIGHT"}, {8, 0, 50, 20}, "Save", function()
+ self:SaveDBFile()
+ end)
+ self.controls.save.enabled = function()
+ return not self.dbFileName or self.unsaved
+ end
+- self.controls.saveAs = new("ButtonControl", {"LEFT",self.controls.save,"RIGHT"}, {8, 0, 70, 20}, "Save As", function()
++ self.controls.saveAs = new("ButtonControl"):ButtonControl({"LEFT",self.controls.save,"RIGHT"}, {8, 0, 70, 20}, "Save As", function()
+ self:OpenSaveAsPopup()
+ end)
+ self.controls.saveAs.enabled = function()
+@@ -140,7 +143,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ local function buildNameConditional()
+ return self.anchorTopBarRight:GetPos() < 800
+ end
+- self.controls.buildName = new("Control", {"LEFT",self.controls.saveAs,"RIGHT"}, {4, 36, 0, 20})
++ self.controls.buildName = new("Control"):Control({"LEFT",self.controls.saveAs,"RIGHT"}, {4, 36, 0, 20})
+ self.controls.buildName.width = function(control)
+ local limit = buildNameConditional() and 203 or
+ (self.anchorTopBarRight:GetPos() - 98 - 62
+@@ -182,12 +185,12 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ end
+
+ -- Controls: top bar, right side
+- self.anchorTopBarRight = new("Control", nil, {function() return main.screenW / 2 + 6 end, 4, 0, 20})
++ self.anchorTopBarRight = new("Control"):Control(nil, {function() return main.screenW / 2 + 6 end, 4, 0, 20})
+
+ local function getPointDisplayX() -- I had it hardcoded to -323 before switching to the control sizing
+ return - (23 + self.controls.pointDisplay:GetSize() + self.controls.levelScalingButton:GetSize() + self.controls.characterLevel:GetSize())
+ end
+- self.controls.pointDisplay = new("Control", {"LEFT",self.anchorTopBarRight,"RIGHT"}, {function() return getPointDisplayX() end, 0, 0, 20})
++ self.controls.pointDisplay = new("Control"):Control({"LEFT",self.anchorTopBarRight,"RIGHT"}, {function() return getPointDisplayX() end, 0, 0, 20})
+ self.controls.pointDisplay.width = function(control)
+ return DrawStringWidth(16, "FIXED", control.str) + 8
+ end
+@@ -208,14 +211,14 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ SetDrawLayer(nil, 0)
+ end
+ end
+- self.controls.levelScalingButton = new("ButtonControl", {"LEFT",self.controls.pointDisplay,"RIGHT"}, {7, 0, 50, 20}, self.characterLevelAutoMode and "Auto" or "Manual", function()
++ self.controls.levelScalingButton = new("ButtonControl"):ButtonControl({"LEFT",self.controls.pointDisplay,"RIGHT"}, {7, 0, 50, 20}, self.characterLevelAutoMode and "Auto" or "Manual", function()
+ self.characterLevelAutoMode = not self.characterLevelAutoMode
+ self.controls.levelScalingButton.label = self.characterLevelAutoMode and "Auto" or "Manual"
+ self.configTab:BuildModList()
+ self.modFlag = true
+ self.buildFlag = true
+ end)
+- self.controls.characterLevel = new("EditControl", {"LEFT",self.controls.levelScalingButton,"RIGHT"}, {5, 0, 106, 20}, "", "Level", "%D", 3, function(buf)
++ self.controls.characterLevel = new("EditControl"):EditControl({"LEFT",self.controls.levelScalingButton,"RIGHT"}, {5, 0, 106, 20}, "", "Level", "%D", 3, function(buf)
+ self.characterLevel = m_min(m_max(tonumber(buf) or 1, 1), 100)
+ self.configTab:BuildModList()
+ self.modFlag = true
+@@ -252,7 +255,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ end
+ end
+ end
+- self.controls.classDrop = new("DropDownControl", {"LEFT",self.controls.characterLevel,"RIGHT"}, {10, 0, 85, 20}, nil, function(index, value)
++ self.controls.classDrop = new("DropDownControl"):DropDownControl({"LEFT",self.controls.characterLevel,"RIGHT"}, {10, 0, 85, 20}, nil, function(index, value)
+ if value.classId ~= self.spec.curClassId then
+ if self.spec:CountAllocNodes() == 0 or self.spec:IsClassConnected(value.classId) then
+ self.spec:SelectClass(value.classId)
+@@ -276,13 +279,13 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ end
+ end
+ end)
+- self.controls.ascendDrop = new("DropDownControl", {"LEFT",self.controls.classDrop,"RIGHT"}, {4, 0, 120, 20}, nil, function(index, value)
++ self.controls.ascendDrop = new("DropDownControl"):DropDownControl({"LEFT",self.controls.classDrop,"RIGHT"}, {4, 0, 120, 20}, nil, function(index, value)
+ self.spec:SelectAscendClass(value.ascendClassId)
+ self.spec:AddUndoState()
+ self.spec:SetWindowTitleWithBuildClass()
+ self.buildFlag = true
+ end)
+- self.controls.secondaryAscendDrop = new("DropDownControl", {"LEFT",self.controls.ascendDrop,"RIGHT"}, {4, 0, 160, 20}, {
++ self.controls.secondaryAscendDrop = new("DropDownControl"):DropDownControl({"LEFT",self.controls.ascendDrop,"RIGHT"}, {4, 0, 160, 20}, {
+ { label = "None", ascendClassId = 0 },
+ }, function(index, value)
+ if not value or not self.spec then
+@@ -298,7 +301,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ local initialSecondarySelection = (self.spec and self.spec.curSecondaryAscendClassId) or 0
+ self.controls.secondaryAscendDrop:SelByValue(initialSecondarySelection, "ascendClassId")
+
+- self.controls.buildLoadouts = new("DropDownControl", {"LEFT",self.controls.secondaryAscendDrop,"RIGHT"}, {4, 0, 190, 20}, {}, function(index, value)
++ self.controls.buildLoadouts = new("DropDownControl"):DropDownControl({"LEFT",self.controls.secondaryAscendDrop,"RIGHT"}, {4, 0, 190, 20}, {}, function(index, value)
+ if value == "^7^7Loadouts:" or value == "^7^7-----" then
+ self.controls.buildLoadouts:SetSel(1)
+ return
+@@ -315,14 +318,14 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ end
+ if value == "^7^7New Loadout" then
+ local controls = { }
+- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter name for this loadout:")
+- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, "New Loadout", nil, nil, 100, function(buf)
++ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter name for this loadout:")
++ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, "New Loadout", nil, nil, 100, function(buf)
+ controls.save.enabled = buf:match("%S")
+ end)
+- controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Save", function()
+ local loadout = controls.edit.buf
+
+- local newSpec = new("PassiveSpec", self, latestTreeVersion)
++ local newSpec = new("PassiveSpec"):PassiveSpec(self, latestTreeVersion)
+ newSpec.title = loadout
+ t_insert(self.treeTab.specList, newSpec)
+
+@@ -343,7 +346,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ main:ClosePopup()
+ end)
+ controls.save.enabled = false
+- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
++ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ end)
+ main:OpenPopup(370, 100, "Set Name", controls, "save", "edit", "cancel")
+@@ -424,54 +427,57 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ end
+
+ -- List of display stats
+- self.displayStats, self.minionDisplayStats, self.extraSaveStats = LoadModule("Modules/BuildDisplayStats")
++ local displayStatsModule = LoadModule("Modules/BuildDisplayStats")
++ self.displayStats = displayStatsModule.displayStats
++ self.minionDisplayStats = displayStatsModule.minionDisplayStats
++ self.extraSaveStats = displayStatsModule.extraSaveStats
+
+ -- Controls: Side bar
+- self.anchorSideBar = new("Control", nil, {4, 60, 0, 0})
++ self.anchorSideBar = new("Control"):Control(nil, {4, 60, 0, 0})
+ self.anchorSideBar.y = function()
+ return buildNameConditional() and 60 or 36
+ end
+
+- self.controls.modeImport = new("ButtonControl", {"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 0, 134, 20}, "Import/Export Build", function()
++ self.controls.modeImport = new("ButtonControl"):ButtonControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 0, 134, 20}, "Import/Export Build", function()
+ self.viewMode = "IMPORT"
+ self.importTab:TryFetchCharacterList()
+ end)
+ self.controls.modeImport.locked = function() return self.viewMode == "IMPORT" end
+- self.controls.modeNotes = new("ButtonControl", {"LEFT",self.controls.modeImport,"RIGHT"}, {4, 0, 58, 20}, "Notes", function()
++ self.controls.modeNotes = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeImport,"RIGHT"}, {4, 0, 58, 20}, "Notes", function()
+ self.viewMode = "NOTES"
+ end)
+ self.controls.modeNotes.locked = function() return self.viewMode == "NOTES" end
+- self.controls.modeConfig = new("ButtonControl", {"TOPRIGHT",self.anchorSideBar,"TOPLEFT"}, {300, 0, 100, 20}, "Configuration", function()
++ self.controls.modeConfig = new("ButtonControl"):ButtonControl({"TOPRIGHT",self.anchorSideBar,"TOPLEFT"}, {300, 0, 100, 20}, "Configuration", function()
+ self.viewMode = "CONFIG"
+ end)
+ self.controls.modeConfig.locked = function() return self.viewMode == "CONFIG" end
+- self.controls.modeTree = new("ButtonControl", {"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 26, 72, 20}, "Tree", function()
++ self.controls.modeTree = new("ButtonControl"):ButtonControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 26, 72, 20}, "Tree", function()
+ self.viewMode = "TREE"
+ end)
+ self.controls.modeTree.locked = function() return self.viewMode == "TREE" end
+- self.controls.modeSkills = new("ButtonControl", {"LEFT",self.controls.modeTree,"RIGHT"}, {4, 0, 72, 20}, "Skills", function()
++ self.controls.modeSkills = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeTree,"RIGHT"}, {4, 0, 72, 20}, "Skills", function()
+ self.viewMode = "SKILLS"
+ end)
+ self.controls.modeSkills.locked = function() return self.viewMode == "SKILLS" end
+- self.controls.modeItems = new("ButtonControl", {"LEFT",self.controls.modeSkills,"RIGHT"}, {4, 0, 72, 20}, "Items", function()
++ self.controls.modeItems = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeSkills,"RIGHT"}, {4, 0, 72, 20}, "Items", function()
+ self.viewMode = "ITEMS"
+ end)
+ self.controls.modeItems.locked = function() return self.viewMode == "ITEMS" end
+- self.controls.modeCalcs = new("ButtonControl", {"LEFT",self.controls.modeItems,"RIGHT"}, {4, 0, 72, 20}, "Calcs", function()
++ self.controls.modeCalcs = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeItems,"RIGHT"}, {4, 0, 72, 20}, "Calcs", function()
+ self.viewMode = "CALCS"
+ end)
+ self.controls.modeCalcs.locked = function() return self.viewMode == "CALCS" end
+- self.controls.modeParty = new("ButtonControl", {"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 52, 72, 20}, "Party", function()
++ self.controls.modeParty = new("ButtonControl"):ButtonControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 52, 72, 20}, "Party", function()
+ self.viewMode = "PARTY"
+ end)
+ self.controls.modeParty.locked = function() return self.viewMode == "PARTY" end
+- self.controls.modeCompare = new("ButtonControl", {"LEFT",self.controls.modeParty,"RIGHT"}, {4, 0, 72, 20}, "Compare", function()
++ self.controls.modeCompare = new("ButtonControl"):ButtonControl({"LEFT",self.controls.modeParty,"RIGHT"}, {4, 0, 72, 20}, "Compare", function()
+ self.viewMode = "COMPARE"
+ end)
+ self.controls.modeCompare.locked = function() return self.viewMode == "COMPARE" end
+ -- Skills
+- self.controls.mainSkillLabel = new("LabelControl", {"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 80, 300, 16}, "^7Main Skill:")
+- self.controls.mainSocketGroup = new("DropDownControl", {"TOPLEFT",self.controls.mainSkillLabel,"BOTTOMLEFT"}, {0, 2, 300, 18}, nil, function(index, value)
++ self.controls.mainSkillLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.anchorSideBar,"TOPLEFT"}, {0, 80, 300, 16}, "^7Main Skill:")
++ self.controls.mainSocketGroup = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.mainSkillLabel,"BOTTOMLEFT"}, {0, 2, 300, 18}, nil, function(index, value)
+ self.mainSocketGroup = index
+ self.modFlag = true
+ self.buildFlag = true
+@@ -483,44 +489,44 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ self.skillsTab:AddSocketGroupTooltip(tooltip, socketGroup)
+ end
+ end
+- self.controls.mainSkill = new("DropDownControl", {"TOPLEFT",self.controls.mainSocketGroup,"BOTTOMLEFT"}, {0, 2, 300, 18}, nil, function(index, value)
++ self.controls.mainSkill = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.mainSocketGroup,"BOTTOMLEFT"}, {0, 2, 300, 18}, nil, function(index, value)
+ local mainSocketGroup = self.skillsTab.socketGroupList[self.mainSocketGroup]
+ mainSocketGroup.mainActiveSkill = index
+ self.modFlag = true
+ self.buildFlag = true
+ end)
+- self.controls.mainSkillPart = new("DropDownControl", {"TOPLEFT",self.controls.mainSkill,"BOTTOMLEFT",true}, {0, 2, 300, 18}, nil, function(index, value)
++ self.controls.mainSkillPart = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.mainSkill,"BOTTOMLEFT",true}, {0, 2, 300, 18}, nil, function(index, value)
+ local mainSocketGroup = self.skillsTab.socketGroupList[self.mainSocketGroup]
+ local srcInstance = mainSocketGroup.displaySkillList[mainSocketGroup.mainActiveSkill].activeEffect.srcInstance
+ srcInstance.skillPart = index
+ self.modFlag = true
+ self.buildFlag = true
+ end)
+- self.controls.mainSkillStageCountLabel = new("LabelControl", {"TOPLEFT",self.controls.mainSkillPart,"BOTTOMLEFT",true}, {0, 3, 0, 16}, "^7Stages:") {
++ self.controls.mainSkillStageCountLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.mainSkillPart,"BOTTOMLEFT",true}, {0, 3, 0, 16}, "^7Stages:") {
+ shown = function()
+ return self.controls.mainSkillStageCount:IsShown()
+ end,
+ }
+- self.controls.mainSkillStageCount = new("EditControl", {"LEFT",self.controls.mainSkillStageCountLabel,"RIGHT",true}, {2, 0, 60, 18}, nil, nil, "%D", nil, function(buf)
++ self.controls.mainSkillStageCount = new("EditControl"):EditControl({"LEFT",self.controls.mainSkillStageCountLabel,"RIGHT",true}, {2, 0, 60, 18}, nil, nil, "%D", nil, function(buf)
+ local mainSocketGroup = self.skillsTab.socketGroupList[self.mainSocketGroup]
+ local srcInstance = mainSocketGroup.displaySkillList[mainSocketGroup.mainActiveSkill].activeEffect.srcInstance
+ srcInstance.skillStageCount = tonumber(buf)
+ self.modFlag = true
+ self.buildFlag = true
+ end)
+- self.controls.mainSkillMineCountLabel = new("LabelControl", {"TOPLEFT",self.controls.mainSkillStageCountLabel,"BOTTOMLEFT",true}, {0, 3, 0, 16}, "^7Active Mines:") {
++ self.controls.mainSkillMineCountLabel = new("LabelControl"):LabelControl({"TOPLEFT",self.controls.mainSkillStageCountLabel,"BOTTOMLEFT",true}, {0, 3, 0, 16}, "^7Active Mines:") {
+ shown = function()
+ return self.controls.mainSkillMineCount:IsShown()
+ end,
+ }
+- self.controls.mainSkillMineCount = new("EditControl", {"LEFT",self.controls.mainSkillMineCountLabel,"RIGHT",true}, {2, 0, 60, 18}, nil, nil, "%D", nil, function(buf)
++ self.controls.mainSkillMineCount = new("EditControl"):EditControl({"LEFT",self.controls.mainSkillMineCountLabel,"RIGHT",true}, {2, 0, 60, 18}, nil, nil, "%D", nil, function(buf)
+ local mainSocketGroup = self.skillsTab.socketGroupList[self.mainSocketGroup]
+ local srcInstance = mainSocketGroup.displaySkillList[mainSocketGroup.mainActiveSkill].activeEffect.srcInstance
+ srcInstance.skillMineCount = tonumber(buf)
+ self.modFlag = true
+ self.buildFlag = true
+ end)
+- self.controls.mainSkillMinion = new("DropDownControl", {"TOPLEFT",self.controls.mainSkillMineCountLabel,"BOTTOMLEFT",true}, {0, 3, 178, 18}, nil, function(index, value)
++ self.controls.mainSkillMinion = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.mainSkillMineCountLabel,"BOTTOMLEFT",true}, {0, 3, 178, 18}, nil, function(index, value)
+ local mainSocketGroup = self.skillsTab.socketGroupList[self.mainSocketGroup]
+ local srcInstance = mainSocketGroup.displaySkillList[mainSocketGroup.mainActiveSkill].activeEffect.srcInstance
+ if value.itemSetId then
+@@ -549,24 +555,24 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ tooltip:AddLine(14, colorCodes.TIP.."Tip: You can drag items from the Items tab onto this dropdown to equip them onto the minion.")
+ end
+ end
+- self.controls.mainSkillMinionLibrary = new("ButtonControl", {"LEFT",self.controls.mainSkillMinion,"RIGHT"}, {2, 0, 120, 18}, "Manage Spectres...", function()
++ self.controls.mainSkillMinionLibrary = new("ButtonControl"):ButtonControl({"LEFT",self.controls.mainSkillMinion,"RIGHT"}, {2, 0, 120, 18}, "Manage Spectres...", function()
+ self:OpenSpectreLibrary()
+ end)
+- self.controls.mainSkillMinionSkill = new("DropDownControl", {"TOPLEFT",self.controls.mainSkillMinion,"BOTTOMLEFT",true}, {0, 2, 200, 16}, nil, function(index, value)
++ self.controls.mainSkillMinionSkill = new("DropDownControl"):DropDownControl({"TOPLEFT",self.controls.mainSkillMinion,"BOTTOMLEFT",true}, {0, 2, 200, 16}, nil, function(index, value)
+ local mainSocketGroup = self.skillsTab.socketGroupList[self.mainSocketGroup]
+ local srcInstance = mainSocketGroup.displaySkillList[mainSocketGroup.mainActiveSkill].activeEffect.srcInstance
+ srcInstance.skillMinionSkill = index
+ self.modFlag = true
+ self.buildFlag = true
+ end)
+- self.controls.statBoxAnchor = new("Control", {"TOPLEFT",self.controls.mainSkillMinionSkill,"BOTTOMLEFT",true}, {0, 2, 0, 0})
+- self.controls.statBox = new("TextListControl", {"TOPLEFT",self.controls.statBoxAnchor,"BOTTOMLEFT"}, {0, 2, 300, 0}, {{x=170,align="RIGHT_X"},{x=174,align="LEFT"}})
++ self.controls.statBoxAnchor = new("Control"):Control({"TOPLEFT",self.controls.mainSkillMinionSkill,"BOTTOMLEFT",true}, {0, 2, 0, 0})
++ self.controls.statBox = new("TextListControl"):TextListControl({"TOPLEFT",self.controls.statBoxAnchor,"BOTTOMLEFT"}, {0, 2, 300, 0}, {{x=170,align="RIGHT_X"},{x=174,align="LEFT"}})
+ self.controls.statBox.height = function(control)
+ local x, y = control:GetPos()
+ local warnHeight = main.showWarnings and #self.controls.warnings.lines > 0 and 18 or 0
+ return main.screenH - main.mainBarHeight - 4 - y - warnHeight
+ end
+- self.controls.warnings = new("Control",{"TOPLEFT",self.controls.statBox,"BOTTOMLEFT",true}, {0, 0, 0, 18})
++ self.controls.warnings = new("Control"):Control({"TOPLEFT",self.controls.statBox,"BOTTOMLEFT",true}, {0, 0, 0, 18})
+ self.controls.warnings.lines = {}
+ self.controls.warnings.width = function(control)
+ return control.str and DrawStringWidth(16, "FIXED", control.str) + 8 or 0
+@@ -595,15 +601,15 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin
+ self.latestTree = main.tree[latestTreeVersion]
+ data.setJewelRadiiGlobally(latestTreeVersion)
+ self.data = data
+- self.importTab = new("ImportTab", self)
+- self.notesTab = new("NotesTab", self)
+- self.partyTab = new("PartyTab", self)
+- self.configTab = new("ConfigTab", self)
+- self.itemsTab = new("ItemsTab", self)
+- self.treeTab = new("TreeTab", self)
+- self.skillsTab = new("SkillsTab", self)
+- self.calcsTab = new("CalcsTab", self)
+- self.compareTab = new("CompareTab", self)
++ self.importTab = new("ImportTab"):ImportTab(self)
++ self.notesTab = new("NotesTab"):NotesTab(self)
++ self.partyTab = new("PartyTab"):PartyTab(self)
++ self.configTab = new("ConfigTab"):ConfigTab(self)
++ self.itemsTab = new("ItemsTab"):ItemsTab(self)
++ self.treeTab = new("TreeTab"):TreeTab(self)
++ self.skillsTab = new("SkillsTab"):SkillsTab(self)
++ self.calcsTab = new("CalcsTab"):CalcsTab(self)
++ self.compareTab = new("CompareTab"):CompareTab(self)
+ -- Used for pined calcs panes
+ self.overlayPanes = { }
+
+@@ -1395,13 +1401,13 @@ function buildMode:OpenSaveAsPopup()
+ end
+ end
+ end
+- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter new build name:")
+- controls.edit = new("EditControl", nil, {0, 40, 450, 20},
++ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter new build name:")
++ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 450, 20},
+ not self.dbFileName and main.predefinedBuildName or (self.buildName or self.dbFileName):gsub("[\\/:%*%?\"<>|%c]", "-"), nil, "\\/:%*%?\"<>|%c", 100, function(buf)
+ updateBuildName()
+ end)
+- controls.folderLabel = new("LabelControl", {"TOPLEFT",nil,"TOPLEFT"}, {10, 70, 0, 16}, "^7Folder:")
+- controls.newFolder = new("ButtonControl", {"TOPLEFT",nil,"TOPLEFT"}, {100, 67, 94, 20}, "New Folder...", function()
++ controls.folderLabel = new("LabelControl"):LabelControl({"TOPLEFT",nil,"TOPLEFT"}, {10, 70, 0, 16}, "^7Folder:")
++ controls.newFolder = new("ButtonControl"):ButtonControl({"TOPLEFT",nil,"TOPLEFT"}, {100, 67, 94, 20}, "New Folder...", function()
+ main:OpenNewFolderPopup(main.buildPath..controls.folder.subPath, function(newFolderName)
+ if newFolderName then
+ controls.folder:OpenFolder(newFolderName)
+@@ -1409,13 +1415,13 @@ function buildMode:OpenSaveAsPopup()
+ end)
+ end)
+
+- controls.folder = new("FolderListControl", nil, {0, 115, 450, 400}, self.dbFileSubPath, function(subPath)
++ controls.folder = new("FolderListControl"):FolderListControl(nil, {0, 115, 450, 400}, self.dbFileSubPath, function(subPath)
+ updateBuildName()
+ end)
+ controls.folder.sortMode = self.saveAsSortMode
+ controls.folder:SortList()
+
+- controls.save = new("ButtonControl", nil, {-45, 525, 80, 20}, "Save", function()
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 525, 80, 20}, "Save", function()
+ main:ClosePopup()
+ self.dbFileName = newFileName
+ self.buildName = newBuildName
+@@ -1423,7 +1429,7 @@ function buildMode:OpenSaveAsPopup()
+ self:SaveDBFile()
+ self.spec:SetWindowTitleWithBuildClass()
+ end)
+- controls.close = new("ButtonControl", nil, {45, 525, 80, 20}, "Cancel", function()
++ controls.close = new("ButtonControl"):ButtonControl(nil, {45, 525, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ self.actionOnSave = nil
+ end)
+@@ -1435,7 +1441,7 @@ function buildMode:OpenSaveAsPopup()
+ controls.save.enabled = false
+ end
+
+- controls.buildSortMode = new("DropDownControl", { "TOPRIGHT", nil, "TOPRIGHT" }, { -10, 70, 120, 18 }, {
++ controls.buildSortMode = new("DropDownControl"):DropDownControl({ "TOPRIGHT", nil, "TOPRIGHT" }, { -10, 70, 120, 18 }, {
+ { label = "Sort By Name", mode = "NAME" },
+ { label = "Sort By Last Edited", mode = "EDITED" },
+ }, function(index, value)
+@@ -1464,19 +1470,19 @@ function buildMode:OpenSpectreLibrary()
+ end
+ end)
+ local controls = { }
+- controls.list = new("MinionListControl", nil, {-139, 40, 265, 250}, self.data, destList)
+- controls.source = new("MinionSearchListControl", nil, {139, 60, 265, 230}, self.data, sourceList, controls.list)
+- controls.save = new("ButtonControl", nil, {-45, 330, 80, 20}, "Save", function()
++ controls.list = new("MinionListControl"):MinionListControl(nil, {-139, 40, 265, 250}, self.data, destList)
++ controls.source = new("MinionSearchListControl"):MinionSearchListControl(nil, {139, 60, 265, 230}, self.data, sourceList, controls.list)
++ controls.save = new("ButtonControl"):ButtonControl(nil, {-45, 330, 80, 20}, "Save", function()
+ self.spectreList = destList
+ self.modFlag = true
+ self.buildFlag = true
+ main:ClosePopup()
+ end)
+- controls.cancel = new("ButtonControl", nil, {45, 330, 80, 20}, "Cancel", function()
++ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 330, 80, 20}, "Cancel", function()
+ main:ClosePopup()
+ end)
+- controls.noteLine1 = new("LabelControl", {"TOPLEFT",controls.list,"BOTTOMLEFT"}, {99, 2, 0, 16}, "^7Spectres in your Library must be assigned to an active")
+- controls.noteLine2 = new("LabelControl", {"TOPLEFT",controls.list,"BOTTOMLEFT"}, {95, 18, 0, 16}, "^7Raise Spectre gem for their buffs and curses to activate")
++ controls.noteLine1 = new("LabelControl"):LabelControl({"TOPLEFT",controls.list,"BOTTOMLEFT"}, {99, 2, 0, 16}, "^7Spectres in your Library must be assigned to an active")
++ controls.noteLine2 = new("LabelControl"):LabelControl({"TOPLEFT",controls.list,"BOTTOMLEFT"}, {95, 18, 0, 16}, "^7Raise Spectre gem for their buffs and curses to activate")
+ local spectrePopup = main:OpenPopup(575, 360, "Spectre Library", controls)
+ spectrePopup:SelectControl(spectrePopup.controls.source.controls.searchText)
+ end
diff --git a/src/Modules/BuildDisplayStats.lua b/src/Modules/BuildDisplayStats.lua
index 538efd46ca..c036e00397 100644
--- a/src/Modules/BuildDisplayStats.lua
+++ b/src/Modules/BuildDisplayStats.lua
@@ -260,4 +260,4 @@ local extraSaveStats = {
"ActiveMinionLimit",
}
-return displayStats, minionDisplayStats, extraSaveStats
+return { displayStats = displayStats, minionDisplayStats = minionDisplayStats, extraSaveStats = extraSaveStats }
diff --git a/src/Modules/BuildList.lua b/src/Modules/BuildList.lua
index c9b67025cd..3f247f2d02 100644
--- a/src/Modules/BuildList.lua
+++ b/src/Modules/BuildList.lua
@@ -10,7 +10,7 @@ local t_insert = table.insert
local buildListHelpers = LoadModule("Modules/BuildListHelpers")
local buildSortDropList = buildListHelpers.buildSortDropList
-local listMode = new("ControlHost")
+local listMode = new("ControlHost"):ControlHost()
function listMode:Init(selBuildName, subPath)
if self.initialised then
@@ -28,7 +28,7 @@ function listMode:Init(selBuildName, subPath)
return
end
- self.anchor = new("Control", nil, {0, 4, 0, 0})
+ self.anchor = new("Control"):Control(nil, {0, 4, 0, 0})
self.anchor.x = function()
return main.screenW / 2
end
@@ -36,34 +36,34 @@ function listMode:Init(selBuildName, subPath)
self.subPath = subPath or ""
self.list = { }
- self.controls.new = new("ButtonControl", {"TOP",self.anchor,"TOP"}, {-259, 0, 60, 20}, "New", function()
+ self.controls.new = new("ButtonControl"):ButtonControl({"TOP",self.anchor,"TOP"}, {-259, 0, 60, 20}, "New", function()
main:SetMode("BUILD", false, "Unnamed build")
end)
- self.controls.newFolder = new("ButtonControl", {"LEFT",self.controls.new,"RIGHT"}, {8, 0, 90, 20}, "New Folder", function()
+ self.controls.newFolder = new("ButtonControl"):ButtonControl({"LEFT",self.controls.new,"RIGHT"}, {8, 0, 90, 20}, "New Folder", function()
self.controls.buildList:NewFolder()
end)
- self.controls.open = new("ButtonControl", {"LEFT",self.controls.newFolder,"RIGHT"}, {8, 0, 60, 20}, "Open", function()
+ self.controls.open = new("ButtonControl"):ButtonControl({"LEFT",self.controls.newFolder,"RIGHT"}, {8, 0, 60, 20}, "Open", function()
self.controls.buildList:LoadBuild(self.controls.buildList.selValue)
end)
self.controls.open.enabled = function() return self.controls.buildList.selValue ~= nil end
- self.controls.copy = new("ButtonControl", {"LEFT",self.controls.open,"RIGHT"}, {8, 0, 60, 20}, "Copy", function()
+ self.controls.copy = new("ButtonControl"):ButtonControl({"LEFT",self.controls.open,"RIGHT"}, {8, 0, 60, 20}, "Copy", function()
self.controls.buildList:RenameBuild(self.controls.buildList.selValue, true)
end)
self.controls.copy.enabled = function() return self.controls.buildList.selValue ~= nil end
- self.controls.rename = new("ButtonControl", {"LEFT",self.controls.copy,"RIGHT"}, {8, 0, 60, 20}, "Rename", function()
+ self.controls.rename = new("ButtonControl"):ButtonControl({"LEFT",self.controls.copy,"RIGHT"}, {8, 0, 60, 20}, "Rename", function()
self.controls.buildList:RenameBuild(self.controls.buildList.selValue)
end)
self.controls.rename.enabled = function() return self.controls.buildList.selValue ~= nil end
- self.controls.delete = new("ButtonControl", {"LEFT",self.controls.rename,"RIGHT"}, {8, 0, 60, 20}, "Delete", function()
+ self.controls.delete = new("ButtonControl"):ButtonControl({"LEFT",self.controls.rename,"RIGHT"}, {8, 0, 60, 20}, "Delete", function()
self.controls.buildList:DeleteBuild(self.controls.buildList.selValue)
end)
self.controls.delete.enabled = function() return self.controls.buildList.selValue ~= nil end
- self.controls.sort = new("DropDownControl", {"LEFT",self.controls.delete,"RIGHT"}, {8, 0, 140, 20}, buildSortDropList, function(index, value)
+ self.controls.sort = new("DropDownControl"):DropDownControl({"LEFT",self.controls.delete,"RIGHT"}, {8, 0, 140, 20}, buildSortDropList, function(index, value)
main.buildSortMode = value.sortMode
self:SortList()
end)
self.controls.sort:SelByValue(main.buildSortMode, "sortMode")
- self.controls.buildList = new("BuildListControl", {"TOP",self.anchor,"TOP"}, {0, 75, 900, 0}, self)
+ self.controls.buildList = new("BuildListControl"):BuildListControl({"TOP",self.anchor,"TOP"}, {0, 75, 900, 0}, self)
self.controls.buildList.height = function()
return main.screenH - 80
end
@@ -111,10 +111,10 @@ function listMode:getPublicBuilds()
local buildProviders = {
{
name = "PoB Archives",
- impl = new("PoBArchivesProvider", "builds")
+ impl = new("PoBArchivesProvider"):PoBArchivesProvider("builds")
}
}
- local extBuildList = new("ExtBuildListControl", {"LEFT",self.controls.buildList,"RIGHT"}, {25, 0, main.screenW * 1 / 4 - 50, 0}, buildProviders)
+ local extBuildList = new("ExtBuildListControl"):ExtBuildListControl({"LEFT",self.controls.buildList,"RIGHT"}, {25, 0, main.screenW * 1 / 4 - 50, 0}, buildProviders)
extBuildList:Init("PoB Archives")
extBuildList.height = function()
return main.screenH - 80
diff --git a/src/Modules/BuildList.lua.rej b/src/Modules/BuildList.lua.rej
new file mode 100644
index 0000000000..0ae26924ab
--- /dev/null
+++ b/src/Modules/BuildList.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Modules/BuildList.lua b/src/Modules/BuildList.lua (rejected hunks)
+@@ -93,7 +93,7 @@ function listMode:Init(selBuildName, subPath)
+ self.controls.ExtBuildList = self:getPublicBuilds()
+ end
+
+- self.controls.searchText = new("EditControl", {"TOP",self.anchor,"TOP"}, {0, 25, 640, 20}, self.filterBuildList, "Search", "%c%(%)", 100, function(buf)
++ self.controls.searchText = new("EditControl"):EditControl({"TOP",self.anchor,"TOP"}, {0, 25, 640, 20}, self.filterBuildList, "Search", "%c%(%)", 100, function(buf)
+ main.filterBuildList = buf
+ self:FilterBuildList()
+ end, nil, nil, true)
diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua
index 49d8ca6c40..6b23040cec 100644
--- a/src/Modules/CalcActiveSkill.lua
+++ b/src/Modules/CalcActiveSkill.lua
@@ -3,7 +3,8 @@
-- Module: Calc Active Skill
-- Active skill setup.
--
-local calcs = ...
+---@class Calcs
+local calcs = require("Modules.CalcBase")
local pairs = pairs
local ipairs = ipairs
diff --git a/src/Modules/CalcActiveSkill.lua.rej b/src/Modules/CalcActiveSkill.lua.rej
new file mode 100644
index 0000000000..6ed6019ece
--- /dev/null
+++ b/src/Modules/CalcActiveSkill.lua.rej
@@ -0,0 +1,22 @@
+diff a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua (rejected hunks)
+@@ -178,9 +179,9 @@ function calcs.copyActiveSkill(env, mode, skill)
+ local newSkill = calcs.createActiveSkill(activeEffect, skill.supportList, skill.actor, skill.socketGroup, skill.summonSkill)
+ local newEnv, _, _, _ = calcs.initEnv(env.build, mode, env.override)
+ calcs.buildActiveSkillModList(newEnv, newSkill)
+- newSkill.skillModList = new("ModList", newSkill.baseSkillModList)
++ newSkill.skillModList = new("ModList"):ModList(newSkill.baseSkillModList)
+ if newSkill.minion then
+- newSkill.minion.modDB = new("ModDB")
++ newSkill.minion.modDB = new("ModDB"):ModDB()
+ newSkill.minion.modDB.actor = newSkill.minion
+ calcs.createMinionSkills(env, newSkill)
+ newSkill.skillPartName = newSkill.minion.mainSkill.activeEffect.grantedEffect.name
+@@ -479,7 +480,7 @@ function calcs.buildActiveSkillModList(env, activeSkill)
+ end
+
+ -- Initialise skill modifier list
+- local skillModList = new("ModList", activeSkill.actor.modDB)
++ local skillModList = new("ModList"):ModList(activeSkill.actor.modDB)
+ activeSkill.skillModList = skillModList
+ activeSkill.baseSkillModList = skillModList
+
diff --git a/src/Modules/CalcBase.lua b/src/Modules/CalcBase.lua
new file mode 100644
index 0000000000..cf23cec318
--- /dev/null
+++ b/src/Modules/CalcBase.lua
@@ -0,0 +1,4 @@
+-- This module is used as a base that the other calc sections can `require` to add their functions to
+---@class Calcs
+local calcs = {}
+return calcs
diff --git a/src/Modules/CalcBreakdown.lua b/src/Modules/CalcBreakdown.lua
index a2ab6b7738..58196bc8a0 100644
--- a/src/Modules/CalcBreakdown.lua
+++ b/src/Modules/CalcBreakdown.lua
@@ -3,8 +3,6 @@
-- Module: Calc Breakdown
-- Calculation breakdown generators
--
-local modDB, output, actor = ...
-
local unpack = unpack
local ipairs = ipairs
local t_insert = table.insert
diff --git a/src/Modules/CalcBreakdown.lua.rej b/src/Modules/CalcBreakdown.lua.rej
new file mode 100644
index 0000000000..92cf3259df
--- /dev/null
+++ b/src/Modules/CalcBreakdown.lua.rej
@@ -0,0 +1,450 @@
+diff a/src/Modules/CalcBreakdown.lua b/src/Modules/CalcBreakdown.lua (rejected hunks)
+@@ -12,240 +10,242 @@ local m_floor = math.floor
+ local m_sqrt = math.sqrt
+ local s_format = string.format
+
+-local breakdown = { }
++return function(modDB, output, actor)
++ local breakdown = {}
+
+-function breakdown.multiChain(out, chain)
+- local base = (chain.base and chain.base[2]) or nil
+- local multiplier = 1
+- local lines = 0 -- lines is the total number of non 1 multipliers.
+- if chain.label then
+- t_insert(out, chain.label)
+- end
+- if base ~= nil then
+- t_insert(out, s_format(unpack(chain.base)))
+- end
+- if base ~= 0 then
+- for _, mult in ipairs(chain) do
+- if mult[2] and mult[2] ~= 1 then
+- multiplier = multiplier * mult[2]
+- t_insert(out, "x "..s_format(unpack(mult)))
+- lines = lines + 1
++ function breakdown.multiChain(out, chain)
++ local base = (chain.base and chain.base[2]) or nil
++ local multiplier = 1
++ local lines = 0 -- lines is the total number of non 1 multipliers.
++ if chain.label then
++ t_insert(out, chain.label)
++ end
++ if base ~= nil then
++ t_insert(out, s_format(unpack(chain.base)))
++ end
++ if base ~= 0 then
++ for _, mult in ipairs(chain) do
++ if mult[2] and mult[2] ~= 1 then
++ multiplier = multiplier * mult[2]
++ t_insert(out, "x " .. s_format(unpack(mult)))
++ lines = lines + 1
++ end
+ end
+ end
++ if chain.total then
++ t_insert(out, chain.total)
++ elseif not chain.noTotal and (lines > 0 and base ~= nil) or (lines > 1 and base == nil) then
++ t_insert(out, s_format("= %.2f", multiplier * (base or 1)))
++ end
++ return lines
+ end
+- if chain.total then
+- t_insert(out, chain.total)
+- elseif not chain.noTotal and (lines > 0 and base ~= nil) or (lines > 1 and base == nil) then
+- t_insert(out, s_format("= %.2f", multiplier * (base or 1)))
+- end
+- return lines
+-end
+
+-function breakdown.simple(extraBase, cfg, total, ...)
+- extraBase = extraBase or 0
+- local base = modDB:Sum("BASE", cfg, (...))
+- if (base + extraBase) ~= 0 then
+- local inc = modDB:Sum("INC", cfg, ...)
+- local more = modDB:More(cfg, ...)
+- if inc ~= 0 or more ~= 1 or (base ~= 0 and extraBase ~= 0) then
+- local out = { }
+- if base ~= 0 and extraBase ~= 0 then
+- out[1] = s_format("(%g + %g) ^8(base)", extraBase, base)
+- else
+- out[1] = s_format("%g ^8(base)", base + extraBase)
+- end
+- if inc ~= 0 then
+- t_insert(out, s_format("x %.2f ^8(increased/reduced)", 1 + inc/100))
++ function breakdown.simple(extraBase, cfg, total, ...)
++ extraBase = extraBase or 0
++ local base = modDB:Sum("BASE", cfg, (...))
++ if (base + extraBase) ~= 0 then
++ local inc = modDB:Sum("INC", cfg, ...)
++ local more = modDB:More(cfg, ...)
++ if inc ~= 0 or more ~= 1 or (base ~= 0 and extraBase ~= 0) then
++ local out = {}
++ if base ~= 0 and extraBase ~= 0 then
++ out[1] = s_format("(%g + %g) ^8(base)", extraBase, base)
++ else
++ out[1] = s_format("%g ^8(base)", base + extraBase)
++ end
++ if inc ~= 0 then
++ t_insert(out, s_format("x %.2f ^8(increased/reduced)", 1 + inc / 100))
++ end
++ if more ~= 1 then
++ t_insert(out, s_format("x %.2f ^8(more/less)", more))
++ end
++ t_insert(out, s_format("= %g", total))
++ return out
+ end
+- if more ~= 1 then
+- t_insert(out, s_format("x %.2f ^8(more/less)", more))
+- end
+- t_insert(out, s_format("= %g", total))
+- return out
+ end
+ end
+-end
+
+-function breakdown.mod(modList, cfg, ...)
+- local inc = modList:Sum("INC", cfg, ...)
+- local more = modList:More(cfg, ...)
+- if inc ~= 0 or more ~= 1 then
+- return {
+- s_format("%.2f ^8(increased/reduced)", 1 + inc/100),
+- s_format("x %.2f ^8(more/less)", more),
+- s_format("= %.2f", (1 + inc/100) * more),
+- }
++ function breakdown.mod(modList, cfg, ...)
++ local inc = modList:Sum("INC", cfg, ...)
++ local more = modList:More(cfg, ...)
++ if inc ~= 0 or more ~= 1 then
++ return {
++ s_format("%.2f ^8(increased/reduced)", 1 + inc / 100),
++ s_format("x %.2f ^8(more/less)", more),
++ s_format("= %.2f", (1 + inc / 100) * more),
++ }
++ end
+ end
+-end
+-
+-function breakdown.slot(source, sourceName, cfg, base, total, ...)
+- local inc = modDB:Sum("INC", cfg, ...)
+- local more = modDB:More(cfg, ...)
+- t_insert(breakdown[...].slots, {
+- base = base,
+- inc = (inc ~= 0) and s_format(" x %.2f", 1 + inc/100),
+- more = (more ~= 1) and s_format(" x %.2f", more),
+- total = s_format("%.2f", total or (base * (1 + inc / 100) * more)),
+- source = source,
+- sourceName = sourceName,
+- item = actor.itemList[source],
+- })
+-end
+
+-function breakdown.area(base, areaMod, total, incBreakpoint, moreBreakpoint, redBreakpoint, lessBreakpoint, label)
+- local out = {}
+- t_insert(out, label)
+- if base ~= total then
+- t_insert(out, s_format("%.1fm ^8(base radius)", base / 10))
+- t_insert(out, s_format("x %.2f ^8(square root of area of effect modifier)", m_floor(100 * m_sqrt(areaMod)) / 100))
+- t_insert(out, s_format("= %.1fm", total / 10))
++ function breakdown.slot(source, sourceName, cfg, base, total, ...)
++ local inc = modDB:Sum("INC", cfg, ...)
++ local more = modDB:More(cfg, ...)
++ t_insert(breakdown[...].slots, {
++ base = base,
++ inc = (inc ~= 0) and s_format(" x %.2f", 1 + inc / 100),
++ more = (more ~= 1) and s_format(" x %.2f", more),
++ total = s_format("%.2f", total or (base * (1 + inc / 100) * more)),
++ source = source,
++ sourceName = sourceName,
++ item = actor.itemList[source],
++ })
+ end
+- if incBreakpoint and moreBreakpoint and redBreakpoint and lessBreakpoint then
+- t_insert(out, s_format("^8Next 0.1m breakpoint: %d%% increased AoE / a %d%% more AoE multiplier", incBreakpoint, moreBreakpoint))
+- t_insert(out, s_format("^8Previous 0.1m breakpoint: %d%% reduced AoE / a %d%% less AoE multiplier", redBreakpoint, lessBreakpoint))
++
++ function breakdown.area(base, areaMod, total, incBreakpoint, moreBreakpoint, redBreakpoint, lessBreakpoint, label)
++ local out = {}
++ t_insert(out, label)
++ if base ~= total then
++ t_insert(out, s_format("%.1fm ^8(base radius)", base / 10))
++ t_insert(out, s_format("x %.2f ^8(square root of area of effect modifier)", m_floor(100 * m_sqrt(areaMod)) / 100))
++ t_insert(out, s_format("= %.1fm", total / 10))
++ end
++ if incBreakpoint and moreBreakpoint and redBreakpoint and lessBreakpoint then
++ t_insert(out, s_format("^8Next 0.1m breakpoint: %d%% increased AoE / a %d%% more AoE multiplier", incBreakpoint, moreBreakpoint))
++ t_insert(out, s_format("^8Previous 0.1m breakpoint: %d%% reduced AoE / a %d%% less AoE multiplier", redBreakpoint, lessBreakpoint))
++ end
++ out.radius = total
++ return out
+ end
+- out.radius = total
+- return out
+-end
+
+-function breakdown.effMult(damageType, resist, pen, taken, mult, takenMore, sourceRes, useRes, invertChance, effectiveResist)
+- local out = { }
+- local resistForm = (damageType == "Physical") and "physical damage reduction" or "resistance"
+- local resistLabel = resistForm
+- effectiveResist = effectiveResist or resist - pen
++ function breakdown.effMult(damageType, resist, pen, taken, mult, takenMore, sourceRes, useRes, invertChance, effectiveResist)
++ local out = {}
++ local resistForm = (damageType == "Physical") and "physical damage reduction" or "resistance"
++ local resistLabel = resistForm
++ effectiveResist = effectiveResist or resist - pen
+
+- if sourceRes and sourceRes ~= damageType then
+- t_insert(out, s_format("Enemy %s: %d%% ^8(%s)", resistLabel, resist, sourceRes))
+- elseif resist ~= 0 then
+- t_insert(out, s_format("Enemy %s: %d%%", resistLabel, resist))
+- end
+- if invertChance and invertChance ~= 0 and useRes then
+- local normalResist = resist - pen
+- local invertedResist = -resist - pen
+- t_insert(out, "Effective resistance:")
+- t_insert(out, s_format("%g%% ^8(non-inverted hit after penetration)", normalResist))
+- t_insert(out, s_format("%g%% ^8(inverted hit after penetration)", invertedResist))
+- t_insert(out, s_format("= %g%% ^8(weighted average from %.0f%% inversion chance)", effectiveResist, invertChance * 100))
+- elseif pen ~= 0 or not useRes then
+- t_insert(out, "Effective resistance:")
+- t_insert(out, s_format("%d%% ^8(resistance)", resist))
+- if pen < 0 then
+- t_insert(out, s_format("+ %d%% ^8(penetration)", -pen))
+- elseif pen > 0 then
+- t_insert(out, s_format("- %d%% ^8(penetration)", pen))
++ if sourceRes and sourceRes ~= damageType then
++ t_insert(out, s_format("Enemy %s: %d%% ^8(%s)", resistLabel, resist, sourceRes))
++ elseif resist ~= 0 then
++ t_insert(out, s_format("Enemy %s: %d%%", resistLabel, resist))
++ end
++ if invertChance and invertChance ~= 0 and useRes then
++ local normalResist = resist - pen
++ local invertedResist = -resist - pen
++ t_insert(out, "Effective resistance:")
++ t_insert(out, s_format("%g%% ^8(non-inverted hit after penetration)", normalResist))
++ t_insert(out, s_format("%g%% ^8(inverted hit after penetration)", invertedResist))
++ t_insert(out, s_format("= %g%% ^8(weighted average from %.0f%% inversion chance)", effectiveResist, invertChance * 100))
++ elseif pen ~= 0 or not useRes then
++ t_insert(out, "Effective resistance:")
++ t_insert(out, s_format("%d%% ^8(resistance)", resist))
++ if pen < 0 then
++ t_insert(out, s_format("+ %d%% ^8(penetration)", -pen))
++ elseif pen > 0 then
++ t_insert(out, s_format("- %d%% ^8(penetration)", pen))
++ end
++ if not useRes then
++ t_insert(out, s_format("x %d%% ^8(resistance ignored)", 0))
++ t_insert(out, s_format("= %d%%", (0)))
++ else
++ t_insert(out, s_format("= %d%%", (resist - pen)))
++ end
+ end
+- if not useRes then
+- t_insert(out, s_format("x %d%% ^8(resistance ignored)", 0))
+- t_insert(out, s_format("= %d%%", (0)))
+- else
+- t_insert(out, s_format("= %d%%", (resist - pen)))
++ if useRes then
++ breakdown.multiChain(out, {
++ label = "Effective DPS modifier:",
++ { "%.2f ^8(%s)", 1 - effectiveResist / 100, resistForm },
++ { "%.2f ^8(increased/reduced damage taken)", 1 + taken / 100 },
++ { "%.2f ^8(more/less damage taken)", takenMore },
++ total = s_format("= %.3f", mult),
++ })
++ else
++ t_insert(out, "Effective DPS modifier:")
++ t_insert(out, s_format("= %.3f ^8(increased/reduced damage taken)", mult))
+ end
++ return out
+ end
+- if useRes then
++
++ function breakdown.dot(out, baseVal, inc, more, mult, rate, aura, effMult, total)
+ breakdown.multiChain(out, {
+- label = "Effective DPS modifier:",
+- { "%.2f ^8(%s)", 1 - effectiveResist / 100, resistForm },
+- { "%.2f ^8(increased/reduced damage taken)", 1 + taken / 100 },
+- { "%.2f ^8(more/less damage taken)", takenMore },
+- total = s_format("= %.3f", mult),
++ base = { "%.1f ^8(base damage per second)", baseVal },
++ { "%.2f ^8(increased/reduced)", 1 + inc / 100 },
++ { "%.2f ^8(more/less)", more },
++ { "%.2f ^8(multiplier)", 1 + (mult or 0) / 100 },
++ { "%.2f ^8(rate modifier)", rate },
++ { "%.3f ^8(aura effect modifier)", aura },
++ { "%.3f ^8(effective DPS modifier)", effMult },
++ total = s_format("= %.1f ^8per second", total),
+ })
+- else
+- t_insert(out, "Effective DPS modifier:")
+- t_insert(out, s_format("= %.3f ^8(increased/reduced damage taken)", mult))
+ end
+- return out
+-end
+-
+-function breakdown.dot(out, baseVal, inc, more, mult, rate, aura, effMult, total)
+- breakdown.multiChain(out, {
+- base = { "%.1f ^8(base damage per second)", baseVal },
+- { "%.2f ^8(increased/reduced)", 1 + inc/100 },
+- { "%.2f ^8(more/less)", more },
+- { "%.2f ^8(multiplier)", 1 + (mult or 0)/100 },
+- { "%.2f ^8(rate modifier)", rate },
+- { "%.3f ^8(aura effect modifier)", aura },
+- { "%.3f ^8(effective DPS modifier)", effMult },
+- total = s_format("= %.1f ^8per second", total),
+- })
+-end
+
+-function breakdown.critDot(dotMulti, critMulti, dotChance, critChance)
+- local combined = (dotMulti * dotChance) + (critMulti * critChance)
+- local out = { }
+- if dotChance > 0 then
+- t_insert(out, s_format("Contribution from Non-crits:"))
+- t_insert(out, s_format("%.2f ^8(dot multiplier for non-crits)", dotMulti))
+- t_insert(out, s_format("x %.4f ^8(portion of instances created by non-crits)", dotChance))
+- t_insert(out, s_format("= %.2f", dotMulti * dotChance))
+- end
+- if critChance > 0 then
+- t_insert(out, s_format("Contribution from Crits:"))
+- t_insert(out, s_format("%.2f ^8(dot multiplier for crits)", critMulti))
+- t_insert(out, s_format("x %.4f ^8(portion of instances created by crits)", critChance))
+- t_insert(out, s_format("= %.2f", critMulti * critChance))
+- end
+- if (dotChance > 0 and critChance > 0) and (dotMulti ~= critMulti)then
+- t_insert(out, s_format("Effective DoT Multiplier:"))
+- t_insert(out, s_format("%.2f + %.2f", dotMulti * dotChance, critMulti * critChance))
+- t_insert(out, s_format("= %.2f", combined))
+- end
+- return out
+-end
+-
+-function breakdown.leech(instant, instantRate, instances, pool, rate, max, dur, instantLeechProportion, hitRate)
+- local out = { }
+- if actor.mainSkill.skillData.showAverage then
+- if instant > 0 then
+- if instantLeechProportion ~= 1 then
+- t_insert(out, s_format("Instant Leech: %.1f ^8(%d%% x %.1f)", instant, instantLeechProportion * 100, dur * pool * data.misc.LeechRateBase / (1-instantLeechProportion)))
+- else
+- t_insert(out, s_format("Instant Leech: %.1f", instant))
+- end
++ function breakdown.critDot(dotMulti, critMulti, dotChance, critChance)
++ local combined = (dotMulti * dotChance) + (critMulti * critChance)
++ local out = {}
++ if dotChance > 0 then
++ t_insert(out, s_format("Contribution from Non-crits:"))
++ t_insert(out, s_format("%.2f ^8(dot multiplier for non-crits)", dotMulti))
++ t_insert(out, s_format("x %.4f ^8(portion of instances created by non-crits)", dotChance))
++ t_insert(out, s_format("= %.2f", dotMulti * dotChance))
+ end
+- if instances > 0 then
+- t_insert(out, "Total leeched per instance:")
+- t_insert(out, s_format("%d ^8(size of leech destination pool)", pool))
+- t_insert(out, s_format("x %.2f ^8(base leech rate is %d%% per second)", data.misc.LeechRateBase, 100 * data.misc.LeechRateBase))
+- local rateMod = calcLib.mod(modDB, skillCfg, rate)
+- if rateMod ~= 1 then
+- t_insert(out, s_format("x %.2f ^8(leech rate modifier)", rateMod))
+- end
+- t_insert(out, s_format("x %.2fs ^8(instance duration)", dur))
+- t_insert(out, s_format("= %.1f", pool * data.misc.LeechRateBase * rateMod * dur))
++ if critChance > 0 then
++ t_insert(out, s_format("Contribution from Crits:"))
++ t_insert(out, s_format("%.2f ^8(dot multiplier for crits)", critMulti))
++ t_insert(out, s_format("x %.4f ^8(portion of instances created by crits)", critChance))
++ t_insert(out, s_format("= %.2f", critMulti * critChance))
+ end
+- else
+- if instantRate > 0 then
+- if instantLeechProportion ~= 1 then
+- t_insert(out, s_format("Instant Leech: %.1f ^8(%d%% x %.1f)", instant, instantLeechProportion * 100, dur * pool * data.misc.LeechRateBase / (1-instantLeechProportion)))
+- else
+- t_insert(out, s_format("Instant Leech: %.1f", instant))
+- end
+- t_insert(out, s_format("Instant Leech per second: %.1f ^8(%.1f x %.2f)", instantRate, instant, hitRate))
++ if (dotChance > 0 and critChance > 0) and (dotMulti ~= critMulti) then
++ t_insert(out, s_format("Effective DoT Multiplier:"))
++ t_insert(out, s_format("%.2f + %.2f", dotMulti * dotChance, critMulti * critChance))
++ t_insert(out, s_format("= %.2f", combined))
+ end
+- if instances > 0 then
+- t_insert(out, "Rate per instance:")
+- t_insert(out, s_format("%d ^8(size of leech destination pool)", pool))
+- t_insert(out, s_format("x %.2f ^8(base leech rate is %d%% per second)", data.misc.LeechRateBase, 100 * data.misc.LeechRateBase))
+- local rateMod = calcLib.mod(modDB, skillCfg, rate)
+- if rateMod ~= 1 then
+- t_insert(out, s_format("x %.2f ^8(leech rate modifier)", rateMod))
++ return out
++ end
++
++ function breakdown.leech(instant, instantRate, instances, pool, rate, max, dur, instantLeechProportion, hitRate)
++ local out = {}
++ if actor.mainSkill.skillData.showAverage then
++ if instant > 0 then
++ if instantLeechProportion ~= 1 then
++ t_insert(out, s_format("Instant Leech: %.1f ^8(%d%% x %.1f)", instant, instantLeechProportion * 100, dur * pool * data.misc.LeechRateBase / (1 - instantLeechProportion)))
++ else
++ t_insert(out, s_format("Instant Leech: %.1f", instant))
++ end
++ end
++ if instances > 0 then
++ t_insert(out, "Total leeched per instance:")
++ t_insert(out, s_format("%d ^8(size of leech destination pool)", pool))
++ t_insert(out, s_format("x %.2f ^8(base leech rate is %d%% per second)", data.misc.LeechRateBase, 100 * data.misc.LeechRateBase))
++ local rateMod = calcLib.mod(modDB, skillCfg, rate)
++ if rateMod ~= 1 then
++ t_insert(out, s_format("x %.2f ^8(leech rate modifier)", rateMod))
++ end
++ t_insert(out, s_format("x %.2fs ^8(instance duration)", dur))
++ t_insert(out, s_format("= %.1f", pool * data.misc.LeechRateBase * rateMod * dur))
+ end
+- t_insert(out, s_format("= %.1f ^8per second", pool * data.misc.LeechRateBase * rateMod))
+- t_insert(out, "Maximum leech rate against one target:")
+- t_insert(out, s_format("%.1f", pool * data.misc.LeechRateBase * rateMod))
+- t_insert(out, s_format("x %.2f ^8(average instances)", instances))
+- local total = pool * data.misc.LeechRateBase * rateMod * instances
+- t_insert(out, s_format("= %.1f ^8per second", total))
+- if total <= max then
+- t_insert(out, s_format("Time to reach max: %.1fs", dur))
++ else
++ if instantRate > 0 then
++ if instantLeechProportion ~= 1 then
++ t_insert(out, s_format("Instant Leech: %.1f ^8(%d%% x %.1f)", instant, instantLeechProportion * 100, dur * pool * data.misc.LeechRateBase / (1 - instantLeechProportion)))
++ else
++ t_insert(out, s_format("Instant Leech: %.1f", instant))
++ end
++ t_insert(out, s_format("Instant Leech per second: %.1f ^8(%.1f x %.2f)", instantRate, instant, hitRate))
+ end
+- t_insert(out, s_format("Leech rate cap: %.1f", max))
+- if total > max then
+- t_insert(out, s_format("Time to reach cap: %.1fs", dur / total * max))
++ if instances > 0 then
++ t_insert(out, "Rate per instance:")
++ t_insert(out, s_format("%d ^8(size of leech destination pool)", pool))
++ t_insert(out, s_format("x %.2f ^8(base leech rate is %d%% per second)", data.misc.LeechRateBase, 100 * data.misc.LeechRateBase))
++ local rateMod = calcLib.mod(modDB, skillCfg, rate)
++ if rateMod ~= 1 then
++ t_insert(out, s_format("x %.2f ^8(leech rate modifier)", rateMod))
++ end
++ t_insert(out, s_format("= %.1f ^8per second", pool * data.misc.LeechRateBase * rateMod))
++ t_insert(out, "Maximum leech rate against one target:")
++ t_insert(out, s_format("%.1f", pool * data.misc.LeechRateBase * rateMod))
++ t_insert(out, s_format("x %.2f ^8(average instances)", instances))
++ local total = pool * data.misc.LeechRateBase * rateMod * instances
++ t_insert(out, s_format("= %.1f ^8per second", total))
++ if total <= max then
++ t_insert(out, s_format("Time to reach max: %.1fs", dur))
++ end
++ t_insert(out, s_format("Leech rate cap: %.1f", max))
++ if total > max then
++ t_insert(out, s_format("Time to reach cap: %.1fs", dur / total * max))
++ end
+ end
+ end
++ return out
+ end
+- return out
+-end
+
+-return breakdown
++ return breakdown
++end
diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua
index e15529390a..770b07a371 100644
--- a/src/Modules/CalcDefence.lua
+++ b/src/Modules/CalcDefence.lua
@@ -3,7 +3,8 @@
-- Module: Calc Defence
-- Performs defence calculations.
--
-local calcs = ...
+---@class Calcs
+local calcs = require("Modules.CalcBase")
local pairs = pairs
local ipairs = ipairs
@@ -4356,3 +4357,5 @@ function calcs.buildDefenceEstimations(env, actor)
end
--endregion
end
+
+return calcs
diff --git a/src/Modules/CalcDefence.lua.rej b/src/Modules/CalcDefence.lua.rej
new file mode 100644
index 0000000000..bd66d9c9f4
--- /dev/null
+++ b/src/Modules/CalcDefence.lua.rej
@@ -0,0 +1,13 @@
+diff a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua (rejected hunks)
+@@ -76,9 +77,9 @@ function calcs.armourReduction(armour, raw)
+ end
+
+ -- Based on code from FR and BS found in act_*.txt
+----@param activeSkill/output/breakdown references table passed in from calc offence
++---@param activeSkill any /output/breakdown references table passed in from calc offence
+ ---@param sourceType string type of incoming damage - it will be converted (taken as) from this type if applicable
+----@param baseDmg for which to calculate the damage
++---@param baseDmg number for which to calculate the damage
+ ---@return table of taken damage parts, and number, sum of damages
+ function calcs.applyDmgTakenConversion(activeSkill, output, breakdown, sourceType, baseDmg)
+ local damageBreakdown = { }
diff --git a/src/Modules/CalcMirages.lua b/src/Modules/CalcMirages.lua
index c28b521d1a..846e67075c 100644
--- a/src/Modules/CalcMirages.lua
+++ b/src/Modules/CalcMirages.lua
@@ -4,7 +4,9 @@
-- Handles mirages that use player skills
--
-local calcs = ...
+---@class Calcs
+local calcs = require("Modules.CalcBase")
+
local pairs = pairs
local ipairs = ipairs
local t_insert = table.insert
diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua
index b6de2bf85d..73b0edbc63 100644
--- a/src/Modules/CalcOffence.lua
+++ b/src/Modules/CalcOffence.lua
@@ -3,7 +3,8 @@
-- Module: Calc Offence
-- Performs offence calculations.
--
-local calcs = ...
+---@class Calcs
+local calcs = require("Modules.CalcBase")
local pairs = pairs
local ipairs = ipairs
@@ -2384,7 +2385,7 @@ function calcs.offence(env, actor, activeSkill)
local critOverride = skillModList:Override(skillCfg, "WeaponBaseCritChance")
if skillFlags.weapon1Attack then
if breakdown then
- breakdown.MainHand = LoadModule(calcs.breakdownModule, skillModList, output.MainHand)
+ breakdown.MainHand = LoadModule(calcs.breakdownModule)(skillModList, output.MainHand)
end
activeSkill.weapon1Cfg.skillStats = output.MainHand
local source = copyTable(actor.weaponData1)
@@ -2414,7 +2415,7 @@ function calcs.offence(env, actor, activeSkill)
end
if skillFlags.weapon2Attack then
if breakdown then
- breakdown.OffHand = LoadModule(calcs.breakdownModule, skillModList, output.OffHand)
+ breakdown.OffHand = LoadModule(calcs.breakdownModule)(skillModList, output.OffHand)
end
activeSkill.weapon2Cfg.skillStats = output.OffHand
local source = copyTable(actor.weaponData2)
diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua
index dbc4bb9767..b2ea93ba6a 100644
--- a/src/Modules/CalcPerform.lua
+++ b/src/Modules/CalcPerform.lua
@@ -3,7 +3,8 @@
-- Module: Calc Perform
-- Manages the offence/defence calculations.
--
-local calcs = ...
+---@class Calcs
+local calcs = require("Modules.CalcBase")
local pairs = pairs
local ipairs = ipairs
@@ -40,7 +41,7 @@ end
-- Merge an instance of a buff, taking the highest value of each modifier
local function mergeBuff(src, destTable, destKey)
if not destTable[destKey] then
- destTable[destKey] = new("ModList")
+ destTable[destKey] = new("ModList"):ModList()
end
local dest = destTable[destKey]
for _, mod in ipairs(src) do
@@ -1168,9 +1169,9 @@ function calcs.perform(env, skipEHP)
-- Build minion skills
for _, activeSkill in ipairs(env.player.activeSkillList) do
- activeSkill.skillModList = new("ModList", activeSkill.baseSkillModList)
+ activeSkill.skillModList = new("ModList"):ModList(activeSkill.baseSkillModList)
if activeSkill.minion then
- activeSkill.minion.modDB = new("ModDB")
+ activeSkill.minion.modDB = new("ModDB"):ModDB()
activeSkill.minion.modDB.actor = activeSkill.minion
calcs.createMinionSkills(env, activeSkill)
activeSkill.skillPartName = activeSkill.minion.mainSkill.activeEffect.grantedEffect.name
@@ -1414,10 +1415,10 @@ function calcs.perform(env, skipEHP)
local breakdown = nil
if env.mode == "CALCS" then
-- Initialise breakdown module
- breakdown = LoadModule(calcs.breakdownModule, modDB, output, env.player)
+ breakdown = LoadModule(calcs.breakdownModule)(modDB, output, env.player)
env.player.breakdown = breakdown
if env.minion then
- env.minion.breakdown = LoadModule(calcs.breakdownModule, env.minion.modDB, env.minion.output, env.minion)
+ env.minion.breakdown = LoadModule(calcs.breakdownModule)(env.minion.modDB, env.minion.output, env.minion)
end
end
@@ -1616,13 +1617,13 @@ function calcs.perform(env, skipEHP)
-- so utility flasks are grouped by base, unique flasks are grouped by name, and magic flasks by their modifiers
if buffModList[1] then
if not onlyMinion then
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(buffModList, effectMod)
mergeBuff(srcList, flaskBuffs, baseName)
mergeBuff(srcList, flaskBuffsPerBase[item.baseName], baseName)
end
if (not onlyRecovery or checkNonRecoveryFlasksForMinions) and (flasksApplyToMinion or quickSilverAppliesToAllies or (nonUniqueFlasksApplyToMinion and item.rarity ~= "UNIQUE" and item.rarity ~= "RELIC")) then
- srcList = new("ModList")
+ srcList = new("ModList"):ModList()
srcList:ScaleAddList(buffModList, effectModNonPlayer)
mergeBuff(srcList, flaskBuffsNonPlayer, baseName)
mergeBuff(srcList, flaskBuffsPerBaseNonPlayer[item.baseName], baseName)
@@ -1741,7 +1742,7 @@ function calcs.perform(env, skipEHP)
end
if modList[1] then
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(modList, effectMod)
local key
if item.rarity == "UNIQUE" or item.rarity == "RELIC" then
@@ -1988,8 +1989,8 @@ function calcs.perform(env, skipEHP)
minionCurses.limit = modData.value + 1
break
elseif modData.name == "AllyModifier" and modData.type == "LIST" then
- buffs["Spectre"] = buffs["Spectre"] or new("ModList")
- minionBuffs["Spectre"] = minionBuffs["Spectre"] or new("ModList")
+ buffs["Spectre"] = buffs["Spectre"] or new("ModList"):ModList()
+ minionBuffs["Spectre"] = minionBuffs["Spectre"] or new("ModList"):ModList()
for _, modValue in pairs(modData.value) do
local copyModValue = copyTable(modValue)
copyModValue.source = "Spectre:"..spectreData.name
@@ -1997,14 +1998,14 @@ function calcs.perform(env, skipEHP)
t_insert(buffs["Spectre"], copyModValue)
end
elseif modData.name == "MinionModifier" and modData.type == "LIST" then
- minionBuffs["Spectre"] = minionBuffs["Spectre"] or new("ModList")
+ minionBuffs["Spectre"] = minionBuffs["Spectre"] or new("ModList"):ModList()
for _, modValue in pairs(modData.value) do
local copyModValue = copyTable(modValue)
copyModValue.source = "Spectre:"..spectreData.name
t_insert(minionBuffs["Spectre"], copyModValue)
end
elseif modData.name == "PlayerModifier" and modData.type == "LIST" then
- buffs["Spectre"] = buffs["Spectre"] or new("ModList")
+ buffs["Spectre"] = buffs["Spectre"] or new("ModList"):ModList()
for _, modValue in pairs(modData.value) do
local copyModValue = copyTable(modValue)
copyModValue.source = "Spectre:"..spectreData.name
@@ -2232,7 +2233,7 @@ function calcs.perform(env, skipEHP)
modDB.conditions["AffectedBy"..buff.name:sub(6):gsub(" ","")] = true
end
modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(buff.modList, mult)
srcList:ScaleAddList(extraAuraModList, mult)
mergeBuff(srcList, buffs, buff.name)
@@ -2247,7 +2248,7 @@ function calcs.perform(env, skipEHP)
activeSkill.minionBuffSkill = true
env.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
env.minion.modDB.conditions["AffectedByAura"] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(buff.modList, mult)
srcList:ScaleAddList(extraAuraModList, mult)
mergeBuff(srcList, minionBuffs, buff.name)
@@ -2354,7 +2355,7 @@ function calcs.perform(env, skipEHP)
activeSkill.debuffSkill = true
enemyDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
local mult = 1
local extraAuraModList = { }
if buff.type == "AuraDebuff" then
@@ -2384,7 +2385,7 @@ function calcs.perform(env, skipEHP)
t_insert(newModList, mod)
end
-- A full modlist causes issues with copy table for mine auras
- --local newModList = new("ModList")
+ --local newModList = new("ModList"):ModList()
--newModList:AddList(buff.modList)
--newModList:AddList(extraAuraModList)
buffExports["Aura"][buff.name..(buffExports["Aura"][buff.name] and "_Debuff" or "")] = { effectMult = mult, modList = newModList }
@@ -2492,7 +2493,7 @@ function calcs.perform(env, skipEHP)
activeSkill.minionBuffSkill = true
env.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
env.minion.modDB.conditions["AffectedByLink"] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
inc = inc + env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "LinkEffectOnSelf")
more = more * env.minion.modDB:More(nil, "BuffEffectOnSelf", "LinkEffectOnSelf")
mult = (1 + inc / 100) * more
@@ -2617,7 +2618,7 @@ function calcs.perform(env, skipEHP)
modDB.conditions["AffectedBy"..buff.name:sub(6):gsub(" ","")] = true
end
modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(buff.modList, mult)
srcList:ScaleAddList(extraAuraModList, mult)
setSpectreSource(srcList, buff.name)
@@ -2632,7 +2633,7 @@ function calcs.perform(env, skipEHP)
activeMinionSkill.minionBuffSkill = true
env.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
env.minion.modDB.conditions["AffectedByAura"] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(buff.modList, mult)
srcList:ScaleAddList(extraAuraModList, mult)
setSpectreSource(srcList, buff.name)
@@ -2715,7 +2716,7 @@ function calcs.perform(env, skipEHP)
end
if env.mode_effective and stackCount > 0 then
activeMinionSkill.debuffSkill = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
local mult = 1
if buff.type == "AuraDebuff" then
mult = 0
@@ -2819,7 +2820,7 @@ function calcs.perform(env, skipEHP)
if not enemyDB.conditions["AffectedBy"..auraNameCompressed] then
enemyDB.conditions["AffectedBy"..auraNameCompressed] = true
modDB.conditions["AffectedBy"..auraNameCompressed] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(aura.modList, aura.effectMult / 100)
mergeBuff(srcList, debuffs, auraName)
end
@@ -2831,7 +2832,7 @@ function calcs.perform(env, skipEHP)
if not enemyDB.conditions["AffectedBy"..auraNameCompressed] then
enemyDB.conditions["AffectedBy"..auraNameCompressed] = true
modDB.conditions["AffectedBy"..auraNameCompressed] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(aura.modList, aura.effectMult / 100)
mergeBuff(srcList, debuffs, auraName)
end
@@ -2844,7 +2845,7 @@ function calcs.perform(env, skipEHP)
if not modDB.conditions["AffectedBy"..warcryNameCompressed] then
modDB.conditions["AffectedByWarcry"] = true
modDB.conditions["AffectedBy"..warcryNameCompressed] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
for _, warcryBuff in ipairs(warcry.modList) do
srcList:ScaleAddList({warcryBuff}, (warcry.effectMult or 100) / 100 * (warcryBuff[1].warcryPowerBonus or 1))
end
@@ -2867,7 +2868,7 @@ function calcs.perform(env, skipEHP)
if not modDB.conditions["AffectedBy"..linkNameCompressed] then
modDB.conditions["AffectedByLink"] = true
modDB.conditions["AffectedBy"..linkNameCompressed] = true
- local srcList = new("ModList")
+ local srcList = new("ModList"):ModList()
srcList:ScaleAddList(link.modList, (link.effectMult or 100) / 100)
mergeBuff(srcList, buffs, linkName)
end
@@ -2889,7 +2890,7 @@ function calcs.perform(env, skipEHP)
-- Check for extra curses
for dest, modDB in pairs({[curses] = modDB, [minionCurses] = env.minion and env.minion.modDB}) do
for _, value in ipairs(modDB:List(nil, "ExtraCurse")) do
- local gemModList = new("ModList")
+ local gemModList = new("ModList"):ModList()
local grantedEffect = env.data.skills[value.skillId]
if grantedEffect then
calcs.mergeSkillInstanceMods(env, gemModList, {
@@ -2941,7 +2942,7 @@ function calcs.perform(env, skipEHP)
local newCurse = {
name = curseName,
priority = 0,
- modList = new("ModList")
+ modList = new("ModList"):ModList()
}
local mult = curse.effectMult / 100
if curse.isMark then
diff --git a/src/Modules/CalcPerform.lua.rej b/src/Modules/CalcPerform.lua.rej
new file mode 100644
index 0000000000..958448753f
--- /dev/null
+++ b/src/Modules/CalcPerform.lua.rej
@@ -0,0 +1,290 @@
+diff a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua (rejected hunks)
+@@ -1719,7 +1720,7 @@ function calcs.perform(env, skipEHP)
+ mergeBuff(srcList, flaskBuffsNonUtility, key)
+ end
+ if (not onlyRecovery or checkNonRecoveryFlasksForMinions) and (flasksApplyToMinion or quickSilverAppliesToAllies or (nonUniqueFlasksApplyToMinion and item.rarity ~= "UNIQUE" and item.rarity ~= "RELIC")) then
+- srcList = new("ModList")
++ srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(modList, effectModNonPlayer)
+ mergeBuff(srcList, flaskBuffsNonPlayer, key)
+ mergeBuff(srcList, flaskBuffsPerBaseNonPlayer[item.baseName], key)
+@@ -1841,14 +1842,14 @@ function calcs.perform(env, skipEHP)
+
+ -- same deal as flasks, go look at the comment there
+ if buffModList[1] then
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(buffModList, effectMod)
+ mergeBuff(srcList, tinctureBuffs, baseName)
+ mergeBuff(srcList, tinctureBuffsPerBase[item.baseName], baseName)
+ end
+
+ if modList[1] then
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(modList, effectMod)
+ local key
+ if item.rarity == "UNIQUE" or item.rarity == "RELIC" then
+@@ -2270,7 +2271,7 @@ function calcs.perform(env, skipEHP)
+ if not buff.applyNotPlayer then
+ activeSkill.buffSkill = true
+ modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = modStore:Sum("INC", skillCfg, "BuffEffect", "BuffEffectOnSelf", "BuffEffectOnPlayer") + skillModList:Sum("INC", skillCfg, buff.name:gsub(" ", "").."Effect")
+ local more = modStore:More(skillCfg, "BuffEffect", "BuffEffectOnSelf")
+ srcList:ScaleAddList(buff.modList, (1 + inc / 100) * more)
+@@ -2282,7 +2283,7 @@ function calcs.perform(env, skipEHP)
+ if env.minion and not env.minion.hostile and (buff.applyMinions or buff.applyAllies or skillModList:Flag(nil, "BuffAppliesToAllies")) then
+ activeSkill.minionBuffSkill = true
+ env.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = modStore:Sum("INC", skillCfg, "BuffEffect") + env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf")
+ local more = modStore:More(skillCfg, "BuffEffect") * env.minion.modDB:More(nil, "BuffEffectOnSelf")
+ srcList:ScaleAddList(buff.modList, (1 + inc / 100) * more)
+@@ -2301,7 +2302,7 @@ function calcs.perform(env, skipEHP)
+ local modStore = buff.activeSkillBuff and skillModList or modDB
+ if not buff.applyNotPlayer then
+ activeSkill.buffSkill = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = modStore:Sum("INC", skillCfg, "BuffEffect", "BuffEffectOnSelf", "BuffEffectOnPlayer")
+ local more = modStore:More(skillCfg, "BuffEffect", "BuffEffectOnSelf")
+ srcList:ScaleAddList(buff.modList, (1 + inc / 100) * more)
+@@ -2334,12 +2335,12 @@ function calcs.perform(env, skipEHP)
+ local cooldownOverride = modStore:Override(skillCfg, "CooldownRecovery")
+ local actual_cooldown = cooldownOverride or (activeSkill.skillData.cooldown + modStore:Sum("BASE", skillCfg, "CooldownRecovery")) / calcLib.mod(modStore, skillCfg, "CooldownRecovery")
+ local uptime = modDB:Flag(nil, "Condition:WarcryMaxHit") and 1 or m_min(full_duration / actual_cooldown, 1)
+- local extraWarcryModList = activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and new("ModList") or {}
++ local extraWarcryModList = activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and new("ModList"):ModList() or {}
+ if not modDB:Flag(nil, "CannotGainWarcryBuffs") then
+ if not buff.applyNotPlayer then
+ activeSkill.buffSkill = true
+ modDB.conditions["AffectedBy"..warcryName] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = modStore:Sum("INC", skillCfg, "BuffEffect", "BuffEffectOnSelf", "BuffEffectOnPlayer")
+ local more = modStore:More(skillCfg, "BuffEffect", "BuffEffectOnSelf")
+ for _, warcryBuff in ipairs(buff.modList) do
+@@ -2352,7 +2353,7 @@ function calcs.perform(env, skipEHP)
+ if env.minion then
+ activeSkill.minionBuffSkill = true
+ env.minion.modDB.conditions["AffectedBy"..warcryName] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = skillModList:Sum("INC", skillCfg, "BuffEffect") + env.minion.modDB:Sum("INC", skillCfg, "BuffEffectOnSelf")
+ local more = skillModList:More(skillCfg, "BuffEffect") * env.minion.modDB:More(skillCfg, "BuffEffectOnSelf")
+ for _, warcryBuff in ipairs(buff.modList) do
+@@ -2380,7 +2381,7 @@ function calcs.perform(env, skipEHP)
+ mergeBuff(srcList, minionBuffs, buff.name)
+ end
+ if partyTabEnableExportBuffs then
+- local newModList = new("ModList")
++ local newModList = new("ModList"):ModList()
+ local inc = skillModList:Sum("INC", skillCfg, "BuffEffect")
+ local more = skillModList:More(skillCfg, "BuffEffect")
+ newModList:AddList(buff.modList)
+@@ -2441,7 +2442,7 @@ function calcs.perform(env, skipEHP)
+ local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect")
+ local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect")
+ local mult = (1 + inc / 100) * more
+- local newModList = new("ModList")
++ local newModList = new("ModList"):ModList()
+ newModList:AddList(buff.modList)
+ newModList:AddList(extraAuraModList)
+ if buffExports["Aura"][buff.name] then
+@@ -2450,7 +2451,7 @@ function calcs.perform(env, skipEHP)
+ buffExports["Aura"][buff.name] = { effectMult = mult, modList = newModList }
+ if modDB:Flag(nil, "AurasAffectEnemies") and not activeSkill.skillModList:Flag(skillCfg, "SelfAurasAffectYouAndLinkedTarget") then
+ local newModList = {}
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ for _, mod in ipairs(buff.modList) do
+ t_insert(newModList, mod)
+ end
+@@ -2468,7 +2469,7 @@ function calcs.perform(env, skipEHP)
+ env.player.mainSkill.skillModList.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
+ env.player.mainSkill.skillModList.conditions["AffectedByAura"] = true
+
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect", "AuraBuffEffect")
+ local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect", "AuraBuffEffect")
+ local lists = {extraAuraModList, buff.modList}
+@@ -2521,7 +2522,7 @@ function calcs.perform(env, skipEHP)
+ local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect", "DebuffEffect")
+ local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect", "DebuffEffect")
+ mult = (1 + inc / 100) * more
+- local newModList = new("ModList")
++ local newModList = new("ModList"):ModList()
+ newModList:AddList(extraAuraModList)
+ buffExports["Aura"][buff.name..(buffExports["Aura"][buff.name] and "_Debuff" or "")] = { effectMult = mult, modList = newModList }
+ if allyBuffs["AuraDebuff"] and allyBuffs["AuraDebuff"][buff.name] and allyBuffs["AuraDebuff"][buff.name].effectMult / 100 > mult then
+@@ -2631,21 +2632,21 @@ function calcs.perform(env, skipEHP)
+ mult = (1 + inc / 100) * more
+ end
+ if buff.type == "Curse" then
+- curse.modList = new("ModList")
++ curse.modList = new("ModList"):ModList()
+ curse.modList:ScaleAddList(buff.modList, mult)
+ if partyTabEnableExportBuffs then
+ buffExports["Curse"][buff.name] = { isMark = curse.isMark, effectMult = curse.isMark and mult or (1 + inc / 100) * moreMark, modList = buff.modList }
+ end
+ else
+ -- Curse applies a buff; scale by curse effect, then buff effect
+- local temp = new("ModList")
++ local temp = new("ModList"):ModList()
+ temp:ScaleAddList(buff.modList, mult)
+- curse.buffModList = new("ModList")
++ curse.buffModList = new("ModList"):ModList()
+ local buffInc = modDB:Sum("INC", skillCfg, "BuffEffectOnSelf")
+ local buffMore = modDB:More(skillCfg, "BuffEffectOnSelf")
+ curse.buffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore)
+ if env.minion then
+- curse.minionBuffModList = new("ModList")
++ curse.minionBuffModList = new("ModList"):ModList()
+ local buffInc = env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf")
+ local buffMore = env.minion.modDB:More(nil, "BuffEffectOnSelf")
+ curse.minionBuffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore)
+@@ -2680,7 +2681,7 @@ function calcs.perform(env, skipEHP)
+ local more = skillModList:More(skillCfg, "LinkEffect", "BuffEffect")
+ local mult = (1 + inc / 100) * more
+ if partyTabEnableExportBuffs then
+- local newModList = new("ModList")
++ local newModList = new("ModList"):ModList()
+ newModList:AddList(buff.modList)
+ newModList:AddList(extraLinkModList)
+ buffExports["Link"][buff.name] = { effectMult = mult, modList = newModList }
+@@ -2744,7 +2745,7 @@ function calcs.perform(env, skipEHP)
+ if buff.applyAllies then
+ activeMinionSkill.buffSkill = true
+ modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = modStore:Sum("INC", skillCfg, "BuffEffect", "BuffEffectOnPlayer") + modDB:Sum("INC", nil, "BuffEffectOnSelf")
+ local more = modStore:More(skillCfg, "BuffEffect", "BuffEffectOnPlayer") * modDB:More(nil, "BuffEffectOnSelf")
+ srcList:ScaleAddList(buff.modList, (1 + inc / 100) * more)
+@@ -2768,7 +2769,7 @@ function calcs.perform(env, skipEHP)
+ else
+ activeSkill.minion.modDB.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
+ end
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = modStore:Sum("INC", skillCfg, "BuffEffect", (env.minion == castingMinion) and "BuffEffectOnSelf" or nil)
+ local more = modStore:More(skillCfg, "BuffEffect", (env.minion == castingMinion) and "BuffEffectOnSelf" or nil)
+ srcList:ScaleAddList(buff.modList, (1 + inc / 100) * more)
+@@ -2833,7 +2834,7 @@ function calcs.perform(env, skipEHP)
+ local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect")
+ local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect")
+ local mult = (1 + inc / 100) * more
+- local newModList = new("ModList")
++ local newModList = new("ModList"):ModList()
+ newModList:AddList(buff.modList)
+ newModList:AddList(extraAuraModList)
+ setSpectreSource(newModList, buff.name)
+@@ -2846,7 +2847,7 @@ function calcs.perform(env, skipEHP)
+ env.player.mainSkill.skillModList.conditions["AffectedBy"..buff.name:gsub(" ","")] = true
+ env.player.mainSkill.skillModList.conditions["AffectedByAura"] = true
+
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ local inc = skillModList:Sum("INC", skillCfg, "AuraEffect", "BuffEffect", "AuraBuffEffect")
+ local more = skillModList:More(skillCfg, "AuraEffect", "BuffEffect", "AuraBuffEffect")
+ local lists = {extraAuraModList, buff.modList}
+@@ -2882,7 +2883,7 @@ function calcs.perform(env, skipEHP)
+ }
+ local inc = skillModList:Sum("INC", skillCfg, "CurseEffect") + enemyDB:Sum("INC", nil, "CurseEffectOnSelf")
+ local more = skillModList:More(skillCfg, "CurseEffect") * enemyDB:More(nil, "CurseEffectOnSelf")
+- curse.modList = new("ModList")
++ curse.modList = new("ModList"):ModList()
+ curse.modList:ScaleAddList(buff.modList, (1 + inc / 100) * more)
+ t_insert(minionCurses, curse)
+ end
+@@ -2943,14 +2944,14 @@ function calcs.perform(env, skipEHP)
+ modDB.conditions["AffectedBy"..buffName:gsub(" ","")] = true
+ local inc = modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
+ local more = modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(buff.modList, (buff.effectMult + inc) / 100 * more)
+ mergeBuff(srcList, buffs, buffName)
+ if env.minion then
+ env.minion.modDB.conditions["AffectedBy"..buffName:gsub(" ","")] = true
+ local inc = env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
+ local more = env.minion.modDB:More(nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(buff.modList, (buff.effectMult + inc) / 100 * more)
+ mergeBuff(srcList, minionBuffs, buffName)
+ end
+@@ -2963,14 +2964,14 @@ function calcs.perform(env, skipEHP)
+ if not modDB:Flag(nil, "AlliesAurasCannotAffectSelf") and not modDB.conditions["AffectedBy"..auraNameCompressed] then
+ modDB.conditions["AffectedByAura"] = true
+ modDB.conditions["AffectedBy"..auraNameCompressed] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(aura.modList, aura.effectMult / 100)
+ mergeBuff(srcList, buffs, auraName)
+ end
+ if env.minion and not env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] then
+ env.minion.modDB.conditions["AffectedByAura"] = true
+ env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(aura.modList, aura.effectMult / 100)
+ mergeBuff(srcList, minionBuffs, auraName)
+ end
+@@ -2983,14 +2984,14 @@ function calcs.perform(env, skipEHP)
+ modDB.conditions["AffectedByAura"] = true
+ modDB.conditions["AffectedBy"..auraName:sub(6):gsub(" ","")] = true
+ modDB.conditions["AffectedBy"..auraNameCompressed] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(aura.modList, aura.effectMult / 100)
+ mergeBuff(srcList, buffs, auraName)
+ end
+ if env.minion and not env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] then
+ env.minion.modDB.conditions["AffectedByAura"] = true
+ env.minion.modDB.conditions["AffectedBy"..auraNameCompressed] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ srcList:ScaleAddList(aura.modList, aura.effectMult / 100)
+ mergeBuff(srcList, minionBuffs, auraName)
+ end
+@@ -3038,7 +3039,7 @@ function calcs.perform(env, skipEHP)
+ if env.minion and not env.minion.modDB.conditions["AffectedBy"..warcryNameCompressed] then
+ env.minion.modDB.conditions["AffectedByWarcry"] = true
+ env.minion.modDB.conditions["AffectedBy"..warcryNameCompressed] = true
+- local srcList = new("ModList")
++ local srcList = new("ModList"):ModList()
+ for _, warcryBuff in ipairs(warcry.modList) do
+ srcList:ScaleAddList({warcryBuff}, (warcry.effectMult or 100) / 100 * (warcryBuff[1].warcryPowerBonus or 1))
+ end
+@@ -3121,7 +3122,7 @@ function calcs.perform(env, skipEHP)
+ fromPlayer = (dest == curses),
+ priority = determineCursePriority(grantedEffect.name),
+ }
+- curse.modList = new("ModList")
++ curse.modList = new("ModList"):ModList()
+ curse.modList:ScaleAddList(curseModList, (1 + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") / 100) * enemyDB:More(nil, "CurseEffectOnSelf"))
+ t_insert(dest, curse)
+ end
+@@ -3329,7 +3330,7 @@ function calcs.perform(env, skipEHP)
+ if modDB:Flag(nil, "ManaIncreasedByOvercappedLightningRes") then
+ -- Calculate resistances for ManaIncreasedByOvercappedLightningRes without mutating conversion mods on the player ModDB.
+ local tempResistActor = {
+- modDB = new("ModDB", modDB),
++ modDB = new("ModDB"):ModDB(modDB),
+ output = output,
+ activeSkillList = env.player.activeSkillList,
+ enemy = env.player.enemy,
+@@ -3349,7 +3350,7 @@ function calcs.perform(env, skipEHP)
+ end
+
+ -- Check for extra auras
+- buffExports["Aura"]["extraAura"] = { effectMult = 1, modList = new("ModList") }
++ buffExports["Aura"]["extraAura"] = { effectMult = 1, modList = new("ModList"):ModList() }
+ for _, value in ipairs(modDB:List(nil, "ExtraAura")) do
+ local modList = { value.mod }
+ if not value.onlyAllies and not (value.fromAllies and modDB:Flag(nil, "AlliesAurasCannotAffectSelf")) then
diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua
index 5ba727778c..1023ec9dc0 100644
--- a/src/Modules/CalcSetup.lua
+++ b/src/Modules/CalcSetup.lua
@@ -3,7 +3,8 @@
-- Module: Calc Setup
-- Initialises the environment for calculations.
--
-local calcs = ...
+---@class Calcs
+local calcs = require("Modules.CalcBase")
local pairs = pairs
local ipairs = ipairs
@@ -225,7 +226,7 @@ function calcs.buildModListForNode(env, node, incSmallPassiveSkill, includeKeyst
-- Apply effect scaling
local scale = calcLib.mod(modList, nil, "PassiveSkillEffect")
if scale ~= 1 then
- local scaledList = new("ModList")
+ local scaledList = new("ModList"):ModList()
scaledList:ScaleAddList(modList, scale)
modList = scaledList
end
@@ -1227,7 +1228,7 @@ function calcs.initEnv(build, mode, override, specEnv)
local info = env.data.weaponTypeInfo[type]
if info and type ~= "Bow" then
local name = info.oneHand and "Energy Blade One Handed" or "Energy Blade Two Handed"
- local item = new("Item")
+ local item = new("Item"):Item()
item.name = name
item.base = data.itemBases[name]
item.baseName = name
@@ -1256,7 +1257,7 @@ function calcs.initEnv(build, mode, override, specEnv)
end
elseif slotName == "Weapon 1" and item.name == "The Iron Mass, Gladius" then
-- Special handling for The Iron Mass
- env.theIronMass = new("ModList")
+ env.theIronMass = new("ModList"):ModList()
for _, mod in ipairs(srcList) do
-- Filter out mods that apply to socketed gems, or which add supports
local add = true
@@ -1274,7 +1275,7 @@ function calcs.initEnv(build, mode, override, specEnv)
end
elseif slotName == "Weapon 1" and item.grantedSkills[1] and item.grantedSkills[1].skillId == "UniqueAnimateWeapon" then
-- Special handling for The Dancing Dervish
- env.weaponModList1 = new("ModList")
+ env.weaponModList1 = new("ModList"):ModList()
for _, mod in ipairs(srcList) do
-- Filter out mods that apply to socketed gems, or which add supports
local add = true
diff --git a/src/Modules/CalcSetup.lua.rej b/src/Modules/CalcSetup.lua.rej
new file mode 100644
index 0000000000..503daa66dd
--- /dev/null
+++ b/src/Modules/CalcSetup.lua.rej
@@ -0,0 +1,96 @@
+diff a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua (rejected hunks)
+@@ -114,7 +115,7 @@ function calcs.initModDB(env, modDB)
+ end
+
+ function calcs.buildModListForNode(env, node)
+- local modList = new("ModList")
++ local modList = new("ModList"):ModList()
+ if node.type == "Keystone" then
+ modList:AddMod(node.keystoneMod)
+ else
+@@ -178,7 +179,7 @@ function calcs.buildModListForNodeList(env, nodeList, finishJewels)
+ end
+
+ -- Add node modifiers
+- local modList = new("ModList")
++ local modList = new("ModList"):ModList()
+ local explodeSources = {}
+ for _, node in pairs(nodeList) do
+ local nodeModList, explode = calcs.buildModListForNode(env, node)
+@@ -400,11 +401,11 @@ function calcs.initEnv(build, mode, override, specEnv)
+ env.override = override
+ env.classId = env.spec.curClassId
+
+- modDB = new("ModDB")
++ modDB = new("ModDB"):ModDB()
+ env.modDB = modDB
+- enemyDB = new("ModDB")
++ enemyDB = new("ModDB"):ModDB()
+ env.enemyDB = enemyDB
+- env.itemModDB = new("ModDB")
++ env.itemModDB = new("ModDB"):ModDB()
+
+ env.enemyLevel = build.configTab.enemyLevel or m_min(data.misc.MaxEnemyLevel, build.characterLevel)
+
+@@ -997,7 +998,7 @@ function calcs.initEnv(build, mode, override, specEnv)
+ end
+ if item.type == "Shield" and env.allocNodes[45175] and env.allocNodes[45175].dn == "Necromantic Aegis" then
+ -- Special handling for Necromantic Aegis
+- env.aegisModList = new("ModList")
++ env.aegisModList = new("ModList"):ModList()
+ for _, mod in ipairs(srcList) do
+ -- Filter out mods that apply to socketed gems, or which add supports
+ local add = true
+@@ -1127,25 +1128,25 @@ function calcs.initEnv(build, mode, override, specEnv)
+ local widowHailMod= (1 + (items["Weapon 1"] and items["Weapon 1"].baseModList:Sum("INC", nil, "EffectOfBonusesFromQuiver") + env.initialNodeModDB:Sum("INC", nil, "EffectOfBonusesFromQuiver") or 100) / 100)
+ scale = scale * widowHailMod
+ env.modDB:NewMod("WidowHailMultiplier", "BASE", widowHailMod, "Widowhail")
+- local combinedList = new("ModList")
++ local combinedList = new("ModList"):ModList()
+ for _, mod in ipairs(srcList) do
+ combinedList:MergeMod(mod)
+ end
+ env.itemModDB:ScaleAddList(combinedList, scale)
+ elseif env.modDB.multipliers["Corrupted" .. item.rarity:gsub("(%a)(%u*)", function(a, b) return a..string.lower(b) end) .. "JewelEffect"] and item.type == "Jewel" and item.corrupted and slot.nodeId and item.base.subType ~= "Charm" and not env.spec.nodes[slot.nodeId].containJewelSocket then
+ scale = scale + env.modDB.multipliers["Corrupted" .. item.rarity:gsub("(%a)(%u*)", function(a, b) return a..string.lower(b) end) .. "JewelEffect"]
+- local combinedList = new("ModList")
++ local combinedList = new("ModList"):ModList()
+ for _, mod in ipairs(srcList) do
+ combinedList:MergeMod(mod)
+ end
+ env.itemModDB:ScaleAddList(combinedList, scale)
+ elseif item.type == "Gloves" and calcLib.mod(env.initialNodeModDB, nil, "EffectOfBonusesFromGloves") ~=1 then
+ scale = calcLib.mod(env.initialNodeModDB, nil, "EffectOfBonusesFromGloves") - 1
+- local combinedList = new("ModList")
++ local combinedList = new("ModList"):ModList()
+ for _, mod in ipairs(srcList) do
+ combinedList:MergeMod(mod)
+ end
+- local scaledList = new("ModList")
++ local scaledList = new("ModList"):ModList()
+ scaledList:ScaleAddList(combinedList, scale)
+ for _, mod in ipairs(scaledList) do
+ combinedList:MergeMod(mod, true)
+@@ -1153,11 +1154,11 @@ function calcs.initEnv(build, mode, override, specEnv)
+ env.itemModDB:AddList(combinedList)
+ elseif item.type == "Boots" and calcLib.mod(env.initialNodeModDB, nil, "EffectOfBonusesFromBoots") ~= 1 then
+ scale = calcLib.mod(env.initialNodeModDB, nil, "EffectOfBonusesFromBoots") - 1
+- local combinedList = new("ModList")
++ local combinedList = new("ModList"):ModList()
+ for _, mod in ipairs(srcList) do
+ combinedList:MergeMod(mod)
+ end
+- local scaledList = new("ModList")
++ local scaledList = new("ModList"):ModList()
+ scaledList:ScaleAddList(combinedList, scale)
+ for _, mod in ipairs(scaledList) do
+ combinedList:MergeMod(mod, true)
+@@ -1322,7 +1323,7 @@ function calcs.initEnv(build, mode, override, specEnv)
+ end
+ if not override or (override and not override.extraJewelFuncs) then
+ override = override or {}
+- override.extraJewelFuncs = new("ModList")
++ override.extraJewelFuncs = new("ModList"):ModList()
+ override.extraJewelFuncs.actor = env.player
+ for _, mod in ipairs(env.modDB:Tabulate("LIST", nil, "ExtraJewelFunc")) do
+ override.extraJewelFuncs:AddMod(mod.mod)
diff --git a/src/Modules/CalcTools.lua b/src/Modules/CalcTools.lua
index a44b7b6f33..93d0f4903e 100644
--- a/src/Modules/CalcTools.lua
+++ b/src/Modules/CalcTools.lua
@@ -208,7 +208,7 @@ end
--- Correct the tags on conversion with multipliers so they carry over correctly
--- @param mod table
--- @param multiplier number
---- @param minionMods bool @convert ActorConditions pointing at parent to normal Conditions
+--- @param minionMods boolean @convert ActorConditions pointing at parent to normal Conditions
--- @return table @converted multipliers
function calcLib.getConvertedModTags(mod, multiplier, minionMods)
local modifiers = { }
@@ -248,7 +248,7 @@ end
--- Use getGameIdFromGemName to get gameId from the gemName and passed in type. Return true if they're the same and not nil
--- @param gemName string
---- @param type string
+--- @param typeName string
--- @param dropVaal boolean
--- @return boolean
function calcLib.isGemIdSame(gemName, typeName, dropVaal)
diff --git a/src/Modules/CalcTriggers.lua b/src/Modules/CalcTriggers.lua
index 5dafee82a0..52dfac2e5c 100644
--- a/src/Modules/CalcTriggers.lua
+++ b/src/Modules/CalcTriggers.lua
@@ -4,8 +4,9 @@
-- Performs trigger rate calculations
--
-local calcs = ...
-local pairs = pairs
+---@class Calcs
+local calcs = require("Modules.CalcBase")
+
local ipairs = ipairs
local t_insert = table.insert
local t_remove = table.remove
diff --git a/src/Modules/Calcs.lua b/src/Modules/Calcs.lua
index f8cf2e8278..b2a4a0c791 100644
--- a/src/Modules/Calcs.lua
+++ b/src/Modules/Calcs.lua
@@ -10,15 +10,16 @@ local s_format = string.format
local m_min = math.min
local m_ceil = math.ceil
-local calcs = { }
+---@class Calcs
+local calcs = require("Modules.CalcBase")
calcs.breakdownModule = "Modules/CalcBreakdown"
-LoadModule("Modules/CalcSetup", calcs)
-LoadModule("Modules/CalcPerform", calcs)
-LoadModule("Modules/CalcActiveSkill", calcs)
-LoadModule("Modules/CalcDefence", calcs)
-LoadModule("Modules/CalcOffence", calcs)
-LoadModule("Modules/CalcTriggers", calcs)
-LoadModule("Modules/CalcMirages.lua", calcs)
+require("Modules.CalcSetup")
+require("Modules.CalcPerform")
+require("Modules.CalcActiveSkill")
+require("Modules.CalcDefence")
+require("Modules.CalcOffence")
+require("Modules.CalcTriggers")
+require("Modules.CalcMirages")
-- Get the average value of a table -- note this is unused
function math.average(t)
diff --git a/src/Modules/Common.lua b/src/Modules/Common.lua
index 6fd1ec57a9..45b39ce78c 100644
--- a/src/Modules/Common.lua
+++ b/src/Modules/Common.lua
@@ -1,3 +1,4 @@
+---@diagnostic disable: lowercase-global
-- Path of Building
--
-- Module: Common
@@ -68,13 +69,17 @@ end
local function getClass(className)
local class = common.classes[className]
if not class then
- LoadModule("Classes/"..className)
+ LoadModule("Classes/" .. className)
class = common.classes[className]
- assert(class, "Class '"..className.."' not defined in class file")
+ assert(class, "Class '" .. className .. "' not defined in class file")
end
return class
end
--- newClass(""[, ""[, "" ...]], constructorFunc)
+
+---@generic T
+---@param className `T`
+---@param ... string parent class names
+---@return T
function newClass(className, ...)
local class = { }
common.classes[className] = class
@@ -87,11 +92,10 @@ function newClass(className, ...)
end
class._className = className
local numVarArg = select("#", ...)
- class._constructor = select(numVarArg, ...)
- if numVarArg > 1 then
+ if numVarArg > 0 then
-- Build list of parent classes
class._parents = { }
- for i = 1, numVarArg - 1 do
+ for i = 1, numVarArg do
class._parents[i] = getClass(select(i, ...))
end
-- Build list of all classes directly or indirectly inherited by this class
@@ -112,9 +116,39 @@ function newClass(className, ...)
end
return class
end
-function new(className, ...)
+
+---@generic T
+---@param className `T`
+---@param extraArg nil Never pass extra parameters. Defined purely to guard against old syntax.
+---@return T
+function new(className, extraArg)
+ if extraArg then
+ local line = s_format(
+ "Extra argument passed to new() during creation of class %s. Extra arguments are not allowed.\nAre you perhaps trying to pass constructor arguments here?",
+ className)
+ error(line)
+ end
local class = getClass(className)
- local object = setmetatable({ }, class)
+ -- protect against calling new("Foo") without calling :Foo()
+ local object
+ if class[className] then
+ if not rawget(class, "_unconstructedMeta") then
+ class._unconstructedMeta = {
+ __index = function(obj, key)
+ if key == className then
+ setmetatable(obj, class)
+ return class[className]
+ end
+ error(s_format(
+ "Object of class '%s' was used before it was constructed (accessed '%s'). Did you forget to call new(\"%s\"):%s()?",
+ className, tostring(key), className, className))
+ end,
+ }
+ end
+ object = setmetatable({}, class._unconstructedMeta)
+ else
+ object = setmetatable({}, class)
+ end
object.Object = object
if class._parents then
-- Add parent and superparent class proxies
@@ -130,30 +164,43 @@ function new(className, ...)
end
end,
__newindex = object,
- __call = function(...)
- if not parent._constructor then
+ __call = function(_, self, ...)
+ if not parent[parent._className] then
error("Parent class '"..parent._className.."' of class '"..class._className.."' has no constructor")
end
if object._parentInit[parent] then
error("Parent class '"..parent._className.."' of class '"..class._className.."' has already been initialised")
end
- parent._constructor(...)
+ if self ~= object then
+ error(string.format("Parent class %s constructor of class %s was not provided self. Are you perhaps calling it with self.%s instead of self:%s?", parent._className, className, parent._className, parent._className))
+ end
+ parent[parent._className](self, ...)
object._parentInit[parent] = true
end,
}
object[parent._className] = setmetatable(proxyMeta, proxyMeta)
end
end
- if class._constructor then
- class._constructor(object, ...)
- end
- if class._parents then
- -- Check that the constructors for all parent and superparent classes have been called
- for parent in pairs(class._superParents) do
- if parent._constructor and not object._parentInit[parent] then
- error("Parent class '"..parent._className.."' of class '"..className.."' must be initialised")
+
+ if class[className] and not rawget(class, "_constructorInitialised") then
+ local originalFunc = class[className]
+ class[className] = function(self, ...)
+ local ret = originalFunc(self, ...)
+ if class._parents then
+ -- Check that the constructors for all parent and superparent classes have been called
+ for parent in pairs(class._superParents) do
+ if parent[parent._className] and not self._parentInit[parent] then
+ error("Parent class '" ..
+ parent._className .. "' of class '" .. className .. "' must be initialised")
+ end
+ end
+ end
+ if not ret then
+ error(string.format("Class %s constructor did not return a value", className))
end
+ return ret
end
+ class._constructorInitialised = true
end
return object
end
@@ -418,6 +465,10 @@ function writeLuaTable(out, t, indent)
end
-- Make a copy of a table and all subtables
+---@generic T
+---@param tbl T
+---@param noRecurse boolean?
+---@return T copy Note that this type can be misleading if noRecurse is set to true. Type hint explicitly if necessary.
function copyTable(tbl, noRecurse)
local out = {}
for k, v in pairs(tbl) do
@@ -466,11 +517,11 @@ function mergeDB(srcDB, modDB)
end
function specCopy(env)
- local modDB = new("ModDB")
+ local modDB = new("ModDB"):ModDB()
modDB:AddDB(env.modDB)
modDB.conditions = copyTable(env.modDB.conditions)
modDB.multipliers = copyTable(env.modDB.multipliers)
- local enemyDB = new("ModDB")
+ local enemyDB = new("ModDB"):ModDB()
if env.enemyDB then
enemyDB:AddDB(env.enemyDB)
enemyDB.conditions = copyTable(env.enemyDB.conditions)
@@ -478,7 +529,7 @@ function specCopy(env)
end
local minionDB = nil
if env.minion then
- minionDB = new("ModDB")
+ minionDB = new("ModDB"):ModDB()
minionDB:AddDB(env.minion.modDB)
minionDB.conditions = copyTable(env.minion.modDB.conditions)
minionDB.multipliers = copyTable(env.minion.modDB.multipliers)
diff --git a/src/Modules/ConfigOptions.lua.rej b/src/Modules/ConfigOptions.lua.rej
new file mode 100644
index 0000000000..200443bd8d
--- /dev/null
+++ b/src/Modules/ConfigOptions.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua (rejected hunks)
+@@ -119,7 +119,7 @@ local function mapAffixDropDownFunction(val, modList, enemyModList, build)
+ local affixData = data.mapMods.AffixData[val] or {}
+ if affixData.apply then
+ if affixData.type == "check" then
+- affixData.apply(var, (1 + (build.configTab.input['multiplierMapModEffect'] or 0)/100), modList, enemyModList)
++ affixData.apply(val, (1 + (build.configTab.input['multiplierMapModEffect'] or 0) / 100), modList, enemyModList)
+ elseif affixData.type == "list" then
+ affixData.apply(4 - (build.configTab.varControls['multiplierMapModTier'].selIndex or 1), (1 + (build.configTab.input['multiplierMapModEffect'] or 0)/100), affixData.values, modList, enemyModList)
+ elseif affixData.type == "count" then
diff --git a/src/Modules/Data.lua b/src/Modules/Data.lua
index 56d22b13aa..51627672ee 100644
--- a/src/Modules/Data.lua
+++ b/src/Modules/Data.lua
@@ -863,8 +863,9 @@ do
UberEvasionMean = 100 + uberEvasionTotal / uberCount
}
- data.bossSkills, data.bossSkillsList = LoadModule("Data/BossSkills")
-
+ local bossSkillData = LoadModule("Data/BossSkills")
+ data.bossSkills = bossSkillData.bossSkills
+ data.bossSkillsList = bossSkillData.bossSkillsList
data.enemyIsBossTooltip = [[Bosses' damage is monster damage scaled to an average damage of their attacks
This is divided by 4.40 to represent 4 damage types + some (40% as much) ^xD02090chaos
^7Fill in the exact damage numbers if more precision is needed
@@ -896,7 +897,7 @@ end
-- Load skills
data.skills = { }
-data.skillStatMap = LoadModule("Data/SkillStatMap", makeSkillMod, makeFlagMod, makeSkillDataMod)
+data.skillStatMap = LoadModule("Data/SkillStatMap")(makeSkillMod, makeFlagMod, makeSkillDataMod)
data.skillStatMapMeta = {
__index = function(t, key)
local map = data.skillStatMap[key]
@@ -911,7 +912,7 @@ data.skillStatMapMeta = {
end
}
for _, type in pairs(skillTypes) do
- LoadModule("Data/Skills/"..type, data.skills, makeSkillMod, makeFlagMod, makeSkillDataMod)
+ LoadModule("Data/Skills/" .. type)(data.skills, makeSkillMod, makeFlagMod, makeSkillDataMod)
end
for skillId, grantedEffect in pairs(data.skills) do
grantedEffect.name = sanitiseText(grantedEffect.name)
@@ -1056,10 +1057,8 @@ for id, gem in pairs(toAddGems) do
end
-- Load minions
-data.minions = { }
-LoadModule("Data/Minions", data.minions, makeSkillMod, makeFlagMod)
-data.spectres = { }
-LoadModule("Data/Spectres", data.spectres, makeSkillMod, makeFlagMod)
+data.minions = LoadModule("Data/Minions")(makeSkillMod, makeFlagMod)
+data.spectres = LoadModule("Data/Spectres")(makeSkillMod, makeFlagMod)
for name, spectre in pairs(data.spectres) do
spectre.limit = "ActiveSpectreLimit"
data.minions[name] = spectre
diff --git a/src/Modules/Data.lua.rej b/src/Modules/Data.lua.rej
new file mode 100644
index 0000000000..971145f313
--- /dev/null
+++ b/src/Modules/Data.lua.rej
@@ -0,0 +1,63 @@
+diff a/src/Modules/Data.lua b/src/Modules/Data.lua (rejected hunks)
+@@ -103,10 +103,16 @@ end
+ -- Remaining Item Data and uniques
+ ----------------------------------------
+
++---@diagnostic disable-next-line: lowercase-global
++---@class Data : MiscDataExport
++---@field bosses BossData
+ data = { }
+
+ -- Misc data tables
+-LoadModule("Data/Misc", data)
++local miscData = LoadModule("Data/Misc")
++for k, v in pairs(miscData) do
++ data[k] = v
++end
+
+ ---@alias TransformFunc fun(in: number|string): (number|string)?
+ ---@class StatTable
+@@ -636,9 +642,6 @@ data.enchantmentSource = {
+ { name = "NORMAL", label = "Normal Labyrinth" },
+ }
+
+--- Misc data tables
+-LoadModule("Data/Misc", data)
+-
+ -- Stat descriptions
+ data.describeStats = LoadModule("Modules/StatDescriber")
+
+@@ -928,7 +931,9 @@ data.timelessJewelAdditions = 337 -- #legionAdditions
+ data.nodeIDList = LoadModule("Data/TimelessJewelData/NodeIndexMapping")
+ data.abyssNotableNames = LoadModule("Data/TimelessJewelData/AbyssNotableNames")
+ data.timelessJewelLUTs = { }
+-data.readLUT, data.repairLUTs = LoadModule("Modules/DataLegionLookUpTableHelper")
++local helperMod = LoadModule("Modules/DataLegionLookUpTableHelper")
++data.readLUT = helperMod.readLUT
++data.repairLUTs = helperMod.repairLUTs
+ data.readAbyssJewelLUT, data.resolveAbyssJewelComponent, data.getAbyssJewelComponentRoll = LoadModule("Modules/DataAbyssJewelLookUpTableHelper")
+
+ -- this runs if the "size" key is missing from nodeIDList and attempts to rebuild all jewel LUTs and the nodeIDList
+@@ -938,10 +943,9 @@ if not data.nodeIDList.size and launch.devMode then
+ end
+
+ -- Load bosses
+-do
+- data.bosses = { }
+- LoadModule("Data/Bosses", data.bosses)
+-
++do
++ ---@class BossData
++ data.bosses = LoadModule("Data/Bosses")
+ local count, uberCount = 0, 0
+ local armourTotal, evasionTotal = 0, 0
+ local uberArmourTotal, uberEvasionTotal = 0, 0
+@@ -1211,7 +1214,7 @@ end
+ ---@type table
+ data.itemBases = { }
+ for _, type in pairs(itemTypes) do
+- LoadModule("Data/Bases/"..type, data.itemBases)
++ LoadModule("Data/Bases/" .. type)(data.itemBases)
+ end
+
+ ---@class ItemBaseEntry
diff --git a/src/Modules/DataLegionLookUpTableHelper.lua b/src/Modules/DataLegionLookUpTableHelper.lua
index cf9cf29a63..2f346810a0 100644
--- a/src/Modules/DataLegionLookUpTableHelper.lua
+++ b/src/Modules/DataLegionLookUpTableHelper.lua
@@ -313,4 +313,4 @@ local function readLUT(seed, nodeID, jewelType)
return { }
end
-return readLUT, repairLUTs
\ No newline at end of file
+return { readLUT = readLUT, repairLUTs = repairLUTs }
diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua
index 98d4a786c0..90eefc2f7b 100644
--- a/src/Modules/Main.lua
+++ b/src/Modules/Main.lua
@@ -47,7 +47,10 @@ end
local tempTable1 = { }
local tempTable2 = { }
-main = new("ControlHost")
+---@diagnostic disable-next-line: lowercase-global
+---@class Main : ControlHost
+---@field allowTreeDownload? boolean
+main = new("ControlHost"):ControlHost()
function main:Init()
self:DetectUnicodeSupport()
@@ -126,7 +129,9 @@ function main:Init()
self.saveNewModCache = true
else
-- Load mod cache
- LoadModule("Data/ModCache", modLib.parseModCache)
+ for k, v in pairs(LoadModule("Data/ModCache")) do
+ modLib.parseModCache[k] = v
+ end
end
--[[ this does not work properly anymore see PR #7675
@@ -138,6 +143,7 @@ function main:Init()
self.inputEvents = { }
self.tooltipLines = { }
+ ---@type table
self.tree = { }
self:LoadTree(latestTreeVersion)
@@ -195,23 +201,23 @@ function main:Init()
self.defaultItemAffixQuality = saved
end
- self.anchorMain = new("Control", nil, {4, 0, 0, 0})
+ self.anchorMain = new("Control"):Control(nil, {4, 0, 0, 0})
self.anchorMain.y = function()
return self.screenH - 4
end
- self.controls.options = new("ButtonControl", {"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {0, 0, 68, 20}, "Options", function()
+ self.controls.options = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {0, 0, 68, 20}, "Options", function()
self:OpenOptionsPopup()
end)
- self.controls.about = new("ButtonControl", {"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {72, 0, 68, 20}, "About", function()
+ self.controls.about = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {72, 0, 68, 20}, "About", function()
self:OpenAboutPopup()
end)
- self.controls.applyUpdate = new("ButtonControl", {"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {0, -24, 140, 20}, "^x50E050Update Ready", function()
+ self.controls.applyUpdate = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {0, -24, 140, 20}, "^x50E050Update Ready", function()
self:OpenUpdatePopup()
end)
self.controls.applyUpdate.shown = function()
return launch.updateAvailable and launch.updateAvailable ~= "none"
end
- self.controls.checkUpdate = new("ButtonControl", {"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {0, -24, 140, 20}, "", function()
+ self.controls.checkUpdate = new("ButtonControl"):ButtonControl({"BOTTOMLEFT",self.anchorMain,"BOTTOMLEFT"}, {0, -24, 140, 20}, "", function()
launch:CheckForUpdate()
end)
self.controls.checkUpdate.shown = function()
@@ -294,7 +300,7 @@ end
function main:SaveModCache()
-- Update mod cache
local out = io.open("Data/ModCache.lua", "w")
- out:write('local c=...')
+ out:write('local c = {}\n')
for line, dat in pairsSortByKey(modLib.parseModCache) do
if not dat[1] or not dat[1][1] or (dat[1][1].name ~= "JewelFunc" and dat[1][1].name ~= "ExtraJewelFunc") then
out:write('c["', line:gsub("\n","\\n"), '"]={')
@@ -310,9 +316,12 @@ function main:SaveModCache()
end
end
end
+ out:write('return c\n')
out:close()
end
+---@param treeVersion string
+---@return PassiveTree?
function main:LoadTree(treeVersion)
if self.tree[treeVersion] then
data.setJewelRadiiGlobally(treeVersion)
@@ -320,7 +329,7 @@ function main:LoadTree(treeVersion)
elseif isValueInTable(treeVersionList, treeVersion) then
data.setJewelRadiiGlobally(treeVersion)
--ConPrintf("[main:LoadTree] - Lazy Loading Tree " .. treeVersion)
- self.tree[treeVersion] = new("PassiveTree", treeVersion)
+ self.tree[treeVersion] = new("PassiveTree"):PassiveTree(treeVersion)
return self.tree[treeVersion]
end
return nil
@@ -706,7 +715,7 @@ function main:LoadSharedItems()
rawItem.raw = subChild
end
end
- local newItem = new("Item", rawItem.raw)
+ local newItem = new("Item"):Item(rawItem.raw)
t_insert(self.sharedItemList, newItem)
elseif child.elem == "ItemSet" then
local sharedItemSet = { title = child.attrib.title, slots = { } }
@@ -718,7 +727,7 @@ function main:LoadSharedItems()
rawItem.raw = subChild
end
end
- local newItem = new("Item", rawItem.raw)
+ local newItem = new("Item"):Item(rawItem.raw)
sharedItemSet.slots[grandChild.attrib.slotName] = newItem
end
end
@@ -815,14 +824,14 @@ function main:OpenPathPopup(invalidPath, errMsg, ignoreBuild)
local controls = { }
local defaultLabelPlacementX = 8
- controls.label = new("LabelControl", { "TOPLEFT", nil, "TOPLEFT" }, { defaultLabelPlacementX, 20, 206, 16 }, function()
+ controls.label = new("LabelControl"):LabelControl({ "TOPLEFT", nil, "TOPLEFT" }, { defaultLabelPlacementX, 20, 206, 16 }, function()
return "^7User settings path cannot be loaded: ".. errMsg ..
"\nCurrent Path: "..invalidPath:gsub("?", "^1?^7").."/Path of Building/"..
"\nIf this location is managed by OneDrive, navigate to that folder and manually try" ..
"\nto open Settings.xml in a text editor before re-opening Path of Building" ..
"\nOtherwise, specify a new location for your Settings.xml:"
end)
- controls.userPath = new("EditControl", { "TOPLEFT", controls.label, "TOPLEFT" }, { 0, 60, 206, 20 }, invalidPath, nil, nil, nil, function(buf)
+ controls.userPath = new("EditControl"):EditControl({ "TOPLEFT", controls.label, "TOPLEFT" }, { 0, 60, 206, 20 }, invalidPath, nil, nil, nil, function(buf)
invalidPath = sanitiseText(buf)
if not invalidPath:match("?") then
controls.save.enabled = true
@@ -830,7 +839,7 @@ function main:OpenPathPopup(invalidPath, errMsg, ignoreBuild)
controls.save.enabled = false
end
end)
- controls.save = new("ButtonControl", { "TOPLEFT", controls.userPath, "TOPLEFT" }, { 0, 26, 206, 20 }, "Save", function()
+ controls.save = new("ButtonControl"):ButtonControl({ "TOPLEFT", controls.userPath, "TOPLEFT" }, { 0, 26, 206, 20 }, "Save", function()
local res, msg = MakeDir(controls.userPath.buf)
if not res and msg ~= "No error" then
self:OpenMessagePopup("Error", "Couldn't create '"..controls.userPath.buf.."' : "..msg)
@@ -840,7 +849,7 @@ function main:OpenPathPopup(invalidPath, errMsg, ignoreBuild)
end
end)
controls.save.enabled = false
- controls.cancel = new("ButtonControl", nil, { 0, 0, 0, 0 }, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, { 0, 0, 0, 0 }, "Cancel", function()
-- Do nothing, require user to enter a location
end)
self:OpenPopup(600, 150, "Change Settings Path", controls, "save", nil, "cancel")
@@ -906,7 +915,7 @@ function main:OpenOptionsPopup(savedState)
local popupWidth = useTwoColumns and columnWidth * 2 or columnWidth
-- Scrollbar anchor
- controls.sectionAnchor = new("Control", { "TOPLEFT", nil, "TOPLEFT" }, { 0, 0, popupWidth, 0 })
+ controls.sectionAnchor = new("Control"):Control({ "TOPLEFT", nil, "TOPLEFT" }, { 0, 0, popupWidth, 0 })
-- local func to make a new line with a heightModifier
local function nextRow(heightModifier)
@@ -918,9 +927,9 @@ function main:OpenOptionsPopup(savedState)
-- local func to make a new section header
local function drawSectionHeader(id, title, omitHorizontalLine)
local headerBGColor ={ .6, .6, .6}
- controls["section-"..id .. "-bg"] = new("RectangleOutlineControl", { "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + scrollBarWidth + 8, currentY, columnWidth - (scrollBarWidth * 2) - 17, 26 }, headerBGColor, 1)
+ controls["section-"..id .. "-bg"] = new("RectangleOutlineControl"):RectangleOutlineControl({ "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + scrollBarWidth + 8, currentY, columnWidth - (scrollBarWidth * 2) - 17, 26 }, headerBGColor, 1)
nextRow(.2)
- controls["section-"..id .. "-label"] = new("LabelControl", { "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + columnWidth / 2 - 60, currentY, 0, 16 }, "^7" .. title)
+ controls["section-"..id .. "-label"] = new("LabelControl"):LabelControl({ "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + columnWidth / 2 - 60, currentY, 0, 16 }, "^7" .. title)
nextRow(1.5)
end
@@ -929,25 +938,25 @@ function main:OpenOptionsPopup(savedState)
drawSectionHeader("app", "Application options")
- controls.connectionProtocol = new("DropDownControl", { "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 100, 18 }, {
+ controls.connectionProtocol = new("DropDownControl"):DropDownControl({ "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 100, 18 }, {
{ label = "Auto", protocol = 0 },
{ label = "IPv4", protocol = 1 },
{ label = "IPv6", protocol = 2 },
}, function(index, value)
self.connectionProtocol = value.protocol
end)
- controls.connectionProtocolLabel = new("LabelControl", { "RIGHT", controls.connectionProtocol, "LEFT" }, { defaultLabelSpacingPx, 0, 0, 16 }, "^7Connection Protocol:")
+ controls.connectionProtocolLabel = new("LabelControl"):LabelControl({ "RIGHT", controls.connectionProtocol, "LEFT" }, { defaultLabelSpacingPx, 0, 0, 16 }, "^7Connection Protocol:")
controls.connectionProtocol.tooltipText = "Changes which protocol is used when downloading updates and importing builds."
controls.connectionProtocol:SelByValue(launch.connectionProtocol, "protocol")
nextRow()
- controls.proxyType = new("DropDownControl", { "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 80, 18 }, {
+ controls.proxyType = new("DropDownControl"):DropDownControl({ "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 80, 18 }, {
{ label = "HTTP", scheme = "http" },
{ label = "SOCKS", scheme = "socks5" },
{ label = "SOCKS5H", scheme = "socks5h" },
})
- controls.proxyLabel = new("LabelControl", { "RIGHT", controls.proxyType, "LEFT" }, { defaultLabelSpacingPx, 0, 0, 16 }, "^7Proxy server:")
- controls.proxyURL = new("EditControl", { "LEFT", controls.proxyType, "RIGHT" }, { 4, 0, 206, 18 })
+ controls.proxyLabel = new("LabelControl"):LabelControl({ "RIGHT", controls.proxyType, "LEFT" }, { defaultLabelSpacingPx, 0, 0, 16 }, "^7Proxy server:")
+ controls.proxyURL = new("EditControl"):EditControl({ "LEFT", controls.proxyType, "RIGHT" }, { 4, 0, 206, 18 })
if launch.proxyURL then
local scheme, url = launch.proxyURL:match("(%w+)://(.+)")
@@ -956,7 +965,7 @@ function main:OpenOptionsPopup(savedState)
end
nextRow()
- controls.dpiScaleOverride = new("DropDownControl", { "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 150, 18 }, {
+ controls.dpiScaleOverride = new("DropDownControl"):DropDownControl({ "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 150, 18 }, {
{ label = "Use system default", percent = 0 },
{ label = "100%", percent = 100 },
{ label = "125%", percent = 125 },
@@ -1167,7 +1176,7 @@ function main:OpenOptionsPopup(savedState)
if launch.devMode then
nextRow()
- controls.disableDevAutoSave = new("CheckBoxControl", { "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 20 }, "^7Disable Dev AutoSave:", function(state)
+ controls.disableDevAutoSave = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 20 }, "^7Disable Dev AutoSave:", function(state)
self.disableDevAutoSave = state
end)
controls.disableDevAutoSave.tooltipText = "Do not Autosave builds while on Dev branch"
@@ -1190,7 +1199,7 @@ function main:OpenOptionsPopup(savedState)
nextRow(1.5)
-- lock the Save/Cancel buttons to the bottom so they don't scroll away
- controls.save = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, {-45, -10, 80, 20}, "Save", function()
+ controls.save = new("ButtonControl"):ButtonControl({ "BOTTOM", nil, "BOTTOM" }, {-45, -10, 80, 20}, "Save", function()
launch.connectionProtocol = tonumber(self.connectionProtocol)
if controls.proxyURL.buf:match("%w") then
launch.proxyURL = controls.proxyType.list[controls.proxyType.selIndex].scheme .. "://" .. controls.proxyURL.buf
@@ -1215,7 +1224,7 @@ function main:OpenOptionsPopup(savedState)
main:ClosePopup()
main:SaveSettings()
end)
- controls.cancel = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, {45, -10, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl({ "BOTTOM", nil, "BOTTOM" }, {45, -10, 80, 20}, "Cancel", function()
self.nodePowerTheme = savedState.nodePowerTheme
self.colorPositive = savedState.colorPositive
updateColorCode("POSITIVE", self.colorPositive)
@@ -1252,7 +1261,7 @@ function main:OpenOptionsPopup(savedState)
local popupHeight = useScrollBar and (self.screenH - 20) or currentY + 30
if useScrollBar then
- controls.scrollBar = new("ScrollBarControl", {"TOPRIGHT", nil, "TOPRIGHT"}, {-2, 25, scrollBarWidth, popupHeight - 65}, 50, "VERTICAL", true)
+ controls.scrollBar = new("ScrollBarControl"):ScrollBarControl({"TOPRIGHT", nil, "TOPRIGHT"}, {-2, 25, scrollBarWidth, popupHeight - 65}, 50, "VERTICAL", true)
controls.scrollBar:SetContentDimension(currentY, popupHeight - 65)
end
@@ -1346,15 +1355,15 @@ function main:OpenUpdatePopup()
end
end
local controls = { }
- controls.changeLog = new("TextListControl", nil, {0, 20, 780, 542}, nil, changeList)
- controls.update = new("ButtonControl", nil, {-45, 570, 80, 20}, "Update", function()
+ controls.changeLog = new("TextListControl"):TextListControl(nil, {0, 20, 780, 542}, nil, changeList)
+ controls.update = new("ButtonControl"):ButtonControl(nil, {-45, 570, 80, 20}, "Update", function()
self:ClosePopup()
local ret = self:CallMode("CanExit", "UPDATE")
if ret == nil or ret == true then
launch:ApplyUpdate(launch.updateAvailable)
end
end)
- controls.cancel = new("ButtonControl", nil, {45, 570, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 570, 80, 20}, "Cancel", function()
self:ClosePopup()
end)
self:OpenPopup(800, 600, "Update Available", controls)
@@ -1648,7 +1657,7 @@ function main:CopyFolder(srcName, dstName)
end
function main:OpenPopup(width, height, title, controls, enterControl, defaultControl, escapeControl, scrollBarFunc, resizeFunc)
- local popup = new("PopupDialog", width, height, title, controls, enterControl, defaultControl, escapeControl, scrollBarFunc, resizeFunc)
+ local popup = new("PopupDialog"):PopupDialog(width, height, title, controls, enterControl, defaultControl, escapeControl, scrollBarFunc, resizeFunc)
t_insert(self.popups, 1, popup)
return popup
end
@@ -1661,10 +1670,10 @@ function main:OpenMessagePopup(title, msg)
local controls = { }
local numMsgLines = 0
for line in string.gmatch(msg .. "\n", "([^\n]*)\n") do
- t_insert(controls, new("LabelControl", nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
+ t_insert(controls, new("LabelControl"):LabelControl(nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
numMsgLines = numMsgLines + 1
end
- controls.close = new("ButtonControl", nil, {0, 40 + numMsgLines * 16, 80, 20}, "Ok", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, {0, 40 + numMsgLines * 16, 80, 20}, "Ok", function()
main:ClosePopup()
end)
return self:OpenPopup(m_max(DrawStringWidth(16, "VAR", msg) + 30, 190), 70 + numMsgLines * 16, title, controls, "close")
@@ -1674,7 +1683,7 @@ function main:OpenConfirmPopup(title, msg, confirmLabel, onConfirm, extraLabel,
local controls = { }
local numMsgLines = 0
for line in string.gmatch(msg .. "\n", "([^\n]*)\n") do
- t_insert(controls, new("LabelControl", nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
+ t_insert(controls, new("LabelControl"):LabelControl(nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
numMsgLines = numMsgLines + 1
end
local confirmWidth = m_max(80, DrawStringWidth(16, "VAR", confirmLabel) + 10)
@@ -1689,7 +1698,7 @@ function main:OpenConfirmPopup(title, msg, confirmLabel, onConfirm, extraLabel,
local buttonY = 40 + numMsgLines * 16
local function placeButton(width, label, onClick, isConfirm)
local centerX = leftEdge + width / 2
- local ctrl = new("ButtonControl", nil, {centerX, buttonY, width, 20}, label, function()
+ local ctrl = new("ButtonControl"):ButtonControl(nil, {centerX, buttonY, width, 20}, label, function()
main:ClosePopup()
onClick()
end)
@@ -1706,11 +1715,11 @@ function main:OpenConfirmPopup(title, msg, confirmLabel, onConfirm, extraLabel,
return self:OpenPopup(m_max(DrawStringWidth(16, "VAR", msg) + 30, totalWidth + 40), 70 + numMsgLines * 16, title, controls, "confirm")
else
-- Two button layout (original)
- controls.confirm = new("ButtonControl", nil, {-5 - m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, confirmLabel, function()
+ controls.confirm = new("ButtonControl"):ButtonControl(nil, {-5 - m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, confirmLabel, function()
main:ClosePopup()
onConfirm()
end)
- t_insert(controls, new("ButtonControl", nil, {5 + m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, "Cancel", function()
+ t_insert(controls, new("ButtonControl"):ButtonControl(nil, {5 + m_ceil(confirmWidth/2), 40 + numMsgLines * 16, confirmWidth, 20}, "Cancel", function()
main:ClosePopup()
end))
return self:OpenPopup(m_max(DrawStringWidth(16, "VAR", msg) + 30, 190), 70 + numMsgLines * 16, title, controls, "confirm")
@@ -1719,11 +1728,11 @@ end
function main:OpenNewFolderPopup(path, onClose)
local controls = { }
- controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter folder name:")
- controls.edit = new("EditControl", nil, {0, 40, 350, 20}, nil, nil, "\\/:%*%?\"<>|%c", 100, function(buf)
+ controls.label = new("LabelControl"):LabelControl(nil, {0, 20, 0, 16}, "^7Enter folder name:")
+ controls.edit = new("EditControl"):EditControl(nil, {0, 40, 350, 20}, nil, nil, "\\/:%*%?\"<>|%c", 100, function(buf)
controls.create.enabled = buf:match("%S")
end)
- controls.create = new("ButtonControl", nil, {-45, 70, 80, 20}, "Create", function()
+ controls.create = new("ButtonControl"):ButtonControl(nil, {-45, 70, 80, 20}, "Create", function()
local newFolderName = controls.edit.buf
local res, msg = MakeDir(path..newFolderName)
if not res then
@@ -1736,7 +1745,7 @@ function main:OpenNewFolderPopup(path, onClose)
main:ClosePopup()
end)
controls.create.enabled = false
- controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function()
+ controls.cancel = new("ButtonControl"):ButtonControl(nil, {45, 70, 80, 20}, "Cancel", function()
if onClose then
onClose()
end
@@ -1761,14 +1770,14 @@ function main:OpenCloudErrorPopup(fileName)
local controls = { }
local numMsgLines = 0
for line in string.gmatch(msg .. "\n", "([^\n]*)\n") do
- t_insert(controls, new("LabelControl", nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
+ t_insert(controls, new("LabelControl"):LabelControl(nil, {0, 20 + numMsgLines * 16, 0, 16}, line))
numMsgLines = numMsgLines + 1
end
- controls.help = new("ButtonControl", nil, {-55, 40 + numMsgLines * 16, 80, 20}, "Help (web)", function()
+ controls.help = new("ButtonControl"):ButtonControl(nil, {-55, 40 + numMsgLines * 16, 80, 20}, "Help (web)", function()
OpenURL(url)
end)
controls.help.tooltipText = url
- controls.close = new("ButtonControl", nil, {55, 40 + numMsgLines * 16, 80, 20}, "Ok", function()
+ controls.close = new("ButtonControl"):ButtonControl(nil, {55, 40 + numMsgLines * 16, 80, 20}, "Ok", function()
main:ClosePopup()
end)
return self:OpenPopup(m_max(DrawStringWidth(16, "VAR", msg) + 30, 190), 70 + numMsgLines * 16, title, controls, "close")
diff --git a/src/Modules/Main.lua.rej b/src/Modules/Main.lua.rej
new file mode 100644
index 0000000000..72feb93f08
--- /dev/null
+++ b/src/Modules/Main.lua.rej
@@ -0,0 +1,9 @@
+diff a/src/Modules/Main.lua b/src/Modules/Main.lua (rejected hunks)
+@@ -1067,7 +1067,6 @@ function main:OpenOptionsPopup(savedState)
+ end)
+ controls.showThousandsSeparators.state = self.showThousandsSeparators
+
+- nextRow()
+ nextRow()
+ controls.useCompactValues = new("CheckBoxControl"):CheckBoxControl({ "TOPLEFT", controls.sectionAnchor, "TOPLEFT" }, { currentX + defaultLabelPlacementX, currentY, 20 }, "^7Compact large numbers (e.g. 12.3K):", function(state)
+ self.useCompactValues = state
diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua
index 52fa3b4316..98c7b13406 100644
--- a/src/Modules/ModParser.lua
+++ b/src/Modules/ModParser.lua
@@ -2254,6 +2254,7 @@ local explodeFunc = function(chance, amount, type, ...)
end
-- List of special modifiers
+---@type table
local specialModList = {
-- Explode mods
["enemies you kill have a (%d+)%% chance to explode, dealing a (.+) of their maximum life as (.+) damage"] = function(chance, _, amount, type) -- Obliteration, Unspeakable Gifts (chaos cluster), synth implicit mod, current crusader body mod, Ngamahu Warmonger tattoo
@@ -6491,6 +6492,11 @@ end
-- Scan a line for the earliest and longest match from the pattern list
-- If a match is found, returns the corresponding value from the pattern list, plus the remainder of the line and a table of captures
+---@generic T
+---@param line string
+---@param patternList table
+---@param plain? boolean
+---@return T?, string, string[]?
local function scan(line, patternList, plain)
local bestIndex, bestEndIndex
local bestPattern = ""
@@ -6634,6 +6640,7 @@ local function parseMod(line, order)
modFlag, line = scan(line, modFlagList, true)
-- Find modifier value and type according to form
+ ---@type string|number|table
local modValue = tonumber(formCap[1]) or formCap[1]
local modType = "BASE"
local modSuffix
@@ -7166,7 +7173,7 @@ local jewelSelfUnallocFuncs = {
["Grants all bonuses of Unallocated Small Passive Skills in Radius"] = function(node, out, data)
if node then
if node.type == "Normal" then
- data.modList = data.modList or new("ModList")
+ data.modList = data.modList or new("ModList"):ModList()
-- Filter out "Condition:ConnectedTo" mods as these nodes are not technically allocated by this jewel func
for _, mod in ipairs(out) do
@@ -7303,23 +7310,26 @@ local unsupported = { }
local count = 0
--local foo = io.open("../unsupported.txt", "w")
--foo:close()
-return function(line, isComb)
- if not cache[line] then
- local modList, extra = parseMod(line, 1)
- if modList and extra then
- modList, extra = parseMod(line, 2)
- end
- cache[line] = { modList, extra }
- if foo and not isComb and not cache[line][1] then
- local form = line:gsub("[%+%-]?%d+%.?%d*","{num}")
- if not unsupported[form] then
- unsupported[form] = true
- count = count + 1
- foo = io.open("../unsupported.txt", "a+")
- foo:write(count, ': ', form, (cache[line][2] and #cache[line][2] < #line and (' {' .. cache[line][2]).. '}') or "", '\n')
- foo:close()
+return {
+ parseMod = function(line, isComb)
+ if not cache[line] then
+ local modList, extra = parseMod(line, 1)
+ if modList and extra then
+ modList, extra = parseMod(line, 2)
+ end
+ cache[line] = { modList, extra }
+ if foo and not isComb and not cache[line][1] then
+ local form = line:gsub("[%+%-]?%d+%.?%d*", "{num}")
+ if not unsupported[form] then
+ unsupported[form] = true
+ count = count + 1
+ foo = io.open("../unsupported.txt", "a+")
+ foo:write(count, ': ', form, (cache[line][2] and #cache[line][2] < #line and (' {' .. cache[line][2]) .. '}') or "", '\n')
+ foo:close()
+ end
end
end
- end
- return unpack(copyTable(cache[line]))
-end, cache
+ return unpack(copyTable(cache[line]))
+ end,
+ parseModCache = cache
+}
diff --git a/src/Modules/ModParser.lua.rej b/src/Modules/ModParser.lua.rej
new file mode 100644
index 0000000000..db292deac5
--- /dev/null
+++ b/src/Modules/ModParser.lua.rej
@@ -0,0 +1,10 @@
+diff a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua (rejected hunks)
+@@ -6378,7 +6379,7 @@ local jewelSelfUnallocFuncs = {
+ ["Grants all bonuses of Unallocated Notable Passive Skills in Radius"] = function(node, out, data)
+ if node then
+ if node.type == "Notable" then
+- data.modList = data.modList or new("ModList")
++ data.modList = data.modList or new("ModList"):ModList()
+
+ -- Filter out "Condition:ConnectedTo" mods as these nodes are not technically allocated by this jewel func
+ for _, mod in ipairs(out) do
diff --git a/src/Modules/ModTools.lua b/src/Modules/ModTools.lua
index 049e9d58e5..ccbcd4da79 100644
--- a/src/Modules/ModTools.lua
+++ b/src/Modules/ModTools.lua
@@ -34,6 +34,7 @@ function modLib.createMod(modName, modType, modVal, ...)
keywordFlags = select(3, ...)
tagStart = 4
end
+ ---@class Mod
return {
name = modName,
type = modType,
@@ -44,8 +45,9 @@ function modLib.createMod(modName, modType, modVal, ...)
select(tagStart, ...)
}
end
-
-modLib.parseMod, modLib.parseModCache = LoadModule("Modules/ModParser", launch)
+local modParserModule = LoadModule("Modules/ModParser")
+modLib.parseMod = modParserModule.parseMod
+modLib.parseModCache = modParserModule.parseModCache
function modLib.parseTags(line)
if not line or line == "-" then
diff --git a/src/Modules/ModTools.lua.rej b/src/Modules/ModTools.lua.rej
new file mode 100644
index 0000000000..ec634a0b3f
--- /dev/null
+++ b/src/Modules/ModTools.lua.rej
@@ -0,0 +1,19 @@
+diff a/src/Modules/ModTools.lua b/src/Modules/ModTools.lua (rejected hunks)
+@@ -15,8 +15,17 @@ local s_format = string.format
+ local band = bit.band
+ local bor = bit.bor
+
++---@diagnostic disable-next-line: lowercase-global
+ modLib = { }
+
++--- "Flag" is only used with CanNotUseItem
++---@alias Doubled ["MORE", "OVERRIDE"]
++---@alias NumericModTypes "INC"|"MORE"|"BASE"|"OVERRIDE"|"MAX"|"CHANCE"|"DUMMY"|"Flag"|"MIN"|Doubled
++
++---@overload fun(modName: string, modType: NumericModTypes, modVal?: number)
++---@overload fun(modName: string, modType: "FLAG", modVal: boolean)
++---@overload fun(modName: string, modType: "LIST", modVal: any[]|any)
++---@return Mod
+ function modLib.createMod(modName, modType, modVal, ...)
+ local flags = 0
+ local keywordFlags = 0
diff --git a/src/UpdateApply.lua b/src/UpdateApply.lua
index 6abaf71ea7..1032a9b149 100644
--- a/src/UpdateApply.lua
+++ b/src/UpdateApply.lua
@@ -4,44 +4,57 @@
-- Module: Update Apply
-- Applies updates.
--
-local opFileName = ...
-print("Applying update...")
-local opFile = io.open(opFileName, "r")
-if not opFile then
- print("No operations list present.\n")
- return
-end
-local lines = { }
-for line in opFile:lines() do
- table.insert(lines, line)
-end
-opFile:close()
-os.remove(opFileName)
-for _, line in ipairs(lines) do
- local op, args = line:match("(%a+) ?(.*)")
- if op == "move" then
- local src, dst = args:match('"(.*)" "(.*)"')
- dst = dst:gsub("{space}", " ")
- print("Updating '"..dst.."'")
- local srcFile = io.open(src, "rb")
- assert(srcFile, "couldn't open "..src)
- local dstFile
- while not dstFile do
- dstFile = io.open(dst, "w+b")
- end
- if dstFile then
- dstFile:write(srcFile:read("*a"))
- dstFile:close()
+---@param opFileName string
+local function applyUpdate(opFileName)
+ print("Applying update...")
+ local opFile = io.open(opFileName, "r")
+ if not opFile then
+ print("No operations list present.\n")
+ return
+ end
+ local lines = {}
+ for line in opFile:lines() do
+ table.insert(lines, line)
+ end
+ opFile:close()
+ os.remove(opFileName)
+ for _, line in ipairs(lines) do
+ local op, args = line:match("(%a+) ?(.*)")
+ if op == "move" then
+ local src, dst = args:match('"(.*)" "(.*)"')
+ dst = dst:gsub("{space}", " ")
+ print("Updating '" .. dst .. "'")
+ local srcFile = io.open(src, "rb")
+ assert(srcFile, "couldn't open " .. src)
+ local dstFile
+ while not dstFile do
+ dstFile = io.open(dst, "w+b")
+ end
+ if dstFile then
+ dstFile:write(srcFile:read("*a"))
+ dstFile:close()
+ end
+ srcFile:close()
+ os.remove(src)
+ elseif op == "delete" then
+ local file = args:match('"(.*)"')
+ print("Deleting '" .. file .. "'")
+ os.remove(file)
+ elseif op == "start" then
+ local target = args:match('"(.*)"')
+ SpawnProcess(target)
end
- srcFile:close()
- os.remove(src)
- elseif op == "delete" then
- local file = args:match('"(.*)"')
- print("Deleting '"..file.."'")
- os.remove(file)
- elseif op == "start" then
- local target = args:match('"(.*)"')
- SpawnProcess(target)
end
end
+
+-- this file is used both as a module and as a script depending on the update
+-- mode. basic mode will spawn a process, while normal mode will use this as a
+-- module.
+
+local opFileName = ...
+if opFileName then
+ return applyUpdate(opFileName)
+end
+
+return applyUpdate
diff --git a/src/_SimpleGraphic.def.lua b/src/_SimpleGraphic.def.lua
new file mode 100644
index 0000000000..158ed456dc
--- /dev/null
+++ b/src/_SimpleGraphic.def.lua
@@ -0,0 +1,516 @@
+--- this file defines function signatures for the runtime API, and is not meant
+-- to be used directly. the function bodies here ARE NOT correct for regular
+-- PoB use. they are implemented by SimpleGraphic, and are only correct for
+-- headless mode, in which case this file IS executed.
+---@meta
+
+---@alias Font "FIXED"|"VAR"|"VAR BOLD"|"FONTIN SC"|"FONTIN SC ITALIC"|"FONTIN"|"FONTIN ITALIC"
+
+---@param name string
+---@param func? fun()
+function SetCallback(name, func)
+ ---@diagnostic disable-next-line: undefined-global headless wrapper
+ __callbackTable__[name] = func
+end
+
+---@param name string
+---@return table
+function GetCallback(name)
+ ---@diagnostic disable-next-line: undefined-global headless wrapper
+ return __callbackTable__[name]
+end
+
+---@param object? table
+function SetMainObject(object)
+ __mainObject__ = object
+end
+
+---@class ImageHandle
+local imageHandleClass = {}
+imageHandleClass.__index = imageHandleClass
+
+---@return ImageHandle
+function NewImageHandle()
+ return setmetatable({}, imageHandleClass)
+end
+
+---@param fileName string
+---@param ... "ASYNC"|"CLAMP"|"MIPMAP"
+function imageHandleClass:Load(fileName, ...)
+ self.valid = true
+end
+
+---@class ArtHandle
+local artHandleClass = {}
+
+---@return integer width
+---@return integer height
+function artHandleClass:Size() end
+
+---@alias ArtFlag "CLAMP"|"MIPMAP"|"NEAREST"
+
+---@param art ArtHandle
+---@param x1 integer
+---@param y1 integer
+---@param x2 integer
+---@param y2 integer
+---@param ... ArtFlag
+function imageHandleClass:LoadArtRectangle(art, x1, y1, x2, y2, ...) end
+
+---@param art ArtHandle
+---@param xC integer
+---@param yC integer
+---@param rMin integer
+---@param rMax integer
+---@param ... ArtFlag
+function imageHandleClass:LoadArtArcBand(art, xC, yC, rMin, rMax, ...) end
+
+function imageHandleClass:Unload()
+ self.valid = false
+end
+
+---@return boolean
+function imageHandleClass:IsValid()
+ return self.valid
+end
+
+---@return boolean
+function imageHandleClass:IsLoading()
+ return false
+end
+
+---@param priority number
+function imageHandleClass:SetLoadingPriority(priority) end
+
+---@return integer width
+---@return integer height
+function imageHandleClass:ImageSize()
+ return 1, 1
+end
+
+---@param fileName string
+---@return userdata
+function NewArtHandle(fileName) end
+
+---@class TexHandle
+local texHandleClass = {}
+
+---@class TextureInfo
+---@field formatStr ""|"RGB"|"RGBA"|"BC1"|"BC7"
+---@field width integer
+---@field height integer
+---@field layerCount integer
+---@field mipCount integer
+local textureInfoClass = {}
+
+---@class Texture
+local Texture = {}
+
+---@return TexHandle
+function Texture.new() end
+
+-- `gli::format` id, or a matching format string. see `core_tex_manipulation.cpp`
+---@alias TextureFormat integer|"RGB"|"RGBA"|"BC1"|"BC7"
+
+---@param format TextureFormat
+---@param width integer
+---@param height integer
+---@param layerCount integer
+---@param mipCount integer
+---@return boolean success
+function texHandleClass:Allocate(format, width, height, layerCount, mipCount) end
+
+---@param fileName string
+---@return boolean success
+function texHandleClass:Load(fileName) end
+
+---@param fileName string
+---@return boolean success
+function texHandleClass:Save(fileName) end
+
+---@return TextureInfo
+function texHandleClass:Info() end
+
+---@return boolean
+function texHandleClass:IsValid() end
+
+---@param textures TexHandle[]
+---@return boolean success
+function texHandleClass:StackTextures(textures) end
+
+---@return integer width
+---@return integer height
+function GetScreenSize()
+ return 1920, 1080
+end
+
+---@return number
+function GetScreenScale()
+ return 1
+end
+
+---@param red number
+---@param green number
+---@param blue number
+---@param alpha? number
+function SetClearColor(red, green, blue, alpha) end
+
+---@param layer? number
+---@param subLayer? number
+function SetDrawLayer(layer, subLayer) end
+
+---@return integer
+function GetDrawLayer() end
+
+---@param x number
+---@param y number
+---@param width number
+---@param height number
+---@overload fun()
+function SetViewport(x, y, width, height) end
+
+---@param mode ("ALPHA"|"PREALPHA"|"ADDITIVE")
+function SetBlendMode(mode) end
+
+---@param r number
+---@param g number
+---@param b number
+---@param a number?
+function SetDrawColor(r, g, b, a) end
+
+---@param escapeStr string
+function SetDrawColor(escapeStr) end
+
+---@return number r
+---@return number g
+---@return number b
+---@return number a
+function GetDrawColor() end
+
+---@param percent integer
+function SetDPIScaleOverridePercent(percent) end
+
+---@return integer
+function GetDPIScaleOverridePercent()
+ return 1
+end
+
+---@param imgHandle? ImageHandle
+---@param left number
+---@param top number
+---@param width number
+---@param height number
+function DrawImage(imgHandle, left, top, width, height) end
+
+---@param imgHandle? ImageHandle
+---@param left number
+---@param top number
+---@param width number
+---@param height number
+---@param tcLeft number
+---@param tcTop number
+---@param tcRight number
+---@param tcBottom number
+function DrawImage(imgHandle, left, top, width, height, tcLeft, tcTop, tcRight, tcBottom) end
+
+---@param imgHandle? ImageHandle
+---@param left number
+---@param top number
+---@param width number
+---@param height number
+---@param stackIdx integer must be positive
+---@param mask? integer must be positive
+function DrawImage(imgHandle, left, top, width, height, tcLeft, tcTop, tcRight, tcBottom, stackIdx, mask) end
+
+---@param imgHandle? ImageHandle
+---@param x1 number
+---@param y1 number
+---@param x2 number
+---@param y2 number
+---@param x3 number
+---@param y3 number
+---@param x4 number
+---@param y4 number
+function DrawImageQuad(imgHandle, x1, y1, x2, y2, x3, y3, x4, y4) end
+
+---@param imgHandle? ImageHandle
+---@param x1 number
+---@param y1 number
+---@param x2 number
+---@param y2 number
+---@param x3 number
+---@param y3 number
+---@param x4 number
+---@param s1 number
+---@param t1 number
+---@param s2 number
+---@param t2 number
+---@param s3 number
+---@param t3 number
+---@param s4 number
+---@param t4 number
+function DrawImageQuad(imgHandle, x1, y1, x2, y2, x3, y3, x4, y4, s1, t1, s2, t2, s3, t3, s4, t4) end
+
+---@param imgHandle? ImageHandle
+---@param x1 number
+---@param y1 number
+---@param x2 number
+---@param y2 number
+---@param x3 number
+---@param y3 number
+---@param x4 number
+---@param y4 number
+---@param stackIdx integer? must be positive
+---@param mask integer? must be positive
+function DrawImageQuad(imgHandle, x1, y1, x2, y2, x3, y3, x4, y4, stackIdx, mask) end
+
+---@param left number
+---@param top number
+---@param align? ("LEFT"|"CENTER"|"RIGHT"|"CENTER_X"|"RIGHT_X")
+---@param height number
+---@param font Font
+---@param text string
+function DrawString(left, top, align, height, font, text) end
+
+---@param height number
+---@param font Font
+---@param text string
+---@return integer physicalWidth
+function DrawStringWidth(height, font, text)
+ return 1
+end
+
+---@param height number
+---@param font Font
+---@param text string
+---@param cursorX number
+---@param cursorY number
+---@return integer
+function DrawStringCursorIndex(height, font, text, cursorX, cursorY)
+ return 0
+end
+
+---@param text string
+---@return string
+function StripEscapes(text)
+ local s, _ = text:gsub("%^%d", ""):gsub("%^x%x%x%x%x%x%x", "")
+ return s
+end
+
+---@return integer asyncCount
+function GetAsyncCount()
+ return 0
+end
+
+---@param flag1 string
+---@param ... string
+function RenderInit(flag1, ...) end
+
+---@class FileSearchHandle
+local fileSearchHandleClass = {}
+
+---@return boolean
+function fileSearchHandleClass:NextFile() end
+
+---@return string
+function fileSearchHandleClass:GetFileName() end
+
+---@return integer
+function fileSearchHandleClass:GetFileSize() end
+
+---@return number
+function fileSearchHandleClass:GetFileModifiedTime() end
+
+---@param spec string
+---@param findDirectories? boolean
+---@return FileSearchHandle
+function NewFileSearch(spec, findDirectories) end
+
+---@param path string
+---@return string? name
+---@return string? version
+---@return integer? status
+function GetCloudProvider(path)
+ return nil, nil, nil
+end
+
+---@param title string
+function SetWindowTitle(title) end
+
+---@return number x
+---@return number y
+function GetCursorPos()
+ return 0, 0
+end
+
+---@param x number
+---@param y number
+function SetCursorPos(x, y) end
+
+---@param doShow boolean
+function ShowCursor(doShow) end
+
+---@param keyName string cannot be empty or an unrecognised key name
+function IsKeyDown(keyName) end
+
+---@param text string
+function Copy(text) end
+
+---@return string? data
+function Paste() end
+
+---@param data string
+---@return string? compressedData
+---@return string? errMsg
+function Deflate(data)
+ return ""
+end
+
+---@param data string
+---@return string? data
+---@return string? errMsg
+function Inflate(data)
+ return ""
+end
+
+---@return integer timeMillis
+function GetTime()
+ return 0
+end
+
+---@return string scriptPath
+---@return string? scriptFallback
+---@return string? errMsg
+function GetScriptPath()
+ return ""
+end
+
+---@return string runtimePath
+---@return string? fallbackPath
+---@return string? errMsg
+function GetRuntimePath()
+ return ""
+end
+
+---@return string? userPath
+---@return string? invalidPath
+---@return string? errMsg
+function GetUserPath()
+ return ""
+end
+
+---@param path string
+---@return true|([nil, string]) true on success, or nil and error message
+function MakeDir(path) end
+
+---@param path string
+---@param recurse? boolean
+function RemoveDir(path, recurse) end
+
+---@param path string
+function SetWorkDir(path) end
+
+---@return string
+function GetWorkDir()
+ return ""
+end
+
+---@alias SubScriptID userdata
+
+---@param scriptText string
+---@param funcList string
+---@param subList string
+---@param ... nil|boolean|number|string
+---@return SubScriptID
+function LaunchSubScript(scriptText, funcList, subList, ...) end
+
+---@param ssID SubScriptID
+function AbortSubScript(ssID) end
+
+---@param ssID SubScriptID
+---@return boolean isRunning
+function IsSubScriptRunning(ssID) end
+
+---@param name string
+---@param ... any
+---@return unknown retVal use ---@module "name" instead
+function LoadModule(name, ...)
+ if not name:match("%.lua") then
+ name = name .. ".lua"
+ end
+ local func, err = loadfile(name)
+ if func then
+ return func(...)
+ else
+ error("LoadModule() error loading '" .. name .. "': " .. err)
+ end
+end
+
+---@param modName string
+---@param ... any
+---@return unknown retVal use ---@module "name" instead
+function PLoadModule(modName, ...)
+ if not modName:match("%.lua") then
+ modName = modName .. ".lua"
+ end
+ local func, err = loadfile(modName)
+ if func then
+ return PCall(func, ...)
+ else
+ error("PLoadModule() error loading '" .. modName .. "': " .. err)
+ end
+end
+
+---@generic T
+---@generic R
+---@param func fun(...: T): R
+---@param ... any
+---@return any? err
+---@return R? retVal
+function PCall(func, ...)
+ local ret = { pcall(func, ...) }
+ if ret[1] then
+ table.remove(ret, 1)
+ ---@diagnostic disable-next-line: redundant-return-value headless wrapper
+ return nil, unpack(ret)
+ else
+ return ret[2]
+ end
+end
+
+--- A function similar to C `printf` which prints to the console (`^~` on US layout) of the program.
+---@param fmt string
+---@param ... any
+function ConPrintf(fmt, ...)
+ -- Optional
+ print(string.format(fmt, ...))
+end
+
+---@param tbl table
+---@param noRecurse any converted to boolean
+function ConPrintTable(tbl, noRecurse) end
+
+---@param cmd string
+function ConExecute(cmd) end
+
+function ConClear() end
+
+---@param cmdName string
+---@param args string?
+function SpawnProcess(cmdName, args) end
+
+---@param url string
+---@return string? error
+function OpenURL(url) end
+
+---@param isEnabled boolean
+function SetProfiling(isEnabled) end
+
+function TakeScreenshot() end
+
+function Restart() end
+
+---@param msg string?
+function Exit(msg) end
+
+function SetForeground() end