Path of Exile Wiki

Wiki поддерживается сообществом, поэтому подумайте над тем, чтобы внести свой вклад.

ПОДРОБНЕЕ

Path of Exile Wiki
мНет описания правки
м (Защитил страницу Модуль:Mod ([Редактирование=Разрешено только администраторам] (бессрочно) [Переименование=Разрешено только администраторам] (бессрочно)))
(не показано 17 промежуточных версий 2 участников)
Строка 3: Строка 3:
 
--
 
--
   
  +
local getArgs = require('Module:Arguments').getArgs
 
local m_util = require('Module:Util')
 
local m_util = require('Module:Util')
local getArgs = require('Module:Arguments').getArgs
+
local m_cargo = require('Module:Cargo')
local game = require('Module:Game')
+
local m_game = require('Module:Game')
 
local f_item_link = require('Module:Item link').item_link
 
local f_item_link = require('Module:Item link').item_link
 
local cargo = mw.ext.cargo
 
   
 
local p = {}
 
local p = {}
Строка 21: Строка 20:
   
 
local i18n = {
 
local i18n = {
args = {
+
categories = {
  +
mods = 'Данные свойств',
--
 
 
},
-- Mod template
 
--
+
  +
tooltips = {
 
-- intro texts
  +
intro_named_id = "'''%s''' — это внутренний идентификатор [[свойства]] '''%s'''.\n",
  +
intro_unnamed_id = "'''%s''' — это внутренний идентификатор безымянного [[свойства]].\n",
 
 
-- main
+
-- core data
id = 'id',
+
id = 'Mod Id',
name = 'name',
+
name = 'Name',
mod_group = 'mod_group',
+
mod_group = 'Group',
mod_type = 'mod_type',
+
mod_type = 'Mod type',
domain = 'domain',
+
domain = 'Domain',
generation_type = 'generation_type',
+
domain_fmt = '%s (Id: %s)',
required_level = 'required_level',
+
generation_type = 'Generation type',
stat_text = 'stat_text',
+
generation_type_fmt = '%s (Id: %s)',
granted_buff_id = 'granted_buff_id',
+
required_level = 'Req. Level',
granted_buff_value = 'granted_buff_value',
+
stat_text = 'Effect',
granted_skill = 'granted_skill',
+
granted_buff_id = 'Granted Buff Id',
tags = 'tags',
+
granted_buff_value = 'Granted Buff Value',
tier_text = 'tier_text',
+
granted_skill = 'Granted Skill',
 
tags = 'Tags',
  +
tier_text = 'Tier Text',
 
 
-- shared
 
ordinal = '#',
 
 
-- stats
 
stats = 'Stats',
  +
stat_id = 'Stat Id',
 
min = 'Minimum',
 
max = 'Maximum',
 
 
-- weights
  +
spawn_weights = 'Spawn weights',
 
generation_weights = 'Generation weights',
 
tag = 'Tag',
  +
weight = 'Weight',
 
 
 
-- sell price
 
-- sell price
sell_price_prefix = 'sell_price',
+
sell_price = 'Modifier sell price',
item_name = 'name',
+
item = 'Item',
amount = 'amount',
 
 
},
 
},
 
 
Строка 52: Строка 71:
 
--
 
--
 
sell_price_duplicate_name = 'Do not specify a sell price item name multiple times. Adjust the amount instead.',
 
sell_price_duplicate_name = 'Do not specify a sell price item name multiple times. Adjust the amount instead.',
sell_price_missing_argument = 'Both %s and %s must be specified',
+
sell_price_missing_argument = 'Должны быть указаны %s и %s',
 
},
 
},
   
Строка 58: Строка 77:
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
-- m_utility / Helper functions
+
-- utility / Helper functions
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
   
 
local h = {}
 
local h = {}
 
-- Validate single value properties and set them
 
 
h.validate = {}
 
 
function h.validate.not_nil (args)
 
return function (arg)
 
if g_args[arg] == nil then
 
error(string.format('%s must not be nil', arg))
 
end
 
end
 
end
 
 
function h.validate.number (args)
 
return function (tpl_args, frame, value)
 
return m_util.cast.number(value, args)
 
end
 
end
 
 
function h.create_header(row)
 
local stat = mw.html.create('span')
 
