Module:Item/recipes

From Path of Exile 2 Wiki
Jump to navigation Jump to search
Module documentation[view] [edit] [history] [purge]


Lua logo

This module depends on the following other modules:

This submodule of Module:Item contains configuration and functions for item recipes.

-------------------------------------------------------------------------------
-- 
-- Recipes for Module:Item2
-- 
-------------------------------------------------------------------------------

local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')

local m_game = mw.loadData('Module:Game')

-- Lazy loading
local f_modifier_link -- require('Module:Modifier link').modifier_link

-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Item2')

-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = use_sandbox and mw.loadData('Module:Item2/config/sandbox') or mw.loadData('Module:Item2/config')

local i18n = cfg.i18n.recipes

-- ----------------------------------------------------------------------------
-- Helper functions 
-- ----------------------------------------------------------------------------

local h = {}

-- Lazy loading for Module:Modifier link
function h.modifier_link(args)
    if not f_modifier_link then
        f_modifier_link = require('Module:Modifier link').main
    end
    return f_modifier_link(args)
end

h.conditions = {}
h.conditions.factory = {}

function h.conditions.factory.arg(args)
    -- Required:
    --  arg: The argument to check against
    --  One must be specified
    --   value: check whether the argument equals this value
    --   values: check whether the argument is in this list of values
    --   values_assoc: check whether the argument is in this associative table
    --
    -- Optional:
    --  negate: negates the check against the value, i.e. whether the value is not equal or not in the list/table.
    args = args or {}
    
    -- Inner type of function depending on whether to check a single value, a list of values or an associative list of values
    local inner
    if args.value ~= nil then
        inner = function (tpl)
            return tpl == args.value
        end
    elseif args.values ~= nil then
        inner = function (tpl)
            for _, value in ipairs(args.values) do
                if tpl == value then
                    return true
                end
            end
            return false
        end
    elseif args.values_assoc ~= nil then
        inner = function(tpl) 
            return args.values_assoc[tpl] ~= nil
        end
    else
        error(string.format('Missing inner comparision function. Args: %s', mw.dumpObject(args)))
    end
    
    -- Outer type of function depending on whether to check a single value or against a table
    return function (tpl_args)
        local tpl_value = tpl_args[args.arg]
        local rtr
        if type(tpl_value) == 'table' then
            rtr = false
            for key, value in pairs(tpl_value) do
                if type(key) == 'number' then
                    rtr = rtr or inner(value)
                else
                    rtr = rtr or inner(key)
                end
            end
        else
            rtr = inner(tpl_value)
        end
        if args.negate then
            rtr = not rtr
        end
        return rtr
     end
end

function h.conditions.factory.not_arg(args)
    args = args or {}
    args.negate = true
    return h.conditions.factory.arg(args)
end

function h.conditions.factory.acquisition_tag(args)
    return function (tpl_args)
        for _, tag in ipairs(tpl_args.acquisition_tags or {}) do
            if tag == args.tag then
                return true
            end
        end
        return false
    end
end

function h.conditions.factory.drop_monsters(args)
    return function (tpl_args)
        for _, monster in ipairs(tpl_args.drop_monsters or {}) do
            if string.find(monster, args.monster, 1, true) then
                return true
            end
        end
        return false
    end
end

h.conditions.normal = h.conditions.factory.arg{arg='rarity_id', value='normal'}
h.conditions.unique = h.conditions.factory.arg{arg='rarity_id', value='unique'}

function h.conditions.item_class_has_corrupted_implicits(tpl_args)
    local groups = {
        cfg.class_groups.weapons.keys,
        cfg.class_groups.armor.keys,
        cfg.class_groups.jewellery.keys,
        {['Quiver'] = true, ['Jewel'] = true, ['AbyssJewel'] = true},
    }
    for _, g in ipairs(groups) do
        if h.conditions.factory.arg{arg='class_id', values_assoc=g}(tpl_args) then
            return true
        end
    end
    return false
end

function h.conditions.item_class_has_influences(tpl_args)
    local groups = {
        cfg.class_groups.weapons.keys,
        cfg.class_groups.armor.keys,
        cfg.class_groups.jewellery.keys,
        {['Quiver'] = true},
    }
    for _, g in ipairs(groups) do
        if h.conditions.factory.arg{arg='class_id', values_assoc=g}(tpl_args) and h.conditions.factory.not_arg{arg='class_id', value='FishingRod'}(tpl_args) then
            return true
        end
    end
    return false
end

-- ----------------------------------------------------------------------------
-- Additional configuration
-- ----------------------------------------------------------------------------

local c = {}

