From e49677d0c5027978f750cc9bb5f6210d58a45500 Mon Sep 17 00:00:00 2001 From: vaisest <4550061+vaisest@users.noreply.github.com> Date: Fri, 31 Jul 2026 19:39:54 +0300 Subject: [PATCH 1/2] Use Currency Exchange API instead of poe.ninja in trader --- spec/System/TestTradeQueryCurrency_spec.lua | 42 +- src/Classes/PoEAPI.lua | 19 +- src/Classes/TradeQuery.lua | 263 ++++---- src/Data/CurrencyNames.lua | 695 ++++++++++++++++++++ src/Export/Scripts/miscdata.lua | 9 + 5 files changed, 869 insertions(+), 159 deletions(-) create mode 100644 src/Data/CurrencyNames.lua diff --git a/spec/System/TestTradeQueryCurrency_spec.lua b/spec/System/TestTradeQueryCurrency_spec.lua index 8ea9819ef3e..103191453f7 100644 --- a/spec/System/TestTradeQueryCurrency_spec.lua +++ b/spec/System/TestTradeQueryCurrency_spec.lua @@ -9,7 +9,8 @@ describe("TradeQuery Currency Conversion", function() -- Pass: Calculates price in divs -- Fail: Wrong value or nil, indicating broken rounding/baseline logic it("handles chaos currency", function() - mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 0.1 } } + mock_tradeQuery.pbCurrencyConversion = { realm = { league = { chaos = 0.1 } } } + mock_tradeQuery.pbRealm = "realm" mock_tradeQuery.pbLeague = "league" local result = mock_tradeQuery:ConvertCurrencyToDivs("chaos", 5) assert.are.equal(result, 0.5) @@ -48,39 +49,6 @@ describe("TradeQuery Currency Conversion", function() assert.are.equals(1, mock_tradeQuery.itemIndexTbl[1]) end) - describe("PriceBuilderProcessPoENinjaResponse", function() - -- Pass: Processes without error, restoring map while adding a notice - -- Fail: Corrupts map or crashes, indicating fragile API response handling, breaking future conversions - it("handles empty response", function() - local orig_conv = mock_tradeQuery.currencyConversionTradeMap - mock_tradeQuery.currencyConversionTradeMap = { div = "id" } - mock_tradeQuery.pbLeague = "league" - mock_tradeQuery.pbCurrencyConversion = { league = {} } - mock_tradeQuery.controls.pbNotice = { label = "" } - local resp = { lines = { }} - mock_tradeQuery:PriceBuilderProcessPoENinjaResponse(resp.lines) - -- No crash expected - assert.is_true(true) - assert.is_true(mock_tradeQuery.controls.pbNotice.label == "No currencies received from PoE Ninja") - mock_tradeQuery.currencyConversionTradeMap = orig_conv - end) - - -- Pass: Processes without error, restoring map while adding a notice - -- Fail: Corrupts map or crashes, indicating fragile API response handling, breaking future conversions - it("handles empty response", function() - local orig_conv = mock_tradeQuery.currencyConversionTradeMap - mock_tradeQuery.currencyConversionTradeMap = { div = "id" } - mock_tradeQuery.pbLeague = "league" - mock_tradeQuery.pbCurrencyConversion = { league = {} } - mock_tradeQuery.controls.pbNotice = { label = "" } - local resp = { lines = { { malformedLine = "lol"} }} - mock_tradeQuery:PriceBuilderProcessPoENinjaResponse(resp.lines) - -- No crash expected - assert.is_true(true) - assert.is_true(mock_tradeQuery.controls.pbNotice.label == "Currencies not updated: malformed PoE Ninja response") - mock_tradeQuery.currencyConversionTradeMap = orig_conv - end) - end) describe("GetTotalPriceString", function() -- Pass: Sums and formats correctly (e.g., "5 chaos, 10 div", should be most valuable currency first) @@ -92,14 +60,14 @@ describe("TradeQuery Currency Conversion", function() assert.are.equal(result, "1 exalted, 10 div, 5 chaos") -- check if they're sorted according to currency value + mock_tradeQuery.pbRealm = "realm" mock_tradeQuery.pbLeague = "league" - mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 0.1, exalted = 0.05, div = 1, mirror = 700} } + mock_tradeQuery.pbCurrencyConversion = { realm = { league = { chaos = 0.1, exalted = 0.05, div = 1, mirror = 700 } } } local result = mock_tradeQuery:GetTotalPriceString() assert.are.equal(result, "10 div, 5 chaos, 1 exalted") -- check that missing currency values don't crash - mock_tradeQuery.pbLeague = "league" - mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 0.1, exalted = 0.05, mirror = 700 } } + mock_tradeQuery.pbCurrencyConversion = { realm = { league = { chaos = 0.1, exalted = 0.05, mirror = 700 } } } local result = mock_tradeQuery:GetTotalPriceString() assert.True(true) end) diff --git a/src/Classes/PoEAPI.lua b/src/Classes/PoEAPI.lua index 7f19756c80d..592664bb986 100644 --- a/src/Classes/PoEAPI.lua +++ b/src/Classes/PoEAPI.lua @@ -17,6 +17,7 @@ local PoEAPIClass = newClass("PoEAPI", function(self, authToken, refreshToken, t self.refreshToken = refreshToken self.tokenExpiry = tokenExpiry or 0 self.baseUrl = "https://api.pathofexile.com" + self.CDNBaseUrl = "https://web.poecdn.com/api" self.rateLimiter = new("TradeQueryRateLimiter") self.tokenHasBeenValidated = false @@ -151,7 +152,8 @@ end --- @param endpoint string --- @param callback fun(response: table?, errorMsg: string) -function PoEAPIClass:DownloadWithRefresh(endpoint, callback) +function PoEAPIClass:DownloadWithRefresh(endpoint, callback, useCDN) + local baseUrl = useCDN and self.CDNBaseUrl or self.baseUrl self:ValidateAuth(function(valid, validationErrMsg) if not valid then -- Clean info about token and refresh token @@ -160,7 +162,7 @@ function PoEAPIClass:DownloadWithRefresh(endpoint, callback) return end - launch:DownloadPage(self.baseUrl .. endpoint, function(response, errMsg) + launch:DownloadPage(baseUrl .. endpoint, function(response, errMsg) if errMsg and errMsg:match("401") and self.retries < 1 then -- try once again with refresh token self.retries = 1 @@ -232,3 +234,16 @@ function PoEAPIClass:DownloadCharacter(realm, name, callback) self:DownloadWithRateLimit("character-request-limit", "/character" .. (realm == "pc" and "" or "/" .. realm) .. "/" .. name, callback) end + +---@param realm string +---@param callback DownloadCallback +function PoEAPIClass:FetchCurrencyExchange(realm, callback) + local url = "/currency-exchange" + if realm ~= "pc" then + url = url .. "/" .. realm + end + local hourSeconds = 60 * 60 + local unixTimeLastHour = (math.floor(os.time() / hourSeconds) - 1) * hourSeconds + url = url .. "/" .. unixTimeLastHour + self:DownloadWithRefresh(url, callback, true) +end diff --git a/src/Classes/TradeQuery.lua b/src/Classes/TradeQuery.lua index ad6b6a48f39..c13d1c0ee21 100644 --- a/src/Classes/TradeQuery.lua +++ b/src/Classes/TradeQuery.lua @@ -5,7 +5,8 @@ -- -local dkjson = require "dkjson" +local dkjson = require("dkjson") +local curl = require("lcurl.safe") local itemSlotHelper = LoadModule("Modules/ItemSlotHelper") local get_time = os.time @@ -35,10 +36,9 @@ local TradeQueryClass = newClass("TradeQuery", function(self, itemsTab) -- default set of trade item sort selection self.slotTables = { } self.pbItemSortSelectionIndex = 1 - -- for each league, a table of values of each currency in div - --- @type table> - self.pbCurrencyConversion = { } - self.lastCurrencyConversionRequest = 0 + -- for each realm and league, a table of values of each currency in div + --- @type table>> + self.pbCurrencyConversion = {} self.lastCurrencyFileTime = { } self.pbFileTimestampDiff = { } self.pbRealm = "" @@ -97,7 +97,6 @@ function TradeQueryClass:PullLeagueList() self.controls.league:SetList(self.itemsTab.leagueDropList) self.controls.league.selIndex = 1 self.pbLeague = self.itemsTab.leagueDropList[self.controls.league.selIndex] - self:SetCurrencyConversionButton() end end) end @@ -106,77 +105,155 @@ end --- @param amount integer --- @return number? function TradeQueryClass:ConvertCurrencyToDivs(currencyId, amount) - local map = self.pbCurrencyConversion[self.pbLeague] + local map = self.pbCurrencyConversion[self.pbRealm] and self.pbCurrencyConversion[self.pbRealm][self.pbLeague] if map and map[currencyId] then return amount * map[currencyId] end end --- Method to pull down and interpret the PoE.Ninja JSON endpoint data ----@param league string -function TradeQueryClass:PullPoENinjaCurrencyConversion(league) +local generalCurrencies = { + ["Metadata/Items/Currency/CurrencyModValues"] = true, + ["Metadata/Items/Currency/CurrencyRerollRare"] = true +} + +---@return table> exchangeData For each league, a map from currency name to value in divines. +local function processCXResponse(static, CXData) + -- short currency names for each base item type id + local currencyNames = {} + -- long currency names for each base item type id + local currencyIdMapData = require("Data.CurrencyNames") + -- make map bidirectional + local currencyIdMap = {} + for k, v in pairs(currencyIdMapData) do + currencyIdMap[v] = k + currencyIdMap[k] = v + end + -- build currencyNames + for _, entry in ipairs(static.result[1].entries) do + if entry.id ~= "sep" then + local itemID = currencyIdMap[entry.text] + -- it's possible for there to be no match as only the "currency" + -- category is exported. the static data is used for the bulk + -- trading function which means not every item is actually used as a + -- trade site currency + if itemID then + currencyNames[itemID] = entry.id + end + end + end + local out = {} + for _, entry in ipairs(CXData.markets) do + local league = entry.league + if not out[league] then + out[league] = {} + end + local leagueOut = out[league] + + -- base type ids in the form of e.g. Metadata/Items/.../CurrencyModValues + local fromID = entry.market_pair[1] + local toID = entry.market_pair[2] + + -- entry is from chaos/div to something else -> flip + if generalCurrencies[fromID] and not (toID == "Metadata/Items/Currency/CurrencyModValues") then + fromID, toID = toID, fromID + end + + -- short name such as "divine" which the trade site actually uses + local fromShort = currencyNames[fromID] + local toShort = currencyNames[toID] + local price + + if (not fromShort) or (not generalCurrencies[toID]) or (entry.lowest_ratio[fromID] == 0) then + goto CXContinue + end + + price = entry.lowest_ratio[toID] / entry.lowest_ratio[fromID] + local newEntry = { + currency = toShort, + price = price, + stock = entry.highest_stock[fromID] + } + -- only keep the most popular option + if (not leagueOut[fromShort]) or (leagueOut[fromShort].stock < newEntry.stock) then + leagueOut[fromShort] = newEntry + end + ::CXContinue:: + end + + -- convert any non-divine prices to divine equivalent prices + for leagueName, leagueEntries in pairs(out) do + for from, to in pairs(leagueEntries) do + if to.currency ~= "divine" then + local divEntry = leagueEntries[to.currency] + if not divEntry then + leagueEntries[from] = nil + else + leagueEntries[from] = divEntry.price * to.price + end + end + end + -- iterate again to convert prices that were already divine to just the price number + for from, to in pairs(leagueEntries) do + if type(to) == "table" then + leagueEntries[from] = to.price + end + end + -- delete empty league entries + if not next(leagueEntries) then + out[leagueName] = nil + else + leagueEntries.divine = 1 + end + end + + return out +end +-- Method to pull down and interpret the Currency Exchange JSON endpoint data +function TradeQueryClass:PullCXData() local now = get_time() - -- Limit PoE Ninja Currency Conversion request to 1 per hour - if (now - self.lastCurrencyConversionRequest) < 3600 then - self:SetNotice(self.controls.pbNotice, "PoE Ninja Rate Limit Exceeded: " .. tostring(3600 - (now - self.lastCurrencyConversionRequest))) + -- Limit Currency Conversion request to 1 per hour + if self.pbCurrencyConversion[self.pbRealm] and ((now - self.pbCurrencyConversion[self.pbRealm].timestamp) < 61 * 60) then return end - self.pbCurrencyConversion[league] = { } - self.lastCurrencyConversionRequest = now - launch:DownloadPage( - "https://poe.ninja/poe1/api/economy/exchange/current/overview?type=Currency&league=" .. urlEncode(league), - function(response, errMsg) + -- download json containing short names for each item id + launch:DownloadPage("https://www.pathofexile.com/api/trade/data/static", function(response, errMsg) + if errMsg then + self:SetNotice(self.controls.pbNotice, "Error: " .. tostring(errMsg)) + return + end + + local static = dkjson.decode(response.body) + if not static then + self:SetNotice(self.controls.pbNotice, "Could not decode static trade data") + return + end + main.api:FetchCurrencyExchange(self.pbRealm, function(response, errMsg) if errMsg then self:SetNotice(self.controls.pbNotice, "Error: " .. tostring(errMsg)) return end - local json_data = dkjson.decode(response.body) - if not json_data or not json_data.lines then - self:SetNotice(self.controls.pbNotice, "Failed to Get PoE Ninja response") + local json = dkjson.decode(response.body) + if not json then + self:SetNotice(self.controls.pbNotice, "Malformed CX API response") return end - if not self:PriceBuilderProcessPoENinjaResponse(json_data.lines) then - -- don't edit json on failure + + if json.error then + self:SetNotice(self.controls.pbNotice, "CX error: " .. json.error.message) return end - local print_str = "" - for key, value in pairs(self.pbCurrencyConversion[self.pbLeague]) do - print_str = print_str .. '"'..key..'": '..tostring(value)..',' + local success, result = pcall(processCXResponse, static, json) + if not success then + self:SetNotice(self.controls.pbNotice, "Failed to process CX response") + ConPrintf("CX error: %s", result) + return + else + result.timestamp = now + self.pbCurrencyConversion[self.pbRealm] = result end - local foo = io.open("../"..self.pbLeague.."_currency_values.json", "w") - foo:write("{" .. print_str .. '"updateTime": ' .. tostring(get_time()) .. "}") - foo:close() - self:SetCurrencyConversionButton() end) - -end - --- Method to process the PoE.Ninja response ---- @param responseLines table[] ---- @return bool -function TradeQueryClass:PriceBuilderProcessPoENinjaResponse(responseLines) - -- Populate the divine-converted values for each tradeId - for _, currencyDetails in ipairs(responseLines) do - -- these use the same ids as the trade site, which are also short - -- readable names, like "transmute" or "aug", which means there's no - -- need for conversion. - local id = currencyDetails.id - -- poe.ninja uses divs as the primary currency, and as far as I know, - -- this figure is equivalent to the best ratio in equivalent divs - local divs = currencyDetails.primaryValue - if not id or not divs then - self:SetNotice(self.controls.pbNotice, "Currencies not updated: malformed PoE Ninja response") - return false - end - self.pbCurrencyConversion[self.pbLeague][id] = divs - end - -- if nothing was actually found, we should add a notice - if next(self.pbCurrencyConversion[self.pbLeague]) == nil then - self:SetNotice(self.controls.pbNotice, "No currencies received from PoE Ninja") - return false - end - return true + end) end local function initStatSortSelectionList(list) @@ -388,13 +465,13 @@ Highest Weight - Displays the order retrieved from trade]] self.controls.realm = new("DropDownControl", {"LEFT", self.controls.realmLabel, "RIGHT"}, {6, 0, 150, row_height}, self.realmDropList, function(index, value) self.pbRealmIndex = index self.pbRealm = self.realmIds[value] + self:PullCXData() local function setLeagueDropList() self.itemsTab.leagueDropList = copyTable(self.allLeagues[self.pbRealm]) self.controls.league:SetList(self.itemsTab.leagueDropList) -- invalidate selIndex to trigger select function call in the SetSel self.controls.league.selIndex = nil self.controls.league:SetSel(self.pbLeagueIndex) - self:SetCurrencyConversionButton() end if self.allLeagues[self.pbRealm] then setLeagueDropList() @@ -429,7 +506,6 @@ Highest Weight - Displays the order retrieved from trade]] self.controls.league = new("DropDownControl", {"LEFT", self.controls.leagueLabel, "RIGHT"}, {6, 0, 150, row_height}, self.itemsTab.leagueDropList, function(index, value) self.pbLeagueIndex = index self.pbLeague = value - self:SetCurrencyConversionButton() end) self.controls.league:SetSel(self.pbLeagueIndex) self.controls.league.enabled = function() @@ -537,7 +613,7 @@ Highest Weight - Displays the order retrieved from trade]] end end - row_count = row_count + 1 + row_count = row_count + 2 local effective_row_count = row_count - ((scrollBarShown and #slotTables >= 19) and #slotTables-19 or 0) + 2 + 2 -- Two top menu rows, two bottom rows, slots after #19 overlap the other controls at the bottom of the pane self.effective_rows_height = row_height * (effective_row_count - #slotTables + (18 - (#slotTables > 37 and 3 or 0))) -- scrollBar height, "18 - slotTables > 37" logic is fine tuning whitespace after last row @@ -552,11 +628,7 @@ Highest Weight - Displays the order retrieved from trade]] main:ClosePopup() end) - self.controls.updateCurrencyConversion = new("ButtonControl", {"BOTTOMLEFT", nil, "BOTTOMLEFT"}, {pane_margins_horizontal, -pane_margins_vertical, 240, row_height}, "Get Currency Conversion Rates", function() - self:PullPoENinjaCurrencyConversion(self.pbLeague) - end) - self.controls.pbNotice = new("LabelControl", {"BOTTOMRIGHT", nil, "BOTTOMRIGHT"}, {-row_height - pane_margins_vertical - row_vertical_padding, -pane_margins_vertical, 300, row_height}, "") - self:SetCurrencyConversionButton() + self.controls.pbNotice = new("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() @@ -590,6 +662,7 @@ Highest Weight - Displays the order retrieved from trade]] end end end + self:PullCXData() main:OpenPopup(pane_width, self.pane_height, "Trader", self.controls, nil, nil, "close", (scrollBarShown and scrollBarFunc or nil)) end @@ -699,58 +772,6 @@ function TradeQueryClass:SetStatWeights(previousSelectionList) main:OpenPopup(420, popupHeight, "Stat Weight Multipliers", controls) end --- Method to update the Currency Conversion button label -function TradeQueryClass:SetCurrencyConversionButton() - local currencyLabel = "Update Currency Conversion Rates" - self.pbFileTimestampDiff[self.controls.league.selIndex] = nil - if self.pbLeague == nil then - return - end - if self.pbRealm ~= "pc" then - self.controls.updateCurrencyConversion.label = "Currency Rates are not available" - self.controls.updateCurrencyConversion.enabled = false - self.controls.updateCurrencyConversion.tooltipFunc = function(tooltip) - tooltip:Clear() - tooltip:AddLine(16, "Currency Conversion rates are pulled from PoE Ninja") - tooltip:AddLine(16, "The data is only available for the PC realm.") - end - return - end - local values_file = io.open("../"..self.pbLeague.."_currency_values.json", "r") - if values_file then - local lines = values_file:read "*a" - values_file:close() - self.pbCurrencyConversion[self.pbLeague] = dkjson.decode(lines) - self.lastCurrencyFileTime[self.controls.league.selIndex] = self.pbCurrencyConversion[self.pbLeague]["updateTime"] - self.pbFileTimestampDiff[self.controls.league.selIndex] = get_time() - self.lastCurrencyFileTime[self.controls.league.selIndex] - if self.pbFileTimestampDiff[self.controls.league.selIndex] < 3600 then - -- Less than 1 hour (60 * 60 = 3600) - currencyLabel = "Currency Rates are very recent" - elseif self.pbFileTimestampDiff[self.controls.league.selIndex] < (24 * 3600) then - -- Less than 1 day - currencyLabel = "Currency Rates are recent" - end - else - currencyLabel = "Get Currency Conversion Rates" - end - self.controls.updateCurrencyConversion.label = currencyLabel - self.controls.updateCurrencyConversion.enabled = function() - return self.pbFileTimestampDiff[self.controls.league.selIndex] == nil or self.pbFileTimestampDiff[self.controls.league.selIndex] >= 3600 - end - self.controls.updateCurrencyConversion.tooltipFunc = function(tooltip) - tooltip:Clear() - if self.lastCurrencyFileTime[self.controls.league.selIndex] ~= nil then - self.pbFileTimestampDiff[self.controls.league.selIndex] = get_time() - self.lastCurrencyFileTime[self.controls.league.selIndex] - end - if self.pbFileTimestampDiff[self.controls.league.selIndex] == nil or self.pbFileTimestampDiff[self.controls.league.selIndex] >= 3600 then - tooltip:AddLine(16, "Currency Conversion rates are pulled from PoE Ninja") - tooltip:AddLine(16, "Updates are limited to once per hour and not necessary more than once per day") - elseif self.pbFileTimestampDiff[self.controls.league.selIndex] ~= nil and self.pbFileTimestampDiff[self.controls.league.selIndex] < 3600 then - tooltip:AddLine(16, "Conversion Rates are less than an hour old (" .. tostring(self.pbFileTimestampDiff[self.controls.league.selIndex]) .. " seconds old)") - end - end -end - -- Method to set the notice message in upper right of PoB Trader pane function TradeQueryClass:SetNotice(notice_control, msg) if msg:find("No Matching Results") then @@ -857,7 +878,7 @@ function TradeQueryClass:UpdateControlsWithItems(row_idx) local sortMode = self.itemSortSelectionList[self.pbItemSortSelectionIndex] local sortedItems, errMsg = self:SortFetchResults(row_idx, sortMode) if errMsg == "MissingConversionRates" then - self:SetNotice(self.controls.pbNotice, "^4Please update currency rates to sort by price. Falling back to Stat Value sort.") + self:SetNotice(self.controls.pbNotice, "^4Currency rates unavailable. Falling back to Stat Value sort.") sortedItems, errMsg = self:SortFetchResults(row_idx, self.sortModes.StatValue) elseif errMsg then self:SetNotice(self.controls.pbNotice, "Error: " .. errMsg) @@ -1300,7 +1321,9 @@ function TradeQueryClass:GetTotalPriceString() for currency, _ in pairs(prices) do table.insert(currencies, currency) end - local currencyMap = self.pbCurrencyConversion[self.pbLeague] or {} + local currencyMap = self.pbCurrencyConversion[self.pbRealm] and + self.pbCurrencyConversion[self.pbRealm][self.pbLeague] + or {} table.sort(currencies, function(a, b) if currencyMap[a] and currencyMap[b] then return currencyMap[a] > currencyMap[b] diff --git a/src/Data/CurrencyNames.lua b/src/Data/CurrencyNames.lua new file mode 100644 index 00000000000..cfa60316441 --- /dev/null +++ b/src/Data/CurrencyNames.lua @@ -0,0 +1,695 @@ +-- This file is automatically generated, do not edit! +-- Game data (c) Grinding Gear Games + +-- This file contains mapping item names for every currency base item type ID. +-- Used for working with the currency exchange which uses item type IDs. + +-- spell-checker: disable +return { + ["Metadata/Items/Currency/AncestralOmenOnChanceMakeUnique"] = "Omen of Fortune", + ["Metadata/Items/Currency/AncestralOmenOnChromaticAddWhiteSockets"] = "Omen of Trichromatism", + ["Metadata/Items/Currency/AncestralOmenOnCriticalLifeAvoidDamage"] = "Omen of Death-dancing", + ["Metadata/Items/Currency/AncestralOmenOnCriticalLifeGainAdrenaline"] = "Omen of Adrenaline", + ["Metadata/Items/Currency/AncestralOmenOnCriticalLifeGainShadeForm"] = "Omen of Death's Door", + ["Metadata/Items/Currency/AncestralOmenOnCriticalLifeRecoupLife"] = "Omen of Resurgence", + ["Metadata/Items/Currency/AncestralOmenOnCriticalLifeRecoverFlaskCharges"] = "Omen of Refreshment", + ["Metadata/Items/Currency/AncestralOmenOnDeathCreatePortal"] = "Omen of Return", + ["Metadata/Items/Currency/AncestralOmenOnDeathGemsGainExperience"] = "Omen of Bequeathal", + ["Metadata/Items/Currency/AncestralOmenOnDeathNearbyEnemiesMoreDamage"] = "Omen of Revenge", + ["Metadata/Items/Currency/AncestralOmenOnDeathPreventExpLoss"] = "Omen of Amelioration", + ["Metadata/Items/Currency/AncestralOmenOnFusingMakeFullLinks"] = "Omen of Connections", + ["Metadata/Items/Currency/AncestralOmenOnJewellersMakeFullSockets"] = "Omen of the Jeweller", + ["Metadata/Items/Currency/AncestralOmenOnLevelingUpGainExperienceBuff"] = "Omen of Brilliance", + ["Metadata/Items/Currency/AncestralOmenOnLevelingUpGainSoulEater"] = "Omen of the Soul Devourer", + ["Metadata/Items/Currency/AncestralOmenOnLevelingUpSpawnAccelerationShrine"] = "Omen of Acceleration", + ["Metadata/Items/Currency/AncestralTattooArohongui1"] = "Tattoo of the Arohongui Moonwarden", + ["Metadata/Items/Currency/AncestralTattooArohongui2"] = "Tattoo of the Arohongui Scout", + ["Metadata/Items/Currency/AncestralTattooArohongui3"] = "Tattoo of the Arohongui Warrior", + ["Metadata/Items/Currency/AncestralTattooArohongui4"] = "Tattoo of the Arohongui Warmonger", + ["Metadata/Items/Currency/AncestralTattooArohongui5"] = "Tattoo of the Arohongui Shaman", + ["Metadata/Items/Currency/AncestralTattooArohongui6"] = "Loyalty Tattoo of Ikiaho", + ["Metadata/Items/Currency/AncestralTattooArohongui7"] = "Tattoo of the Arohongui Makanga", + ["Metadata/Items/Currency/AncestralTattooHinekora1"] = "Tattoo of the Hinekora Warrior", + ["Metadata/Items/Currency/AncestralTattooHinekora2"] = "Tattoo of the Hinekora Deathwarden", + ["Metadata/Items/Currency/AncestralTattooHinekora3"] = "Tattoo of the Hinekora Shaman", + ["Metadata/Items/Currency/AncestralTattooHinekora4"] = "Tattoo of the Hinekora Storyteller", + ["Metadata/Items/Currency/AncestralTattooHinekora5"] = "Tattoo of the Hinekora Warmonger", + ["Metadata/Items/Currency/AncestralTattooHinekora6"] = "Loyalty Tattoo of Tawhanuku", + ["Metadata/Items/Currency/AncestralTattooHinekora7"] = "Tattoo of the Hinekora Makanga", + ["Metadata/Items/Currency/AncestralTattooKitava1"] = "Tattoo of the Kitava Blood Drinker", + ["Metadata/Items/Currency/AncestralTattooKitava2"] = "Tattoo of the Kitava Rebel", + ["Metadata/Items/Currency/AncestralTattooKitava3"] = "Tattoo of the Kitava Warrior", + ["Metadata/Items/Currency/AncestralTattooKitava4"] = "Tattoo of the Kitava Heart Eater", + ["Metadata/Items/Currency/AncestralTattooKitava5"] = "Tattoo of the Kitava Shaman", + ["Metadata/Items/Currency/AncestralTattooKitava6"] = "Loyalty Tattoo of Utula", + ["Metadata/Items/Currency/AncestralTattooKitava7"] = "Tattoo of the Kitava Makanga", + ["Metadata/Items/Currency/AncestralTattooNgamahu1"] = "Tattoo of the Ngamahu Firewalker", + ["Metadata/Items/Currency/AncestralTattooNgamahu2"] = "Tattoo of the Ngamahu Shaman", + ["Metadata/Items/Currency/AncestralTattooNgamahu3"] = "Tattoo of the Ngamahu Warrior", + ["Metadata/Items/Currency/AncestralTattooNgamahu4"] = "Tattoo of the Ngamahu Warmonger", + ["Metadata/Items/Currency/AncestralTattooNgamahu5"] = "Tattoo of the Ngamahu Woodcarver", + ["Metadata/Items/Currency/AncestralTattooNgamahu6"] = "Loyalty Tattoo of Kaom", + ["Metadata/Items/Currency/AncestralTattooNgamahu7"] = "Tattoo of the Ngamahu Makanga", + ["Metadata/Items/Currency/AncestralTattooRamako1"] = "Tattoo of the Ramako Scout", + ["Metadata/Items/Currency/AncestralTattooRamako2"] = "Tattoo of the Ramako Archer", + ["Metadata/Items/Currency/AncestralTattooRamako3"] = "Tattoo of the Ramako Sniper", + ["Metadata/Items/Currency/AncestralTattooRamako4"] = "Tattoo of the Ramako Fleetfoot", + ["Metadata/Items/Currency/AncestralTattooRamako5"] = "Tattoo of the Ramako Shaman", + ["Metadata/Items/Currency/AncestralTattooRamako6"] = "Loyalty Tattoo of Ahuana", + ["Metadata/Items/Currency/AncestralTattooRamako7"] = "Tattoo of the Ramako Makanga", + ["Metadata/Items/Currency/AncestralTattooRongokurai1"] = "Tattoo of the Rongokurai Warrior", + ["Metadata/Items/Currency/AncestralTattooRongokurai2"] = "Tattoo of the Rongokurai Brute", + ["Metadata/Items/Currency/AncestralTattooRongokurai3"] = "Tattoo of the Rongokurai Goliath", + ["Metadata/Items/Currency/AncestralTattooRongokurai4"] = "Tattoo of the Rongokurai Turtle", + ["Metadata/Items/Currency/AncestralTattooRongokurai5"] = "Tattoo of the Rongokurai Guard", + ["Metadata/Items/Currency/AncestralTattooRongokurai6"] = "Loyalty Tattoo of Kahuturoa", + ["Metadata/Items/Currency/AncestralTattooRongokurai7"] = "Tattoo of the Rongokurai Makanga", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableDex1"] = "Honoured Tattoo of the Hunter", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableDex2"] = "Honoured Tattoo of the Barbarian", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableDex3"] = "Honoured Tattoo of the Berserker", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableInt1"] = "Honoured Tattoo of the Wise", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableInt2"] = "Honoured Tattoo of the Storm", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableInt3"] = "Honoured Tattoo of the Flood", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableStr1"] = "Honoured Tattoo of the Warlord", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableStr2"] = "Honoured Tattoo of the Mountain", + ["Metadata/Items/Currency/AncestralTattooSpecialNotableStr3"] = "Honoured Tattoo of the Pa", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode1"] = "Honoured Tattoo of the Dove", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode2"] = "Honoured Tattoo of the Sky", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode3"] = "Honoured Tattoo of the Tuatara", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode4"] = "Honoured Tattoo of the Pillager", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode5"] = "Honoured Tattoo of the Turtle", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode6"] = "Honoured Tattoo of the Oak", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode7"] = "Honoured Tattoo of the Hatungo", + ["Metadata/Items/Currency/AncestralTattooSpecialSmallNode8"] = "Honoured Tattoo of the Flock", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique1"] = "Ancestral Tattoo of Bloodlines", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique2"] = "Honoured Tattoo of the Makanga", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique3"] = "Journey Tattoo of the Body", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique4"] = "Journey Tattoo of the Mind", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique5"] = "Journey Tattoo of the Soul", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique6"] = "Journey Tattoo of Makanui", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique7Duelist"] = "Forbidden Tattoo of the Duelist", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique7Marauder"] = "Forbidden Tattoo of the Marauder", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique7Ranger"] = "Forbidden Tattoo of the Ranger", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique7Scion"] = "Forbidden Tattoo of the Scion", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique7Shadow"] = "Forbidden Tattoo of the Shadow", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique7Templar"] = "Forbidden Tattoo of the Templar", + ["Metadata/Items/Currency/AncestralTattooSpecialUnique7Witch"] = "Forbidden Tattoo of the Witch", + ["Metadata/Items/Currency/AncestralTattooTasalio1"] = "Tattoo of the Tasalio Bladedancer", + ["Metadata/Items/Currency/AncestralTattooTasalio2"] = "Tattoo of the Tasalio Tideshifter", + ["Metadata/Items/Currency/AncestralTattooTasalio3"] = "Tattoo of the Tasalio Shaman", + ["Metadata/Items/Currency/AncestralTattooTasalio4"] = "Tattoo of the Tasalio Warrior", + ["Metadata/Items/Currency/AncestralTattooTasalio5"] = "Tattoo of the Tasalio Scout", + ["Metadata/Items/Currency/AncestralTattooTasalio6"] = "Loyalty Tattoo of Rakiata", + ["Metadata/Items/Currency/AncestralTattooTasalio7"] = "Tattoo of the Tasalio Makanga", + ["Metadata/Items/Currency/AncestralTattooTawhoa1"] = "Tattoo of the Tawhoa Naturalist", + ["Metadata/Items/Currency/AncestralTattooTawhoa2"] = "Tattoo of the Tawhoa Scout", + ["Metadata/Items/Currency/AncestralTattooTawhoa3"] = "Tattoo of the Tawhoa Warrior", + ["Metadata/Items/Currency/AncestralTattooTawhoa4"] = "Tattoo of the Tawhoa Herbalist", + ["Metadata/Items/Currency/AncestralTattooTawhoa5"] = "Tattoo of the Tawhoa Shaman", + ["Metadata/Items/Currency/AncestralTattooTawhoa6"] = "Loyalty Tattoo of Maata", + ["Metadata/Items/Currency/AncestralTattooTawhoa7"] = "Tattoo of the Tawhoa Makanga", + ["Metadata/Items/Currency/AncestralTattooTukohama1"] = "Tattoo of the Tukohama Shaman", + ["Metadata/Items/Currency/AncestralTattooTukohama2"] = "Tattoo of the Tukohama Warrior", + ["Metadata/Items/Currency/AncestralTattooTukohama3"] = "Tattoo of the Tukohama Brawler", + ["Metadata/Items/Currency/AncestralTattooTukohama4"] = "Tattoo of the Tukohama Warmonger", + ["Metadata/Items/Currency/AncestralTattooTukohama5"] = "Tattoo of the Tukohama Warcaller", + ["Metadata/Items/Currency/AncestralTattooTukohama6"] = "Loyalty Tattoo of Akoya", + ["Metadata/Items/Currency/AncestralTattooTukohama7"] = "Tattoo of the Tukohama Makanga", + ["Metadata/Items/Currency/AncestralTattooValako1"] = "Tattoo of the Valako Stormrider", + ["Metadata/Items/Currency/AncestralTattooValako2"] = "Tattoo of the Valako Scout", + ["Metadata/Items/Currency/AncestralTattooValako3"] = "Tattoo of the Valako Warrior", + ["Metadata/Items/Currency/AncestralTattooValako4"] = "Tattoo of the Valako Shieldbearer", + ["Metadata/Items/Currency/AncestralTattooValako5"] = "Tattoo of the Valako Shaman", + ["Metadata/Items/Currency/AncestralTattooValako6"] = "Loyalty Tattoo of Kiloava", + ["Metadata/Items/Currency/AncestralTattooValako7"] = "Tattoo of the Valako Makanga", + ["Metadata/Items/Currency/AstrolabeAbyss"] = "Lightless Astrolabe", + ["Metadata/Items/Currency/AstrolabeBlight"] = "Fungal Astrolabe", + ["Metadata/Items/Currency/AstrolabeBreach"] = "Grasping Astrolabe", + ["Metadata/Items/Currency/AstrolabeDelirium"] = "Deceptive Astrolabe", + ["Metadata/Items/Currency/AstrolabeExpedition"] = "Runic Astrolabe", + ["Metadata/Items/Currency/AstrolabeGeneric"] = "Templar Astrolabe", + ["Metadata/Items/Currency/AstrolabeHarvest"] = "Fruiting Astrolabe", + ["Metadata/Items/Currency/AstrolabeLegion"] = "Timeless Astrolabe", + ["Metadata/Items/Currency/AstrolabeRitual"] = "Nameless Astrolabe", + ["Metadata/Items/Currency/AstrolabeSettlers"] = "Prospecting Astrolabe", + ["Metadata/Items/Currency/AstrolabeUltimatum"] = "Chaotic Astrolabe", + ["Metadata/Items/Currency/BenevolenceMemoryThread"] = "Memory of Reverence", + ["Metadata/Items/Currency/Bestiary/BestiaryNet1"] = "Simple Rope Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet10"] = "Thaumaturgical Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet11"] = "Necromancy Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet2"] = "Reinforced Rope Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet3"] = "Strong Rope Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet4"] = "Simple Iron Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet5"] = "Reinforced Iron Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet6"] = "Strong Iron Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet7"] = "Simple Steel Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet8"] = "Reinforced Steel Net", + ["Metadata/Items/Currency/Bestiary/BestiaryNet9"] = "Strong Steel Net", + ["Metadata/Items/Currency/CrucibleGeode"] = "Igneous Geode", + ["Metadata/Items/Currency/CrucibleGeodeUber"] = "Crystalline Geode", + ["Metadata/Items/Currency/CurrencyAddAtlasMod"] = "Simple Sextant", + ["Metadata/Items/Currency/CurrencyAddAtlasModHigh"] = "Awakened Sextant", + ["Metadata/Items/Currency/CurrencyAddAtlasModMaven"] = "Elevated Sextant", + ["Metadata/Items/Currency/CurrencyAddAtlasModMid"] = "Prime Sextant", + ["Metadata/Items/Currency/CurrencyAddCrucibleExperience"] = "Magmatic Ore", + ["Metadata/Items/Currency/CurrencyAddGemExperience"] = "Facetor's Lens", + ["Metadata/Items/Currency/CurrencyAddModToMagic"] = "Orb of Augmentation", + ["Metadata/Items/Currency/CurrencyAddModToRare"] = "Exalted Orb", + ["Metadata/Items/Currency/CurrencyAddModToRareElder"] = "Elder's Exalted Orb", + ["Metadata/Items/Currency/CurrencyAddModToRareShaper"] = "Shaper's Exalted Orb", + ["Metadata/Items/Currency/CurrencyAddModToRareShard"] = "Exalted Shard", + ["Metadata/Items/Currency/CurrencyAddZanaInfluence"] = "Orb of Remembrance", + ["Metadata/Items/Currency/CurrencyAfflictionOrbAbyss"] = "Abyssal Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbArmour"] = "Armoursmith's Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbBlight"] = "Blighted Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbBreach"] = "Obscured Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbCurrency"] = "Fine Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbDivinationCards"] = "Diviner's Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbEssences"] = "Whispering Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbFossils"] = "Fossilised Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbFragments"] = "Fragmented Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbGems"] = "Thaumaturge's Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbGeneric"] = "Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbHarbinger"] = "Fine Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbHardMode"] = "Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbIncubators"] = "Timeless Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbLabyrinth"] = "Imperial Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbMaps"] = "Cartographer's Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbMetamorphosis"] = "Challenging Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbPerandus"] = "Kalguuran Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbProphecies"] = "Fine Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbScarabs"] = "Skittering Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbTalismans"] = "Primal Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbTrinkets"] = "Jeweller's Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbUniques"] = "Singular Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionOrbWeapons"] = "Blacksmith's Delirium Orb", + ["Metadata/Items/Currency/CurrencyAfflictionRerollClusterEnchant"] = "Refracting Fog", + ["Metadata/Items/Currency/CurrencyAfflictionShard"] = "Simulacrum Splinter", + ["Metadata/Items/Currency/CurrencyAlbinoCrabClaw"] = "Albino Crab Claw", + ["Metadata/Items/Currency/CurrencyAncestralSilverCoin"] = "Silver Coin", + ["Metadata/Items/Currency/CurrencyArmourQuality"] = "Armourer's Scrap", + ["Metadata/Items/Currency/CurrencyAtlasPassiveRefund"] = "Orb of Unmaking", + ["Metadata/Items/Currency/CurrencyBreachChaosShard"] = "Splinter of Chayula", + ["Metadata/Items/Currency/CurrencyBreachColdShard"] = "Splinter of Tul", + ["Metadata/Items/Currency/CurrencyBreachFireShard"] = "Splinter of Xoph", + ["Metadata/Items/Currency/CurrencyBreachLightningShard"] = "Splinter of Esh", + ["Metadata/Items/Currency/CurrencyBreachPhysicalShard"] = "Splinter of Uul-Netol", + ["Metadata/Items/Currency/CurrencyBreachUpgradeUniqueChaos"] = "Blessing of Chayula", + ["Metadata/Items/Currency/CurrencyBreachUpgradeUniqueCold"] = "Blessing of Tul", + ["Metadata/Items/Currency/CurrencyBreachUpgradeUniqueFire"] = "Blessing of Xoph", + ["Metadata/Items/Currency/CurrencyBreachUpgradeUniqueGeneral"] = "Flesh of Xesht", + ["Metadata/Items/Currency/CurrencyBreachUpgradeUniqueLightning"] = "Blessing of Esh", + ["Metadata/Items/Currency/CurrencyBreachUpgradeUniquePhysical"] = "Blessing of Uul-Netol", + ["Metadata/Items/Currency/CurrencyConflictOrb"] = "Orb of Conflict", + ["Metadata/Items/Currency/CurrencyConvertToNormal"] = "Orb of Scouring", + ["Metadata/Items/Currency/CurrencyCorrupt"] = "Vaal Orb", + ["Metadata/Items/Currency/CurrencyCorruptMonolith"] = "Remnant of Corruption", + ["Metadata/Items/Currency/CurrencyDeepwater"] = "Dead Man's Sulphur", + ["Metadata/Items/Currency/CurrencyDelveCraftingAbyss"] = "Hollow Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingAttackMods"] = "Serrated Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingBleedPoison"] = "Corroded Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingCasterMods"] = "Aetheric Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingChaos"] = "Aberrant Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingCold"] = "Frigid Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingCorruptEssence"] = "Glyphic Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingDefences"] = "Dense Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingElemental"] = "Prismatic Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingEnchant"] = "Deft Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingFire"] = "Scorched Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingGemLevel"] = "Faceted Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingLife"] = "Pristine Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingLightning"] = "Metallic Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingLuckyModRolls"] = "Sanctified Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingMana"] = "Lucent Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingMinionsAuras"] = "Bound Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingMirror"] = "Fractured Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingPhysical"] = "Jagged Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingQuality"] = "Opulent Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingRandom"] = "Tangled Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingSellPrice"] = "Gilded Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingSockets"] = "Fundamental Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingSpeed"] = "Shuddering Fossil", + ["Metadata/Items/Currency/CurrencyDelveCraftingVaal"] = "Bloodstained Fossil", + ["Metadata/Items/Currency/CurrencyDuplicate"] = "Mirror of Kalandra", + ["Metadata/Items/Currency/CurrencyDuplicateShard"] = "Mirror Shard", + ["Metadata/Items/Currency/CurrencyDuplicateShattered"] = "Broken Mirror of Kalandra", + ["Metadata/Items/Currency/CurrencyEldritchAddModToRare"] = "Eldritch Exalted Orb", + ["Metadata/Items/Currency/CurrencyEldritchEmber1"] = "Lesser Eldritch Ember", + ["Metadata/Items/Currency/CurrencyEldritchEmber2"] = "Greater Eldritch Ember", + ["Metadata/Items/Currency/CurrencyEldritchEmber3"] = "Grand Eldritch Ember", + ["Metadata/Items/Currency/CurrencyEldritchEmber4"] = "Exceptional Eldritch Ember", + ["Metadata/Items/Currency/CurrencyEldritchIchor1"] = "Lesser Eldritch Ichor", + ["Metadata/Items/Currency/CurrencyEldritchIchor2"] = "Greater Eldritch Ichor", + ["Metadata/Items/Currency/CurrencyEldritchIchor3"] = "Grand Eldritch Ichor", + ["Metadata/Items/Currency/CurrencyEldritchIchor4"] = "Exceptional Eldritch Ichor", + ["Metadata/Items/Currency/CurrencyEldritchRemoveMod"] = "Eldritch Orb of Annulment", + ["Metadata/Items/Currency/CurrencyEldritchRerollRare"] = "Eldritch Chaos Orb", + ["Metadata/Items/Currency/CurrencyEnkindlingOrb"] = "Enkindling Orb", + ["Metadata/Items/Currency/CurrencyEssenceAnger1"] = "Muttering Essence of Anger", + ["Metadata/Items/Currency/CurrencyEssenceAnger2"] = "Weeping Essence of Anger", + ["Metadata/Items/Currency/CurrencyEssenceAnger3"] = "Wailing Essence of Anger", + ["Metadata/Items/Currency/CurrencyEssenceAnger4"] = "Screaming Essence of Anger", + ["Metadata/Items/Currency/CurrencyEssenceAnger5"] = "Shrieking Essence of Anger", + ["Metadata/Items/Currency/CurrencyEssenceAnger6"] = "Deafening Essence of Anger", + ["Metadata/Items/Currency/CurrencyEssenceAnguish1"] = "Wailing Essence of Anguish", + ["Metadata/Items/Currency/CurrencyEssenceAnguish2"] = "Screaming Essence of Anguish", + ["Metadata/Items/Currency/CurrencyEssenceAnguish3"] = "Shrieking Essence of Anguish", + ["Metadata/Items/Currency/CurrencyEssenceAnguish4"] = "Deafening Essence of Anguish", + ["Metadata/Items/Currency/CurrencyEssenceContempt1"] = "Whispering Essence of Contempt", + ["Metadata/Items/Currency/CurrencyEssenceContempt2"] = "Muttering Essence of Contempt", + ["Metadata/Items/Currency/CurrencyEssenceContempt3"] = "Weeping Essence of Contempt", + ["Metadata/Items/Currency/CurrencyEssenceContempt4"] = "Wailing Essence of Contempt", + ["Metadata/Items/Currency/CurrencyEssenceContempt5"] = "Screaming Essence of Contempt", + ["Metadata/Items/Currency/CurrencyEssenceContempt6"] = "Shrieking Essence of Contempt", + ["Metadata/Items/Currency/CurrencyEssenceContempt7"] = "Deafening Essence of Contempt", + ["Metadata/Items/Currency/CurrencyEssenceDelirium1"] = "Essence of Delirium", + ["Metadata/Items/Currency/CurrencyEssenceDoubt1"] = "Weeping Essence of Doubt", + ["Metadata/Items/Currency/CurrencyEssenceDoubt2"] = "Wailing Essence of Doubt", + ["Metadata/Items/Currency/CurrencyEssenceDoubt3"] = "Screaming Essence of Doubt", + ["Metadata/Items/Currency/CurrencyEssenceDoubt4"] = "Shrieking Essence of Doubt", + ["Metadata/Items/Currency/CurrencyEssenceDoubt5"] = "Deafening Essence of Doubt", + ["Metadata/Items/Currency/CurrencyEssenceDread1"] = "Screaming Essence of Dread", + ["Metadata/Items/Currency/CurrencyEssenceDread2"] = "Shrieking Essence of Dread", + ["Metadata/Items/Currency/CurrencyEssenceDread3"] = "Deafening Essence of Dread", + ["Metadata/Items/Currency/CurrencyEssenceEnvy1"] = "Screaming Essence of Envy", + ["Metadata/Items/Currency/CurrencyEssenceEnvy2"] = "Shrieking Essence of Envy", + ["Metadata/Items/Currency/CurrencyEssenceEnvy3"] = "Deafening Essence of Envy", + ["Metadata/Items/Currency/CurrencyEssenceFaridun1"] = "Essence of Desolation", + ["Metadata/Items/Currency/CurrencyEssenceFear1"] = "Muttering Essence of Fear", + ["Metadata/Items/Currency/CurrencyEssenceFear2"] = "Weeping Essence of Fear", + ["Metadata/Items/Currency/CurrencyEssenceFear3"] = "Wailing Essence of Fear", + ["Metadata/Items/Currency/CurrencyEssenceFear4"] = "Screaming Essence of Fear", + ["Metadata/Items/Currency/CurrencyEssenceFear5"] = "Shrieking Essence of Fear", + ["Metadata/Items/Currency/CurrencyEssenceFear6"] = "Deafening Essence of Fear", + ["Metadata/Items/Currency/CurrencyEssenceGreed1"] = "Whispering Essence of Greed", + ["Metadata/Items/Currency/CurrencyEssenceGreed2"] = "Muttering Essence of Greed", + ["Metadata/Items/Currency/CurrencyEssenceGreed3"] = "Weeping Essence of Greed", + ["Metadata/Items/Currency/CurrencyEssenceGreed4"] = "Wailing Essence of Greed", + ["Metadata/Items/Currency/CurrencyEssenceGreed5"] = "Screaming Essence of Greed", + ["Metadata/Items/Currency/CurrencyEssenceGreed6"] = "Shrieking Essence of Greed", + ["Metadata/Items/Currency/CurrencyEssenceGreed7"] = "Deafening Essence of Greed", + ["Metadata/Items/Currency/CurrencyEssenceHatred1"] = "Whispering Essence of Hatred", + ["Metadata/Items/Currency/CurrencyEssenceHatred2"] = "Muttering Essence of Hatred", + ["Metadata/Items/Currency/CurrencyEssenceHatred3"] = "Weeping Essence of Hatred", + ["Metadata/Items/Currency/CurrencyEssenceHatred4"] = "Wailing Essence of Hatred", + ["Metadata/Items/Currency/CurrencyEssenceHatred5"] = "Screaming Essence of Hatred", + ["Metadata/Items/Currency/CurrencyEssenceHatred6"] = "Shrieking Essence of Hatred", + ["Metadata/Items/Currency/CurrencyEssenceHatred7"] = "Deafening Essence of Hatred", + ["Metadata/Items/Currency/CurrencyEssenceHorror1"] = "Essence of Horror", + ["Metadata/Items/Currency/CurrencyEssenceHysteria1"] = "Essence of Hysteria", + ["Metadata/Items/Currency/CurrencyEssenceInsanity1"] = "Essence of Insanity", + ["Metadata/Items/Currency/CurrencyEssenceLoathing1"] = "Wailing Essence of Loathing", + ["Metadata/Items/Currency/CurrencyEssenceLoathing2"] = "Screaming Essence of Loathing", + ["Metadata/Items/Currency/CurrencyEssenceLoathing3"] = "Shrieking Essence of Loathing", + ["Metadata/Items/Currency/CurrencyEssenceLoathing4"] = "Deafening Essence of Loathing", + ["Metadata/Items/Currency/CurrencyEssenceMisery1"] = "Screaming Essence of Misery", + ["Metadata/Items/Currency/CurrencyEssenceMisery2"] = "Shrieking Essence of Misery", + ["Metadata/Items/Currency/CurrencyEssenceMisery3"] = "Deafening Essence of Misery", + ["Metadata/Items/Currency/CurrencyEssenceRage1"] = "Weeping Essence of Rage", + ["Metadata/Items/Currency/CurrencyEssenceRage2"] = "Wailing Essence of Rage", + ["Metadata/Items/Currency/CurrencyEssenceRage3"] = "Screaming Essence of Rage", + ["Metadata/Items/Currency/CurrencyEssenceRage4"] = "Shrieking Essence of Rage", + ["Metadata/Items/Currency/CurrencyEssenceRage5"] = "Deafening Essence of Rage", + ["Metadata/Items/Currency/CurrencyEssenceScorn1"] = "Screaming Essence of Scorn", + ["Metadata/Items/Currency/CurrencyEssenceScorn2"] = "Shrieking Essence of Scorn", + ["Metadata/Items/Currency/CurrencyEssenceScorn3"] = "Deafening Essence of Scorn", + ["Metadata/Items/Currency/CurrencyEssenceSorrow1"] = "Muttering Essence of Sorrow", + ["Metadata/Items/Currency/CurrencyEssenceSorrow2"] = "Weeping Essence of Sorrow", + ["Metadata/Items/Currency/CurrencyEssenceSorrow3"] = "Wailing Essence of Sorrow", + ["Metadata/Items/Currency/CurrencyEssenceSorrow4"] = "Screaming Essence of Sorrow", + ["Metadata/Items/Currency/CurrencyEssenceSorrow5"] = "Shrieking Essence of Sorrow", + ["Metadata/Items/Currency/CurrencyEssenceSorrow6"] = "Deafening Essence of Sorrow", + ["Metadata/Items/Currency/CurrencyEssenceSpite1"] = "Wailing Essence of Spite", + ["Metadata/Items/Currency/CurrencyEssenceSpite2"] = "Screaming Essence of Spite", + ["Metadata/Items/Currency/CurrencyEssenceSpite3"] = "Shrieking Essence of Spite", + ["Metadata/Items/Currency/CurrencyEssenceSpite4"] = "Deafening Essence of Spite", + ["Metadata/Items/Currency/CurrencyEssenceSuffering1"] = "Weeping Essence of Suffering", + ["Metadata/Items/Currency/CurrencyEssenceSuffering2"] = "Wailing Essence of Suffering", + ["Metadata/Items/Currency/CurrencyEssenceSuffering3"] = "Screaming Essence of Suffering", + ["Metadata/Items/Currency/CurrencyEssenceSuffering4"] = "Shrieking Essence of Suffering", + ["Metadata/Items/Currency/CurrencyEssenceSuffering5"] = "Deafening Essence of Suffering", + ["Metadata/Items/Currency/CurrencyEssenceTorment1"] = "Muttering Essence of Torment", + ["Metadata/Items/Currency/CurrencyEssenceTorment2"] = "Weeping Essence of Torment", + ["Metadata/Items/Currency/CurrencyEssenceTorment3"] = "Wailing Essence of Torment", + ["Metadata/Items/Currency/CurrencyEssenceTorment4"] = "Screaming Essence of Torment", + ["Metadata/Items/Currency/CurrencyEssenceTorment5"] = "Shrieking Essence of Torment", + ["Metadata/Items/Currency/CurrencyEssenceTorment6"] = "Deafening Essence of Torment", + ["Metadata/Items/Currency/CurrencyEssenceWoe1"] = "Whispering Essence of Woe", + ["Metadata/Items/Currency/CurrencyEssenceWoe2"] = "Muttering Essence of Woe", + ["Metadata/Items/Currency/CurrencyEssenceWoe3"] = "Weeping Essence of Woe", + ["Metadata/Items/Currency/CurrencyEssenceWoe4"] = "Wailing Essence of Woe", + ["Metadata/Items/Currency/CurrencyEssenceWoe5"] = "Screaming Essence of Woe", + ["Metadata/Items/Currency/CurrencyEssenceWoe6"] = "Shrieking Essence of Woe", + ["Metadata/Items/Currency/CurrencyEssenceWoe7"] = "Deafening Essence of Woe", + ["Metadata/Items/Currency/CurrencyEssenceWrath1"] = "Weeping Essence of Wrath", + ["Metadata/Items/Currency/CurrencyEssenceWrath2"] = "Wailing Essence of Wrath", + ["Metadata/Items/Currency/CurrencyEssenceWrath3"] = "Screaming Essence of Wrath", + ["Metadata/Items/Currency/CurrencyEssenceWrath4"] = "Shrieking Essence of Wrath", + ["Metadata/Items/Currency/CurrencyEssenceWrath5"] = "Deafening Essence of Wrath", + ["Metadata/Items/Currency/CurrencyEssenceZeal1"] = "Wailing Essence of Zeal", + ["Metadata/Items/Currency/CurrencyEssenceZeal2"] = "Screaming Essence of Zeal", + ["Metadata/Items/Currency/CurrencyEssenceZeal3"] = "Shrieking Essence of Zeal", + ["Metadata/Items/Currency/CurrencyEssenceZeal4"] = "Deafening Essence of Zeal", + ["Metadata/Items/Currency/CurrencyExtractOil"] = "Oil Extractor", + ["Metadata/Items/Currency/CurrencyFlaskQuality"] = "Glassblower's Bauble", + ["Metadata/Items/Currency/CurrencyFractureRare"] = "Fracturing Orb", + ["Metadata/Items/Currency/CurrencyFractureRareShard"] = "Fracturing Shard", + ["Metadata/Items/Currency/CurrencyGemQuality"] = "Gemcutter's Prism", + ["Metadata/Items/Currency/CurrencyGraftAddModToMagic"] = "Augmentation Implant", + ["Metadata/Items/Currency/CurrencyGraftAddModToRare"] = "Exalted Implant", + ["Metadata/Items/Currency/CurrencyGraftCorrupt"] = "Unstable Implant", + ["Metadata/Items/Currency/CurrencyGraftUpgradeMagicToRare"] = "Regal Implant", + ["Metadata/Items/Currency/CurrencyHarbingerBlessingBelt"] = "Time-light Scroll", + ["Metadata/Items/Currency/CurrencyHarbingerBlessingHelmet"] = "Deregulation Scroll", + ["Metadata/Items/Currency/CurrencyHarbingerBlessingQuiver"] = "Fragmentation Scroll", + ["Metadata/Items/Currency/CurrencyHarbingerBlessingShield"] = "Specularity Scroll", + ["Metadata/Items/Currency/CurrencyHarbingerBlessingStaff"] = "Haemocombustion Scroll", + ["Metadata/Items/Currency/CurrencyHarbingerBlessingSword"] = "Electroshock Scroll", + ["Metadata/Items/Currency/CurrencyHeistArmourEnchant"] = "Tailoring Orb", + ["Metadata/Items/Currency/CurrencyHeistWeaponEnchant"] = "Tempering Orb", + ["Metadata/Items/Currency/CurrencyHellscapeAddModToRare"] = "Tainted Exalted Orb", + ["Metadata/Items/Currency/CurrencyHellscapeArmourQuality"] = "Tainted Armourer's Scrap", + ["Metadata/Items/Currency/CurrencyHellscapeModValues"] = "Volatile Vaal Orb", + ["Metadata/Items/Currency/CurrencyHellscapeRerollRare"] = "Tainted Chaos Orb", + ["Metadata/Items/Currency/CurrencyHellscapeRerollSocketColours"] = "Tainted Chromatic Orb", + ["Metadata/Items/Currency/CurrencyHellscapeRerollSocketLinks"] = "Tainted Orb of Fusing", + ["Metadata/Items/Currency/CurrencyHellscapeRerollSocketNumbers"] = "Tainted Jeweller's Orb", + ["Metadata/Items/Currency/CurrencyHellscapeUpgradeModTier"] = "Tainted Divine Teardrop", + ["Metadata/Items/Currency/CurrencyHellscapeUpgradeToUnique"] = "Tainted Mythic Orb", + ["Metadata/Items/Currency/CurrencyHellscapeWeaponQuality"] = "Tainted Blacksmith's Whetstone", + ["Metadata/Items/Currency/CurrencyHinekorasLock"] = "Hinekora's Lock", + ["Metadata/Items/Currency/CurrencyIdentification"] = "Scroll of Wisdom", + ["Metadata/Items/Currency/CurrencyIdentificationShard"] = "Scroll Fragment", + ["Metadata/Items/Currency/CurrencyImprint"] = "Imprint", + ["Metadata/Items/Currency/CurrencyImprintOrb"] = "Eternal Orb", + ["Metadata/Items/Currency/CurrencyIncubationAbyss"] = "Abyssal Incubator", + ["Metadata/Items/Currency/CurrencyIncubationAbyssStackable"] = "Abyssal Incubator", + ["Metadata/Items/Currency/CurrencyIncubationArmour6Linked"] = "Geomancer's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationArmour6LinkedStackable"] = "Geomancer's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationArmourShaperElder"] = "Celestial Armoursmith's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationArmourShaperElderStackable"] = "Celestial Armoursmith's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationBestiary"] = "Feral Incubator", + ["Metadata/Items/Currency/CurrencyIncubationBestiaryStackable"] = "Feral Incubator", + ["Metadata/Items/Currency/CurrencyIncubationBlight"] = "Blighted Incubator", + ["Metadata/Items/Currency/CurrencyIncubationBlightStackable"] = "Blighted Incubator", + ["Metadata/Items/Currency/CurrencyIncubationBreach"] = "Obscured Incubator", + ["Metadata/Items/Currency/CurrencyIncubationBreachStackable"] = "Obscured Incubator", + ["Metadata/Items/Currency/CurrencyIncubationCurrency"] = "Fine Incubator", + ["Metadata/Items/Currency/CurrencyIncubationCurrencyMid"] = "Ornate Incubator", + ["Metadata/Items/Currency/CurrencyIncubationCurrencyMidStackable"] = "Ornate Incubator", + ["Metadata/Items/Currency/CurrencyIncubationCurrencyStackable"] = "Fine Incubator", + ["Metadata/Items/Currency/CurrencyIncubationDelirium"] = "Maddening Incubator", + ["Metadata/Items/Currency/CurrencyIncubationDeliriumStackable"] = "Maddening Incubator", + ["Metadata/Items/Currency/CurrencyIncubationDivination"] = "Diviner's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationDivinationStackable"] = "Diviner's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationEssence"] = "Whispering Incubator", + ["Metadata/Items/Currency/CurrencyIncubationEssenceHigh"] = "Infused Incubator", + ["Metadata/Items/Currency/CurrencyIncubationEssenceHighStackable"] = "Infused Incubator", + ["Metadata/Items/Currency/CurrencyIncubationEssenceStackable"] = "Whispering Incubator", + ["Metadata/Items/Currency/CurrencyIncubationFaridunHighStackable"] = "Sacred Incubator", + ["Metadata/Items/Currency/CurrencyIncubationFaridunLowStackable"] = "Honoured Incubator", + ["Metadata/Items/Currency/CurrencyIncubationFaridunMapStackable"] = "Miraged Incubator", + ["Metadata/Items/Currency/CurrencyIncubationFossils"] = "Fossilised Incubator", + ["Metadata/Items/Currency/CurrencyIncubationFossilsStackable"] = "Fossilised Incubator", + ["Metadata/Items/Currency/CurrencyIncubationFragments"] = "Fragmented Incubator", + ["Metadata/Items/Currency/CurrencyIncubationFragmentsStackable"] = "Fragmented Incubator", + ["Metadata/Items/Currency/CurrencyIncubationGem"] = "Thaumaturge's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationGemLow"] = "Gemcutter's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationGemLowStackable"] = "Gemcutter's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationGemStackable"] = "Thaumaturge's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationGeneric"] = "Mysterious Incubator", + ["Metadata/Items/Currency/CurrencyIncubationGenericStackable"] = "Mysterious Incubator", + ["Metadata/Items/Currency/CurrencyIncubationHarbingerShard"] = "Foreboding Incubator", + ["Metadata/Items/Currency/CurrencyIncubationHarbingerShardStackable"] = "Foreboding Incubator", + ["Metadata/Items/Currency/CurrencyIncubationLabyrinthHelm"] = "Enchanted Incubator", + ["Metadata/Items/Currency/CurrencyIncubationLabyrinthHelmStackable"] = "Enchanted Incubator", + ["Metadata/Items/Currency/CurrencyIncubationMapElder"] = "Eldritch Incubator", + ["Metadata/Items/Currency/CurrencyIncubationMapElderStackable"] = "Eldritch Incubator", + ["Metadata/Items/Currency/CurrencyIncubationMaps"] = "Cartographer's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationMapsStackable"] = "Cartographer's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationMetamorph"] = "Challenging Incubator", + ["Metadata/Items/Currency/CurrencyIncubationMetamorphStackable"] = "Challenging Incubator", + ["Metadata/Items/Currency/CurrencyIncubationPerandus"] = "Kalguuran Incubator", + ["Metadata/Items/Currency/CurrencyIncubationPerandusStackable"] = "Kalguuran Incubator", + ["Metadata/Items/Currency/CurrencyIncubationScarabs"] = "Skittering Incubator", + ["Metadata/Items/Currency/CurrencyIncubationScarabsStackable"] = "Skittering Incubator", + ["Metadata/Items/Currency/CurrencyIncubationTalismans"] = "Primal Incubator", + ["Metadata/Items/Currency/CurrencyIncubationTalismansStackable"] = "Primal Incubator", + ["Metadata/Items/Currency/CurrencyIncubationTrinketShaperElder"] = "Celestial Jeweller's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationTrinketShaperElderStackable"] = "Celestial Jeweller's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationUniqueLeague"] = "Time-Lost Incubator", + ["Metadata/Items/Currency/CurrencyIncubationUniqueLeagueStackable"] = "Time-Lost Incubator", + ["Metadata/Items/Currency/CurrencyIncubationUniqueMaps"] = "Otherworldly Incubator", + ["Metadata/Items/Currency/CurrencyIncubationUniqueMapsStackable"] = "Otherworldly Incubator", + ["Metadata/Items/Currency/CurrencyIncubationUniques"] = "Singular Incubator", + ["Metadata/Items/Currency/CurrencyIncubationUniquesStackable"] = "Singular Incubator", + ["Metadata/Items/Currency/CurrencyIncubationWeaponShaperElder"] = "Celestial Blacksmith's Incubator", + ["Metadata/Items/Currency/CurrencyIncubationWeaponShaperElderStackable"] = "Celestial Blacksmith's Incubator", + ["Metadata/Items/Currency/CurrencyIncursionCorrupt1"] = "Corrupt", + ["Metadata/Items/Currency/CurrencyIncursionCorrupt2"] = "Corrupt", + ["Metadata/Items/Currency/CurrencyIncursionCorruptGem"] = "Corrupt", + ["Metadata/Items/Currency/CurrencyIncursionVialBossAmulet"] = "Vial of Sacrifice", + ["Metadata/Items/Currency/CurrencyIncursionVialBossFlask"] = "Vial of the Ghost", + ["Metadata/Items/Currency/CurrencyIncursionVialBossJewel"] = "Vial of Transcendence", + ["Metadata/Items/Currency/CurrencyIncursionVialFire"] = "Vial of Fate", + ["Metadata/Items/Currency/CurrencyIncursionVialHealing"] = "Vial of Summoning", + ["Metadata/Items/Currency/CurrencyIncursionVialLightning"] = "Vial of the Ritual", + ["Metadata/Items/Currency/CurrencyIncursionVialMinion"] = "Vial of Consequence", + ["Metadata/Items/Currency/CurrencyIncursionVialPoison"] = "Vial of Awakening", + ["Metadata/Items/Currency/CurrencyIncursionVialTrap"] = "Vial of Dominance", + ["Metadata/Items/Currency/CurrencyInstillingOrb"] = "Instilling Orb", + ["Metadata/Items/Currency/CurrencyItemiseCapturedMonster"] = "Bestiary Orb", + ["Metadata/Items/Currency/CurrencyItemiseNecropolisCorpse"] = "Empty Coffin", + ["Metadata/Items/Currency/CurrencyItemiseSextantModifier"] = "Surveyor's Compass", + ["Metadata/Items/Currency/CurrencyItemisedCapturedMonster"] = "Imprinted Bestiary Orb", + ["Metadata/Items/Currency/CurrencyItemisedNecropolisCorpse"] = "Filled Coffin", + ["Metadata/Items/Currency/CurrencyItemisedProphecy"] = "Prophecy", + ["Metadata/Items/Currency/CurrencyItemisedSextantModifier"] = "Charged Compass", + ["Metadata/Items/Currency/CurrencyJewelleryQualityAttack"] = "Abrasive Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityAttribute"] = "Intrinsic Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityCaster"] = "Imbued Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityCritical"] = "Unstable Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityDefense"] = "Tempering Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityElemental"] = "Turbulent Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityPhysicalChaos"] = "Noxious Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityPrefix"] = "Sinistral Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityResistance"] = "Prismatic Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityResource"] = "Fertile Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualitySpeed"] = "Accelerating Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualitySuffix"] = "Dextral Catalyst", + ["Metadata/Items/Currency/CurrencyJewelleryQualityVaal"] = "Tainted Catalyst", + ["Metadata/Items/Currency/CurrencyLabyrinthEnchant"] = "Enchant", + ["Metadata/Items/Currency/CurrencyLabyrinthEnchantCorrupt"] = "Tainted Blessing", + ["Metadata/Items/Currency/CurrencyLegionEternalEmpireShard"] = "Timeless Eternal Empire Splinter", + ["Metadata/Items/Currency/CurrencyLegionKaruiShard"] = "Timeless Karui Splinter", + ["Metadata/Items/Currency/CurrencyLegionMarakethShard"] = "Timeless Maraketh Splinter", + ["Metadata/Items/Currency/CurrencyLegionTemplarShard"] = "Timeless Templar Splinter", + ["Metadata/Items/Currency/CurrencyLegionVaalShard"] = "Timeless Vaal Splinter", + ["Metadata/Items/Currency/CurrencyMapQuality"] = "Cartographer's Chisel", + ["Metadata/Items/Currency/CurrencyMapQualityCurrency"] = "Maven's Chisel of Avarice", + ["Metadata/Items/Currency/CurrencyMapQualityDivinationCards"] = "Maven's Chisel of Divination", + ["Metadata/Items/Currency/CurrencyMapQualityPackSize"] = "Maven's Chisel of Proliferation", + ["Metadata/Items/Currency/CurrencyMapQualityRarity"] = "Maven's Chisel of Procurement", + ["Metadata/Items/Currency/CurrencyMapQualityScarabs"] = "Maven's Chisel of Scarabs", + ["Metadata/Items/Currency/CurrencyModValues"] = "Divine Orb", + ["Metadata/Items/Currency/CurrencyMoreCorrupt"] = "Djinn-Touched Vaal Orb", + ["Metadata/Items/Currency/CurrencyMoreZanaInfluencedItems"] = "Orb of Intention", + ["Metadata/Items/Currency/CurrencyMutatedAddModToMagic"] = "Foulborn Orb of Augmentation", + ["Metadata/Items/Currency/CurrencyMutatedAddModToRare"] = "Foulborn Exalted Orb", + ["Metadata/Items/Currency/CurrencyMutatedUpgradeMagicToRare"] = "Foulborn Regal Orb", + ["Metadata/Items/Currency/CurrencyPassiveRefund"] = "Orb of Regret", + ["Metadata/Items/Currency/CurrencyPerandusCoin"] = "Perandus Coin", + ["Metadata/Items/Currency/CurrencyPortal"] = "Portal Scroll", + ["Metadata/Items/Currency/CurrencyRefreshBarter"] = "Exotic Coinage", + ["Metadata/Items/Currency/CurrencyRefreshDealer"] = "Scrap Metal", + ["Metadata/Items/Currency/CurrencyRefreshGambler"] = "Astragali", + ["Metadata/Items/Currency/CurrencyRefreshSaga"] = "Burial Medallion", + ["Metadata/Items/Currency/CurrencyRemoveMod"] = "Orb of Annulment", + ["Metadata/Items/Currency/CurrencyRemoveModShard"] = "Annulment Shard", + ["Metadata/Items/Currency/CurrencyRemoveZanaInfluence"] = "Orb of Unravelling", + ["Metadata/Items/Currency/CurrencyRerollDefences"] = "Sacred Orb", + ["Metadata/Items/Currency/CurrencyRerollGem"] = "Gemcutters Lens", + ["Metadata/Items/Currency/CurrencyRerollImplicit"] = "Blessed Orb", + ["Metadata/Items/Currency/CurrencyRerollMagic"] = "Orb of Alteration", + ["Metadata/Items/Currency/CurrencyRerollMagicShard"] = "Alteration Shard", + ["Metadata/Items/Currency/CurrencyRerollMapType"] = "Orb of Horizons", + ["Metadata/Items/Currency/CurrencyRerollMapTypeShard"] = "Horizon Shard", + ["Metadata/Items/Currency/CurrencyRerollRare"] = "Chaos Orb", + ["Metadata/Items/Currency/CurrencyRerollRareShard"] = "Chaos Shard", + ["Metadata/Items/Currency/CurrencyRerollRareVeiled"] = "Veiled Exalted Orb", + ["Metadata/Items/Currency/CurrencyRerollRareVeiledChaos"] = "Veiled Chaos Orb", + ["Metadata/Items/Currency/CurrencyRerollSkillQualityType"] = "Prime Regrading Lens", + ["Metadata/Items/Currency/CurrencyRerollSocketColours"] = "Chromatic Orb", + ["Metadata/Items/Currency/CurrencyRerollSocketLinks"] = "Orb of Fusing", + ["Metadata/Items/Currency/CurrencyRerollSocketNumbers"] = "Jeweller's Orb", + ["Metadata/Items/Currency/CurrencyRerollSupportQualityType"] = "Secondary Regrading Lens", + ["Metadata/Items/Currency/CurrencyRerollUnique"] = "Ancient Orb", + ["Metadata/Items/Currency/CurrencyRerollUniqueShard"] = "Ancient Shard", + ["Metadata/Items/Currency/CurrencyRespecShapersOrb"] = "Unshaping Orb", + ["Metadata/Items/Currency/CurrencyRhoaFeather"] = "Albino Rhoa Feather", + ["Metadata/Items/Currency/CurrencyRitualSplinter"] = "Ritual Splinter", + ["Metadata/Items/Currency/CurrencyRitualStone"] = "Ritual Vessel", + ["Metadata/Items/Currency/CurrencyScryingOrb"] = "Scrying Orb", + ["Metadata/Items/Currency/CurrencySealMapHigh"] = "Master Cartographer's Seal", + ["Metadata/Items/Currency/CurrencySealMapLow"] = "Apprentice Cartographer's Seal", + ["Metadata/Items/Currency/CurrencySealMapMid"] = "Journeyman Cartographer's Seal", + ["Metadata/Items/Currency/CurrencySilverCoin"] = "Silver Coin", + ["Metadata/Items/Currency/CurrencySkillGemToken"] = "Uncarved Gemstone", + ["Metadata/Items/Currency/CurrencyStackedScarab"] = "Veiled Scarab", + ["Metadata/Items/Currency/CurrencyStrongboxQuality"] = "Engineer's Orb", + ["Metadata/Items/Currency/CurrencyStrongboxQualityInfused"] = "Infused Engineer's Orb", + ["Metadata/Items/Currency/CurrencyStrongboxQualityShard"] = "Engineer's Shard", + ["Metadata/Items/Currency/CurrencyUpgradeInfluenceMod"] = "Orb of Dominance", + ["Metadata/Items/Currency/CurrencyUpgradeMagicToRare"] = "Regal Orb", + ["Metadata/Items/Currency/CurrencyUpgradeMagicToRareShard"] = "Regal Shard", + ["Metadata/Items/Currency/CurrencyUpgradeMapTier"] = "Harbinger's Orb", + ["Metadata/Items/Currency/CurrencyUpgradeMapTierShard"] = "Harbinger's Shard", + ["Metadata/Items/Currency/CurrencyUpgradeRandomly"] = "Orb of Chance", + ["Metadata/Items/Currency/CurrencyUpgradeToMagic"] = "Orb of Transmutation", + ["Metadata/Items/Currency/CurrencyUpgradeToMagicShard"] = "Transmutation Shard", + ["Metadata/Items/Currency/CurrencyUpgradeToRare"] = "Orb of Alchemy", + ["Metadata/Items/Currency/CurrencyUpgradeToRareAndSetSockets"] = "Orb of Binding", + ["Metadata/Items/Currency/CurrencyUpgradeToRareAndSetSocketsShard"] = "Binding Shard", + ["Metadata/Items/Currency/CurrencyUpgradeToRareShard"] = "Alchemy Shard", + ["Metadata/Items/Currency/CurrencyValdoPuzzleBox"] = "Valdo's Puzzle Box", + ["Metadata/Items/Currency/CurrencyWeaponQuality"] = "Blacksmith's Whetstone", + ["Metadata/Items/Currency/CurrencyWishConvertUnique"] = "Coin of Restoration", + ["Metadata/Items/Currency/CurrencyWishConvertUniqueCorrupt"] = "Coin of Desecration", + ["Metadata/Items/Currency/CurrencyWishSupportGemBlue"] = "Coin of Knowledge", + ["Metadata/Items/Currency/CurrencyWishSupportGemGreen"] = "Coin of Skill", + ["Metadata/Items/Currency/CurrencyWishSupportGemRed"] = "Coin of Power", + ["Metadata/Items/Currency/FearMemoryThread"] = "Memory of Trauma", + ["Metadata/Items/Currency/GoldCoin"] = "Gold", + ["Metadata/Items/Currency/HarvestSeedBlue"] = "Primal Crystallised Lifeforce", + ["Metadata/Items/Currency/HarvestSeedBoss"] = "Sacred Crystallised Lifeforce", + ["Metadata/Items/Currency/HarvestSeedFaridun"] = "Crystallised Rancour", + ["Metadata/Items/Currency/HarvestSeedGreen"] = "Vivid Crystallised Lifeforce", + ["Metadata/Items/Currency/HarvestSeedRed"] = "Wild Crystallised Lifeforce", + ["Metadata/Items/Currency/IgnoranceMemoryThread"] = "Memory of Loneliness", + ["Metadata/Items/Currency/KalguuranRune1"] = "Sun Rune", + ["Metadata/Items/Currency/KalguuranRune10"] = "Power Rune", + ["Metadata/Items/Currency/KalguuranRune2"] = "Bound Rune", + ["Metadata/Items/Currency/KalguuranRune3"] = "Life Rune", + ["Metadata/Items/Currency/KalguuranRune4"] = "War Rune", + ["Metadata/Items/Currency/KalguuranRune5"] = "River Rune", + ["Metadata/Items/Currency/KalguuranRune6"] = "Bounty Rune", + ["Metadata/Items/Currency/KalguuranRune7"] = "Journey Rune", + ["Metadata/Items/Currency/KalguuranRune8"] = "Mountain Rune", + ["Metadata/Items/Currency/KalguuranRune9"] = "Time Rune", + ["Metadata/Items/Currency/LegionCocoonBodyArmour"] = "Maraketh Enshrouding Crystal", + ["Metadata/Items/Currency/LegionCocoonBoots"] = "Imperial Enshrouding Crystal", + ["Metadata/Items/Currency/LegionCocoonGloves"] = "Karui Enshrouding Crystal", + ["Metadata/Items/Currency/LegionCocoonHelmet"] = "Vaal Enshrouding Crystal", + ["Metadata/Items/Currency/LegionCocoonShield"] = "Templar Enshrouding Crystal", + ["Metadata/Items/Currency/Mushrune1"] = "Clear Oil", + ["Metadata/Items/Currency/Mushrune10"] = "Opalescent Oil", + ["Metadata/Items/Currency/Mushrune11"] = "Silver Oil", + ["Metadata/Items/Currency/Mushrune12"] = "Golden Oil", + ["Metadata/Items/Currency/Mushrune2"] = "Sepia Oil", + ["Metadata/Items/Currency/Mushrune3"] = "Amber Oil", + ["Metadata/Items/Currency/Mushrune4"] = "Verdant Oil", + ["Metadata/Items/Currency/Mushrune5"] = "Teal Oil", + ["Metadata/Items/Currency/Mushrune6"] = "Azure Oil", + ["Metadata/Items/Currency/Mushrune6b"] = "Indigo Oil", + ["Metadata/Items/Currency/Mushrune7"] = "Violet Oil", + ["Metadata/Items/Currency/Mushrune8"] = "Crimson Oil", + ["Metadata/Items/Currency/Mushrune9"] = "Black Oil", + ["Metadata/Items/Currency/MushruneCorrupt"] = "Tainted Oil", + ["Metadata/Items/Currency/MushruneMirror"] = "Reflective Oil", + ["Metadata/Items/Currency/MushruneUber"] = "Prismatic Oil", + ["Metadata/Items/Currency/ReflectiveMist"] = "Reflecting Mist", + ["Metadata/Items/Currency/ReflectiveMistWeak"] = "Fading Reflecting Mist", + ["Metadata/Items/Currency/RunegraftAilmentRedirect"] = "Runegraft of Loyalty", + ["Metadata/Items/Currency/RunegraftAttributeGlobalDefences"] = "Runegraft of the Fortress", + ["Metadata/Items/Currency/RunegraftBootsGloves"] = "Runegraft of the Bound", + ["Metadata/Items/Currency/RunegraftBuffScaling"] = "Runegraft of the Warp", + ["Metadata/Items/Currency/RunegraftChainMana"] = "Runegraft of Refraction", + ["Metadata/Items/Currency/RunegraftConnection"] = "Runegraft of Connection", + ["Metadata/Items/Currency/RunegraftConsecratedGround"] = "Runegraft of Consecration", + ["Metadata/Items/Currency/RunegraftCooldownRefresh"] = "Runegraft of Time", + ["Metadata/Items/Currency/RunegraftCritRecoup"] = "Runegraft of Restitching", + ["Metadata/Items/Currency/RunegraftDamagePerSocket"] = "Runegraft of the Jeweller", + ["Metadata/Items/Currency/RunegraftElusive"] = "Runegraft of the Agile", + ["Metadata/Items/Currency/RunegraftFishing"] = "Runegraft of the Angler", + ["Metadata/Items/Currency/RunegraftFlatOffhandAttackTime"] = "Runegraft of the Sinistral", + ["Metadata/Items/Currency/RunegraftFortificationBanner"] = "Runegraft of Rallying", + ["Metadata/Items/Currency/RunegraftLifeFlaskRage"] = "Runegraft of Fury", + ["Metadata/Items/Currency/RunegraftLifeFromManaFlasks"] = "Runegraft of Quaffing", + ["Metadata/Items/Currency/RunegraftLowLifeRestore"] = "Runegraft of the River", + ["Metadata/Items/Currency/RunegraftMatchedAttackDamage"] = "Runegraft of the Combatant", + ["Metadata/Items/Currency/RunegraftMatchedSpeed"] = "[DNT - UNUSED] Limiting Runegraft", + ["Metadata/Items/Currency/RunegraftMinionCannotAttack"] = "[DNT - UNUSED] Arcane Orders Runegraft", + ["Metadata/Items/Currency/RunegraftMinionCannotCast"] = "[DNT - UNUSED] Martial Orders Runegraft", + ["Metadata/Items/Currency/RunegraftNovaMarkedTarget"] = "Runegraft of the Novamark", + ["Metadata/Items/Currency/RunegraftOffhandInvert"] = "Runegraft of the Gauche", + ["Metadata/Items/Currency/RunegraftPoisonConversion"] = "Runegraft of Rotblood", + ["Metadata/Items/Currency/RunegraftRandomCurse"] = "Runegraft of Blasphemy", + ["Metadata/Items/Currency/RunegraftResurgence"] = "Runegraft of Resurgence", + ["Metadata/Items/Currency/RunegraftSouls"] = "Runegraft of the Soulwick", + ["Metadata/Items/Currency/RunegraftSpellLifeCost"] = "Runegraft of the Witchmark", + ["Metadata/Items/Currency/RunegraftSpellbound"] = "Runegraft of the Spellbound", + ["Metadata/Items/Currency/RunegraftSuffering"] = "Runegraft of Suffering", + ["Metadata/Items/Currency/RunegraftSupportLevels"] = "Runegraft of Gemcraft", + ["Metadata/Items/Currency/RunegraftTest"] = "[DNT - UNUSED] Test Runegraft", + ["Metadata/Items/Currency/RunegraftTinctures"] = "Runegraft of the Imbued", + ["Metadata/Items/Currency/RunegraftTreacherousAuras"] = "Runegraft of Treachery", + ["Metadata/Items/Currency/RunegraftUnexciting"] = "Runegraft of Stability", + ["Metadata/Items/Currency/RunegraftWarcrySpeed"] = "Runegraft of Bellows", + ["Metadata/Items/Currency/SanctumCurrencyAcrobatics"] = "Lycia's Invocation of Acrobatics", + ["Metadata/Items/Currency/SanctumCurrencyAncestralBond"] = "Lycia's Invocation of Ancestral Bond", + ["Metadata/Items/Currency/SanctumCurrencyArrowDancing"] = "Lycia's Invocation of Arrow Dancing", + ["Metadata/Items/Currency/SanctumCurrencyAvatarOfFire"] = "Lycia's Invocation of Avatar of Fire", + ["Metadata/Items/Currency/SanctumCurrencyBloodMagic"] = "Lycia's Invocation of Blood Magic", + ["Metadata/Items/Currency/SanctumCurrencyCallToArms"] = "Lycia's Invocation of Call to Arms", + ["Metadata/Items/Currency/SanctumCurrencyConduit"] = "Lycia's Invocation of Conduit", + ["Metadata/Items/Currency/SanctumCurrencyCrimsonDance"] = "Lycia's Invocation of Crimson Dance", + ["Metadata/Items/Currency/SanctumCurrencyDivineShield"] = "Lycia's Invocation of Divine Shield", + ["Metadata/Items/Currency/SanctumCurrencyDoomsday"] = "Lycia's Invocation of Hex Master", + ["Metadata/Items/Currency/SanctumCurrencyEldritchBattery"] = "Lycia's Invocation of Eldritch Battery", + ["Metadata/Items/Currency/SanctumCurrencyElementalEquilibrium"] = "Lycia's Invocation of Elemental Equilibrium", + ["Metadata/Items/Currency/SanctumCurrencyElementalOverload"] = "Lycia's Invocation of Elemental Overload", + ["Metadata/Items/Currency/SanctumCurrencyEternalYouth"] = "Lycia's Invocation of Eternal Youth", + ["Metadata/Items/Currency/SanctumCurrencyGhostDance"] = "Lycia's Invocation of Ghost Dance", + ["Metadata/Items/Currency/SanctumCurrencyGhostReaver"] = "Lycia's Invocation of Ghost Reaver", + ["Metadata/Items/Currency/SanctumCurrencyGlancingBlows"] = "Lycia's Invocation of Glancing Blows", + ["Metadata/Items/Currency/SanctumCurrencyImbalancedGuard"] = "Lycia's Invocation of Imbalanced Guard", + ["Metadata/Items/Currency/SanctumCurrencyIronGrip"] = "Lycia's Invocation of Iron Grip", + ["Metadata/Items/Currency/SanctumCurrencyIronReflexes"] = "Lycia's Invocation of Iron Reflexes", + ["Metadata/Items/Currency/SanctumCurrencyIronWill"] = "Lycia's Invocation of Iron Will", + ["Metadata/Items/Currency/SanctumCurrencyLetheShade"] = "Lycia's Invocation of Lethe Shade", + ["Metadata/Items/Currency/SanctumCurrencyMagebane"] = "Lycia's Invocation of Magebane", + ["Metadata/Items/Currency/SanctumCurrencyMindoverMatter"] = "Lycia's Invocation of Mind over Matter", + ["Metadata/Items/Currency/SanctumCurrencyMinionInstability"] = "Lycia's Invocation of Minion Instability", + ["Metadata/Items/Currency/SanctumCurrencyPainAttunement"] = "Lycia's Invocation of Pain Attunement", + ["Metadata/Items/Currency/SanctumCurrencyPerfectAgony"] = "Lycia's Invocation of Perfect Agony", + ["Metadata/Items/Currency/SanctumCurrencyPointBlank"] = "Lycia's Invocation of Point Blank", + ["Metadata/Items/Currency/SanctumCurrencyPreciseTechnique"] = "Lycia's Invocation of Precise Technique", + ["Metadata/Items/Currency/SanctumCurrencyResoluteTechnique"] = "Lycia's Invocation of Resolute Technique", + ["Metadata/Items/Currency/SanctumCurrencyRunebinder"] = "Lycia's Invocation of Runebinder", + ["Metadata/Items/Currency/SanctumCurrencySolipsism"] = "Lycia's Invocation of Solipsism", + ["Metadata/Items/Currency/SanctumCurrencySupremeEgo"] = "Lycia's Invocation of Supreme Ego", + ["Metadata/Items/Currency/SanctumCurrencyTheAgnostic"] = "Lycia's Invocation of the Agnostic", + ["Metadata/Items/Currency/SanctumCurrencyTheImpaler"] = "Lycia's Invocation of the Impaler", + ["Metadata/Items/Currency/SanctumCurrencyUnwaveringStance"] = "Lycia's Invocation of Unwavering Stance", + ["Metadata/Items/Currency/SanctumCurrencyVaalPact"] = "Lycia's Invocation of Vaal Pact", + ["Metadata/Items/Currency/SanctumCurrencyVersatileCombatant"] = "Lycia's Invocation of Versatile Combatant", + ["Metadata/Items/Currency/SanctumCurrencyWickedWard"] = "Lycia's Invocation of Wicked Ward", + ["Metadata/Items/Currency/SanctumCurrencyWindDancer"] = "Lycia's Invocation of Wind Dancer", + ["Metadata/Items/Currency/SanctumCurrencyZealotsOath"] = "Lycia's Invocation of Zealot's Oath", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportBlighted"] = "Blighted Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportBreachstone"] = "Otherworldly Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportCorrupted"] = "Vaal Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportDelirium"] = "Delirious Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportExplorers"] = "Explorer's Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportGuardian"] = "Influenced Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportJuiced"] = "Operative's Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportMoreHidden"] = "Comprehensive Scouting Report", + ["Metadata/Items/Currency/ScoutingReports/AtlasScoutingReportUnique"] = "Singular Scouting Report", + ["Metadata/Items/Currency/SentinelCurrencyAddMod"] = "Augmenting Power Core", + ["Metadata/Items/Currency/SentinelCurrencyArmour"] = "Armour Recombinator", + ["Metadata/Items/Currency/SentinelCurrencyBasic"] = "Power Core", + ["Metadata/Items/Currency/SentinelCurrencyJewellery"] = "Jewellery Recombinator", + ["Metadata/Items/Currency/SentinelCurrencyMutate"] = "Transforming Power Core", + ["Metadata/Items/Currency/SentinelCurrencyUpgradeMod"] = "Amplifying Power Core", + ["Metadata/Items/Currency/SentinelCurrencyWeapon"] = "Weapon Recombinator", +} diff --git a/src/Export/Scripts/miscdata.lua b/src/Export/Scripts/miscdata.lua index fd0cb2863bf..c3a15088e4b 100644 --- a/src/Export/Scripts/miscdata.lua +++ b/src/Export/Scripts/miscdata.lua @@ -1,3 +1,5 @@ +---@module "Modules.Utils" +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') @@ -141,4 +143,11 @@ out:write('}\n') out:close() +local currencies = {} +for row in dat("BaseItemTypes"):Rows() do + if row.Id:find("^Metadata/Items/Currency/") and row.Name ~= "" then + currencies[row.Id] = row.Name + end +end +utils.saveTableToFile("../Data/CurrencyNames.lua", currencies, "This file contains mapping item names for every currency base item type ID.\nUsed for working with the currency exchange which uses item type IDs.") print("Misc data exported.") From b397a400d1f95885fd6e4e72bf41616f46655d15 Mon Sep 17 00:00:00 2001 From: vaisest <4550061+vaisest@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:16:57 +0300 Subject: [PATCH 2/2] Add basic tests --- spec/System/TestTradeQueryCurrency_spec.lua | 147 ++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/spec/System/TestTradeQueryCurrency_spec.lua b/spec/System/TestTradeQueryCurrency_spec.lua index 103191453f7..051f92135cb 100644 --- a/spec/System/TestTradeQueryCurrency_spec.lua +++ b/spec/System/TestTradeQueryCurrency_spec.lua @@ -50,6 +50,153 @@ describe("TradeQuery Currency Conversion", function() end) + describe("PullCXData", function() + local dkjson = require("dkjson") + + -- base type ids the currency exchange uses + local DIVINE = "Metadata/Items/Currency/CurrencyModValues" + local CHAOS = "Metadata/Items/Currency/CurrencyRerollRare" + local EXALT = "Metadata/Items/Currency/CurrencyAddModToRare" + local ALCH = "Metadata/Items/Currency/CurrencyUpgradeToRare" + + -- static trade data: maps display name -> short trade id + local static = { + result = { { + entries = { + { id = "sep", text = "" }, -- separator, must be ignored + { id = "divine", text = "Divine Orb" }, + { id = "chaos", text = "Chaos Orb" }, + { id = "exalt", text = "Exalted Orb" }, + { id = "alch", text = "Orb of Alchemy" }, + } + } } + } + + local origDownloadPage, origApi + + before_each(function() + mock_tradeQuery.pbRealm = "pc" + mock_tradeQuery.controls.pbNotice = {} + origDownloadPage = launch.DownloadPage + origApi = main.api + -- static trade data is fetched first via launch:DownloadPage + launch.DownloadPage = function(_, _url, callback) + callback({ body = dkjson.encode(static) }) + end + end) + + after_each(function() + launch.DownloadPage = origDownloadPage + main.api = origApi + end) + + -- helper: make main.api:FetchCurrencyExchange feed the given markets back + local function mockCX(markets) + main.api = { + FetchCurrencyExchange = function(_, _realm, callback) + callback({ body = dkjson.encode({ markets = markets }) }) + end + } + end + + it("converts a chained market to divine values", function() + mockCX({ + -- exalt -> divine directly (1 exalt = 0.1 div) + { + league = "Standard", + market_pair = { EXALT, DIVINE }, + lowest_ratio = { [EXALT] = 10, [DIVINE] = 1 }, + highest_stock = { [EXALT] = 100, [DIVINE] = 100 }, + }, + -- chaos -> divine directly (1 chaos = 0.005 div) + { + league = "Standard", + market_pair = { CHAOS, DIVINE }, + lowest_ratio = { [CHAOS] = 200, [DIVINE] = 1 }, + highest_stock = { [CHAOS] = 500, [DIVINE] = 500 }, + }, + -- alch -> chaos (1 alch = 0.2 chaos), needs a second hop to divine + { + league = "Standard", + market_pair = { ALCH, CHAOS }, + lowest_ratio = { [ALCH] = 5, [CHAOS] = 1 }, + highest_stock = { [ALCH] = 1000, [CHAOS] = 1000 }, + }, + }) + + mock_tradeQuery:PullCXData() + + local rates = mock_tradeQuery.pbCurrencyConversion.pc.Standard + assert.is_not_nil(rates) + assert.are.equal(1, rates.divine) + assert.are.equal(0.1, rates.exalt) + assert.are.equal(0.005, rates.chaos) + -- 0.2 chaos * 0.005 div/chaos = 0.001 div + assert.are.equal(0.001, rates.alch) + end) + + it("keeps the highest-stock listing for a currency", function() + mockCX({ + { + league = "Standard", + market_pair = { EXALT, DIVINE }, + lowest_ratio = { [EXALT] = 10, [DIVINE] = 1 }, -- 0.1 div + highest_stock = { [EXALT] = 50, [DIVINE] = 5 }, + }, + { + league = "Standard", + market_pair = { EXALT, DIVINE }, + lowest_ratio = { [EXALT] = 5, [DIVINE] = 1 }, -- 0.2 div + highest_stock = { [EXALT] = 200, [DIVINE] = 40 }, -- more stock, wins + }, + }) + + mock_tradeQuery:PullCXData() + + assert.are.equal(0.2, mock_tradeQuery.pbCurrencyConversion.pc.Standard.exalt) + end) + + it("skips listings with a zero ratio", function() + mockCX({ + { + league = "Standard", + market_pair = { EXALT, DIVINE }, + lowest_ratio = { [EXALT] = 0, [DIVINE] = 1 }, + highest_stock = { [EXALT] = 100, [DIVINE] = 100 }, + }, + }) + + mock_tradeQuery:PullCXData() + + -- league had no usable listings, so it should not appear + assert.is_nil(mock_tradeQuery.pbCurrencyConversion.pc.Standard) + end) + + it("shows a notice on an API error response", function() + main.api = { + FetchCurrencyExchange = function(_, _realm, callback) + callback({ body = dkjson.encode({ error = { message = "kaput" } }) }) + end + } + + mock_tradeQuery:PullCXData() + + assert.are.equal("CX error: kaput", mock_tradeQuery.controls.pbNotice.label) + assert.is_nil(mock_tradeQuery.pbCurrencyConversion.pc) + end) + + it("does not refetch within the rate-limit window", function() + mock_tradeQuery.pbCurrencyConversion.pc = { timestamp = os.time() } + local fetched = false + main.api = { + FetchCurrencyExchange = function() fetched = true end + } + + mock_tradeQuery:PullCXData() + + assert.is_false(fetched) + end) + end) describe("GetTotalPriceString", function() -- Pass: Sums and formats correctly (e.g., "5 chaos, 10 div", should be most valuable currency first) -- Fail: Wrong string (e.g., unsorted/missing sums), indicating aggregation bug, misleading users on totals