local text, nsub = mw.ustring.gsub(row['Has stat text'], '%d+', '?')
 
stat
 
:attr('class', 'mod-table-header-stat')
 
:wikitext(text)
 
:done()
 
 
local mgroup = mw.html.create('span')
 
mgroup
 
:attr('class', 'mod-table-header-modgroup')
 
:wikitext(row['Has mod group'])
 
:done()
 
 
local tbl = mw.html.create('table')
 
tbl
 
:attr('class', 'wikitable mw-collapsible mw-collapsed mod-table')
 
:tag('tr')
 
:tag('th')
 
:attr('class', 'mod-table-header')
 
:attr('colspan', g_args.colspan)
 
:tag('span')
 
:attr('class', 'mod-table-header-container')
 
:wikitext(tostring(stat) .. tostring(mgroup))
 
:done()
 
:done()
 
return tbl
 
end
 
 
function h.format_mod(tbl, row, tags)
 
local tr = tbl:tag('tr')
 
tr
 
:tag('td')
 
:wikitext(string.format('[[%s|%s]]', row[1], row['Has name']))
 
:attr('class', 'mod-table-cell-name')
 
:done()
 
:tag('td')
 
:wikitext(row['Has level requirement'])
 
:attr('class', 'mod-table-cell-level')
 
:done()
 
:tag('td')
 
:wikitext(row['Has stat text'])
 
:attr('class', 'mod-table-cell-stat')
 
:done()
 
:tag('td')
 
:wikitext(table.concat(tags, ', '))
 
:attr('class', 'mod-table-cell-tags')
 
:done()
 
end
 
 
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
Строка 143: Строка 93:
 