-- Default for all entries, but can be disabled by specific ones.
c.automatic_recipe_defaults = {
    is_drop_restricted = h.conditions.factory.arg{arg='is_drop_restricted', value=false},
    is_corrupted = h.conditions.factory.arg{arg='is_corrupted', value=false},
    is_replica = h.conditions.factory.arg{arg='is_replica', value=false},
}
-- Order matters!
-- Put most specific outcome at the top and the least specific at the bottom.
c.automatic_recipes = {
--[[
    {
        defaults = {
            arg_key = function (tpl_args) end,
        },
        condition = {
            function (tpl_args) end,
        },
        text = '',
        groups = {
            {
                name = '',
                item_id = '',
                amount = 0,
                notes = '',
            },
        },
    },
]]
    --
    -- Automatic recipes for specific maps - reduces maintenance when a new map series is introduced
    --
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='name', values={i18n['Forge of the Phoenix Map'], i18n['Lair of the Hydra Map'], i18n['Maze of the Minotaur Map'], i18n['Pit of the Chimera Map']}},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.shaper_guardian_map))
        end,
        groups = {
            {
                -- Guardian's Challenge
                item_id = 'Metadata/Items/DivinationCards/DivinationCardGuardiansChallenge',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='name', value=i18n['Vaal Temple Map']},
        },
        text = function ()
            return string.format(i18n.fmt.corrupted_x, string.format(i18n.fmt.item_level_x, 83, m_util.html.poe_color('rare', i18n['Vaal Temple Map'])))
        end,
        groups = {
            {
                -- Lingering Remnants
                item_id = 'Metadata/Items/DivinationCards/DivinationCardLingeringRemnants',
                amount = 16,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='name', value=i18n['Vaal Temple Map']},
        },
        text = function ()
            return string.format(i18n.fmt.corrupted_x, string.format(i18n.fmt.map_with_x_percent_delirium, string.format(i18n.fmt.tier_x, 16, m_util.html.poe_color('rare', i18n['Vaal Temple Map'])), 100))
        end,
        groups = {
            {
                -- The Price of Prescience
                item_id = 'Metadata/Items/DivinationCards/DivinationCardThePriceOfPrescience',
                amount = 5,
            },
        },
    },
    --
    -- Item base specific
    --
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Amulets/Amulet9'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.agate_amulet))
        end,
        groups = {
            {
                -- Lysah's Respite
                item_id = 'Metadata/Items/DivinationCards/DivinationCardLysahsRespite',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Rings/Ring15'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.unset_ring))
        end,
        groups = {
            {
                -- The Penitent
                item_id = 'Metadata/Items/DivinationCards/DivinationCardThePenitent',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Rings/Ring4'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.gold_ring))
        end,
        groups = {
            {
                -- Glimmer of Hope
                item_id = 'Metadata/Items/DivinationCards/DivinationCardGlimmerOfHope',
                amount = 8,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Rings/Ring8'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.prismatic_ring))
        end,
        groups = {
            {
                -- Hope
                item_id = 'Metadata/Items/DivinationCards/DivinationCardHope',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='metadata_id', values={'Metadata/Items/Rings/Ring12', 'Metadata/Items/Rings/Ring13', 'Metadata/Items/Rings/Ring14'}},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('rare', i18n.two_stone_ring))
        end,
        groups = {
            {
                -- Lantador's Lost Love
                item_id = 'Metadata/Items/DivinationCards/DivinationCardLantadorsLostLove',
                amount = 7,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', values={'Metadata/Items/Rings/Ring12', 'Metadata/Items/Rings/Ring13', 'Metadata/Items/Rings/Ring14'}},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.two_stone_ring))
        end,
        groups = {
            {
                -- Heterochromia
                item_id = 'Metadata/Items/DivinationCards/DivinationCardHeterochromia',
                amount = 2,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Weapons/OneHandWeapons/OneHandMaces/Sceptre11'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.crystal_sceptre))
        end,
        groups = {
            {
                -- Light and Truth
                item_id = 'Metadata/Items/DivinationCards/DivinationCardLightAndTruth',
                amount = 2,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Flasks/FlaskUtility5'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.granite_flask))
        end,
        groups = {
            {
                -- Earth Drinker
                item_id = 'Metadata/Items/DivinationCards/DivinationCardEarthDrinker',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Armours/Helmets/HelmetStrDex10'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.nightmare_bascinet))
        end,
        groups = {
            {
                -- The Gladiator
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheGladiator',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Belts/Belt1'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.rustic_sash))
        end,
        groups = {
            {
                -- The Standoff
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheStandoff',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Belts/Belt3'},
        },
        text = function ()
            return string.format(i18n.fmt.random_two_influenced_x, m_util.html.poe_color('unique', i18n['Leather Belt']))
        end,
        groups = {
            {
                -- The Forgotten Treasure
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheForgottenTreasure',
                amount = 6,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Jewels/JewelTimeless'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.timeless_jewel))
        end,
        groups = {
            {
                -- Peaceful Moments
                item_id = 'Metadata/Items/DivinationCards/DivinationCardPeacefulMoments',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique, 
            h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Jewels/JewelTimeless'},
        },
        text = function ()
            return string.format(i18n.fmt.random_two_implicit_corrupted, m_util.html.poe_color('unique', i18n.timeless_jewel))
        end,
        groups = {
            {
                -- The Eternal War
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheEternalWar',
                amount = 4,
            },
        },
    },
    -- 
    -- Item name
    -- 
    {
        defaults = {
            is_drop_restricted = false,
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='name', value=i18n.precursors_emblem},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.precursors_emblem))
        end,
        groups = {
            {
                -- Remembrance
                item_id = 'Metadata/Items/DivinationCards/DivinationCardRemembrance',
                amount = 8,
            },
        },
    },
    -- 
    -- Item name like
    -- 
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            function (tpl_args)
                -- Items that have "Atziri" in their name
                if string.find(tpl_args.name, i18n.atziri, 1, true) then
                    return true
                end
                -- Items that drop from Atziri
                for _, monster in ipairs(tpl_args.drop_monsters or {}) do
                    if string.find(monster, 'Metadata/Monsters/Atziri/Atziri', 1, true) then
                        return true
                    end
                end
                return false
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.atziri)))
        end,
        groups = {
            {
                -- The Admirer
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheAdmirer',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            function (tpl_args)
                return string.find(tpl_args.name, i18n.doedre, 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.doedre)))
        end,
        groups = {
            {
                -- Doedre's Madness
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDoedresMadness',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            function (tpl_args)
                return string.find(tpl_args.name, i18n.shavronne, 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.shavronne)))
        end,
        groups = {
            {
                -- The Aesthete
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheAesthete',
                amount = 8,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            function (tpl_args)
                return string.find(tpl_args.name, i18n.rigwald, 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.rigwald)))
        end,
        groups = {
            {
                -- The Wolf
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheWolf',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            function (tpl_args)
                return string.find(tpl_args.name, i18n.lioneye, 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.lioneye)))
        end,
        groups = {
            {
                -- The Lion
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheLion',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            function (tpl_args)
                return string.find(tpl_args.name, i18n.farrul, 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.farrul)))
        end,
        groups = {
            {
                -- Council of Cats
                item_id = 'Metadata/Items/DivinationCards/DivinationCardCouncilOfCats',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            function (tpl_args)
                return string.find(tpl_args.name, i18n.farrul, 1, true) or string.find(tpl_args.name, i18n.fenumus, 1, true) or string.find(tpl_args.name, i18n.saqawal, 1, true) or string.find(tpl_args.name, i18n.craiceann, 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Bestiary'].name)))
        end,
        groups = {
            {
                -- Boon of the First Ones
                item_id = 'Metadata/Items/DivinationCards/DivinationCardBoonOfTheFirstOnes',
                amount = 6,
            },
        },
    },
    -- 
    -- Monster-specific items
    --
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.drop_monsters{monster = 'Metadata/Monsters/BreachBosses/BreachBossChaos'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.chayula)))
        end,
        groups = {
            {
                -- The Dreamer
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheDreamer',
                amount = 6,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.drop_monsters{monster = 'Metadata/Monsters/BreachBosses/'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Breach'].name)))
        end,
        groups = {
            {
                -- The Breach
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheBreach',
                amount = 4,
            },
        },
    },
    -- 
    -- Themed/league items (acquisition tags)
    --
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = 'fishing'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, i18n.fishing)))
        end,
        groups = {
            {
                -- Baited Expectations
                item_id = 'Metadata/Items/DivinationCards/DivinationCardBaitedExpectations',
                amount = 8,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = m_game.constants.leagues['Nemesis'].name},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Nemesis'].name)))
        end,
        groups = {
            {
                -- The Valkyrie
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheValkyrie',
                amount = 8,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = m_game.constants.leagues['Nemesis'].name},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Nemesis'].name)))
        end,
        groups = {
            {
                -- The Undaunted
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheUndaunted',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = m_game.constants.leagues['Beyond'].name},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Beyond'].name)))
        end,
        groups = {
            {
                -- The Calling
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheCalling',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = m_game.constants.leagues['Delve'].name},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Delve'].name)))
        end,
        groups = {
            {
                -- Alone in the Darkness
                item_id = 'Metadata/Items/DivinationCards/DivinationCardAloneInTheDarkness',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = m_game.constants.leagues['Metamorph'].name},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Metamorph'].name)))
        end,
        groups = {
            {
                -- Haunting Shadows
                item_id = 'Metadata/Items/DivinationCards/DivinationCardHauntingShadows',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.acquisition_tag{tag = m_game.constants.leagues['Abyss'].name},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('rare', string.format(i18n.fmt.x_item, m_game.constants.leagues['Abyss'].name)))
        end,
        groups = {
            {
                -- Abyssal Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationAbyssStackable',
                amount = 1,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            -- h.conditions.factory.acquisition_tag{tag = m_game.constants.leagues['Synthesis'].name},
            h.conditions.factory.arg{arg='is_synthesised', value=true},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', string.format(i18n.fmt.x_item, m_game.constants.leagues['Synthesis'].name)))
        end,
        groups = {
            {
                -- Chasing Risk
                item_id = 'Metadata/Items/DivinationCards/DivinationCardChasingRisk',
                amount = 4,
            },
        },
    },
    --
    -- Subset of item class
    --
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Jewel'},
            function(tpl_args)
                -- Get Primordial modifier from stats
                if tpl_args._stats.primordial_jewel_count then
                    return true
                end
                return false
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, string.format('%s %s', m_util.html.poe_color('mod', i18n.primordial), m_util.html.poe_color('unique', i18n.jewel)))
        end,
        groups = {
            {
                -- The Primordial
                item_id = 'Metadata/Items/DivinationCards/DivinationCardThePrimordial',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Jewel'},
            function(tpl_args)
                -- Get Primordial modifier from stats
                if tpl_args._stats.primordial_jewel_count then
                    return true
                end
                return false
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_one_or_two_implicit_corrupted, string.format('%s %s', m_util.html.poe_color('mod', i18n.primordial), m_util.html.poe_color('unique', i18n.jewel)))
        end,
        groups = {
            {
                -- A Stone Perfected
                item_id = 'Metadata/Items/DivinationCards/DivinationCardAStonePerfected',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='is_talisman', value=true},
            h.conditions.factory.arg{arg='talisman_tier', value=1},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('rare', i18n.tier_1_talisman))
        end,
        groups = {
            {
                -- Call to the First Ones
                item_id = 'Metadata/Items/DivinationCards/DivinationCardCallToTheFirstOnes',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
            is_corrupted = false,
        },
        condition = {
            h.conditions.factory.arg{arg='is_talisman', value=true},
        },
        text = function ()
            return string.format(i18n.fmt.random, i18n.talisman)
        end,
        groups = {
            {
                -- Primal Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationTalismansStackable',
                amount = 1,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            h.conditions.factory.arg{arg='tags', value='atziri1'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.sacrifice_fragment))
        end,
        groups = {
            {
                -- Her Mask
                item_id = 'Metadata/Items/DivinationCards/DivinationCardHerMask',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            h.conditions.factory.arg{arg='tags', value='atziri2'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.mortal_fragment))
        end,
        groups = {
            {
                -- Sambodhi's Vow
                item_id = 'Metadata/Items/DivinationCards/DivinationCardSambodhisVow',
                amount = 3,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'UberElderFragment', 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.uber_elder_fragment))
        end,
        groups = {
            {
                -- The Eldritch Decay
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheEldritchDecay',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            function (tpl_args)
                if tpl_args.metadata_id then
                    local patterns = {
                        'CurrencyShaperFragment',
                        'CurrencyElderFragment',
                        'CurrencyVaalFragment1_',
                        'CurrencyVaalFragment2_',
                        'CurrencyOfferingToTheGoddess$',
                    }
                    for _, p in ipairs(patterns) do
                        if string.find(tpl_args.metadata_id, p) then
                            return true
                        end
                    end
                end
                return false
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.fragment))
        end,
        groups = {
            {
                -- Fragmented Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationFragmentsStackable',
                amount = 1,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            h.conditions.factory.arg{arg='tags', value='breachstone'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.breachstone))
        end,
        groups = {
            {
                -- The Obscured
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheObscured',
                amount = 7,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            h.conditions.factory.arg{arg='tags', value='breachstone4'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.pure_breachstone))
        end,
        groups = {
            {
                -- The Bargain
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheBargain',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='is_essence', value=true},
            h.conditions.factory.arg{arg='essence_level', value=7},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.deafening_essence), 3)
        end,
        groups = {
            {
                -- The Cacophony
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheCacophony',
                amount = 8,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='is_essence', value=true},
            h.conditions.factory.arg{arg='essence_level', value=6},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.shrieking_essence), 9)
        end,
        groups = {
            {
                -- Harmony of Souls
                item_id = 'Metadata/Items/DivinationCards/DivinationCardHarmonyOfSouls',
                amount = 9,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='is_essence', value=true},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.essence), 3)
        end,
        groups = {
            {
                -- Three Voices
                item_id = 'Metadata/Items/DivinationCards/DivinationCardThreeVoices',
                amount = 3,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='is_essence', value=true},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.essence), 3)
        end,
        groups = {
            {
                -- Infused Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationEssenceHighStackable',
                amount = 1,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='StackableCurrency'},
            h.conditions.factory.arg{arg='tags', value='affliction_orb'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('currency', i18n.delirium_orb))
        end,
        groups = {
            {
                -- Disdain
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDisdain',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='StackableCurrency'},
            h.conditions.factory.arg{arg='tags', value='affliction_orb'},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.delirium_orb), 10)
        end,
        groups = {
            {
                -- Dementophobia
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDementophobia',
                amount = 11,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='StackableCurrency'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'Metadata/Items/Currency/CurrencyIncursionVial', 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.vial), 10)
        end,
        groups = {
            {
                -- The Rabbit's Foot
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheRabbitsFoot',
                amount = 8,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=5},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', string.format(i18n.fmt.tier_x_map, 5)))
        end,
        groups = {
            {
                -- Cartographer's Delight
                item_id = 'Metadata/Items/DivinationCards/DivinationCardCartographersDelight',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=6},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', string.format(i18n.fmt.tier_x_map, 6)))
        end,
        groups = {
            {
                -- Rain Tempter
                item_id = 'Metadata/Items/DivinationCards/DivinationCardRainTempter',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=10},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', string.format(i18n.fmt.tier_x_map, 10)))
        end,
        groups = {
            {
                -- The Tumbleweed
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheTumbleweed',
                amount = 2,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=12},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', string.format(i18n.fmt.tier_x_map, 12)))
        end,
        groups = {
            {
                -- The Arena Champion
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheArenaChampion',
                amount = 10,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=14},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', string.format(i18n.fmt.tier_x_map, 14)))
        end,
        groups = {
            {
                -- The Surveyor
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheSurveyor',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=15},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', string.format(i18n.fmt.tier_x_map, 15)))
        end,
        groups = {
            {
                -- Lost Worlds
                item_id = 'Metadata/Items/DivinationCards/DivinationCardLostWorlds',
                amount = 8,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=15},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('rare', string.format(i18n.fmt.tier_x_map, 15)))
        end,
        groups = {
            {
                -- The Trial
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheTrial',
                amount = 7,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=15},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('rare', string.format(i18n.fmt.tier_x_map_with_y_modifiers, 15, 8)))
        end,
        groups = {
            {
                -- The Easy Stroll
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheEasyStroll',
                amount = 2,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=16},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', string.format(i18n.fmt.tier_x_map, 16)))
        end,
        groups = {
            {
                -- The Price of Protection
                item_id = 'Metadata/Items/DivinationCards/DivinationCardThePriceOfProtection',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=16},
        },
        text = function ()
            return string.format(i18n.fmt.random_unidentified_corrupted, m_util.html.poe_color('rare', string.format(i18n.fmt.tier_x_map, 16)))
        end,
        groups = {
            {
                -- Left to Fate
                item_id = 'Metadata/Items/DivinationCards/DivinationCardLeftToFate',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
            h.conditions.factory.arg{arg='map_tier', value=13},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, string.format(i18n.fmt.triskaidekaphobia, m_util.html.poe_color('rare', string.format(i18n.fmt.tier_x_map, 13))))
        end,
        groups = {
            {
                -- Triskaidekaphobia
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTriskaidekaphobia',
                amount = 13,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Active Skill Gem'},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.golem.tag},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.level_x_y_gem, 21, m_game.constants.item.gem_tags.golem.tag)))
        end,
        groups = {
            {
                -- The Rite of Elements
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheRiteOfElements',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Active Skill Gem'},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.golem.tag},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.any_quality_level_x_y_gem_q_z, 21, m_game.constants.item.gem_tags.golem.tag, 23)))
        end,
        groups = {
            {
                -- Terrible Secret of Space
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTerribleSecretOfSpace',
                amount = 8,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.trap.tag},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_level_x_y_gem_q_z, 21, m_game.constants.item.gem_tags.trap.tag, 23)))
        end,
        groups = {
            {
                -- Deathly Designs
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDeathlyDesigns',
                amount = 7,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Support Skill Gem'},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('gem', string.format(i18n.fmt.level_x_y_gem, 20, m_game.constants.item.gem_tags.support.tag)))
        end,
        groups = {
            {
                -- Gift of the Gemling Queen
                item_id = 'Metadata/Items/DivinationCards/DivinationCardGiftOfTheGemlingQueen',
                amount = 9,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Support Skill Gem'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_x_gem_q_y, m_game.constants.item.gem_tags.support.tag, 23)))
        end,
        groups = {
            {
                -- Dialla's Subjugation
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDiallasSubjugation',
                amount = 7,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Support Skill Gem'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'Plus', 1, true)
            end,
            h.conditions.factory.arg{arg='max_level', value=5},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_level_x_support_plus_gem_q_y, 6, 20)))
        end,
        groups = {
            {
                -- The Cheater
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheCheater',
                amount = 3,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Support Skill Gem'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'Plus', 1, true)
            end,
            h.conditions.factory.arg{arg='max_level', value=5},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_level_x_support_plus_gem_q_y, 6, 23)))
        end,
        groups = {
            {
                -- Desecrated Virtue
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDesecratedVirtue',
                amount = 9,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.chaos.tag},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_level_x_y_gem_q_z, 21, m_game.constants.item.gem_tags.chaos.tag, 23)))
        end,
        groups = {
            {
                -- The Bitter Blossom
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheBitterBlossom',
                amount = 3,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Active Skill Gem'},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.vaal.tag},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_x_gem_q_y, m_game.constants.item.gem_tags.vaal.tag, 20)))
        end,
        groups = {
            {
                -- Volatile Power
                item_id = 'Metadata/Items/DivinationCards/DivinationCardVolatilePower',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
            h.conditions.factory.arg{arg='max_level', value=20},
            function (tpl_args)
                return tpl_args._flags.is_alt_quality_gem == true -- Flag is set in Module:Skill
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('gem', string.format(i18n.fmt.alt_level_x_gem_q_y, 19, 19)))
        end,
        groups = {
            {
                -- Dying Anguish
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDyingAnguish',
                amount = 8,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_gem)))
        end,
        groups = {
            {
                -- Gemcutter's Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationGemLowStackable',
                amount = 1,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'Scarab', 1, true)
            end,
            h.conditions.factory.arg{arg='tags', value='gilded_scarab'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.gilded_scarab))
        end,
        groups = {
            {
                -- More is Never Enough
                item_id = 'Metadata/Items/DivinationCards/DivinationCardMoreIsNeverEnough',
                amount = 7,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'Scarab', 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.scarab))
        end,
        groups = {
            {
                -- Cameria's Cut
                item_id = 'Metadata/Items/DivinationCards/DivinationCardCameriasCut',
                amount = 2,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='MapFragment'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'Scarab', 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.scarab))
        end,
        groups = {
            {
                -- Skittering Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationScarabsStackable',
                amount = 1,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='StackableCurrency'},
            h.conditions.factory.arg{arg='tags', value='breachstone_splinter'},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.breachstone_splinter), 5)
        end,
        groups = {
            {
                -- The Puzzle
                item_id = 'Metadata/Items/DivinationCards/DivinationCardThePuzzle',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='StackableCurrency'},
            h.conditions.factory.arg{arg='tags', value='quality_currency'},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.quality_currency), 20)
        end,
        groups = {
            {
                -- The Master Artisan
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheMasterArtisan',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='StackableCurrency'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'CurrencyDelve', 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_x_amount, m_util.html.poe_color('currency', i18n.fossil), 5)
        end,
        groups = {
            {
                -- The Tinkerer's Table
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheTinkerersTable',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='StackableCurrency'},
            function (tpl_args)
                return tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'CurrencyDelve', 1, true)
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('currency', i18n.fossil))
        end,
        groups = {
            {
                -- Fossilised Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationFossilsStackable',
                amount = 1,
            },
        },
    },
    --
    -- Single item class
    --
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='UniqueFragment'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.harbinger_fragment))
        end,
        groups = {
            {
                -- The Messenger
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheMessenger',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Body Armour'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.body_armour))
        end,
        groups = {
            {
                -- The Body
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheBody',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Shield'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.shield))
        end,
        groups = {
            {
                -- The Mercenary
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheMercenary',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Helmet'},
        },
        text = function ()
            return string.format(i18n.fmt.random_two_veiled, m_util.html.poe_color('rare', i18n.helmet))
        end,
        groups = {
            {
                -- The Journalist
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheJournalist',
                amount = 10,
            },
        },
    },
    {
        condition = {
            h.conditions.unique, 
            h.conditions.factory.arg{arg='class_id', value='Helmet'}, 
        },
        text = function ()
            return string.format(i18n.fmt.random_eternal_labyrinth_enchantment, m_util.html.poe_color('unique', i18n.helmet))
        end,
        groups = {
            {
                -- Divine Justice
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDivineJustice',
                amount = 1,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Claw'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.claw))
        end,
        groups = {
            {
                -- The Wolverine
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheWolverine',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', values={'Dagger', 'Rune Dagger'}},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.dagger))
        end,
        groups = {
            {
                -- Assassin's Favour
                item_id = 'Metadata/Items/DivinationCards/DivinationCardAssassinsFavour',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Sceptre'},
        },
        text = function ()
            return string.format(i18n.fmt.random_shaper, m_util.html.poe_color('magic', string.format('%s %s', i18n.sceptre, h.modifier_link{id='LocalIncreasedAttackSpeed8'})))
        end,
        groups = {
            {
                -- The Lord of Celebration
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheLordOfCelebration',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Bow'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.bow))
        end,
        groups = {
            {
                -- Hunter's Resolve
                item_id = 'Metadata/Items/DivinationCards/DivinationCardHuntersResolve',
                amount = 8,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Jewel'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.jewel))
        end,
        groups = {
            {
                -- The Garish Power
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheGarishPower',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Jewel'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.jewel))
        end,
        groups = {
            {
                -- The Eye of the Dragon
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheEyeOfTheDragon',
                amount = 10,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Jewel'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='PercentIncreasedLifeJewel'}, i18n.jewel)))
        end,
        groups = {
            {
                -- Shard of Fate
                item_id = 'Metadata/Items/DivinationCards/DivinationCardShardOfFate',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Jewel'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('magic', string.format('%s %s', i18n.jewel, h.modifier_link{id='CriticalStrikeMultiplierJewel'})))
        end,
        groups = {
            {
                -- The Mountain
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheMountain',
                amount = 6,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Jewel'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted_implicit, m_util.html.poe_color('rare', i18n.jewel), h.modifier_link{id='V2CorruptedBloodImmunityCorrupted'})
        end,
        groups = {
            {
                -- Lachrymal Necrosis
                item_id = 'Metadata/Items/DivinationCards/DivinationCardLachrymalNecrosis',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Amulet'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='IncreasedEnergyShieldPercent7'}, i18n.amulet)))
        end,
        groups = {
            {
                -- The Sigil
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheSigil',
                amount = 3,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Amulet'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('rare', i18n.amulet))
        end,
        groups = {
            {
                -- The Warden
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheWarden',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Ring'},
            function (tpl_args)
                return tpl_args.drop_level <= 83
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 83, m_util.html.poe_color('magic', string.format('%s %s', i18n.ring, h.modifier_link{id='ChaosResist6'})))
        end,
        groups = {
            {
                -- The Lord in Black
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheLordInBlack',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Ring'},
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 100, m_util.html.poe_color('rare', i18n.ring))
        end,
        groups = {
            {
                -- The Opulent
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheOpulecent',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Ring'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.ring))
        end,
        groups = {
            {
                -- Hubris
                item_id = 'Metadata/Items/DivinationCards/DivinationCardHubris',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Ring'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.ring))
        end,
        groups = {
            {
                -- Blind Venture
                item_id = 'Metadata/Items/DivinationCards/DivinationCardBlindVenture',
                amount = 7,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Belt'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.belt))
        end,
        groups = {
            {
                -- The Wretched
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheWretched',
                amount = 6,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Map'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.map))
        end,
        groups = {
            {
                -- The Encroaching Darkness
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheEncroachingDarkness',
                amount = 8,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Map'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.map))
        end,
        groups = {
            {
                -- Otherworldly Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationUniqueMapsStackable',
                amount = 1,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Wand'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.wand))
        end,
        groups = {
            {
                -- The Traitor
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheTraitor',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', values={'Staff', 'Warstaff'}},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.staff))
        end,
        groups = {
            {
                -- The Tower
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheTower',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Staff', 'Warstaff'}},
            h.conditions.factory.not_arg{arg='tags', value='small_staff'}, -- Small staves excluded because they don't have enough sockets
            function (tpl_args)
                return tpl_args.drop_level <= 66
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_x_link_item_level_y, 5, 66, m_util.html.poe_color('normal', i18n.staff))
        end,
        groups = {
            {
                -- The Flora's Gift
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheFlorasGift',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Staff', 'Warstaff'}},
            h.conditions.factory.not_arg{arg='tags', value='small_staff'}, -- Small staves excluded because they don't have enough sockets
            function (tpl_args)
                return tpl_args.drop_level <= 55
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_x_link_item_level_y, 6, 55, m_util.html.poe_color('normal', i18n.staff))
        end,
        groups = {
            {
                -- The Dark Mage
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheDarkMage',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Body Armour'},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_link_item_level_y, 6, 100, m_util.html.poe_color('normal', i18n.body_armour))
        end,
        groups = {
            {
                -- The Dapper Prodigy
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheDapperProdigy',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Body Armour'},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_link_item_level_y_random_influenced, 6, 100, m_util.html.poe_color('normal', i18n.body_armour))
        end,
        groups = {
            {
                -- Draped in Dreams
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDrapedInDreams',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Body Armour'},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_link, 6, m_util.html.poe_color('normal', i18n.body_armour))
        end,
        groups = {
            {
                -- The Chains that Bind
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheChainsThatBind',
                amount = 11,
            },
        },
    },
    {
        condition = {
            h.conditions.normal, 
            h.conditions.factory.arg{arg='class_id', value='Body Armour'}, 
        },
        text = function ()
            return string.format(i18n.fmt.random_x_link, 6, m_util.html.poe_color('normal', i18n.body_armour))
        end,
        groups = {
            {
                -- Geomancer's Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationArmour6LinkedStackable',
                amount = 1,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Body Armour'},
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 100, m_util.html.poe_color('rare', i18n.body_armour))
        end,
        groups = {
            {
                -- Destined to Crumble
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDestinedToCrumble',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('normal', i18n.map))
        end,
        groups = {
            {
                -- Boundless Realms
                item_id = 'Metadata/Items/DivinationCards/DivinationCardBoundlessRealms',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Map'},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('rare', i18n.map))
        end,
        groups = {
            {
                -- The Explorer
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheExplorer',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', value='Gloves'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.gloves))
        end,
        groups = {
            {
                -- Mitts
                item_id = 'Metadata/Items/DivinationCards/DivinationCardMitts',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='DivinationCard'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('divination', i18n.divination_card))
        end,
        groups = {
            {
                -- The Gambler
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheGambler',
                item_page = 'The Gambler', -- These need to be specified so that The Gambler can be a recipe for itself while saving itself.
                item_name = 'The Gambler',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='DivinationCard'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('divination', i18n.divination_card))
        end,
        groups = {
            {
                -- Stacked Deck
                item_id = 'Metadata/Items/DivinationCards/DivinationCardDeck',
                amount = 1,
            },
        },
    },
    --
    -- Multiple item classes
    --
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', values={'One Hand Axe', 'Two Hand Axe'}},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.axe))
        end,
        groups = {
            {
                -- The Battle Born
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheBattleBorn',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', value='Active Skill Gem'},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.aura.tag},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.level_x_y_gem, 21, m_game.constants.item.gem_tags.aura.tag)))
        end,
        groups = {
            {
                -- The Wilted Rose
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheWiltedRose',
                amount = 7,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('gem', string.format(i18n.fmt.level_x_gem, 20)))
        end,
        groups = {
            {
                -- The Fox
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheFox',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.minion.tag},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_x_gem_q_y, m_game.constants.item.gem_tags.minion.tag, 20)))
        end,
        groups = {
            {
                -- The Summoner
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheSummoner',
                amount = 6,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
            h.conditions.factory.arg{arg='gem_tags', value=m_game.constants.item.gem_tags.spell.tag},
            h.conditions.factory.arg{arg='max_level', value=20},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('gem', string.format(i18n.fmt.level_x_y_gem, 21, m_game.constants.item.gem_tags.spell.tag)))
        end,
        groups = {
            {
                --The Cataclysm
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheCataclysm',
                amount = 13,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.gems.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('gem', string.format(i18n.fmt.superior_gem_q_x, 20)))
        end,
        groups = {
            {
                -- Gemcutter's Promise
                item_id = 'Metadata/Items/DivinationCards/DivinationCardGemcuttersPromise',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.armor.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random_x_quality, m_util.html.poe_color('unique', i18n.armour), 30)
        end,
        groups = {
            {
                -- Sambodhi's Wisdom
                item_id = 'Metadata/Items/DivinationCards/DivinationCardSambodhisWisdom',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.armor.keys},
            h.conditions.factory.arg{arg='tags', value='int_armour'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='LocalIncreasedEnergyShieldPercentAndStunRecovery6'}, i18n.armour)))
        end,
        groups = {
            {
                -- The Inoculated
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheInoculated',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.armor.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('magic', string.format('%s %s', i18n.life, i18n.armour)))
        end,
        groups = {
            {
                -- The Carrion Crow
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheCarrionCrow',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.jewellery.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random_shaper_item_level_x, 100, m_util.html.poe_color('rare', i18n.jewellery))
        end,
        groups = {
            {
                -- Perfection
                item_id = 'Metadata/Items/DivinationCards/DivinationCardPerfection',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.jewellery.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.jewellery))
        end,
        groups = {
            {
                -- The Cache
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheCache',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.jewellery.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random_two_influenced_item_level_x, 86, m_util.html.poe_color('rare', i18n.jewellery))
        end,
        groups = {
            {
                -- The Awakened
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheAwakened',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.jewellery.keys},
            function (tpl_args)
                return tpl_args.drop_level <= 79
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 79, m_util.html.poe_color('rare', i18n.jewellery))
        end,
        groups = {
            {
                -- The Lover
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheLover',
                amount = 2,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Ring', 'Amulet'}},
            function (tpl_args)
                return tpl_args.drop_level <= 85
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 85, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='ReduceGlobalFlatManaCostStrIntMasterVendor'}, i18n.jewellery)))
        end,
        groups = {
            {
                -- Blessing of God
                item_id = 'Metadata/Items/DivinationCards/DivinationCardBlessingOfGod',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Ring', 'Amulet'}},
            function (tpl_args)
                return tpl_args.drop_level <= 76
            end,
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 76, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='AddedLightningDamage9'}, i18n.jewellery)))
        end,
        groups = {
            {
                -- Struck by Lightning
                item_id = 'Metadata/Items/DivinationCards/DivinationCardStruckByLightning',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.jewellery.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random_shaper_hunter_item_level_x, 100, m_util.html.poe_color('magic', string.format('%s %s', i18n.jewellery, h.modifier_link{id='GrantsCatAspectCrafted'})))
        end,
        groups = {
            {
                -- A Familiar Call
                item_id = 'Metadata/Items/DivinationCards/DivinationCardAFamiliarCall',
                amount = 3,
            },
        },
    },
    {
        condition = {
            h.conditions.unique, 
            h.conditions.factory.arg{arg='class_id', values={'Helmet', 'Gloves', 'Boots'}}, 
        },
        text = function ()
            return string.format(i18n.fmt.random_labyrinth_enchantment, m_util.html.poe_color('unique', i18n.item))
        end,
        groups = {
            {
                -- The Blessing of Moosh
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheBlessingOfMoosh',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Two Hand Sword', 'Two Hand Axe', 'Two Hand Mace', 'Staff', 'Bow', 'Warstaff'}},
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 100, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='LocalIncreasedPhysicalDamagePercent8'}, i18n.two_hand_weapon)))
        end,
        groups = {
            {
                -- Merciless Armament
                item_id = 'Metadata/Items/DivinationCards/DivinationCardMercilessArmament',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Thrusting One Hand Sword', 'One Hand Sword', 'One Hand Axe', 'One Hand Mace', 'Sceptre', 'Dagger', 'Claw', 'Wand', 'Rune Dagger'}},
        },
        text = function ()
            return string.format(i18n.fmt.random_two_influenced_item_level_x, 100, m_util.html.poe_color('rare', i18n.one_hand_weapon))
        end,
        groups = {
            {
                -- Prometheus' Armoury
                item_id = 'Metadata/Items/DivinationCards/DivinationCardPrometheusArmoury',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Thrusting One Hand Sword', 'One Hand Sword', 'One Hand Axe', 'One Hand Mace', 'Sceptre', 'Dagger', 'Claw', 'Wand', 'Rune Dagger'}},
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 100, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='LocalIncreasedPhysicalDamagePercent8'}, i18n.one_hand_weapon)))
        end,
        groups = {
            {
                -- The Jester
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheJester',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values={'Sceptre', 'Wand', 'Rune Dagger'}},
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 100, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='SpellDamageOnWeapon8_'}, i18n.one_hand_weapon)))
        end,
        groups = {
            {
                -- The Road to Power
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheRoadToPower',
                amount = 7,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', values={'Thrusting One Hand Sword', 'One Hand Sword', 'Two Hand Sword'}},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.sword))
        end,
        groups = {
            {
                -- The Gentleman
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheGentleman',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.weapons.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random_item_level_x, 100, m_util.html.poe_color('magic',string.format('%s %s', h.modifier_link{id='LocalIncreasedPhysicalDamagePercent8'}, i18n.weapon)))
        end,
        groups = {
            {
                -- The Tyrant
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheTyrant',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.weapons.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('magic', string.format('%s %s', i18n.weapon, h.modifier_link{id='StrIntMasterItemGenerationCanHaveMultipleCraftedMods'})))
        end,
        groups = {
            {
                -- The Web
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheWeb',
                amount = 8,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.arg{arg='class_id', values_assoc=cfg.class_groups.weapons.keys},
        },
        text = function ()
            return string.format(i18n.fmt.random_corrupted, m_util.html.poe_color('unique', i18n.weapon))
        end,
        groups = {
            {
                -- Atziri's Arsenal
                item_id = 'Metadata/Items/DivinationCards/DivinationCardAtzirisArsenal',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            -- specifically exclude crit flasks
            h.conditions.factory.arg{arg='class_id', values={'LifeFlask', 'ManaFlask', 'HybridFlask', 'UtilityFlask'}},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('magic', string.format('%s %s', h.modifier_link{id='FlaskChanceRechargeOnCrit5'}, i18n.flask)))
        end,
        groups = {
            {
                -- The Surgeon
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheSurgeon',
                amount = 4,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = 'fated'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.fated_item))
        end,
        groups = {
            {
                -- Akil's Prophecy
                item_id = 'Metadata/Items/DivinationCards/DivinationCardAkilsProphecy',
                amount = 3,
            },
        },
    },
    {
        defaults = {
            is_drop_restricted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.factory.acquisition_tag{tag = 'fated'},
        },
        text = function ()
            return string.format(i18n.fmt.random_two_implicit_corrupted, m_util.html.poe_color('unique', i18n.fated_item))
        end,
        groups = {
            {
                -- The Transformation
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheTransformation',
                amount = 5,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.item_class_has_corrupted_implicits,
            h.conditions.item_class_has_influences,
            h.conditions.factory.acquisition_tag{tag = 'league-specific'},
        },
        text = function ()
            return string.format(i18n.fmt.random_two_implicit_corrupted_two_influenced_item_level_x, 97, m_util.html.poe_color('unique', i18n.league_specific_item))
        end,
        groups = {
            {
                -- Fateful Meeting
                item_id = 'Metadata/Items/DivinationCards/DivinationCardFatefulMeeting',
                amount = 9,
            },
        },
    },
    {
        condition = {
            h.conditions.unique, 
            h.conditions.factory.acquisition_tag{tag = 'league-specific'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.league_specific_item))
        end,
        groups = {
            {
                -- Time-Lost Relic
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTimeLostRelic',
                amount = 10,
            },
        },
    },
    {
        condition = {
            h.conditions.unique, 
            h.conditions.factory.acquisition_tag{tag = 'league-specific'},
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.league_specific_item))
        end,
        groups = {
            {
                -- Time-Lost Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationUniqueLeagueStackable',
                amount = 1,
            },
        },
    },
    --
    -- Generic items
    --
    {
        condition = {
            h.conditions.normal,
            h.conditions.item_class_has_influences,
        },
        text = function ()
            return string.format(i18n.fmt.random_elder_item_level_x, 100, m_util.html.poe_color('rare', i18n.item))
        end,
        groups = {
            {
                -- The Hale Heart
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheHaleHeart',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.item_class_has_influences,
        },
        text = function ()
            return string.format(i18n.fmt.random_influenced, m_util.html.poe_color('unique', i18n.item))
        end,
        groups = {
            {
                -- Prejudice
                item_id = 'Metadata/Items/DivinationCards/DivinationCardPrejudice',
                amount = 7,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
            h.conditions.item_class_has_influences,
        },
        text = function ()
            return string.format(i18n.fmt.random_two_influenced_x, m_util.html.poe_color('unique', i18n.item))
        end,
        groups = {
            {
                -- Costly Curio
                item_id = 'Metadata/Items/DivinationCards/DivinationCardCostlyCurio',
                amount = 6,
            },
        },
    },
    {
        condition = {
            h.conditions.normal,
            h.conditions.item_class_has_influences,
        },
        text = function ()
            return string.format(i18n.fmt.random_influenced_x_elevated, m_util.html.poe_color('magic', i18n.item))
        end,
        groups = {
            {
                -- The Aspirant
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheAspirant',
                amount = 5,
            },
        },
    },
    {
        defaults = {
            is_corrupted = false,
        },
        condition = {
            h.conditions.unique,
            h.conditions.item_class_has_corrupted_implicits,
        },
        text = function ()
            return string.format(i18n.fmt.random_two_implicit_corrupted, m_util.html.poe_color('unique', i18n.item))
        end,
        groups = {
            {
                -- Arrogance of the Vaal
                item_id = 'Metadata/Items/DivinationCards/DivinationCardArroganceOfTheVaal',
                amount = 8,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.item))
        end,
        groups = {
            {
                -- Jack in the Box
                item_id = 'Metadata/Items/DivinationCards/DivinationCardJackInTheBox',
                amount = 4,
            },
        },
    },
    {
        condition = {
            h.conditions.unique,
        },
        text = function ()
            return string.format(i18n.fmt.random, m_util.html.poe_color('unique', i18n.item))
        end,
        groups = {
            {
                -- Singular Incubator
                item_id = 'Metadata/Items/Currency/CurrencyIncubationUniquesStackable',
                amount = 1,
            },
        },
    },
}

-- ----------------------------------------------------------------------------
-- Exported functions
-- ----------------------------------------------------------------------------

local p = {}

function p.process_recipes(tpl_args)
    local query_data = {
        id = {},
        name = {},
        page = {},
    }
    local sets = {}
    
    -- ------------------------------------------------------------------------
    -- Manual data
    -- ------------------------------------------------------------------------
    local setid = #sets + 1
    local set
    repeat
        local prefix = string.format('recipe%s_', setid)
        local groupid = 1
        local group
        set = {
            groups = {},
            result_amount = tonumber(tpl_args[prefix .. 'result_amount']) or 1,
            text = m_util.cast.text(tpl_args[prefix .. 'description']),
            automatic = false,
        }
        repeat 
            local group_prefix = string.format('%spart%s_', prefix, groupid)
            group = {
                item_name = tpl_args[group_prefix .. 'item_name'],
                item_id = tpl_args[group_prefix .. 'item_id'], 
                item_page = tpl_args[group_prefix .. 'item_page'], 
                amount = tonumber(tpl_args[group_prefix .. 'amount']),
                notes = m_util.cast.text(tpl_args[group_prefix .. 'notes']),
            }
            
            if group.item_name ~= nil or group.item_id ~= nil or group.item_page ~= nil then
                if group.amount == nil then
                    error(string.format(i18n.errors.missing_amount, group_prefix .. 'amount'))
                else
                    for key, array in pairs(query_data) do
                        local value = group['item_' .. key]
                        if value then
                            if array[value] then
                                table.insert(array[value], {setid, groupid})
                            else
                                array[value] = {{setid, groupid}, }
                            end
                        end
                    end
                    set.groups[#set.groups+1] = group
                end
            end
            
            groupid = groupid + 1
        until group.item_name == nil and group.item_id == nil and group.item_page == nil
        
        -- set was empty, can terminate safely
        if #set.groups == 0 then
            set = nil
        else
            setid = setid + 1
            sets[#sets+1] = set
        end
    until set == nil

    -- ------------------------------------------------------------------------
    -- Automatic
    -- ------------------------------------------------------------------------
    
    --
    --  maps
    --
    local automatic_index = #sets + 1
    -- TODO: 3.9.0 Unsure how this works yet, so disabled for now
    --[[if tpl_args.atlas_connections and tpl_args.rarity_id == 'normal' then
        local results = m_cargo.query(
            {'items', 'maps'},
            {'items._pageName',  'items.name'},
            {
                join='items._pageID=maps._pageID',
                where=string.format('items.class_id = "Map" AND items.rarity_id = "normal" AND maps.tier < %s AND items._pageName IN ("%s")', tpl_args.map_tier, table.concat(tpl_args.atlas_connections, '", "')),
            }
        )
        for _, row in ipairs(results) do
            sets[#sets+1] = {
                text = i18n.misc.upgraded_from_map,
                result_amount = 1,
                groups = {
                    {
                        item_name = row['items.name'],
                        item_page = row['items._pageName'],
                        amount = 3,
                        notes = nil,
                    },
                },
                automatic = true,
            }
        end
    end]]
    
    --
    -- oils
    --
    if tpl_args._flags.is_blight_item and tpl_args.blight_item_tier > 1 then
        local results = m_cargo.query(
            {'items', 'blight_items'},
            {'items._pageName',  'items.name'},
            {
                join='items._pageID=blight_items._pageID',
                where=string.format('blight_items.tier = %s', tpl_args.blight_item_tier - 1),
            }
        )
        for _, row in ipairs(results) do
            sets[#sets+1] = {
                text = nil,
                result_amount = 1,
                groups = {
                    {
                        item_name = row['items.name'],
                        item_page = row['items._pageName'],
                        amount = 3,
                        notes = nil,
                    },
                },
                automatic = true,
            }
        end
    end
    
    
    --
    -- essences
    --
    
    -- exclude remnant of corruption via type
    if tpl_args.is_essence and tpl_args.essence_type > 0 then 
        local results = m_cargo.query(
            {'items', 'essences'},
            {
                'items._pageName',  
                'items.name', 
                'items.metadata_id',
                'essences.category',
                'essences.type',
            },
            {
                join='items._pageID=essences._pageID',
                where=string.format([[
                        (essences.category="%s" AND essences.level = %s)
                        OR (essences.type = %s AND essences.level = %s)
                        OR items.metadata_id = 'Metadata/Items/Currency/CurrencyCorruptMonolith'
                        OR (%s = 6 AND essences.type = 5 AND essences.level >= 5) 
                    ]], 
                    tpl_args.essence_category, tpl_args.essence_level - 1, 
                    tpl_args.essence_type - 1, tpl_args.essence_level,
                    -- special case for corruption only essences
                    tpl_args.essence_type
                ),
                orderBy='essences.level ASC, essences.type ASC',
            }
        )
        
        local remnant = results[1]
        if remnant['items.metadata_id'] ~= 'Metadata/Items/Currency/CurrencyCorruptMonolith' then
            error(string.format('Something went seriously wrong here. Got results: %s', mw.dumpObject(results)))
        end
        for i=2, #results do
            local row = results[i]
            if row['essences.category'] == tpl_args.essence_category then
                -- 3 to 1 recipe
                sets[#sets+1] = {
                    automatic = true,
                    result_amount = 1,
                    text = nil,
                    groups = {
                        {
                            item_id = row['items.metadata_id'],
                            item_page = row['items._pageName'],
                            item_name = row['items.name'],
                            amount = 3,
                        },
                    },
                }
                -- corruption +1
                sets[#sets+1] = {
                    automatic = true,
                    result_amount = 1,
                    text = i18n.essence_plus_one_level,
                    groups = {
                        {
                            item_id = row['items.metadata_id'],
                            item_page = row['items._pageName'],
                            item_name = row['items.name'],
                            amount = 1,
                        },
                        {
                            item_id = remnant['items.metadata_id'],
                            item_page = remnant['items._pageName'],
                            item_name = remnant['items.name'],
                            amount = 1,
                        },
                    },
                }
            elseif tonumber(row['essences.type']) == tpl_args.essence_type - 1 then
                -- corruption type change
                sets[#sets+1] = {
                    automatic = true,
                    result_amount = 1,
                    text = i18n.essence_type_change,
                    groups = {
                        {
                            item_id = row['items.metadata_id'],
                            item_page = row['items._pageName'],
                            item_name = row['items.name'],
                            amount = 1,
                        },
                        {
                            item_id = remnant['items.metadata_id'],
                            item_page = remnant['items._pageName'],
                            item_name = remnant['items.name'],
                            amount = 1,
                        },
                    },
                }
            end
        end
    end
    
    -- data based on mapping
    if tpl_args.drop_enabled and not tpl_args.disable_automatic_recipes then
        for _, data in ipairs(c.automatic_recipes) do
            data.defaults = data.defaults or {}
            local continue = true
            for key, value in pairs(c.automatic_recipe_defaults) do
                local func
                local v = data.defaults[key]
                if v == false then
                    -- check is disabled specifically, continue
                elseif v == nil then
                    func = value
                elseif type(v) == 'function' then
                    func = v
                else 
                    error(string.format('Invalid value for defaults at data %s', mw.dumpObject(data)))
                end
                if func then
                    continue = func(tpl_args) and continue
                    if not continue then
                        break
                    end 
                end
            end
            for _, condition in ipairs(data.condition) do
                continue = condition(tpl_args) and continue
                if not continue then
                    break
                end
            end
            
            if continue then
                sets[#sets+1] = {
                    automatic = true,
                    result_amount = 1,
                    text = data.text(),
                    groups = data.groups,
                }
                for groupid, row in ipairs(data.groups) do
                    if query_data['id'][row.item_id] then
                        table.insert(query_data['id'][row.item_id], {#sets, groupid})
                    else
                        query_data['id'][row.item_id] = {{#sets, groupid}, }
                    end
                end
            end
        end
    end
    
    if #sets == 0 then
        return
    end
    --
    -- Fetch item data in a single query to sacrifice database load with a lot of references
    --
    local query_data_array = {
        id = {},
        name = {},
        page = {},
    }
    local query_fields = {
        id = 'items.metadata_id',
        page = 'items._pageName',
        name = 'items.name',
    }
    local where = {}
    local expected_count = 0
    for key, thing_array in pairs(query_data) do
        for thing, _ in pairs(thing_array) do
            table.insert(query_data_array[key], thing)
        end
        if #query_data_array[key] > 0 then
            expected_count = expected_count + #query_data_array[key]
            local q_data = table.concat(query_data_array[key], '", "')
            table.insert(where, string.format('%s IN ("%s")', query_fields[key], q_data))
        end
    end
    local results = m_cargo.query(
        {'items'},
        {'items._pageName',  'items.name', 'items.metadata_id'},
        {
            where=table.concat(where, ' OR '),
        }
    )

    -- Now do The Void
    for _, row in ipairs(results) do
        if row[query_fields.id] and string.find(row[query_fields.id], 'Metadata/Items/DivinationCards/', 1, true) then
            local group = {
                item_id = 'Metadata/Items/DivinationCards/DivinationCardTheVoid',
                amount = 1,
            }
            local result = m_cargo.query(
                {'items'},
                {'items._pageName',  'items.name', 'items.metadata_id'},
                {
                    where=string.format('%s = "%s"', query_fields.id, group.item_id),
                }
            )
            if #result > 0 then
                sets[#sets+1] = {
                    automatic = true,
                    result_amount = 1,
                    text = i18n.the_void,
                    groups = {group},
                }
                if query_data['id'][group.item_id] then
                    table.insert(query_data['id'][group.item_id], {#sets, 1})
                else
                    query_data['id'][group.item_id] = {{#sets, 1}, }
                end
                table.insert(results, result[1])
            end
            break
        end
    end

    for _, row in ipairs(results) do
        for key, thing_array in pairs(query_data) do
            local set_groups = thing_array[row[query_fields[key]]]
            if set_groups then
                for _, set_group in ipairs(set_groups) do
                    local entry = sets[set_group[1]].groups[set_group[2]]
                    for entry_key, data_key in pairs(query_fields) do
                        -- metadata_id may be nil, since we don't know them for unique items
                        if row[data_key] then
                            entry['item_' .. entry_key] = row[data_key]
                        end
                    end
                end
                -- set this to nil for error checking in later step
                thing_array[row[query_fields[key]]] = nil
            end
        end
    end
    
    -- sbow the broken references if needed
    if #results ~= expected_count then
        -- query data was pruned of existing keys earlier, so only broken keys remain
        for key, array in pairs(query_data) do
            for thing, set_groups in pairs(array) do
                for _, set_group in ipairs(set_groups) do
                    tpl_args._flags.invalid_recipe_parts = true
                    tpl_args._errors[#tpl_args._errors+1] = m_util.string.format(i18n.errors.invalid_recipe_parts, string.format('recipe%s_part%s_item_%s', set_group[1], set_group[2], key), thing)
                end
            end
        end
    end
    
    --
    -- Check for duplicates
    --
    local delete_sets = {}
    for i=automatic_index, #sets do
        for j=1, automatic_index-1 do
            if #sets[i].groups == #sets[j].groups then
                local match = true
                for row_id, row in ipairs(sets[i].groups) do
                    -- Only the fields from the database query are matched since we can be sure they're correct. Other fields may be subject to user error.
                    for _, key in ipairs({'item_id', 'item_name', 'item_page'})  do
                        match = match and (row[key] == sets[j].groups[row_id][key])
                    end
                end
                if match then
                    tpl_args._flags.duplicate_recipes = true
                    tpl_args._errors[#tpl_args._errors+1] = string.format(i18n.errors.duplicate_recipes, j)
                    delete_sets[#delete_sets+1] = j 
                end
            end
        end
    end
    
    for offset, index in ipairs(delete_sets) do
        table.remove(sets, index-(offset-1))
    end
    --
    -- Set data
    -- 
    tpl_args.recipes = sets
    
    -- set recipes data
    for i, set in ipairs(sets) do
        tpl_args._subobjects[#tpl_args._subobjects+1] = {
            _table = 'acquisition_recipes',
            recipe_id = i,
            result_amount = set.result_amount,
            description = set.text,
            automatic = set.automatic,
        }
        
        for j, group in ipairs(set.groups) do
            tpl_args._subobjects[#tpl_args._subobjects+1] = {
                _table = 'acquisition_recipe_parts',
                part_id = j,
                recipe_id = i,
                item_name = group.item_name,
                item_id = group.item_id,
                item_page = group.item_page,
                amount = group.amount,
                notes = group.notes,
            }
        end
    end
end

--
-- Debugging
--

function p.debug_validate_auto_upgraded_from(frame)
    local q = {}
    local chk = {}
    for _, data in ipairs(c.automatic_recipes) do
        for _, group in ipairs(data.groups) do
            q[#q+1] = group.item_id
            chk[group.item_id] = {
                amount=group.amount,
                text=data.text(),
            }
        end
    end
    
    local results = m_cargo.array_query{
        tables={'items', 'stackables'},
        fields={'items.name', 'items.class_id', 'items.description', 'stackables.stack_size'},
        id_field='items.metadata_id',
        id_array=q,
        query={
            join='items._pageName=stackables._pageName',
        },
    }
    
    for _, row in ipairs(results) do
        if row['items.class_id'] == 'DivinationCard' and chk[row['items.metadata_id']].amount ~= tonumber(row['stackables.stack_size']) then
            mw.logObject(string.format('Amount mismatch %s, expected %s', row['items.metadata_id'], row['stackables.stack_size']))
        end
    end
    
    tbl = mw.html.create('table')
    tbl:attr('class', 'wikitable sortable')
    for _, row in ipairs(results) do
        tbl
            :tag('tr')
                :tag('td')
                    :wikitext(row['items.name'])
                    :done()
                :tag('td')
                    :wikitext(chk[row['items.metadata_id']].text)
                    :done()
                :tag('td')
                    :wikitext(row['items.description'])
                    :done()
                :done()
    end
    
    return tostring(tbl)
end

return p