Path of Exile Wiki

Please consider helping keep the wiki up to date. Check the to-do list of updates needed for version 3.14.0.

Game data exports will becoming later as the technical changes in addition to regular changes take some more time.

READ MORE

Path of Exile Wiki
Advertisement
Module documentation[view] [edit] [history] [purge]

--
-- Module for passive skill table
--

local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local getArgs = require('Module:Arguments').getArgs
local f_passive_skill_link = require('Module:passive_skill_link').passive_skill_link

-- ----------------------------------------------------------------------------
-- Strings
-- ----------------------------------------------------------------------------

local i18n = {
    icon_name = 'File:%s passive skill icon.png',

    cats = {
        data = 'Passive skill data',

        keystone = 'Keystone passive skills',
        notable = 'Notable passive skills',
        basic = 'Basic passive skills',
        ascendancy_notable = 'Ascendancy notable passive skills',
        ascendancy_basic = 'Ascendancy basic passive skills',
    },

    passive_table = {
        ascendancy_class = 'Ascendancy<br>Class',
        name = 'Name',
        id = 'Id',
        int_id = 'Integer id',
        stats = 'Stats',
        skill_points = 'Skill points',
        connections = 'Connections',
        flavour_text = 'Flavour text',
        reminder_text = 'Reminder text',
        is_notable = 'Notable',
        is_keystone = 'Keystone',
    },

    errors = {
        invalid_args = 'Passive skill table: q_where must be specified',
        no_passives_found = 'No passive skills with the given name found',
        cats = 'Pages with broken passive skill tables',
    },
}


-- ----------------------------------------------------------------------------
-- Constants & Data
-- ----------------------------------------------------------------------------

-- local c = {}

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

local h = {}

function h.make_order(results, field, args)
    --[[
    Merge duplicates and then create a ordered list.
    ]]
    local values = {}
    local order = {}
    for _, row in ipairs(results) do
        local val = row[field]
        if args.fmt then
            val = args.fmt(row[field])
        end
        -- Can't show results here that don't have a value:
        if val then
            if values[val] == nil then
                values[val] = {row}
                table.insert(order, val)
            else
                table.insert(values[val], row)
            end
        end
    end

    return values, order
end

function h.data_page_links(values, order)
    local out = {}
    for i, key in ipairs(order) do
        local links = {}
        for j, row in ipairs(values[key]) do
            links[#links+1] = string.format(
                '[[%s|&#91;%s&#93;]]',
                row['passive_skills._pageName'],
                j + (i-1) * #values[key]
            )
        end
        out[i] = string.format(
            '<span class="passive-line">%s <span class="passive-hover">%s</span></span>',
            key,
            table.concat(links, ' ')
        )
    end

    return table.concat(out, '<hr>')
end

function h.get_type(passive)
    --[[
    Determine what type of passive skill this passive is.
    ]]
    local key
    if tonumber(passive['passive_skills.is_keystone']) == 1 then
        key = 'keystone'
    elseif tonumber(passive['passive_skills.is_notable']) == 1 then
        key = 'notable'
    else
        key = 'basic'
    end

    if passive['passive_skills.ascendancy_class'] ~= nil then
        key = 'ascendancy_' .. key
    end

    return key
end

function h.na_or_val(tr, value, func, args)
    --[[

    Parameters
    ----------
    tr :

    value :

    func : function

    args : list of
        Valid keys are:
        * colour

    ]]
    local args = args or {}
    if value == nil or value == '' then
        tr:wikitext(m_util.html.td.na())
    else
        local raw_value = value
        if func ~= nil then
            value = func(value)
        end

        local td = tr:tag('td')
        td:attr('data-sort-value', raw_value)
        td:wikitext(value)
        if args.colour then
            td:attr('class', 'tc -' .. args.colour)
        end
    end
end

-- Format style for field:
h.fmt = {}
function h.fmt.link(field)
    local fields = m_util.string.split(field, ',')
    for i, v in ipairs(fields) do
        fields[i] = string.format('[[%s]]', v)
    end
    return table.concat(fields, ', ')
end
function h.fmt.passive_skill_link(field)
    local fields = m_util.string.split(field, ',')
    for i, v in ipairs(fields) do
        fields[i] = f_passive_skill_link{id=v}
    end
    return table.concat(fields, ', ')
