Module:Modifier table: Difference between revisions
Jump to navigation
Jump to search
>Illviljan (Comment out enchantments to reduce template size issues.) |
Mefisto1029 (talk | contribs) (no labs) |
||
| (30 intermediate revisions by 6 users not shown) | |||
| Line 1: | Line 1: | ||
-- | ------------------------------------------------------------------------------- | ||
Module responsible for displaying modifiers in various ways. | -- | ||
-- Module:Modifier table | |||
-- | |||
-- Module responsible for displaying modifiers in various ways. Implements | |||
-- Template:Modifier table and Template:Item modifiers | |||
------------------------------------------------------------------------------- | |||
require('strict') | |||
local m_util = require('Module:Util') | |||
local m_util | -- Should we use the sandbox version of our submodules? | ||
local | local use_sandbox = m_util.misc.maybe_sandbox('Modifier table') | ||
local | local m_cargo = use_sandbox and require('Module:Cargo/sandbox') or require('Module:Cargo') | ||
local m_game = use_sandbox and mw.loadData('Module:Game/sandbox') or mw.loadData('Module:Game') | |||
local | -- 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:Modifier table/config/sandbox') or mw.loadData('Module:Modifier table/config') | |||
local | local i18n = cfg.i18n | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
-- | -- Helper functions | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
local h = {} | local h = {} | ||
function h.query_weights(table_name, page_ids) | function h.query_weights(table_name, page_ids) | ||
| Line 120: | Line 34: | ||
{ | { | ||
'mods._pageID', | 'mods._pageID', | ||
table_name .. '.tag', | table_name .. '.tag=tag', | ||
table_name .. '. | table_name .. '.value=value' | ||
}, | }, | ||
{ | { | ||
where=page_ids, | where = page_ids, | ||
join=string.format('mods._pageID=%s._pageID', table_name), | join = string.format('mods._pageID=%s._pageID', table_name), | ||
orderBy=string.format('mods.id ASC,%s.ordinal ASC', table_name), | orderBy = string.format('mods.id ASC,%s.ordinal ASC', table_name), | ||
} | } | ||
), | ), | ||
field='mods._pageID', | field='mods._pageID', | ||
} | } | ||
end | end | ||
| Line 163: | Line 57: | ||
args.delimiter = args.delimiter or ', ' | args.delimiter = args.delimiter or ', ' | ||
return function(tpl_args | return function(tpl_args, tr, data, fields) | ||
local values = {} | local values = {} | ||
local fmt_values = {} | local fmt_values = {} | ||
| Line 180: | Line 74: | ||
opts.no_color = true | opts.no_color = true | ||
end | end | ||
fmt_values[#fmt_values+1] = m_util.html.format_value( | fmt_values[#fmt_values+1] = m_util.html.format_value(nil, value, opts) | ||
end | end | ||
end | end | ||
| Line 186: | Line 80: | ||
if #values == 0 then | if #values == 0 then | ||
tr | tr | ||
: | :node(m_util.html.table_cell('na')) | ||
else | else | ||
local td = tr:tag('td') | local td = tr:tag('td') | ||
| Line 193: | Line 87: | ||
:wikitext(table.concat(fmt_values, args.delimiter)) | :wikitext(table.concat(fmt_values, args.delimiter)) | ||
if args.color then | if args.color then | ||
td: | td:addClass('tc -' .. args.color) | ||
end | end | ||
end | |||
end | |||
end | |||
function h.tbl.display.factory.weights(args) | |||
return function(tpl_args, tr, data, fields) | |||
local weights = {} | |||
for _, v in ipairs(tpl_args[string.format('_%s_data', args.key)][data['mods._pageID']]) do | |||
if v.tag and v.value then | |||
table.insert(weights, string.format( | |||
'%s %s', | |||
v.tag, | |||
v.value | |||
)) | |||
end | |||
end | |||
if #weights == 0 then | |||
tr | |||
:node(m_util.html.table_cell('na')) | |||
else | |||
tr | |||
:tag('td') | |||
:wikitext(table.concat(weights, '<br>')) | |||
end | end | ||
end | end | ||
| Line 200: | Line 117: | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
-- | -- Additional configuration | ||
-- ---------------------------------------------------------------------------- | -- ---------------------------------------------------------------------------- | ||
| Line 214: | Line 131: | ||
}, | }, | ||
}, | }, | ||
display = function(tpl_args | display = function(tpl_args, tr, data, fields) | ||
local name | local name | ||
if data['mods.name'] then | if data['mods.name'] then | ||
| Line 233: | Line 150: | ||
header = i18n.mod_table.domain, | header = i18n.mod_table.domain, | ||
fields = {'mods.domain'}, | fields = {'mods.domain'}, | ||
display = function(tpl_args | display = function(tpl_args, tr, data, fields) | ||
local k = 'mods.domain' | local k = 'mods.domain' | ||
local i = tonumber(data[k]) | local i = tonumber(data[k]) | ||
if m_game.constants.mod.domains[i] == nil then | |||
error('Undefined Modifier Domain ['..i..'] needs to be added to Module:Game') | |||
end | |||
data[k] = m_game.constants.mod.domains[i]['short_upper'] | data[k] = m_game.constants.mod.domains[i]['short_upper'] | ||
h.tbl.display.factory.value | h.tbl.display.factory.value{}(tpl_args, tr, data, fields) | ||
end, | end, | ||
order = 2000, | order = 2000, | ||
| Line 246: | Line 166: | ||
header = i18n.mod_table.generation_type, | header = i18n.mod_table.generation_type, | ||
fields = {'mods.generation_type'}, | fields = {'mods.generation_type'}, | ||
display = function(tpl_args | display = function(tpl_args, tr, data, fields) | ||
local k = 'mods.generation_type' | local k = 'mods.generation_type' | ||
local i = tonumber(data[k]) | local i = tonumber(data[k]) | ||
if m_game.constants.mod.generation_types[i] == nil then | |||
error('Undefined Modifier Generation Type ['..i..'] needs to be added to Module:Game') | |||
end | |||
data[k] = m_game.constants.mod.generation_types[i]['short_upper'] | data[k] = m_game.constants.mod.generation_types[i]['short_upper'] | ||
h.tbl.display.factory.value{}(tpl_args | h.tbl.display.factory.value{}(tpl_args, tr, data, fields) | ||
end, | end, | ||
order = 2001, | order = 2001, | ||
| Line 257: | Line 180: | ||
{ | { | ||
arg = {'group', 'mod_group'}, | arg = {'group', 'mod_group'}, | ||
header = i18n.mod_table. | header = i18n.mod_table.mod_groups, | ||
fields = {'mods. | fields = {'mods.mod_groups'}, | ||
display = h.tbl.display.factory.value{}, | display = function(tpl_args, tr, data, fields) | ||
order = | local k = 'mods.mod_groups' | ||
data[k] = table.concat(m_util.string.split(data[k], ',%s*'), ', ') | |||
h.tbl.display.factory.value{}(tpl_args, tr, data, fields) | |||
end, | |||
order = 2010, | |||
sort_type = 'text', | sort_type = 'text', | ||
}, | }, | ||
| Line 268: | Line 195: | ||
fields = {'mods.mod_type'}, | fields = {'mods.mod_type'}, | ||
display = h.tbl.display.factory.value{}, | display = h.tbl.display.factory.value{}, | ||
order = | order = 2011, | ||
sort_type = 'text', | sort_type = 'text', | ||
}, | }, | ||
| Line 276: | Line 203: | ||
fields = {'mods.required_level'}, | fields = {'mods.required_level'}, | ||
display = h.tbl.display.factory.value{}, | display = h.tbl.display.factory.value{}, | ||
order = | order = 2012, | ||
}, | }, | ||
{ | { | ||
| Line 303: | Line 209: | ||
header = i18n.mod_table.stat_text, | header = i18n.mod_table.stat_text, | ||
fields = {'mods.stat_text'}, | fields = {'mods.stat_text'}, | ||
display = function(tpl_args | display = function(tpl_args, tr, data, fields) | ||
local value | local value | ||
-- map display type shows this in another column, remove this text to avoid clogging up the list | -- map display type shows this in another column, remove this text to avoid clogging up the list | ||
| Line 330: | Line 236: | ||
end | end | ||
data['mods.stat_text'] = value | data['mods.stat_text'] = value | ||
h.tbl.display.factory.value{color='mod'}(tpl_args | h.tbl.display.factory.value{color='mod'}(tpl_args, tr, data, fields) | ||
end, | end, | ||
order = 3000, | order = 3000, | ||
| Line 355: | Line 261: | ||
header = i18n.mod_table.tags, | header = i18n.mod_table.tags, | ||
fields = {'mods.tags'}, | fields = {'mods.tags'}, | ||
display = function(tpl_args | display = function(tpl_args, tr, data, fields) | ||
local k = 'mods.tags' | local k = 'mods.tags' | ||
data[k] = table.concat(m_util.string.split(data[k], ',%s*'), ', ') | data[k] = table.concat(m_util.string.split(data[k], ',%s*'), ', ') | ||
h.tbl.display.factory.value{}(tpl_args | h.tbl.display.factory.value{}(tpl_args, tr, data, fields) | ||
end, | end, | ||
order = 5000, | order = 5000, | ||
sort_type = 'text', | sort_type = 'text', | ||
}, | }, | ||
{ | |||
arg = {'spawn_weights'}, | |||
header = i18n.mod_table.spawn_weights, | |||
fields = {}, | |||
display = h.tbl.display.factory.weights{key='spawn_weights'}, | |||
order = 6000, | |||
sort_type = 'text', | |||
}, | |||
{ | |||
arg = {'generation_weights'}, | |||
header = i18n.mod_table.generation_weights, | |||
fields = {}, | |||
display = h.tbl.display.factory.weights{key='generation_weights'}, | |||
order = 6001, | |||
sort_type = 'text', | |||
}, | |||
--[[{ | |||
arg = {'game_mode'}, | |||
header = i18n.mod_table.game_modes, | |||
fields = {'mods.game_mode'}, | |||
display = function (tpl_args, tr, data, fields) | |||
local key = 'mods.game_mode' | |||
local value = data[key] | |||
if value ~= nil then | |||
local modes = {} | |||
value = m_util.cast.number(value) | |||
for k, m in ipairs(m_game.modes) do | |||
if value == 0 or value == k then | |||
table.insert(modes, m.short_upper) | |||
end | |||
end | |||
data[key] = table.concat(modes, ', ') | |||
end | |||
h.tbl.display.factory.value{}(tpl_args, tr, data, fields) | |||
end, | |||
order = 6010, | |||
sort_type = 'text', | |||
},--]] | |||
} | } | ||
mod_table.stat_ids = { | mod_table.stat_ids = { | ||
| Line 380: | Line 324: | ||
mod_table.weights = {'spawn_weights', 'generation_weights'} | mod_table.weights = {'spawn_weights', 'generation_weights'} | ||
function | -- ---------------------------------------------------------------------------- | ||
-- Main functions | |||
-- ---------------------------------------------------------------------------- | |||
local function _mod_table(tpl_args) | |||
--[[ | --[[ | ||
Creates a generic table for modifiers. | Creates a generic table for modifiers. | ||
| Line 387: | Line 335: | ||
-------- | -------- | ||
= p.mod_table{ | = p.mod_table{ | ||
q_tables=' | q_tables='mod_spawn_weights', | ||
q_join='mods._pageID= | q_join='mods._pageID=mod_spawn_weights._pageID', | ||
q_where='mods.generation_type = 10 AND | q_where='mods.generation_type = 10 AND mod_spawn_weights.tag = "boots" AND mod_spawn_weights.weight > 0', | ||
q_orderBy='mods.id, mods.required_level', | q_orderBy='mods.id, mods.required_level', | ||
q_limit=100, | q_limit=100, | ||
| Line 395: | Line 343: | ||
enchantment=1, | enchantment=1, | ||
} | } | ||
]] | ]] | ||
-- default to enabled | -- default to enabled | ||
| Line 498: | Line 439: | ||
page_ids = table.concat(page_ids, ' OR ') | page_ids = table.concat(page_ids, ' OR ') | ||
for _, key in ipairs(mod_table.weights) do | for _, key in ipairs(mod_table.weights) do | ||
if tpl_args[key] then | if tpl_args[key] then | ||
weights[key] = h.query_weights(key, page_ids) | -- Store weights data in tpl_args to be accessed later | ||
tpl_args[string.format('_%s_data', key)] = h.query_weights('mod_' .. key, page_ids) | |||
end | end | ||
end | end | ||
| Line 559: | Line 500: | ||
local tbl = mw.html.create('table') | local tbl = mw.html.create('table') | ||
tbl: | tbl:addClass('wikitable sortable modifier-table') | ||
if m_util.cast.boolean(tpl_args.responsive) then | |||
tbl:addClass('responsive-table') | |||
end | |||
-- Header | -- Header | ||
local tr = tbl:tag('tr') | local tr = tbl:tag('tr') | ||
local display_fields = {} | local display_fields = {} | ||
for i, row_info in ipairs(row_infos) do | for i, row_info in ipairs(row_infos) do | ||
display_fields[i] = display_fields[i] or {} | |||
for j, field in ipairs(row_info.fields) do | for j, field in ipairs(row_info.fields) do | ||
-- Aliased name is used as keys in the results: | -- Aliased name is used as keys in the results: | ||
local name = m_util.string.split(field, '%s*=%s*') | |||
name = name[2] or name[1] | |||
display_fields[i][j] = name | |||
display_fields[i][j] = | |||
end | end | ||
| Line 592: | Line 531: | ||
:wikitext(data.header) | :wikitext(data.header) | ||
:done() | :done() | ||
end | end | ||
end | end | ||
| Line 629: | Line 560: | ||
end | end | ||
if display then | if display then | ||
row_info.display(tpl_args | row_info.display(tpl_args, tr, row, display_fields[i]) | ||
else | else | ||
tr: | tr:node(m_util.html.table_cell('na')) | ||
end | end | ||
end | end | ||
| Line 652: | Line 583: | ||
:done() | :done() | ||
else | else | ||
tr: | tr:node(m_util.html.table_cell('na')) | ||
end | end | ||
end | end | ||
| Line 687: | Line 594: | ||
:wikitext(row[field]) | :wikitext(row[field]) | ||
else | else | ||
tr: | tr:node(m_util.html.table_cell('na')) | ||
end | end | ||
end | end | ||
| Line 695: | Line 602: | ||
end | end | ||
-- ---------------------------------------------------------------------------- | |||
-- Exported functions | |||
-- ---------------------------------------------------------------------------- | |||
local p = {} | |||
-- | |||
-- Template:Modifier table | |||
-- | |||
p.mod_table = m_util.misc.invoker_factory(_mod_table, { | |||
parentFirst = true, | |||
}) | |||
-- | |||
-- Debug | |||
-- | |||
-- Debug | |||
-- | |||
p.debug = {} | p.debug = {} | ||
function p.debug.tbl_data(tbl) | function p.debug.tbl_data(tbl) | ||
| Line 1,971: | Line 642: | ||
return table.concat(out, ', ') | return table.concat(out, ', ') | ||
end | end | ||
return p | return p | ||
Latest revision as of 17:16, 7 December 2025
The above documentation is transcluded from Module:Modifier table/doc.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
-------------------------------------------------------------------------------
--
-- Module:Modifier table
--
-- Module responsible for displaying modifiers in various ways. Implements
-- Template:Modifier table and Template:Item modifiers
-------------------------------------------------------------------------------
require('strict')
local m_util = require('Module:Util')
-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Modifier table')
local m_cargo = use_sandbox and require('Module:Cargo/sandbox') or require('Module:Cargo')
local m_game = use_sandbox and mw.loadData('Module:Game/sandbox') or mw.loadData('Module:Game')
-- 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:Modifier table/config/sandbox') or mw.loadData('Module:Modifier table/config')
local i18n = cfg.i18n
-- ----------------------------------------------------------------------------
-- Helper functions
-- ----------------------------------------------------------------------------
local h = {}
function h.query_weights(table_name, page_ids)
return m_cargo.map_results_to_id{
results=m_cargo.query(
{'mods', table_name},
{
'mods._pageID',
table_name .. '.tag=tag',
table_name .. '.value=value'
},
{
where = page_ids,
join = string.format('mods._pageID=%s._pageID', table_name),
orderBy = string.format('mods.id ASC,%s.ordinal ASC', table_name),
}
),
field='mods._pageID',
}
end
h.tbl = {}
h.tbl.display = {}
h.tbl.display.factory = {}
function h.tbl.display.factory.value(args)
-- Format options for each field:
args.options = args.options or {}
-- Separator between fields:
args.delimiter = args.delimiter or ', '
return function(tpl_args, tr, data, fields)
local values = {}
local fmt_values = {}
for index, field in ipairs(fields) do
local value = {
min=data[field],
max=data[field],
base=data[field],
}
if value.min then
values[#values+1] = value.max
local opts = args.options[index] or {}
-- Global colour is set, no overrides.
if args.color ~= nil or opts.color == nil then
opts.no_color = true
end
fmt_values[#fmt_values+1] = m_util.html.format_value(nil, value, opts)
end
end
if #values == 0 then
tr
:node(m_util.html.table_cell('na'))
else
local td = tr:tag('td')
td
:attr('data-sort-value', table.concat(values, args.delimiter))
:wikitext(table.concat(fmt_values, args.delimiter))
if args.color then
td:addClass('tc -' .. args.color)
end
end
end
end
function h.tbl.display.factory.weights(args)
return function(tpl_args, tr, data, fields)
local weights = {}
for _, v in ipairs(tpl_args[string.format('_%s_data', args.key)][data['mods._pageID']]) do
if v.tag and v.value then
table.insert(weights, string.format(
'%s %s',
v.tag,
v.value
))
end
end
if #weights == 0 then
tr
:node(m_util.html.table_cell('na'))
else
tr
:tag('td')
:wikitext(table.concat(weights, '<br>'))
end
end
end
-- ----------------------------------------------------------------------------
-- Additional configuration
-- ----------------------------------------------------------------------------
local mod_table = {}
mod_table.data = {
{
arg = 'name',
header = i18n.mod_table.name,
fields = {'mods._pageName', 'mods.id', 'mods.name'},
options = {
[3] = {
optional=true,
},
},
display = function(tpl_args, tr, data, fields)
local name
if data['mods.name'] then
name = data['mods.name']
else
name = data['mods.id']
end
tr
:tag('td')
:wikitext(string.format('[[%s|%s]]', data['mods._pageName'], name))
end,
order = 1000,
sort_type = 'text',
},
{
arg = 'domain',
header = i18n.mod_table.domain,
fields = {'mods.domain'},
display = function(tpl_args, tr, data, fields)
local k = 'mods.domain'
local i = tonumber(data[k])
if m_game.constants.mod.domains[i] == nil then
error('Undefined Modifier Domain ['..i..'] needs to be added to Module:Game')
end
data[k] = m_game.constants.mod.domains[i]['short_upper']
h.tbl.display.factory.value{}(tpl_args, tr, data, fields)
end,
order = 2000,
sort_type = 'text',
},
{
arg = 'generation_type',
header = i18n.mod_table.generation_type,
fields = {'mods.generation_type'},
display = function(tpl_args, tr, data, fields)
local k = 'mods.generation_type'
local i = tonumber(data[k])
if m_game.constants.mod.generation_types[i] == nil then
error('Undefined Modifier Generation Type ['..i..'] needs to be added to Module:Game')
end
data[k] = m_game.constants.mod.generation_types[i]['short_upper']
h.tbl.display.factory.value{}(tpl_args, tr, data, fields)
end,
order = 2001,
sort_type = 'text',
},
{
arg = {'group', 'mod_group'},
header = i18n.mod_table.mod_groups,
fields = {'mods.mod_groups'},
display = function(tpl_args, tr, data, fields)
local k = 'mods.mod_groups'
data[k] = table.concat(m_util.string.split(data[k], ',%s*'), ', ')
h.tbl.display.factory.value{}(tpl_args, tr, data, fields)
end,
order = 2010,
sort_type = 'text',
},
{
arg = {'mod_type'},
header = i18n.mod_table.mod_type,
fields = {'mods.mod_type'},
display = h.tbl.display.factory.value{},
order = 2011,
sort_type = 'text',
},
{
arg = {'level', 'required_level'},
header = i18n.mod_table.required_level,
fields = {'mods.required_level'},
display = h.tbl.display.factory.value{},
order = 2012,
},
{
arg = {'stat_text'},
header = i18n.mod_table.stat_text,
fields = {'mods.stat_text'},
display = function(tpl_args, tr, data, fields)
local value
-- map display type shows this in another column, remove this text to avoid clogging up the list
if tpl_args.type == 'map' then
local texts = m_util.string.split(data['mods.stat_text'], '<br>')
local out = {}
local valid
for _, v in ipairs(texts) do
valid = true
for _, data in pairs(mod_table.stat_ids) do
if string.find(v, data.pattern) ~= nil then
valid = false
break
end
end
if valid then
table.insert(out, v)
end
end
value = table.concat(out, '<br>')
else
value = data['mods.stat_text']
end
data['mods.stat_text'] = value
h.tbl.display.factory.value{color='mod'}(tpl_args, tr, data, fields)
end,
order = 3000,
sort_type = 'text',
},
{
arg = 'buff',
header = i18n.mod_table.buff,
fields = {'mods.granted_buff_id', 'mods.granted_buff_value'},
display = h.tbl.display.factory.value{delimiter=' '},
order = 4000,
sort_type = 'text',
},
{
arg = {'skill', 'granted_skill'},
header = i18n.mod_table.granted_skill,
fields = {'mods.granted_skill'},
display = h.tbl.display.factory.value{},
order = 4001,
sort_type = 'text',
},
{
arg = {'tags'},
header = i18n.mod_table.tags,
fields = {'mods.tags'},
display = function(tpl_args, tr, data, fields)
local k = 'mods.tags'
data[k] = table.concat(m_util.string.split(data[k], ',%s*'), ', ')
h.tbl.display.factory.value{}(tpl_args, tr, data, fields)
end,
order = 5000,
sort_type = 'text',
},
{
arg = {'spawn_weights'},
header = i18n.mod_table.spawn_weights,
fields = {},
display = h.tbl.display.factory.weights{key='spawn_weights'},
order = 6000,
sort_type = 'text',
},
{
arg = {'generation_weights'},
header = i18n.mod_table.generation_weights,
fields = {},
display = h.tbl.display.factory.weights{key='generation_weights'},
order = 6001,
sort_type = 'text',
},
--[[{
arg = {'game_mode'},
header = i18n.mod_table.game_modes,
fields = {'mods.game_mode'},
display = function (tpl_args, tr, data, fields)
local key = 'mods.game_mode'
local value = data[key]
if value ~= nil then
local modes = {}
value = m_util.cast.number(value)
for k, m in ipairs(m_game.modes) do
if value == 0 or value == k then
table.insert(modes, m.short_upper)
end
end
data[key] = table.concat(modes, ', ')
end
h.tbl.display.factory.value{}(tpl_args, tr, data, fields)
end,
order = 6010,
sort_type = 'text',
},--]]
}
mod_table.stat_ids = {
['map_item_drop_quantity_+%'] = {
header = i18n.mod_table.iiq,
pattern = '%d+%% increased Quantity of Items found in this Area',
},
['map_item_drop_rarity_+%'] = {
header = i18n.mod_table.iir,
pattern = '%d+%% increased Rarity of Items found in this Area',
},
['map_pack_size_+%'] = {
header = i18n.mod_table.pack_size,
pattern = '%+%d+%% Monster pack size',
}
}
mod_table.weights = {'spawn_weights', 'generation_weights'}
-- ----------------------------------------------------------------------------
-- Main functions
-- ----------------------------------------------------------------------------
local function _mod_table(tpl_args)
--[[
Creates a generic table for modifiers.
Examples
--------
= p.mod_table{
q_tables='mod_spawn_weights',
q_join='mods._pageID=mod_spawn_weights._pageID',
q_where='mods.generation_type = 10 AND mod_spawn_weights.tag = "boots" AND mod_spawn_weights.weight > 0',
q_orderBy='mods.id, mods.required_level',
q_limit=100,
stat_text=1,
enchantment=1,
}
]]
-- default to enabled
tpl_args.name = tpl_args.name or true
for _, key in ipairs(mod_table.weights) do
tpl_args[key] = m_util.cast.boolean(tpl_args[key])
end
if string.find(tpl_args.q_where, '%[%[') ~= nil then
error('SMW leftover in where clause')
end
local row_infos = {}
for _, row_info in ipairs(mod_table.data) do
local enabled = false
if row_info.arg == nil then
enabled = true
elseif type(row_info.arg) == 'string' and m_util.cast.boolean(tpl_args[row_info.arg]) then
enabled = true
elseif type(row_info.arg) == 'table' then
for _, argument in ipairs(row_info.arg) do
if m_util.cast.boolean(tpl_args[argument]) then
enabled = true
break
end
end
end
if enabled then
row_info.options = row_info.options or {}
row_infos[#row_infos+1] = row_info
end
end
-- sort the rows
table.sort(row_infos, function (a, b)
return (a.order or 0) < (b.order or 0)
end)
-- Set required and extra tables:
local tables = {'mods'}
for _, v in ipairs(m_util.string.split_args(tpl_args.q_tables, {',%s*'})) do
tables[#tables+1] = v
end
-- Set required and extra fields:
local fields = {
'mods._pageID',
}
for _, row_info in ipairs(row_infos) do
if type(row_info.fields) == 'function' then
row_info.fields = row_info.fields()
end
for index, field in ipairs(row_info.fields) do
row_info.options[index] = row_info.options[index] or {}
fields[#fields+1] = field
end
end
tpl_args._extra_fields = m_util.string.split_args(tpl_args.q_fields, {',%s*'})
for _, v in ipairs(tpl_args._extra_fields) do
fields[#fields+1] = v
end
-- Parse query arguments:
local query = {
-- Workaround: fix duplicates
groupBy='mods._pageID',
}
for key, value in pairs(tpl_args) do
if string.sub(key, 0, 2) == 'q_' then
query[string.sub(key, 3)] = value
end
end
local results = m_cargo.query(tables, fields, query)
if #results == 0 then
if tpl_args.default ~= nil then
return tpl_args.default
else
return 'No results found'
end
end
-- this might be needed in other queries, currently not checking if
-- it's actually needed because performance impact should be neglible
local page_ids = {}
for _, row in ipairs(results) do
page_ids[#page_ids+1] = string.format(
'mods._pageID="%s"',
row['mods._pageID']
)
end
page_ids = table.concat(page_ids, ' OR ')
for _, key in ipairs(mod_table.weights) do
if tpl_args[key] then
-- Store weights data in tpl_args to be accessed later
tpl_args[string.format('_%s_data', key)] = h.query_weights('mod_' .. key, page_ids)
end
end
local stats
if tpl_args.type == 'map' then
local query_stat_ids = {}
for k, _ in pairs(mod_table.stat_ids) do
query_stat_ids[#query_stat_ids+1] = string.format('mod_stats.id="%s"', k)
end
stats = m_cargo.map_results_to_id{
results=m_cargo.query(
{'mods', 'mod_stats'},
{
'mods._pageID',
'mod_stats.id',
'mod_stats.min',
'mod_stats.max',
},
{
where=string.format(
'(%s) AND (%s)',
page_ids,
table.concat(query_stat_ids, ' OR ')
),
join='mods._pageID=mod_stats._pageID',
orderBy='mods.id ASC',
}
),
field='mods._pageID'
}
-- In addition map stats to stat <-> min/max pairs
for page_id, rows in pairs(stats) do
local stat_id_map = {}
for _, row in ipairs(rows) do
stat_id_map[row['mod_stats.id']] = {
min=tonumber(row['mod_stats.min']),
max=tonumber(row['mod_stats.max'])
}
end
stats[page_id] = stat_id_map
end
end
--
-- Display
--
-- Preformance optimization
for index, field in ipairs(tpl_args._extra_fields) do
field = m_util.string.split(field, '%s*=%s*')
-- field[2] will be nil if there is no alias
tpl_args._extra_fields[index] = field[2] or field[1]
end
local tbl = mw.html.create('table')
tbl:addClass('wikitable sortable modifier-table')
if m_util.cast.boolean(tpl_args.responsive) then
tbl:addClass('responsive-table')
end
-- Header
local tr = tbl:tag('tr')
local display_fields = {}
for i, row_info in ipairs(row_infos) do
display_fields[i] = display_fields[i] or {}
for j, field in ipairs(row_info.fields) do
-- Aliased name is used as keys in the results:
local name = m_util.string.split(field, '%s*=%s*')
name = name[2] or name[1]
display_fields[i][j] = name
end
tr
:tag('th')
:attr('data-sort-type', row_info.sort_type or 'number')
:wikitext(row_info.header)
:done()
end
if tpl_args.type == 'map' then
for stat_id, data in pairs(mod_table.stat_ids) do
tr
:tag('th')
:attr('data-sort-type', 'number')
:wikitext(data.header)
:done()
end
end
for _, field in ipairs(tpl_args._extra_fields) do
tr
:tag('th')
:wikitext(field)
end
-- Body
for _, row in ipairs(results) do
tr = tbl:tag('tr')
for i, row_info in ipairs(row_infos) do
-- this has been cast from a function in an earlier step
local display = true
for j, field in ipairs(display_fields[i]) do
-- this will bet set to an empty value not nil confusingly
if row[field] == nil or row[field] == '' then
if row_info.options[j].optional ~= true then
display = false
break
else
row[field] = nil
end
end
end
if display then
row_info.display(tpl_args, tr, row, display_fields[i])
else
tr:node(m_util.html.table_cell('na'))
end
end
if tpl_args.type == 'map' then
for stat_id, data in pairs(mod_table.stat_ids) do
local stat_data = stats[row['mods._pageID']]
if stat_data and stat_data[stat_id] then
local v = stat_data[stat_id]
local text
if v.min == v.max then
text = v.min
else
text = string.format('(%s to %s)', v.min, v.max)
end
tr
:tag('td')
:attr('data-sort-value', (v.min+v.max)/2)
:wikitext(string.format('%s%%', text))
:done()
else
tr:node(m_util.html.table_cell('na'))
end
end
end
for _, field in ipairs(tpl_args._extra_fields) do
if row[field] then
tr
:tag('td')
:wikitext(row[field])
else
tr:node(m_util.html.table_cell('na'))
end
end
end
return tostring(tbl)
end
-- ----------------------------------------------------------------------------
-- Exported functions
-- ----------------------------------------------------------------------------
local p = {}
--
-- Template:Modifier table
--
p.mod_table = m_util.misc.invoker_factory(_mod_table, {
parentFirst = true,
})
--
-- Debug
--
p.debug = {}
function p.debug.tbl_data(tbl)
keys = {}
for _, data in ipairs(mod_table.data) do
if type(data.arg) == 'string' then
keys[data.arg] = 1
elseif type(data.arg) == 'table' then
for _, arg in ipairs(data.arg) do
keys[arg] = 1
end
end
end
for _, key in ipairs(mod_table.weights) do
keys[key] = 1
end
local out = {}
for key, _ in pairs(keys) do
out[#out+1] = string.format("['%s'] = '1'", key)
end
return table.concat(out, ', ')
end
return p