Module:Sandbox/Aurelain/ArtifactsOverview

From Heroes of Might and Magic: Olden Era Official Wiki

This module renders a giant table with all artifacts. Scroll artifacts are consolidated into 3 generic scroll artifacts (normal, enchanted and mythic). Campaign artifacts are excluded.

A hyper parameter is supported. For more information, see Module:UtilHyper/doc.

Usage

Input: {{#invoke:Sandbox/Aurelain/ArtifactsOverview|display | lang=en | hyper=Attack=Hero_Basics#Attributes}}

Output:

table#1 {
    table#2 {
        ["description"] = "Parchment imbued with magical knowledge.",
        ["id"] = "enchanted_magic_scroll_artifact_day_10_magic_second_song",
        ["language"] = "en",
        ["type"] = "artifact_narrative",
    },
    table#3 {
        ["description"] = "Adds the max. level “Song of Power” spell to the hero’s Spellbook.",
        ["id"] = "enchanted_magic_scroll_artifact_day_10_magic_second_song",
        ["language"] = "en",
        ["name"] = "Enchanted Magic Scroll",
        ["type"] = "artifact",
    },
}

-- Usage: {{#invoke:ArtifactsOverview|display | lang=en}}
local p = {}
local f = mw.ustring.format

-- Note: The right side is just a fallback, it will seldom be used.
local TRANSLATION_IDS = {
    wiki_none = 'None',
    wiki_artifact = 'Artifact',
    unit_window_narrative = 'Description'
}

-- Displays a variable
------------------------------------------------------------------------------------------------------------------------
local function dump(target)
    return '<pre>' .. mw.dumpObject(target) .. '</pre>'
end

-- Spawns a safe robotic url from an English name, fit for adding it before the visible name
------------------------------------------------------------------------------------------------------------------------
local function getUrl(nameEn, lang)
    if not nameEn then
        return ''
    end
    local url = nameEn
    if lang ~= 'en' then
        url = url .. '/' .. lang
    end
    return url
end

-- Retrieves the text for some specific ids from Cargo Translations.
------------------------------------------------------------------------------------------------------------------------
local function translateIds(ids, lang, extra)
    -- Key list
    local list = {}
    for key, _ in pairs(ids) do
        list[#list + 1] = key
    end
    local idListString = '"' .. table.concat(list, '", "') .. '"'

    -- Cargo
    local where = {}
    table.insert(where, 'target_id IN (' .. idListString .. ')')
    table.insert(where, 'language = "' .. lang .. '"')
    if extra then
        table.insert(where, extra)
    end
    local results = mw.ext.cargo.query('Translation', 'target_id, name', {
        where = table.concat(where, ' AND '),
        limit = 100
    })

    -- Dictionary
    local dictionary = mw.clone(ids)
    for key, value in pairs(dictionary) do
        dictionary[key] = value .. '🗯️'
    end
    for _, row in ipairs(results) do
        local name = row['name']
        if name and name ~= '' then
            dictionary[row['target_id']] = name
        end
    end
    return dictionary
end

-- Converts a dictionary into a linear array
------------------------------------------------------------------------------------------------------------------------
local function flatten(hub)
    local list = {}
    for _, entry in pairs(hub) do
        list[#list + 1] = entry
    end
    return list
end

-- Interrogates the main Cargo table
------------------------------------------------------------------------------------------------------------------------
local function queryMain(lang)
    -- fields:
    local fields = {}
    table.insert(fields, 'A.id = id');
    --table.insert(fields, 'A.slot = slot');
    --table.insert(fields, 'A.rarity = rarity');
    --table.insert(fields, 'A.artifact_set_id = artifact_set_id');
    --table.insert(fields, 'A.goods_value = goods_value');
    --table.insert(fields, 'A.max_level = max_level');
    --table.insert(fields, 'A.cost_base = cost_base');
    --table.insert(fields, 'A.cost_per_level = cost_per_level');
    table.insert(fields, 'T.language = language');
    table.insert(fields, 'T.name = name');
    table.insert(fields, 'T.description = description');
    table.insert(fields, 'T.type = type');

    -- where:
    local where = {}
    table.insert(where, 'A.id NOT LIKE "campaign_%"')
    table.insert(where, 'A.id LIKE "enchanted_magic_scroll_artifact_day_10_magic_second_song"')
    --table.insert(where, 'T.type = "artifact"')
    table.insert(where, '(T.language = "en" OR T.language = "' .. lang .. '")')

    -- query:
    return mw.ext.cargo.query('Artifact=A, Translation=T', table.concat(fields, ','), {
        join = 'A.id = T.target_id',
        where = table.concat(where, ' AND '),
        limit = 500
    })
end

-- Folds magic scrolls into 3 artifacts (normal, enchanted and mythic):
------------------------------------------------------------------------------------------------------------------------
local function consolidateScrolls(lang, results)
    local hub = {}
    for _, row in ipairs(results) do
        local id = row.id
        if id:find('magic_scroll') then
            if id:find('mythic') then
                id = 'mythic_scroll_box_artifact'
            else
                if id:find('enchanted') then
                    id = 'enchanted_magic_scroll_artifact'
                else
                    id = 'magic_scroll_artifact'
                end
            end
            local entry = hub[id]
            if not entry then
                entry = {}
                entry.id = id or ''
                entry.spells = {}
                entry.slot = row.slot or ''
                entry.rarity = row.rarity or ''
                entry.artifact_set_id = row.artifact_set_id or ''
                --entry.goods_value = row.goods_value or 0
                entry.max_level = row.max_level or 0
                entry.cost_base = row.cost_base or 0
                entry.cost_per_level = row.cost_per_level or 0
                hub[id] = entry
            end
            if row.language == lang then
                entry.name = row.name or ''
            end
            if row.language == 'en' then
                entry.nameEn = row.name or ''
                local spellId = row.id:gsub('.*artifact_', '')
                table.insert(entry.spells, spellId)
            end
        end
    end
    return hub
end

-- Folds all Cargo results into a single dictionary:
------------------------------------------------------------------------------------------------------------------------
local function consolidate(lang, results)
    local hub = consolidateScrolls(lang, results)
    do return hub end;
    for _, row in ipairs(results) do
        local id = row.id
        if not id:find('magic_scroll') then
            local entry = hub[id]
            if not entry then
                entry = {}
                entry.id = id or ''
                entry.slot = row.slot or ''
                entry.rarity = row.rarity or ''
                entry.artifact_set_id = row.artifact_set_id or ''
                --entry.goods_value = row.goods_value or 0
                entry.max_level = row.max_level or 0
                entry.cost_base = row.cost_base or 0
                entry.cost_per_level = row.cost_per_level or 0
                hub[id] = entry
            end
            if row.language == lang then
                entry.name = row.name or ''
                if row.type == 'artifact' then
                    entry.description = row.description or ''
                end
                if row.type == 'artifact_upgrade' then
                    entry.upgrade = row.description or ''
                end
                if row.type == 'artifact_narrative' then
                    entry.narrative = row.description or ''
                end
            end
            if row.language == 'en' then
                entry.nameEn = row.name or ''
            end
        end
    end
    return hub
end

------------------------------------------------------------------------------------------------------------------------
local function sortList(a, b)
    return a.id < b.id
end

-- Boilerplate for the header cells
------------------------------------------------------------------------------------------------------------------------
local function addTh(tr, text)
    return tr:tag('th'):wikitext(text)
end

-- Boilerplate for the body cells
------------------------------------------------------------------------------------------------------------------------
local function addTd(tr, content)
    if type(content) == "string" then
        return tr:tag('td'):wikitext(content)
    else
        return tr:tag('td'):node(content)
    end
end

-- Boilerplate for the separator rows
------------------------------------------------------------------------------------------------------------------------
local function addSeparator(htmlTable, className, content)
    htmlTable:tag('tr')
        :addClass('separator')
        :addClass(className)
        :tag('td'):attr('data-sort-value', ''):attr('colspan', 100):wikitext(content):done()
end

-- TABLE HEADER
------------------------------------------------------------------------------------------------------------------------
local function createHeader(htmlTable, words)
    local tr = htmlTable:tag('tr')
    --addTh(tr, 'id')
    addTh(tr, words.wiki_artifact):attr('colspan', 2)
    addTh(tr, words.unit_window_narrative)
    addTh(tr, 'upgrade')
    --addTh(tr, 'narrative')
    addTh(tr, 'slot')
    addTh(tr, 'rarity')
    addTh(tr, 'artifact_set_id')
    addTh(tr, 'max_level')
    addTh(tr, 'cost_base')
    addTh(tr, 'cost_per_level')
end

------------------------------------------------------------------------------------------------------------------------
local function renderIcon(id, nameEn, lang)
    local url = getUrl(nameEn, lang)
    return f('[[File:%s.png|64px|link=%s]]', id, url)
end

------------------------------------------------------------------------------------------------------------------------
local function renderName(name, nameEn, lang)
    local url = getUrl(nameEn, lang)
    return f('[[%s|%s]]', url, name)
end

-- TABLE BODY
------------------------------------------------------------------------------------------------------------------------
local function createBody(htmlTable, list, lang)
    local currentType = list[1].param1
    local currentFaction = list[1].faction
    for _, item in ipairs(list) do
        -- separators
        if item.faction ~= currentFaction then
            currentFaction = item.faction
            currentType = item.class_type
            addSeparator(htmlTable, 'separator-large', '')
        elseif item.class_type ~= currentType then
            currentType = item.class_type
            addSeparator(htmlTable, 'separator-tiny', '')
        end

        local tr = htmlTable:tag('tr'):addClass('artifact')
        --addTd(tr, item.id)
        addTd(tr, renderIcon(item.id, item.nameEn, lang))
        addTd(tr, renderName(item.name, item.nameEn, lang))
        addTd(tr, item.description)
        addTd(tr, item.upgrade)
        --addTd(tr, item.narrative)
        addTd(tr, item.slot)
        addTd(tr, item.rarity)
        addTd(tr, item.artifact_set_id)
        addTd(tr, item.max_level)
        addTd(tr, item.cost_base)
        addTd(tr, item.cost_per_level)
    end
end

-- M A I N
------------------------------------------------------------------------------------------------------------------------
function p.display(frame)
    --do return dump(frame) end

    -- Args
    local args = frame.args
    local lang = args.lang ~= '' and args.lang or 'en'
    --lang = 'ja'

    -- Language
    local words = translateIds(TRANSLATION_IDS, lang)

    -- Cargo
    local results = queryMain(lang)
    do return dump(results) end
    local hub = consolidate(lang, results)
    --do return dump(hub) end
    local list = flatten(hub);
    if #list == 0 then return words.wiki_none end

    -- Various manipulations
    table.sort(list, sortList)

    -- Table
    local htmlTable = mw.html.create('table')
    htmlTable:addClass('wikitable sortable')
    createHeader(htmlTable, words)
    createBody(htmlTable, list, lang)

    -- Output
    local styleTag = frame:extensionTag('templatestyles', '', { src = frame:getTitle() .. '/styles.css' })
    return '<div class="artifacts-overview">' .. styleTag .. tostring(htmlTable) .. '</div>'
end

return p