end
function h.fmt.boolean(field)
    local fields = m_util.string.split(field, ',')
    for i, v in ipairs(fields) do
        if m_util.cast.boolean(v) then
            fields[i] = '<div class="table-yes" data-sort-value=1><span>&#x2713;</span></div>'
        else
            fields[i] = '<div class="table-no" data-sort-value=0><span>&#x2717;</span></div>'
        end
    end
    return table.concat(fields, ', ')
end
function h.fmt.link_passive(field)
    --[[
    Create a link to the passive skill data page from the ID.
    ]]
    local fields = m_util.string.split(field, ',')
    for i, v in ipairs(fields) do
        fields[i] = string.format(
            '[[Passive Skill:%s|%s]]',
            string.gsub(v, '_', '~'),
            v
        )
    end
    return table.concat(fields, ', ')
end

-- Display
h.tbl = {}
h.tbl.display = {}

h.tbl.display.factory = {}
function h.tbl.display.factory.merged_values(args)
    local args = args or {}
    return function (tpl_args, frame, tr, rows, rowinfo)
        local values, order = h.make_order(rows, args.field, args)
        local value = h.data_page_links(values, order)
        h.na_or_val(tr, value, func, args)
    end
end

-- ----------------------------------------------------------------------------
-- Data mappings
-- ----------------------------------------------------------------------------

data = {}
data.passive_skill_table = {
    tables = {
        passive_skill_stats = {
            join='passive_skills._pageID=passive_skill_stats._pageID',
        },
        main_pages = {
            join='passive_skills.id=main_pages.id'
        }
    },
    -- Display data
    {
        args = nil,
        header = i18n.passive_table.name,
        fields = {
            -- Optional:
            'passive_skills.is_keystone',
            'passive_skills.is_notable',
            'passive_skills.ascendancy_class',
            'passive_skills.main_page',
            'main_pages._pageName',
            -- 'passive_skills.html',

            -- Required:
            'passive_skills._pageName',
            'passive_skills.name',
            'passive_skills.icon',
        },
        display = function (tpl_args, frame, tr, data)
            local passive = data[1]

            local psl_args = {
                skip_query = true,
                page = passive['passive_skills.main_page']
                    or passive['main_pages._pageName']
                    or passive['passive_skills.name']
                    or passive['passive_skills._pageName'],
                name = passive['passive_skills.name'],
                icon = passive['passive_skills.icon'],
                is_keystone = passive['passive_skills.is_keystone'],
                is_notable = passive['passive_skills.is_notable'],
                ascendancy_class = passive['passive_skills.ascendancy_class'],
            }
            if tpl_args.no_html == nil then
                psl_args.html = passive['passive_skills.html']
            end
            if tpl_args.large then
                psl_args.large = tpl_args.large
            end

            tr
                :tag('td')
                    :attr(
                        'data-sort-value',
                        passive['passive_skills.name'] .. h.get_type(passive)
                    )
                    :attr('style', 'text-align:center;')
                    :wikitext(f_passive_skill_link(psl_args))
                    :done()

        end,
        order = 1000,
        sort_type = 'text',
        options = {
            [1] = {optional=true},
            [2] = {optional=true},
            [3] = {optional=true},
            [4] = {optional=true},
            [5] = {optional=true},
        },
    },
    {
        args = {'ascendancy'},
        header = i18n.passive_table.ascendancy_class,
        fields = {'passive_skills.ascendancy_class'},
        display = function (tpl_args, frame, tr, data)
            local passive = data[1]
            h.na_or_val(tr, passive['passive_skills.ascendancy_class'],
                function ()
                    return string.format(
                        '[[%s]]<br>[[File:%s avatar.png|link=%s]]',
                        passive['passive_skills.ascendancy_class'],
                        passive['passive_skills.ascendancy_class'],
                        passive['passive_skills.ascendancy_class']
                    )
                end
            )
        end,
        order = 0,
        sort_type = 'text',
    },
    {
        args = 'id',
        header = i18n.passive_table.id,
        fields = {'passive_skills.id'},
        display = h.tbl.display.factory.merged_values{field='passive_skills.id'},
        order = 1001,
        sort_type = 'text',
    },
    {
        args = 'int_id',
        header = i18n.passive_table.int_id,
        fields = {'passive_skills.int_id'},
        display = h.tbl.display.factory.merged_values{field='passive_skills.int_id'},
        order = 1002,
        sort_type = 'text',
    },
    {
        args = {'stat', 'stats', 'stat_text'},
        header = i18n.passive_table.stats,
        fields = {'passive_skills.stat_text'},
        display = h.tbl.display.factory.merged_values{field='passive_skills.stat_text', colour='mod'},
        order = 2000,
        sort_type = 'text',
    },
    {
        args = 'skill_points',
        header = i18n.passive_table.skill_points,
        fields = {'passive_skills.skill_points'},
        display = h.tbl.display.factory.merged_values{field='passive_skills.skill_points'},
        order = 2001,
        sort_type = 'text',
    },
    {
        args = 'connections',
        header = i18n.passive_table.connections,
        fields = {'passive_skills.connections'},
        display = h.tbl.display.factory.merged_values{
            field='passive_skills.connections',
            fmt=h.fmt.passive_skill_link,
        },
        order = 3000,
        sort_type = 'text',
    },
    {
        args = 'flavour_text',
        header = i18n.passive_table.flavour_text,
        fields = {'passive_skills.flavour_text'},
        display = h.tbl.display.factory.merged_values{
            field='passive_skills.flavour_text',
            colour='flavour',
        },
        order = 3001,
        sort_type = 'text',
    },
    {
        args = 'reminder_text',
        header = i18n.passive_table.reminder_text,
        fields = {'passive_skills.reminder_text'},
        display = h.tbl.display.factory.merged_values{
            field='passive_skills.reminder_text',
            colour='help',
        },
        order = 3002,
        sort_type = 'text',
    },
    {
        args = 'is_notable',
        header = i18n.passive_table.is_notable,
        fields = {'passive_skills.is_notable'},
        display = h.tbl.display.factory.merged_values{
            field='passive_skills.is_notable',
            fmt=h.fmt.boolean
        },
        order = 4000,
        sort_type = 'number',
    },
    {
        args = 'is_keystone',
        header = i18n.passive_table.is_keystone,
        fields = {'passive_skills.is_keystone'},
        display = h.tbl.display.factory.merged_values{
            field='passive_skills.is_keystone',
            fmt=h.fmt.boolean
        },
        order = 4001,
        sort_type = 'number',
    },
}

