Module:Mastery group

From Path of Exile Wiki
Revision as of 02:53, 12 November 2021 by Angelic knight (talk | contribs) (Initial module based on a copy of Passive skill)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
Module documentation[view] [edit] [history] [purge]


Lua logo

This module depends on the following other modules:

This module is for specifying one passive mastery. Implements {{mastery group}}.

--
-- Module for Mastery Groups
--

local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local getArgs = require('Module:Arguments').getArgs
local f_infocard = require('Module:Infocard')._main

local p = {}

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

local i18n = {
    cats = {
        effect = 'Mastery Group',
        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_box = {
        keystone = 'Keystone',
        notable = 'Notable Passive Skill',
        basic = 'Passive Skill',
        ascendancy_notable = 'Ascendancy Notable Passive Skill',
        ascendancy_basic = 'Ascendancy Passive Skill',
    },
    
    intro = {
        text_with_name = "'''%s''' is the internal id for the [[%s|%s]] [[passive skill]]. ",
        text_without_name = "'''%s''' is the internal id of an unnamed [[passive skill]]. ",
    },
    
    passive_box_table = {
        id = 'Id',
        int_id = 'Integer Id',
        flavour_text = 'Flavour Text',
        reminder_text = 'Reminder Text',
        skill_points = 'Skill Points Granted',
        ascendancy_class = 'Ascendancy Class',
        connections = 'Connections',
    },
    
    passive_table = {
        ascendancy_class = 'Ascendancy<br>Class',
        name = 'Name',
        stats = 'Stats',
    },
    
    errors = {
        no_passives_found = 'No passive skills with the given name found',
    },
}

-- ----------------------------------------------------------------------------
-- Cargo
-- ----------------------------------------------------------------------------

local tables = {}

tables.mastery_groups = {
    table = 'mastery_groups',
    order = {'id', 'main_page', 'mastery_effects',},
    fields = {
        id = {
            field = 'id',
            type = 'String',
            required = true,
        },
        main_page = {
            field = 'main_page',
            type = 'Page',
        },
        stat_text = {
            field = 'stat_text',
            type = 'Text',
        },
        mastery_effects = {
            field = 'mastery_effects',
            type = 'List (,) of String',
        },
    }
}


-- local display = {}
-- display.map_to_property = {'icon', 'is_keystone', 'is_notable', 'ascendancy_class'}
-- display.tbl = {
--     {
--         key = 'id',
--         header = i18n.passive_box_table.id,
--         display = nil,
--     },
--     {
--         key = 'int_id',
--         header = i18n.passive_box_table.int_id,
--         display = nil,
--     },
--     {
--         css = 'tc -flavour',
--         key = 'flavour_text',
--         header = i18n.passive_box_table.flavour_text,
--         display = nil,
--     },
--     {
--         key = 'reminder_text',
--         header = i18n.passive_box_table.reminder_text,
--         display = nil,
--     },
--     {
--         key = 'skill_points',
--         header = i18n.passive_box_table.skill_points,
--         display = nil,
--     },
--     {
--         key = 'ascendancy_class',
--         header = i18n.passive_box_table.ascendancy_class,
--         display = function (tpl_args, frame, value)
--             return string.format('[[%s]]', value)
--         end,
--     },
--     {
--         key = 'connections',
--         header = i18n.passive_box_table.connections,
--         display = function (tpl_args, frame, value)
--             local results = m_cargo.map_results_to_id{
--                 field='passive_skills.id',
--                 results=m_cargo.array_query{
--                     tables={'passive_skills'},
--                     fields={'passive_skills.name', 'passive_skills._pageName'},
--                     id_array=value,
--                     id_field='passive_skills.id',
--                     ignore_missing=true,
--                 }
--             }
            
--             local ul = mw.html.create('ul')
--             for _, key in ipairs(value) do
--                 local row = results[key]
--                 if row then
--                     row = row[1]
--                 end
--                 local text
--                 if row then
--                     text = string.format('[[%s|%s]]', row['passive_skills._pageName'], row['passive_skills.name'] or row['passive_skills._pageName'])
--                 else
--                     text = key
--                 end
--                 ul
--                     :tag('li')
--                         :wikitext(text)
--                         :done()
--             end
            
--             return tostring(ul)
--         end,
--     },
-- }

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

local h = {}

-- function h.format_passive_icon(passive, passive_type)
--     if passive['passive_skills.icon'] == nil then
--         return ''
--     end
    
--     local cls = string.format('passive-icon-type__%s', passive_type)
--     local main_page = passive['passive_skills.main_page'] or passive['main_pages._pageName'] or passive['passive_skills.name'] or passive['passive_skills.icon']
--     div = mw.html.create('div')
--     div:addClass('passive-icon-container')
--     div:addClass(cls)
--     div:tag('div')
--         :addClass('passive-icon-frame')
--         :done()
--     div:wikitext(
--         string.format(
--             '[[%s|link=%s]]', 
--             passive['passive_skills.icon'], 
--             main_page
--         )
--     )
    
--     return tostring(div)
-- end

-- function h.make_stat_order(results)
--     local stats = {}
--     local stat_order = {}
--     for _, row in ipairs(results) do 
--         local stat = row['passive_skills.stat_text']
--         -- Can't show results here that don't have a stat line
--         if stat then
--             if stats[stat] == nil then
--                 stats[stat] = {row}
--                 table.insert(stat_order, stat)
--             else
--                 table.insert(stats[stat], row)
--             end
--         end
--     end
    
--     return stats, stat_order
-- end

-- function h.stat_page_links(stat_order, stats)
--     local out = {}
--     for i, key in ipairs(stat_order) do
--         local links = {}
--         for j, row in ipairs(stats[key]) do
--             links[#links+1] = string.format('[[%s|&#91;%s&#93;]]', row['passive_skills._pageName'], j)
--         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

-- h.type_order = {'basic', 'notable', 'keystone', 'ascendancy_basic', 'ascendancy_notable'}
-- function h.get_type(passive)
--     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.sort_by_type(results)
--     local new = {}
--     for _, key in ipairs(h.type_order) do
--         new[key] = {}
--     end
    
--     for _, passive in ipairs(results) do
--         table.insert(new[h.get_type(passive)], passive)
--     end
    
--     return new
-- end

-- function h.intro_text(tpl_args, frame)
--     --[[
--     Display an introductory text about the passive skill.
--     ]]
--     local out = {}
--     if mw.ustring.find(tpl_args['id'], '_') then
--         out[#out+1] = frame:expandTemplate{
--             title='Incorrect title', 
--             args = {title=tpl_args['id']} 
--         }
--     end
    
--     if tpl_args['name'] then
--         out[#out+1] = string.format(
--             i18n.intro.text_with_name, 
--             tpl_args['id'], 
--             tpl_args['main_page'] or tostring(mw.title.getCurrentTitle()), 
--             tpl_args['name']
--         )
--     else 
--         out[#out+1] = string.format(
--             i18n.intro.text_without_name,
--             tpl_args['id']
--         )
--     end 
    
--     return table.concat(out)
-- end

-- function h.stat_box(tpl_args, frame)
--     --[[
--     Display the stat box.
--     ]]
--     local container = mw.html.create('div')
--     container
--         :attr('class', 'modbox floatright')
        
--     -- stat table 
--     tbl = container:tag('table')
--     tbl
--         :attr('class', 'wikitable sortable')
--         -- :attr('style', 'style="width: 100%;"')
--         :tag('tr')
--             :tag('th')
--                 :attr('colspan', 3)
--                 :wikitext('Stats')
--                 :done()
--             :done()
--         :tag('tr')
--             :tag('th')
--                 :wikitext('#')
--                 :done()
--             :tag('th')
--                 :wikitext('Stat Id')
--                 :done()
--             :tag('th')
--                 :wikitext('Value')
--                 :done()
--             :done()
--             :done()
--         :done()
        
--     local i = 0
--     local value = nil
--     repeat
--         i = i + 1
--         value = {
--             id = tpl_args[string.format('stat%s_id', i)],
--             value = tpl_args[string.format('stat%s_value', i)],
--         }
        
--         if value.id then
--             tbl
--                 :tag('tr')
--                     :tag('td')
--                         :wikitext(i)
--                         :done()
--                     :tag('td')
--                         :wikitext(value.id)
--                         :done()
--                     :tag('td')
--                         :wikitext(value.value)
--                         :done()
--                     :done()
--                 :done()
--         end
--     until value.id == nil
    
--     return tostring(container)
-- end


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

local p = {}

-- This way the helper functions can be used in other modules
p.h = h

-- Declare cargo tables:
p.table_mastery_groups = m_cargo.declare_factory{data=tables.mastery_groups}
p.table_mastery_group_stats = m_cargo.declare_factory{data=tables.mastery_group_stats}

function p.mastery_group(frame)
    --[[
    Stores data and displays a infobox about the passive skill.
    
    Examples
    --------
    = p.mastery_group{
        id = 'Armour',
        mastery_effects = 'Armour1,Armour2,Armour3,Armour4,Armour5,Armour6',
    }
    
    ]]

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

    -- parse and store mastery group into cargo table
    m_util.args.from_cargo_map{
        tpl_args=tpl_args,
        frame=frame,
        table_map=tables.mastery_groups,
    }
    
    --
    -- Infobox
    --
    -- local passive = {}
    -- for _, key in ipairs(display.map_to_property) do
    --     local v = tpl_args[key]
    --     if type(v) == 'boolean' then
    --         if v then
    --             v = 1
    --         else
    --             v = 0
    --         end
    --     end
    --     passive[string.format('%s.%s', tables.passive_skills.table, tables.passive_skills.fields[key].field)] = v
    -- end
    
    -- local type_key = h.get_type(passive)
    
    -- local infocard_args = {}
    -- infocard_args.header = tpl_args.name
    -- infocard_args.subheader = i18n.passive_box[type_key]
    
    -- local tbl = mw.html.create('table')
    -- for _, data in ipairs(display.tbl) do
    --     local value = tpl_args[data.key]
    --     -- if default is nil, this will be compared against nil which is what we want, so value ~= nil isn't needed
    --     if value ~= tables.passive_skills.fields[data.key].default then
    --         local dsp
    --         if data.display then
    --             dsp = data.display(tpl_args, frame, value)
    --         else
    --             dsp = value
    --         end
    --         tbl
    --             :tag('tr')
    --                 :tag('th')
    --                     :wikitext(data.header)
    --                     :done()
    --                 :tag('td')
    --                     :attr('class', data.css)
    --                     :wikitext(dsp)
    --                     :done()
    --                 :done()
    --     end
    -- end
    
    -- infocard_args[1] = tostring(tbl)
    -- infocard_args[2] = tpl_args.stat_text
    -- infocard_args[3] = h.format_passive_icon(passive, type_key)

    -- local out = {
    --     f_infocard(infocard_args),
    --     h.intro_text(tpl_args, frame),
    --     h.stat_box(tpl_args, frame),
    -- }
    
    -- local cats = {
    --     i18n.cats.data,
    -- }
    -- return table.concat(out) .. m_util.misc.add_category(cats)
end

-- function p.passive_skill_box(frame)
--     --[[
--     Queries a passive skill and displays it.
    
--     Examples
--     --------
--     = p.passive_skill_box{name='Ghost Reaver'}
    
--     ]]
    
--     -- Get args
--     tpl_args = getArgs(frame, {
--         parentFirst = true
--     })
--     frame = m_util.misc.get_frame(frame)
    
--     tpl_args.name = tpl_args.name or tpl_args[1]
    
--     if not tpl_args.q_where and tpl_args.name then
--         tpl_args.q_where = string.format('passive_skills.name="%s" AND passive_skills.stat_text IS NOT NULL', tpl_args.name)
--     elseif not (tpl_args.q_where and not tpl_args.name) then
--         error('q_where or name must be specified')
--     end
    
--     local results = m_cargo.query(
--         {'passive_skills'},
--         {
--             'passive_skills._pageName', 
--             'passive_skills.main_page',
--             'passive_skills.name', 
--             'passive_skills.stat_text',
--             -- TODO: only really need these once, maybe put in extra query
--             'passive_skills.flavour_text',
--             'passive_skills.icon',
--             'passive_skills.is_keystone',
--             'passive_skills.is_notable',
--             'passive_skills.ascendancy_class',
--             'passive_skills.id'
--         }, 
--         {
--             where=tpl_args.q_where,
--             orderBy='passive_skills.stat_text',
--             limit=5000,
--         }
--     )
--     if #results == 0 then
--         error(i18n.errors.no_passives_found)
--     end
    
--     results = h.sort_by_type(results)
--     local out = {}
--     local cats = {}
--     for _, type_key in ipairs(h.type_order) do
--         local type_results = results[type_key]
--         if #type_results > 0 then
--             cats[#cats+1] = i18n.cats[type_key]
--             local stats, stat_order = h.make_stat_order(type_results)
            
--             local passive = type_results[1]
            
--             local infocard_args = {}
--             infocard_args.header = passive['passive_skills.name']
--             infocard_args.subheader = i18n.passive_box[type_key]
            
--             infocard_args[1] = h.format_passive_icon(passive, type_key)
--             infocard_args[2] = h.stat_page_links(stat_order, stats)
--             infocard_args[3] = m_util.html.poe_color('flavour', passive['passive_skills.flavour_text'])
            
--             out[#out+1] = f_infocard(infocard_args)
            
--             -- Store as main page:
--             for _, v in ipairs(type_results) do
--                 m_cargo.store(
--                     frame, 
--                     {
--                         _table='main_pages', 
--                         id=v['passive_skills.id'],
--                     }
--                 )
--             end
--         end
--     end
    
--     if tpl_args.cats == nil or m_util.cast.boolean(tpl_args.cats) then
--         out[#out+1] = m_util.misc.add_category(cats)
--     end
    
--     return table.concat(out)
-- end

-- function p.passive_skill_link(frame)
--     --[[
--     Links a passive skill
    
--     Examples
--     --------
--     = p.passive_skill_link{id='AscendancyAscendant45', format='tablerow'}
--     ]]
    
--     -- Get args
--     tpl_args = getArgs(frame, {
--         parentFirst = true
--     })
--     frame = m_util.misc.get_frame(frame)
    
--     tpl_args.name = tpl_args.name or tpl_args[1]
--     if tpl_args.name then
--         tpl_args.q_where = string.format('passive_skills.name="%s"', tpl_args.name)
--     elseif tpl_args.id then
--         tpl_args.q_where = string.format('passive_skills.id="%s"', tpl_args.id)
--     elseif tpl_args.q_where then
--     else
--         error('Either name, id or q_where must be specified')
--     end
    
--     local results = m_cargo.query(
--         {'passive_skills', 'main_pages'},
--         {
--             'passive_skills._pageName', 
--             'passive_skills.stat_text',
--             'passive_skills.main_page',
--             'passive_skills.name',
--             'passive_skills.icon',
--             'passive_skills.is_keystone',
--             'passive_skills.is_notable',
--             'passive_skills.ascendancy_class',
--             'main_pages._pageName',
--         }, 
--         {   
--             join='passive_skills.id=main_pages.id',
--             where=string.format('(%s) AND passive_skills.stat_text IS NOT NULL', tpl_args.q_where),
--             orderBy='passive_skills.stat_text',
--             limit=2,
--         }
--     )
    
--     if #results > 1 then
--         error('Too many passives found!')
--     elseif #results < 1 then
--         error('No passives found')
--     end
--     local passive = results[1]
    
--     if tpl_args.format == 'tablerow' then
--         local main_page = passive['passive_skills.main_page'] or passive['main_pages._pageName'] or passive['passive_skills.name']
--         return string.format(
--             '| [[%s|%s]]%s\n| %s', 
--             main_page, 
--             passive['passive_skills.name'], 
--             h.format_passive_icon(passive, h.get_type(passive)), 
--             passive['passive_skills.stat_text']
--         )
--     elseif tpl_args.format == nil then
--         return
--     else
--         error(string.format('Invalid return format specified: %s', tpl_args.format))
--     end
-- end

-- -- Not sure whether we need a more sophisticated variant like item or mod tables here yet

-- function p.passive_skill_table2(frame)
--     -- Get args
--     tpl_args = getArgs(frame, {
--         parentFirst = true
--     })
--     frame = m_util.misc.get_frame(frame)
    
--     if tpl_args.q_tables then 
--         tpl_args.q_tables = tpl_args.q_tables .. ',' .. 'passive_skill_stats'
--     else
--         tpl_args.q_tables = 'passive_skill_stats'
--     end
    
--     if tpl_args.q_join then 
--         tpl_args.q_join = tpl_args.q_join .. ',' .. 'passive_skills._pageID=passive_skill_stats._pageID'
--     else
--         tpl_args.q_join = 'passive_skills._pageID=passive_skill_stats._pageID'
--     end 
    
--     tpl_args.q_orderBy = 'passive_skills.ascendancy_class IS NULL DESC, passive_skills.is_keystone, passive_skills.is_notable, passive_skills.name'
    
--     return m_cargo.table_query{
--         tpl_args=tpl_args,
--         frame=frame,
--         main_table='passive_skills',
--         row_unique_fields = {'passive_skills.name'},
--         data={
--             tables = {
--                 passive_skill_stats = {
--                     join='passive_skills._pageID=passive_skill_stats._pageID',
--                 },
--             },
--             -- display data
--             {
--                 args = {'ascendancy'},
--                 header = i18n.passive_table.ascendancy_class,
--                 fields = {
--                     'passive_skills.ascendancy_class',
--                 },
--                 display = function (tpl_args, frame, tr, data)
--                     local passive = data[1]
--                     if passive['passive_skills.ascendancy_class'] then
--                         tr:tag('td')
--                             :wikitext(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']))
--                     else
--                         tr:wikitext(m_util.html.td.na{})
--                     end
--                 end,
--                 order = 0,
--                 sort_type = 'text',
--             },
--             {
--                 args = nil,
--                 header = i18n.passive_table.name,
--                 fields = {
--                     'passive_skills._pageName',
--                     'passive_skills.main_page',
--                     'passive_skills.name',
--                     'passive_skills.icon',
--                     'passive_skills.is_keystone',
--                     'passive_skills.is_notable',
--                     'passive_skills.ascendancy_class',
--                 },
--                 display = function (tpl_args, frame, tr, data)
--                     local passive = data[1]
--                     local type_key = h.get_type(passive)
--                     tr
--                         :tag('td')
--                             :attr('data-sort-value', passive['passive_skills.name'] .. type_key)
--                             :wikitext(string.format('[[%s|%s]]<br>%s', passive['passive_skills.main_page'] or passive['passive_skills.name'], passive['passive_skills.name'], h.format_passive_icon(passive, type_key)))
--                             :done()
--                 end,
--                 order = 1000,
--                 sort_type = 'text',
--                 options = {
--                     [7] = {
--                         optional=true,
--                     },
--                 },
--             },
--             {
--                 arg = {'default', 'stat', 'stats', 'stat_text'},
--                 header = i18n.passive_table.stats,
--                 fields = {
--                     'passive_skills.stat_text',
--                 },
--                 display = function (tpl_args, frame, tr, data)
--                     local passive = data[1]
--                     local stats, stat_order = h.make_stat_order(data)
--                     tr
--                         :tag('td')
--                             :wikitext(h.stat_page_links(stat_order, stats))
--                             :done()
--                 end,
--                 order = 1001,
--                 sort_type = 'text',
--             }
--         },
--     }
-- end

-- function p.passive_skill_table(frame)
--     -- Get args
--     tpl_args = getArgs(frame, {
--         parentFirst = true
--     })
--     frame = m_util.misc.get_frame(frame)
    
--     tpl_args.ascendancy = m_util.cast.boolean(tpl_args.ascendancy)
    
--     local prepend = {
--         q_join=true,
--     }
    
--     local query = {
--         join='passive_skills._pageID=passive_skill_stats._pageID',
--         limit=5000,
--         groupBy='passive_skills._pageID',
--     }
--     for key, value in pairs(tpl_args) do 
--         if string.sub(key, 0, 2) == 'q_' then
--             if prepend[key] then
--                 value = ',' .. value
--             end
            
--             query[string.sub(key, 3)] = value
--         end
--     end
    
--     local results = m_cargo.query(
--         {'passive_skills', 'passive_skill_stats'},
--         {
--             'passive_skills._pageName', 
--             'passive_skills.main_page',
--             'passive_skills.name',
--             'passive_skills.stat_text',
--             'passive_skills.icon',
--             'passive_skills.is_keystone',
--             'passive_skills.is_notable',
--             'passive_skills.ascendancy_class',
--         }, 
--         query
--     )
--     result_map = m_cargo.map_results_to_id{
--         results=results,
--         field='passive_skills.name',
--         keep_id_field=true,
--     }
--     for key, rows in pairs(result_map) do
--         result_map[key] = h.sort_by_type(rows)
--     end
    
--     -- header
--     local tbl = mw.html.create('table')
--     tbl:addClass('wikitable')
--     tbl:addClass('sortable')
    
--     local tr = tbl:tag('tr')
--     if tpl_args.ascendancy then
--         tr:tag('th')
--             :wikitext(i18n.passive_table.ascendancy_class)
--     end
    
--     tr
--         :tag('th')
--             :wikitext(i18n.passive_table.name)
--             :done()
--         :tag('th')
--             :wikitext(i18n.passive_table.stats)
--             :done()
    
--     -- rows
--     local used_names = {}
--     for _, passive_row in ipairs(results) do
--         local pn = passive_row['passive_skills.name']
--         if used_names[pn] == nil then
--             local type_results_map = result_map[passive_row['passive_skills.name']]
--             used_names[pn] = true
--             for _, type_key in ipairs(h.type_order) do
--                 local type_results = type_results_map[type_key]
--                 if #type_results > 0 then
--                     local row = type_results[1]
--                     tr = tbl:tag('tr')
                        
--                     if tpl_args.ascendancy then
--                         if row['passive_skills.ascendancy_class'] then
--                             tr:tag('td')
--                                 :wikitext(string.format('[[%s]]<br>[[File:%s avatar.png|link=%s]]', row['passive_skills.ascendancy_class'], row['passive_skills.ascendancy_class'], row['passive_skills.ascendancy_class']))
--                         else
--                             tr:wikitext(m_util.html.td.na{})
--                         end
--                     end
                    
--                     local stats, stat_order = h.make_stat_order(type_results)
--                     tr
--                         :tag('td')
--                             :attr('data-sort-value', row['passive_skills.name'] .. type_key)
--                             :wikitext(string.format('[[%s|%s]]<br>%s', row['passive_skills.main_page'] or row['passive_skills.name'], row['passive_skills.name'], h.format_passive_icon(row, type_key)))
--                             :done()
--                         :tag('td')
--                             :wikitext(h.stat_page_links(stat_order, stats))
--                             :done()
--                 end
--             end
--         end
--     end
    
--     return tostring(tbl)
-- end

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

return p