main = {
 
main = {
 
table = 'mods',
 
table = 'mods',
order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags'},
+
display_order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags', 'tier_text'},
parse_order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'stat_text_raw', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags'},
+
order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'stat_text_raw', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags', 'tier_text'},
 
fields = {
 
fields = {
 
id = {
 
id = {
name = i18n.args.id,
+
name = 'id',
field = i18n.args.id,
+
field = 'id',
 
type = 'String',
 
type = 'String',
wikitext = 'Mod Id',
+
wikitext = i18n.tooltips.id,
 
},
 
},
 
name = {
 
name = {
name = i18n.args.name,
+
name = 'name',
field = i18n.args.name,
+
field = 'name',
 
type = 'String',
 
type = 'String',
wikitext = 'Name',
+
wikitext = i18n.tooltips.name,
 
},
 
},
 
mod_group = {
 
mod_group = {
name = i18n.args.mod_group,
+
name = 'mod_group',
field = i18n.args.mod_group,
+
field = 'mod_group',
 
type = 'String',
 
type = 'String',
wikitext = 'Group',
+
wikitext = i18n.tooltips.mod_group,
 
},
 
},
 
mod_type = {
 
mod_type = {
name = i18n.args.mod_type,
+
name = 'mod_type',
field = i18n.args.mod_type,
+
field = 'mod_type',
 
type = 'String',
 
type = 'String',
wikitext = 'Mod type',
+
wikitext = i18n.tooltips.mod_type,
 
},
 
},
 
domain = {
 
domain = {
name = i18n.args.domain,
+
name = 'domain',
field = i18n.args.domain,
+
field = 'domain',
 
type = 'Integer',
 
type = 'Integer',
func = h.validate.number{min=1, max=15},
 
 
wikitext = 'Mod domain',
 
wikitext = 'Mod domain',
 
display = function (value)
 
display = function (value)
return game.constants.mod.domains[value]['short_upper'] .. ' (Id: ' .. value .. ')'
+
return string.format(i18n.tooltips.domain_fmt, m_game.constants.mod.domains[value]['short_upper'], value)
 
end,
 
end,
 
},
 
},
 
generation_type = {
 
generation_type = {
name = i18n.args.generation_type,
+
name = 'generation_type',
field = i18n.args.generation_type,
+
field = 'generation_type',
 
type = 'Integer',
 
type = 'Integer',
func = h.validate.number{min=1, max=13},
+
wikitext = i18n.tooltips.generation_type,
wikitext = 'Generation type',
 
 
display = function (value)
 
display = function (value)
return game.constants.mod.generation_types[value]['short_upper'] .. ' (Id: ' .. value .. ')'
+
return string.format(i18n.tooltips.generation_type_fmt, m_game.constants.mod.generation_types[value]['short_upper'], value)
 
end,
 
end,
 
},
 
},
 
required_level = {
 
required_level = {
name = i18n.args.required_level,
+
name = 'required_level',
field = i18n.args.required_level,
+
field = 'required_level',
 
type = 'Integer',
 
type = 'Integer',
func = h.validate.number{min=0, max=100},
+
wikitext = i18n.tooltips.required_level,
wikitext = 'Req. level',
 
 
},
 
},
 
stat_text = {
 
stat_text = {
name = i18n.args.stat_text,
+
name = 'stat_text',
field = i18n.args.stat_text,
+
field = 'stat_text',
 
type = 'Text',
 
type = 'Text',
wikitext = 'Effect',
+
wikitext = i18n.tooltips.stat_text,
 
},
 
},
 
stat_text_raw = {
 
stat_text_raw = {
Строка 222: Строка 169:
 
},
 
},
 
granted_buff_id = {
 
granted_buff_id = {
name = i18n.args.granted_buff_id,
+
name = 'granted_buff_id',
field = i18n.args.granted_buff_id,
+
field = 'granted_buff_id',
 
type = 'String',
 
type = 'String',
wikitext = 'Granted Buff Id',
+
wikitext = i18n.tooltips.granted_buff_id,
 
},
 
},
 
granted_buff_value = {
 
granted_buff_value = {
name = i18n.args.granted_buff_value,
+
name = 'granted_buff_value',
field = i18n.args.granted_buff_value,
+
field = 'granted_buff_value',
 
type = 'Integer',
 
type = 'Integer',
wikitext = 'Granted Buff Value',
+
wikitext = i18n.tooltips.granted_buff_value,
 
},
 
},
 
granted_skill = {
 
granted_skill = {
name = i18n.args.granted_skill,
+
name = 'granted_skill',
field = i18n.args.granted_skill,
+
field = 'granted_skill',
 
type = 'String',
 
type = 'String',
wikitext = 'Granted Skill',
+
wikitext = i18n.tooltips.granted_skill,
 
},
 
},
 
tags = {
 
tags = {
name = i18n.args.tags,
+
name = 'tags',
field = i18n.args.tags,
+
field = 'tags',
 
type = 'List (,) of String',
 
type = 'List (,) of String',
 
wikitext = 'Tags',
 
wikitext = 'Tags',
func = function (tpl_args, frame, value)
 
if value == nil then
 
return {}
 
else
 
return m_util.string.split(value, ', ')
 
end
 
end,
 
func_cargo = function(tpl_args, frame)
 
return table.concat(tpl_args.tags, ',')
 
end,
 
 
display = function(value)
 
display = function(value)
 
return table.concat(value, ', ')
 
return table.concat(value, ', ')
end,
+
end,
 
default = {},
 
},
 
},
 
tier_text = {
 
tier_text = {
name = i18n.args.tier_text,
+
name = 'tier_text',
 
field = 'tier_text',
 
field = 'tier_text',
 
type = 'Text',
 
type = 'Text',
wikitext = 'Tier Text',
+
wikitext = i18n.tooltips.tier_text,
 
},
 
},
 
},
 
},
Строка 271: Строка 209:
 
fields = {
 
fields = {
 
name = {
 
name = {
name = i18n.args.item_name,
+
name = 'name',
field = i18n.args.item_name,
+
field = 'name',
 
type = 'String',
 
type = 'String',
 
func = function (value) return value end,
 
func = function (value) return value end,
 
},
 
},
 
amount = {
 
amount = {
name = i18n.args.amount,
+
name = 'amount',
field = i18n.args.amount,
+
field = 'amount',
 
type = 'Integer',
 
type = 'Integer',
 
func = tonumber,
 
func = tonumber,
Строка 286: Строка 224:
 
}
 
}
   
p.table_main = m_util.cargo.declare_factory{data=mod_map.main}
+
p.table_main = m_cargo.declare_factory{data=mod_map.main}
p.table_mod_sell_prices = m_util.cargo.declare_factory{data=mod_map.mod_sell_prices}
+
p.table_mod_sell_prices = m_cargo.declare_factory{data=mod_map.mod_sell_prices}
   
 
function p.table_mod_stats(frame)
 
function p.table_mod_stats(frame)
m_util.cargo.declare(frame, {
+
m_cargo.declare(frame, {
 
_table = 'mod_stats',
 
_table = 'mod_stats',
 
id = 'String',
 
id = 'String',
Строка 313: Строка 251:
 
-- Validate single value properties and set them
 
-- Validate single value properties and set them
 
 
  +
m_util.args.from_cargo_map{
local cargo_data = {
 
_table = mod_map.main.table,
+
tpl_args=tpl_args,
  +
frame=frame,
 
table_map=mod_map.main,
 
}
 
}
 
for _, key in pairs(mod_map.main.parse_order) do
 
data = mod_map.main.fields[key]
 
local value
 
if data.func ~= nil then
 
if data.name then
 
value = data.func(tpl_args, frame, tpl_args[data.name])
 
else
 
value = data.func(tpl_args, frame)
 
end
 
else
 
value = tpl_args[data.name]
 
end
 
 
tpl_args[key] = value
 
 
if data.field ~= nil then
 
if data.func_cargo then
 
cargo_data[data.field] = data.func_cargo(tpl_args, frame)
 
else
 
cargo_data[data.field] = value
 
end
 
end
 
end
 
 
m_util.cargo.store(frame, cargo_data)
 
 
 
 
-- Validate % set the stat subobjects
 
-- Validate % set the stat subobjects
 
m_util.args.stats(tpl_args, {frame=frame})
 
m_util.args.stats(tpl_args, {frame=frame})
 
for _, stat_data in pairs(tpl_args.stats) do
 
for _, stat_data in pairs(tpl_args.stats) do
m_util.cargo.store(frame, {
+
m_cargo.store(frame, {
 
_table = 'mod_stats',
 
_table = 'mod_stats',
 
id = stat_data.id,
 
id = stat_data.id,
Строка 374: Строка 288:
 
value = {}
 
value = {}
 
for key, data in pairs(mod_map.mod_sell_prices.fields) do
 
for key, data in pairs(mod_map.mod_sell_prices.fields) do
id[key] = string.format('%s%s_%s', i18n.args.sell_price_prefix, i, data.name)
+
id[key] = string.format('%s%s_%s', 'sell_price', i, data.name)
 
value[key] = data.func(tpl_args[id[key]])
 
value[key] = data.func(tpl_args[id[key]])
 
end
 
end
Строка 393: Строка 307:
 
cargo_data[data.field] = value[key]
 
cargo_data[data.field] = value[key]
 
end
 
end
m_util.cargo.store(frame, cargo_data)
+
m_cargo.store(frame, cargo_data)
 
 
 
sell_prices[#sell_prices+1] = value
 
sell_prices[#sell_prices+1] = value
Строка 416: Строка 330:
 
:attr('class', 'wikitable')
 
:attr('class', 'wikitable')
 
 
for _, key in ipairs(mod_map.main.order) do
+
for _, key in ipairs(mod_map.main.display_order) do
 
local data = mod_map.main.fields[key]
 
local data = mod_map.main.fields[key]
 
local text
 
local text
Строка 436: Строка 350:
 
:done()
 
:done()
 
end
 
end
 
tbl
 
:tag('tr')
 
:tag('th')
 
:wikitext('Tags')
 
:done()
 
:tag('td')
 
:wikitext(table.concat(tpl_args['tags'], ', '))
 
:done()
 
:done()
 
:done()
 
 
 
 
-- stat table
 
-- stat table
Строка 456: Строка 359:
 
:tag('th')
 
:tag('th')
 
:attr('colspan', 4)
 
:attr('colspan', 4)
:wikitext('Stats')
+
:wikitext(i18n.tooltips.stats)
 
:done()
 
:done()
 
:done()
 
:done()
 
:tag('tr')
 
:tag('tr')
 
:tag('th')
 
:tag('th')
:wikitext('#')
+
:wikitext(i18n.tooltips.ordinal)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Stat Id')
+
:wikitext(i18n.tooltips.stat_id)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Min')
+
:wikitext(i18n.tooltips.min)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Max')
+
:wikitext(i18n.tooltips.max)
 
:done()
 
:done()
 
:done()
 
:done()
Строка 510: Строка 413:
 
:tag('th')
 
:tag('th')
 
:attr('colspan', 3)
 
:attr('colspan', 3)
:wikitext('Spawn Weights')
+
:wikitext(i18n.tooltips.spawn_weights)
 
:done()
 
:done()
 
:done()
 
:done()
 
:tag('tr')
 
:tag('tr')
 
:tag('th')
 
:tag('th')
:wikitext('#')
+
:wikitext(i18n.tooltips.ordinal)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Tag')
+
:wikitext(i18n.tooltips.tag)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Weight')
+
:wikitext(i18n.tooltips.weight)
 
:done()
 
:done()
 
:done()
 
:done()
Строка 560: Строка 463:
 
:tag('th')
 
:tag('th')
 
:attr('colspan', 3)
 
:attr('colspan', 3)
:wikitext('Generation Weights')
+
:wikitext(i18n.tooltips.generation_weights)
 
:done()
 
:done()
 
:done()
 
:done()
 
:tag('tr')
 
:tag('tr')
 
:tag('th')
 
:tag('th')
:wikitext('#')
+
:wikitext(i18n.tooltips.ordinal)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Tag')
+
:wikitext(i18n.tooltips.tag)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Weight')
+
:wikitext(i18n.tooltips.weight)
 
:done()
 
:done()
 
:done()
 
:done()
Строка 609: Строка 512:
 
:tag('th')
 
:tag('th')
 
:attr('colspan', 2)
 
:attr('colspan', 2)
:wikitext('Modifier sell price')
+
:wikitext(i18n.tooltips.sell_price)
 
:done()
 
:done()
 
:done()
 
:done()
 
:tag('tr')
 
:tag('tr')
 
:tag('th')
 
:tag('th')
:wikitext('#')
+
:wikitext(i18n.tooltips.ordinal)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext('Item')
+
:wikitext(i18n.tooltips.item)
 
:done()
 
:done()
 
:done()
 
:done()
Строка 643: Строка 546:
 
 
 
if tpl_args['name'] then
 
if tpl_args['name'] then
 
out[#out+1] = string.format("'''%s''' is the internal id of modifier '''%s'''.\n", tpl_args['id'], tpl_args['name'])
+
out[#out+1] = string.format(i18n.tooltips.intro_named_id, tpl_args['id'], tpl_args['name'])
 
else
 
else
out[#out+1] = string.format("'''%s''' is the internal id of an unnamed modifier.\n", tpl_args['id'], tpl_args['name'])
+
out[#out+1] = string.format(i18n.tooltips.intro_unnamed_id, tpl_args['id'])
 
end
 
end
 
 
 
-- Categories
 
-- Categories
 
 
cats = {'Mods'}
+
cats = {i18n.categories.mods}
 
 
 
-- Done -> output
 
-- Done -> output

Версия от 08:20, 2 мая 2021

Template info icon Документация модуля[просмотр] [править] [история] [очистить]

Модуль для обработки Модификаторов с поддержкой Semantic MediaWiki.

Список реализованных шаблонов

--
-- Module for mod related templates
--

local getArgs = require('Module:Arguments').getArgs
local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local m_game = require('Module:Game')
local f_item_link = require('Module:Item link').item_link

local p = {}

-- ----------------------------------------------------------------------------
-- Strings
-- ----------------------------------------------------------------------------
-- This section contains strings used by this module.
-- Add new strings here instead of in-code directly, this will help other
-- people to correct spelling mistakes easier and help with translation to
-- other PoE wikis.

local i18n = {
    categories = {
        mods = 'Данные свойств',
    },
    
    tooltips = {
        -- intro texts
        intro_named_id = "'''%s''' — это внутренний идентификатор [[свойства]] '''%s'''.\n",
        intro_unnamed_id = "'''%s''' — это внутренний идентификатор безымянного [[свойства]].\n",
        
        -- core data
        id = 'Mod Id',
        name = 'Name',
        mod_group = 'Group',
        mod_type = 'Mod type',
        domain = 'Domain',
        domain_fmt = '%s (Id: %s)',
        generation_type = 'Generation type',
        generation_type_fmt = '%s (Id: %s)',
        required_level = 'Req. Level',
        stat_text = 'Effect',
        granted_buff_id = 'Granted Buff Id',
        granted_buff_value = 'Granted Buff Value',
        granted_skill = 'Granted Skill',
        tags = 'Tags',
        tier_text = 'Tier Text',
        
        -- shared
        ordinal = '#',
        
        -- stats
        stats = 'Stats',
        stat_id = 'Stat Id',
        min = 'Minimum',
        max = 'Maximum',
        
        -- weights
        spawn_weights = 'Spawn weights',
        generation_weights = 'Generation weights',
        tag = 'Tag',
        weight = 'Weight',
        
        -- sell price
        sell_price = 'Modifier sell price',
        item = 'Item',
    },
    
    errors = {
        --
        -- Mod template
        --
        sell_price_duplicate_name = 'Do not specify a sell price item name multiple times. Adjust the amount instead.',
        sell_price_missing_argument = 'Должны быть указаны %s и %s',
    },

}

-- ----------------------------------------------------------------------------
-- utility / Helper functions
-- ----------------------------------------------------------------------------

local h = {}

-- ----------------------------------------------------------------------------
-- Templates
-- ----------------------------------------------------------------------------

--
-- Template: Mod
--

local mod_map = {
    main = {
        table = 'mods',
        display_order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags', 'tier_text'},
        order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'stat_text_raw', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags', 'tier_text'},
        fields = {
            id = {
                name = 'id',
                field = 'id',
                type = 'String',
                wikitext = i18n.tooltips.id,
            },
            name = {
                name = 'name',
                field = 'name',
                type = 'String',
                wikitext = i18n.tooltips.name,
            },
            mod_group = {
                name = 'mod_group',
                field = 'mod_group',
                type = 'String',
                wikitext = i18n.tooltips.mod_group,
            },
            mod_type = {
                name = 'mod_type',
                field = 'mod_type',
                type = 'String',
                wikitext = i18n.tooltips.mod_type,
            },
            domain = {
                name = 'domain',
                field = 'domain',
                type = 'Integer',
                wikitext = 'Mod domain',
                display = function (value)
                    return string.format(i18n.tooltips.domain_fmt, m_game.constants.mod.domains[value]['short_upper'], value)
                end,
            },
            generation_type = {
                name = 'generation_type',
                field = 'generation_type',
                type = 'Integer',
                wikitext = i18n.tooltips.generation_type,
                display = function (value)
                    return string.format(i18n.tooltips.generation_type_fmt, m_game.constants.mod.generation_types[value]['short_upper'], value)
                end,
            },
            required_level = {
                name = 'required_level',
                field = 'required_level',
                type = 'Integer',
                wikitext = i18n.tooltips.required_level,
            },
            stat_text = {
                name = 'stat_text',
                field = 'stat_text',
                type = 'Text',
                wikitext = i18n.tooltips.stat_text,
            },
            stat_text_raw = {
                name = nil,
                field = 'stat_text_raw',
                type = 'Text',
                func = function(tpl_args, frame)
                    if tpl_args.stat_text then
                        tpl_args.stat_text_raw = string.gsub(
                            -- [[x]] -> x
                            string.gsub(
                                tpl_args.stat_text, '%[%[([^%]|]+)%]%]', '%1'
                            ), 
                            -- [[x|y]] -> y
                            '%[%[[^|]+|([^%]|]+)%]%]', '%1'
                        )
                    end
                    return tpl_args.stat_text_raw
                end
            },
            granted_buff_id = {
                name = 'granted_buff_id',
                field = 'granted_buff_id',
                type = 'String',
                wikitext = i18n.tooltips.granted_buff_id,
            },
            granted_buff_value = {
                name = 'granted_buff_value',
                field = 'granted_buff_value',
                type = 'Integer',
                wikitext = i18n.tooltips.granted_buff_value,
            },
            granted_skill = {
                name = 'granted_skill',
                field = 'granted_skill',
                type = 'String',
                wikitext = i18n.tooltips.granted_skill,
            },
            tags = {
                name = 'tags',
                field = 'tags',
                type = 'List (,) of String',
                wikitext = 'Tags', 
                display = function(value)
                    return table.concat(value, ', ')  
                end,
                default = {},
            },
            tier_text = {
                name = 'tier_text',
                field = 'tier_text',
                type = 'Text',
                wikitext = i18n.tooltips.tier_text,
            },
        },
    },
    mod_sell_prices = {
        table = 'mod_sell_prices',
        order = {'name', 'amount'},
        fields = {
            name = {
                name = 'name',
                field = 'name',
                type = 'String',
                func = function (value) return value end,
            },
            amount = {
                name = 'amount',
                field = 'amount',
                type = 'Integer',
                func = tonumber,
            },
        },
    },
}

p.table_main = m_cargo.declare_factory{data=mod_map.main}
p.table_mod_sell_prices = m_cargo.declare_factory{data=mod_map.mod_sell_prices}

function p.table_mod_stats(frame)
    m_cargo.declare(frame, {
        _table = 'mod_stats',
        id = 'String',
        min = 'Integer',
        max = 'Integer',
    })
end


-- p.mod{id = "LocalIncreasedPhysicalDamagePercentUniqueOneHandSword2", name = "", mod_group = "LocalPhysicalDamagePercent", domain = "1", generation_type = "3", required_level = "1", mod_type = "LocalPhysicalDamagePercent", stat_text = "150% increased Physical Damage", stat1_id = "local_physical_damage_+%", stat1_min = "150", stat1_max = "150"}
function p.mod(frame)
    -- Get args
    tpl_args = getArgs(frame, {
        parentFirst = true
    })
    frame = m_util.misc.get_frame(frame)
    
    --
    -- Validation & semantic properties
    --
    
    -- Validate single value properties and set them
    
    m_util.args.from_cargo_map{
        tpl_args=tpl_args,
        frame=frame,
        table_map=mod_map.main,
    }
    
    -- Validate % set the stat subobjects
    m_util.args.stats(tpl_args, {frame=frame})
    for _, stat_data in pairs(tpl_args.stats) do
        m_cargo.store(frame, {
            _table = 'mod_stats', 
            id = stat_data.id,
            min = stat_data.min,
            max = stat_data.max,
        })
    end
    
    -- Validate & set spawn weight subobjects
    m_util.args.spawn_weight_list(tpl_args, {
        frame=frame, 
    })
    
    -- Validate & set generation weight subobjects
    m_util.args.generation_weight_list(tpl_args, {
        frame=frame, 
    })
    
    -- Validate & set mod sell values
    i = 0
    local names = {}
    local sell_prices = {}
    repeat 
        i = i + 1
        
        local id = {}
        value = {}
        for key, data in pairs(mod_map.mod_sell_prices.fields) do
            id[key] = string.format('%s%s_%s', 'sell_price', i, data.name)
            value[key] = data.func(tpl_args[id[key]])
        end
        
        if value.name == nil and value.amount == nil then
            value = nil
        elseif value.name ~= nil and value.amount ~= nil then
            if names[value.name] then
                error(i18n.errors.sell_price_duplicate_name)
            else
                names[value.name] = true
            end

            local cargo_data = {
                _table = mod_map.mod_sell_prices.table,
            }
            for key, data in pairs(mod_map.mod_sell_prices.fields) do
                cargo_data[data.field] = value[key]
            end
            m_cargo.store(frame, cargo_data)
            
            sell_prices[#sell_prices+1] = value
        else
            error (string.format(i18n.errors.sell_price_missing_arguments, id.name, id.amount))
        end
        
    until value == nil
    
    --
    -- Display
    --
    
    local container = mw.html.create('div')
    container
        :attr('class', 'modbox')
    
    -- core stats
    
    local tbl = container:tag('table')
    tbl
        :attr('class', 'wikitable')
    
    for _, key in ipairs(mod_map.main.display_order) do
        local data = mod_map.main.fields[key]
        local text
        if data.display == nil then
            text = tpl_args[key]
        else
            text = data.display(tpl_args[key])
        end
        
        tbl
            :tag('tr')
                :tag('th')
                    :wikitext(data.wikitext)
                    :done()
                :tag('td')
                    :wikitext(text)
                    :done()
                :done()
            :done()
    end
    
    -- stat table
    
    tbl = container:tag('table')
    tbl
        :attr('class', 'wikitable sortable')
        :tag('tr')
            :tag('th')
                :attr('colspan', 4)
                :wikitext(i18n.tooltips.stats)
                :done()
            :done()
        :tag('tr')
            :tag('th')
                :wikitext(i18n.tooltips.ordinal)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.stat_id)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.min)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.max)
                :done()
            :done()
        :done()
        
    for i=1, #tpl_args.stats do
        local value = {
            id = tpl_args['stat' .. i .. '_id'],
            min = tpl_args['stat' .. i .. '_min'],
            max = tpl_args['stat' .. i .. '_max'],
        }
        
        if value.id then
            tbl
                :tag('tr')
                    :tag('td')
                        :wikitext(i)
                        :done()
                    :tag('td')
                        :wikitext(value.id)
                        :done()
                    :tag('td')
                        :wikitext(value.min)
                        :done()
                    :tag('td')
                        :wikitext(value.max)
                        :done()
                    :done()
                :done()
        end
    end
    
    -- spawn weight table
    
    tbl = container:tag('table')
    tbl
        :attr('class', 'wikitable sortable')
        :tag('tr')
            :tag('th')
                :attr('colspan', 3)
                :wikitext(i18n.tooltips.spawn_weights)
                :done()
            :done()
        :tag('tr')
            :tag('th')
                :wikitext(i18n.tooltips.ordinal)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.tag)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.weight)
                :done()
            :done()
        :done()
        
    i = 0
    value = nil
    repeat
        i = i + 1
        value = {
            tag = tpl_args[string.format('spawn_weight%s_tag', i)],
            value = tpl_args[string.format('spawn_weight%s_value', i)],
        }
        
        if value.tag then
            tbl
                :tag('tr')
                    :tag('td')
                        :wikitext(i)
                        :done()
                    :tag('td')
                        :wikitext(value.tag)
                        :done()
                    :tag('td')
                        :wikitext(value.value)
                        :done()
                    :done()
                :done()
        end
    until value.tag == nil
    
    -- generation weight table
    
    tbl = container:tag('table')
    tbl
        :attr('class', 'wikitable sortable')
        :tag('tr')
            :tag('th')
                :attr('colspan', 3)
                :wikitext(i18n.tooltips.generation_weights)
                :done()
            :done()
        :tag('tr')
            :tag('th')
                :wikitext(i18n.tooltips.ordinal)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.tag)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.weight)
                :done()
            :done()
        :done()
    
    i = 0
    value = nil
    repeat
        i = i + 1
        value = {
            tag = tpl_args[string.format('generation_weight%s_tag', i)],
            value = tpl_args[string.format('generation_weight%s_value', i)],
        }
        
        if value.tag then
            tbl
                :tag('tr')
                    :tag('td')
                        :wikitext(i)
                        :done()
                    :tag('td')
                        :wikitext(value.tag)
                        :done()
                    :tag('td')
                        :wikitext(value.value)
                        :done()
                    :done()
                :done()
        end
    until value.tag == nil
    
    -- Sell prices
    tbl = container:tag('table')
    tbl
        :attr('class', 'wikitable sortable')
        :tag('tr')
            :tag('th')
                :attr('colspan', 2)
                :wikitext(i18n.tooltips.sell_price)
                :done()
            :done()
        :tag('tr')
            :tag('th')
                :wikitext(i18n.tooltips.ordinal)
                :done()
            :tag('th')
                :wikitext(i18n.tooltips.item)
                :done()
            :done()
        :done()
    
    for i, value in ipairs(sell_prices) do
        tbl
            :tag('tr')
                :tag('td')
                    :wikitext(value.amount)
                    :done()
                :tag('td')
                    :wikitext(string.format('[[%s]]', value.name))
                    :done()
                :done()
    end
    
    -- Generic messages on the page
    
    out = {}
    
    if mw.ustring.find(tpl_args['id'], '_') then
        out[#out+1] = frame:expandTemplate{ title = 'Incorrect title', args = { title=tpl_args['id'] } } .. '\n\n\n'
    end
    
    if tpl_args['name'] then
    
        out[#out+1] = string.format(i18n.tooltips.intro_named_id, tpl_args['id'], tpl_args['name'])
    else
        out[#out+1] = string.format(i18n.tooltips.intro_unnamed_id, tpl_args['id'])
    end
    
    -- Categories
    
    cats = {i18n.categories.mods}
    
    -- Done -> output
    
    return tostring(container) .. m_util.misc.add_category(cats) .. '\n' .. table.concat(out) 
end

return p