-- ----------------------------------------------------------------------------
-- Page functions
-- ----------------------------------------------------------------------------

local p = {}

function p.passive_skill_table(frame)
    --[[
    Displays a table of passive skills.

    TODO: Why is the groupBy necessary?

    Examples
    --------
    = p.passive_skill_table{
        q_where = 'passive_skills.ascendancy_class = "Gladiator"',
        large=1,
    }
    = p.passive_skill_table{
        q_where='passive_skills.stat_text LIKE "%damage%taken%as%"',
        ascendancy=1,
        stat_text=1,
    }

    ]]
    local t = os.clock()

    -- Get args
    local tpl_args = getArgs(frame, {
        parentFirst = true
    })
    frame = m_util.misc.get_frame(frame)

    -- Check if the correct parameters have been set:
    if tpl_args.q_where == nil then
        return m_util.html.error{msg=i18n.errors.invalid_args .. m_util.misc.add_category(i18n.errors.cats)}
    end

    -- Cargo query settings:
    tpl_args.q_groupBy = tpl_args.q_groupBy or 'passive_skills._pageID'
    tpl_args.q_orderBy = tpl_args.q_orderBy or [[
        passive_skills.ascendancy_class IS NULL DESC,
        passive_skills.is_keystone,
        passive_skills.is_notable,
        passive_skills.name
    ]]

    -- Run the query and display the results:
    local out = m_cargo.table_query{
        tpl_args=tpl_args,
        frame=frame,
        main_table='passive_skills',
        row_unique_fields={'passive_skills.name'},
        data=data.passive_skill_table,
        empty_cell=m_util.html.td.na()
    }

    mw.logObject({os.clock() - t, tpl_args})

    return out
end


-- ----------------------------------------------------------------------------
-- End
-- ----------------------------------------------------------------------------

return p