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
m (bypass ordinal number for now)
mNo edit summary
 
(45 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
--[[
 
--[[
 
Module for data tables
 
Module for data tables
  +
 
  +
Attempts to create advanced infoboxes in a standardized way.
 
]]
 
]]
   
 
local getArgs = require('Module:Arguments').getArgs
 
local getArgs = require('Module:Arguments').getArgs
local util = require('Module:Util')
+
local m_util = require('Module:Util')
local game = require('Module:Game')
+
local m_cargo = require('Module:Cargo')
  +
local m_game = require('Module:Game')
 
local f_infocard = require('Module:Infocard')._main
 
local f_infocard = require('Module:Infocard')._main
 
local mw_language = mw.getLanguage('en')
 
local mw_language = mw.getLanguage('en')
Line 12: Line 14:
 
local p = {}
 
local p = {}
   
  +
-- Internationalization of public strings:
 
local i18n = {
 
local i18n = {
  +
character_class = {
  +
name = 'Name',
  +
id = 'Id',
  +
},
  +
generic_stats = {
  +
name = 'Name',
  +
id = 'Id',
  +
str_id = 'Str_id',
  +
str = 'Strength',
  +
dex = 'Dexterity',
  +
int = 'Intelligence',
  +
stat_text = 'Text',
  +
value = 'Value',
  +
},
 
ascendancy_class = {
 
ascendancy_class = {
  +
name = 'Name',
 
  +
id = 'Id',
  +
flavour_text = 'Flavour text',
  +
character_id = 'Character id',
  +
character = 'Character',
 
},
 
},
 
event = {
 
event = {
+
name = 'Name',
  +
id = 'Id',
  +
type = 'Type',
  +
type_challenge = 'Challenge league',
  +
type_expansion = 'Expansion',
  +
type_pvp = 'PvP season',
  +
type_race = 'Race season',
  +
release_version = 'Release version',
  +
release_date = 'Release date',
  +
end_date = 'End date',
  +
standard = 'Standard',
  +
hardcore = 'Hardcore',
  +
ordinal = 'Ordinal number',
  +
short_name = 'Short name',
  +
match_challenge = 'league',
  +
match_expansion = 'Please, do not match this.',
  +
match_pvp = 'pvp season',
  +
match_race = 'race season',
  +
number_of_events = 'Number of events',
  +
price = 'Price',
  +
rewards = 'Rewards',
  +
links = 'Links',
 
},
 
},
 
}
 
}
Line 24: Line 66:
 
-- Utility / Helper functions
 
-- Utility / Helper functions
 
-- ---------------------------------------------------------------------
 
-- ---------------------------------------------------------------------
 
 
local h = {}
 
local h = {}
   
Line 30: Line 71:
 
--[[
 
--[[
 
Format dates in correct and useable form.
 
Format dates in correct and useable form.
  +
 
  +
Parameters
value = date string
 
  +
----------
args = table of extra args.
 
  +
value : String, required
 
  +
Date
  +
args : Table
  +
Table with extra formatting args.
  +
 
To do:
 
To do:
 
Remove hours if it isn't specified.
 
Remove hours if it isn't specified.
 
]]
 
]]
  +
 
 
local args = args or {}
 
local args = args or {}
  +
 
 
-- List of allowed extra arguments:
 
-- List of allowed extra arguments:
 
local arg_list = {
 
local arg_list = {
 
format = {
 
format = {
 
default = 'Y-m-d H:i:s',
 
default = 'Y-m-d H:i:s',
cargo = 'Y-m-d H:i:s',
+
cargo = 'Y-m-d H:i:s',
  +
no_time = 'Y-m-d',
 
},
 
},
 
}
 
}
  +
 
local date_format = arg_list.format.default
+
local date_format = arg_list['format']['default']
  +
local timestamp = mw_language:formatDate(date_format, value)
  +
  +
-- If the time is 00:00:00 then assume that the time isn't defined:
  +
if mw_language:formatDate('H:i:s', timestamp) == '00:00:00' then
  +
date_format = arg_list['format']['no_time']
  +
end
  +
  +
-- Add the extra arguments:
 
for i,v in pairs(args) do
 
for i,v in pairs(args) do
 
if i == 'format' then
 
if i == 'format' then
date_format = arg_list[i][v]
+
date_format = arg_list[i][v]
 
end
 
end
 
end
 
end
  +
  +
-- Return the final timestamp format:
 
local out
 
local out
 
if value ~= nil then
 
if value ~= nil then
out = mw_language:formatDate(date_format, value)
+
out = mw_language:formatDate(date_format, timestamp)
else
 
out = nil
 
 
end
 
end
  +
 
 
return out
 
return out
 
end
 
end
Line 66: Line 120:
 
function h.timezone(str)
 
function h.timezone(str)
 
--[[
 
--[[
Check if the string contains Z at the end, if it does it implies
+
Check if the string contains Z at the end, if it does it implies
 
the time is in UTC and then return UTC.
 
the time is in UTC and then return UTC.
 
]]
 
]]
  +
 
if str ~= nil and str:sub(-1,-1) == 'Z' then
+
local out = ''
  +
if str ~= nil and str:sub(-1,-1) == 'Z' then
return 'UTC'
 
  +
out = 'UTC'
else
 
  +
end
return ''
 
  +
end
 
  +
return out
 
end
 
end
   
 
function h.cargo_query(tpl_args)
 
function h.cargo_query(tpl_args)
 
--[[
 
--[[
Returns a Cargo query of all the results, even if there are more
+
Returns a Cargo query of all the results.
  +
results than the maximum query limit. It also adds popular fields.
 
 
 
tpl_args should include these keys:
 
tpl_args should include these keys:
 
tpl_args.tables
 
tpl_args.tables
 
tpl_args.fields
 
tpl_args.fields
 
tpl_args.q_*
 
tpl_args.q_*
  +
 
 
]]
 
]]
  +
 
local tables = util.string.split(tpl_args.tables, ', ')
+
local tables = m_util.string.split(tpl_args.tables, ', ')
local fields = util.string.split(tpl_args.fields, ', ')
+
local fields = m_util.string.split(tpl_args.fields, ', ')
  +
 
 
-- Parse query arguments
 
-- Parse query arguments
 
local query = {
 
local query = {
-- Workaround: Fix duplicates but removes other rows as well.
 
groupBy = tables[1] .. '._pageID',
 
limit = 5000,
 
offset = 0,
 
 
}
 
}
for key, value in pairs(tpl_args) do
+
for key, value in pairs(tpl_args) do
 
if string.sub(key, 0, 2) == 'q_' then
 
if string.sub(key, 0, 2) == 'q_' then
 
query[string.sub(key, 3)] = value
 
query[string.sub(key, 3)] = value
 
end
 
end
 
end
 
end
 
-- Add commonly used fields:
 
fields_base = {
 
'_pageNamespace',
 
'_pageTitle',
 
'_ID',
 
'_rowID',
 
'_pageID',
 
'_pageName'
 
-- '_value'
 
}
 
for _, tbl in ipairs(tables) do
 
for _, fld in ipairs(fields_base) do
 
fields[#fields+1] = string.format('%s.%s', tbl, fld)
 
end
 
end
 
 
-- Query cargo table. If there are too many results then repeat,
 
-- offset, re-query and add the remaining results:
 
local results = {}
 
repeat
 
local result = mw.ext.cargo.query(
 
table.concat(tables, ', '),
 
table.concat(fields, ', '),
 
query
 
)
 
query.offset = query.offset + #result
 
   
  +
-- Query cargo rows:
for _,v in ipairs(result) do
 
  +
local results = m_cargo.query(tables, fields, query, args)
results[#results + 1] = v
 
  +
end
 
until #result < query.limit
 
 
 
return results
 
return results
 
end
 
end
   
function h.parse_map(tpl_args, frame, map)
+
function h.parse_map(tpl_args, frame, tbldef)
 
--[[
 
--[[
 
Parse the map
 
Parse the map
  +
 
 
Input:
 
Input:
  +
 
 
]]
 
]]
 
local cargo_data = {
 
local cargo_data = {
_table = map.main.table,
+
_table = tbldef.table,
 
}
 
}
for _, key in pairs(map.main.parse_order) do
+
for _, key in pairs(tbldef.parse_order) do
local data = map.main.fields[key]
+
local data = tbldef.fields[key]
local value
+
local value
 
if data.func ~= nil then
 
if data.func ~= nil then
 
if data.name then
 
if data.name then
Line 162: Line 183:
 
value = tpl_args[data.name]
 
value = tpl_args[data.name]
 
end
 
end
  +
 
 
tpl_args[key] = value
 
tpl_args[key] = value
   
Line 173: Line 194:
 
end
 
end
 
end
 
end
  +
 
 
local out = {
 
local out = {
 
tpl_args = tpl_args,
 
tpl_args = tpl_args,
 
cargo_data = cargo_data,
 
cargo_data = cargo_data,
 
}
 
}
  +
 
 
return out
 
return out
 
end
 
end
  +
  +
h.parse_stat_args = function(tpl_args, args)
  +
--[[
  +
Parse template args that starts with stat.+ and return them as a
  +
array.
  +
  +
]]
  +
  +
out = {}
  +
for key, value in pairs(tpl_args) do
  +
if string.sub(key, 0, 4) == 'stat' then
  +
local n,k = string.match(key, 'stat(%d+)_(.+)')
  +
n = tostring(n)
  +
if out[n] == nil then
  +
out[n] = {}
  +
end
  +
if n ~= nil and k ~= nil then
  +
out[n][k] = value
  +
else
  +
error(string.format(
  +
'Wrong stat argument format. The template argument "%s" matched "%s" and "%s".',
  +
key or 'n/a', n or 'n/a', k or 'n/a'
  +
)
  +
)
  +
end
  +
end
  +
end
  +
  +
return out
  +
end
  +
   
 
-- ---------------------------------------------------------------------
 
-- ---------------------------------------------------------------------
-- Template: Character classes
+
-- Template: Generic stats
 
-- ---------------------------------------------------------------------
 
-- ---------------------------------------------------------------------
  +
local character_map = {
 
main = {
+
local tables = {
  +
generic_stats = {
table = 'character_classes',
 
order = {'flavour_text'},
+
table = 'generic_stats',
parse_order = {'name', 'flavour_text', 'id'},
+
order = {},
  +
parse_order = {'name', 'id', 'stat_text', 'value'},
 
fields = {
 
fields = {
-- Header:
 
 
name = {
 
name = {
 
name = 'name',
 
name = 'name',
 
field = 'name',
 
field = 'name',
 
type = 'String',
 
type = 'String',
wikitext = 'Name',
+
wikitext = i18n.generic_stats.name,
 
},
 
},
-- Main text:
 
flavour_text = {
 
name = 'flavour_text',
 
field = 'flavour_text',
 
type = 'String',
 
display = function(tpl_args, frame, value)
 
return util.html.poe_color('unique', value)
 
end,
 
},
 
-- Fields only:
 
 
id = {
 
id = {
name = nil,
+
name = 'row',
 
field = 'id',
 
field = 'id',
 
type = 'String',
 
type = 'String',
wikitext = 'Id',
+
wikitext = i18n.generic_stats.id,
func = function(tpl_args, frame)
+
func = function(tpl_args, frame, value)
return game.constants.characters[tpl_args.name].id
+
return tpl_args.stats[value].id
  +
end,
  +
},
  +
stat_text = {
  +
name = 'row',
  +
field = 'stat_text',
  +
type = 'Wikitext',
  +
wikitext = i18n.generic_stats.stat_text,
  +
func = function(tpl_args, frame, value)
  +
return tpl_args.stats[value].stat_text
  +
end,
  +
},
  +
value = {
  +
name = 'row',
  +
field = 'value',
  +
type = 'Integer',
  +
wikitext = i18n.generic_stats.value,
  +
func = function(tpl_args, frame, val)
  +
return tpl_args.stats[val].value
 
end,
 
end,
 
},
 
},
Line 221: Line 281:
 
}
 
}
   
  +
-- Declare cargo table:
p.declare_character_classes = util.cargo.declare_factory{data=character_map.main}
 
  +
p.declare_generic_stats = m_cargo.declare_factory{
  +
data=tables.generic_stats,
  +
}
  +
  +
-- Attach cargo table:
  +
p.attach_generic_stats = m_cargo.attach_factory{
  +
data=tables.generic_stats,
  +
}
  +
  +
p.store_data = m_cargo.store_from_lua{tables=tables, module='Data tables'}
  +
  +
-- --------------------------------------------------------------------
  +
-- Template: Character class
  +
-- ---------------------------------------------------------------------
  +
tables.character_classes = {
  +
table = 'character_classes',
  +
order = {'flavour_text'},
  +
parse_order = {'name', 'flavour_text', 'id', 'str_id', 'str', 'dex', 'int'},
  +
fields = {
  +
-- Header:
  +
name = {
  +
name = 'name',
  +
field = 'name',
  +
type = 'String',
  +
wikitext = i18n.character_class.name,
  +
},
  +
-- Main text:
  +
flavour_text = {
  +
name = 'flavour_text',
  +
field = 'flavour_text',
  +
type = 'String',
  +
display = function(tpl_args, frame, value)
  +
return m_util.html.poe_color('unique', value)
  +
end,
  +
},
  +
-- Fields only:
  +
id = {
  +
name = nil,
  +
field = 'id',
  +
type = 'Integer',
  +
wikitext = i18n.character_class.id,
  +
func = function(tpl_args, frame)
  +
return m_game.constants.characters[tpl_args.name].id
  +
end,
  +
},
  +
str_id = {
  +
name = nil,
  +
field = 'str_id',
  +
type = 'String',
  +
wikitext = i18n.character_class.str_id,
  +
func = function(tpl_args, frame)
  +
return m_game.constants.characters[tpl_args.name].str_id
  +
end,
  +
},
  +
str = {
  +
name = nil,
  +
field = 'strength',
  +
type = 'String',
  +
wikitext = i18n.character_class.str,
  +
func = function(tpl_args, frame)
  +
return m_game.constants.characters[tpl_args.name].str
  +
end,
  +
},
  +
dex = {
  +
name = nil,
  +
field = 'dexterity',
  +
type = 'String',
  +
wikitext = i18n.character_class.dex,
  +
func = function(tpl_args, frame)
  +
return m_game.constants.characters[tpl_args.name].dex
  +
end,
  +
},
  +
int = {
  +
name = nil,
  +
field = 'intelligence',
  +
type = 'String',
  +
wikitext = i18n.character_class.int,
  +
func = function(tpl_args, frame)
  +
return m_game.constants.characters[tpl_args.name].int
  +
end,
  +
},
  +
},
  +
}
  +
  +
tables.character_classes_test = {
  +
table = 'character_classes_test',
  +
order = {},
  +
parse_order = {'flavour_text_author'},
  +
fields = {
  +
flavour_text_author = {
  +
name = nil,
  +
field = 'flavour_text_author',
  +
type = 'String',
  +
func = function(tpl_args, frame, value)
  +
return 'John (JD) Doe'
  +
end,
  +
},
  +
},
  +
}
  +
  +
  +
tables.character_classes_test2 = {
  +
table = 'character_classes_test2',
  +
order = {},
  +
parse_order = {'flavour_text_author'},
  +
fields = {
  +
flavour_text_author = {
  +
name = nil,
  +
field = 'flavour_text_author',
  +
type = 'String',
  +
func = function(tpl_args, frame, value)
  +
return 'Jane Smith'
  +
end,
  +
},
  +
},
  +
}
  +
  +
-- Declare cargo table:
  +
p.declare_character_classes = m_cargo.declare_factory{data=tables.character_classes}
  +
p.declare_character_classes_test = m_cargo.declare_factory{data=tables.character_classes_test}
  +
p.declare_character_classes_test2 = m_cargo.declare_factory{data=tables.character_classes_test2}
  +
  +
  +
-- Attach cargo table:
  +
p.attach_character_classes = m_cargo.attach_factory{data=tables.character_classes}
  +
p.attach_character_classes_test = m_cargo.attach_factory{data=tables.character_classes_test}
  +
p.attach_character_classes_test2 = m_cargo.attach_factory{data=tables.character_classes_test2}
  +
   
 
function p.character_class(frame)
 
function p.character_class(frame)
 
--[[
 
--[[
 
Displays a infobox and stores cargo data for character classes.
 
Displays a infobox and stores cargo data for character classes.
  +
 
 
Examples:
 
Examples:
 
= p.character_class{
 
= p.character_class{
Line 233: Line 421:
 
}
 
}
 
]]
 
]]
  +
 
  +
 
-- Get args
+
-- Get template args:
 
local tpl_args = getArgs(frame, {parentFirst = true})
 
local tpl_args = getArgs(frame, {parentFirst = true})
local frame = util.misc.get_frame(frame)
+
local frame = m_util.misc.get_frame(frame)
  +
 
 
-- Parse character map:
 
-- Parse character map:
  +
local parsed_map = h.parse_map(tpl_args, frame, tables.character_classes)
local map = character_map
 
local parsed_map = h.parse_map(tpl_args, frame, map)
 
 
tpl_args = parsed_map.tpl_args
 
tpl_args = parsed_map.tpl_args
 
local cargo_data = parsed_map.cargo_data
 
local cargo_data = parsed_map.cargo_data
  +
 
 
 
-- Store cargo fields:
 
-- Store cargo fields:
util.cargo.store(frame, cargo_data)
+
m_cargo.store(frame, cargo_data)
  +
 
  +
-- Parse and store character test maps:
  +
m_cargo.store(frame, h.parse_map(tpl_args, frame, tables.character_classes_test).cargo_data)
  +
m_cargo.store(frame, h.parse_map(tpl_args, frame, tables.character_classes_test2).cargo_data)
  +
 
-- Main sections, loop through
 
-- Main sections, loop through
 
local tbl = mw.html.create('table')
 
local tbl = mw.html.create('table')
for _, key in ipairs(map.main.order) do
+
for _, key in ipairs(tables.character_classes.order) do
local data = map.main.fields[key]
+
local data = tables.character_classes.fields[key]
  +
 
 
if data.display == nil then
 
if data.display == nil then
 
text = tpl_args[key]
 
text = tpl_args[key]
Line 259: Line 449:
 
text = data.display(tpl_args, frame, tpl_args[key])
 
text = data.display(tpl_args, frame, tpl_args[key])
 
end
 
end
  +
 
if text ~= nil then
+
if text ~= nil then
 
tbl
 
tbl
 
:tag('tr')
 
:tag('tr')
Line 280: Line 470:
 
end
 
end
 
end
 
end
  +
 
 
-- Output Infocard
 
-- Output Infocard
local infocard_args = {
+
local infocard_args = {
['class'] = 'character_class',
+
['class'] = 'character_class',
['header'] = tpl_args.name,
+
['header'] = tpl_args.name,
['subheader'] = nil,
+
['subheader'] = nil,
[1] = string.format(
+
[1] = string.format(
 
'[[File:%s character class.png|250px]]',
 
'[[File:%s character class.png|250px]]',
 
tpl_args.name
 
tpl_args.name
 
),
 
),
[2] = tostring(tbl),
+
[2] = tostring(tbl),
 
}
 
}
  +
 
-- cats
+
-- Add categories:
 
local cats = {
 
local cats = {
'Character Classes'
+
'Character classes'
 
}
 
}
  +
 
return f_infocard(infocard_args) .. util.misc.add_category(cats)
+
return f_infocard(infocard_args) .. m_util.misc.add_category(cats)
 
end
 
end
   
Line 305: Line 495:
 
-- ---------------------------------------------------------------------
 
-- ---------------------------------------------------------------------
   
  +
tables.ascendancy_classes = {
local ascendancy_map = {
 
main = {
+
table = 'ascendancy_classes',
table = 'ascendancy_classes',
+
order = {'flavour_text'},
  +
parse_order = {'name', 'character', 'flavour_text', 'id', 'character_id'},
order = {'flavour_text'},
 
  +
fields = {
parse_order = {'name', 'character', 'flavour_text', 'id', 'character_id'},
 
fields = {
+
-- Header:
-- Header:
+
name = {
name = {
+
name = 'name',
name = 'name',
+
field = 'name',
field = 'name',
+
type = 'String',
type = 'String',
+
wikitext = i18n.ascendancy_class.name,
wikitext = 'Name',
+
},
},
+
-- Subheader:
-- Subheader:
+
character = {
character = {
+
name = nil,
name = nil,
+
field = 'character_class',
field = 'character',
+
type = 'String',
type = 'String',
+
wikitext = i18n.ascendancy_class.character,
wikitext = 'Character',
+
func = function(tpl_args, frame, value)
func = function(tpl_args, frame, value)
+
local id = m_game.constants.ascendancy[tpl_args.name].id
local id = game.constants.ascendancy[tpl_args.name].id
+
local character_id = m_game.constants.ascendancy[tpl_args.name].character
  +
local character_id = game.constants.ascendancy[tpl_args.name].character
 
+
local character
local character
+
for i,v in pairs(m_game.constants.characters) do
for i,v in pairs(game.constants.characters) do
+
if v.id == character_id then
if v.id == character_id then
+
character = i
character = i
+
break
break
 
end
 
 
end
 
end
+
end
  +
return character
 
end,
+
return character
},
+
end,
-- Main text:
+
},
flavour_text = {
+
-- Main text:
name = 'flavour_text',
+
flavour_text = {
field = 'flavour_text',
+
name = 'flavour_text',
type = 'String',
+
field = 'flavour_text',
display = function(tpl_args, frame, value)
+
type = 'String',
return util.html.poe_color('unique', value)
+
display = function(tpl_args, frame, value)
end,
+
return m_util.html.poe_color('unique', value)
},
+
end,
-- Fields only:
+
},
id = {
+
-- Fields only:
name = nil,
+
id = {
field = 'id',
+
name = nil,
type = 'Integer',
+
field = 'id',
wikitext = 'Id',
+
type = 'Integer',
func = function(tpl_args, frame, value)
+
wikitext = i18n.ascendancy_class.id,
  +
func = function(tpl_args, frame, value)
return game.constants.ascendancy[tpl_args.name].id
 
end,
+
return m_game.constants.ascendancy[tpl_args.name].id
},
+
end,
character_id = {
+
},
name = nil,
+
character_id = {
field = 'character_id',
+
name = nil,
type = 'Integer',
+
field = 'character_id',
wikitext = 'Character id',
+
type = 'Integer',
func = function(tpl_args, frame, value)
+
wikitext = i18n.ascendancy_class.character_id,
  +
func = function(tpl_args, frame, value)
return game.constants.ascendancy[tpl_args.name].character
 
end,
+
return m_game.constants.ascendancy[tpl_args.name].character
},
+
end,
 
},
 
},
 
},
 
},
 
}
 
}
   
  +
-- Declare cargo table:
p.declare_ascendancy_classes = util.cargo.declare_factory{data=ascendancy_map.main}
 
  +
p.declare_ascendancy_classes = m_cargo.declare_factory{data=tables.ascendancy_classes}
  +
  +
-- Attach cargo table:
  +
p.attach_ascendancy_classes = m_cargo.attach_factory{data=tables.ascendancy_classes}
   
   
Line 377: Line 569:
 
--[[
 
--[[
 
Displays a infobox and stores cargo data for ascendancy classes.
 
Displays a infobox and stores cargo data for ascendancy classes.
  +
 
 
Examples:
 
Examples:
 
= p.ascendancy_class{
 
= p.ascendancy_class{
Line 384: Line 576:
 
}
 
}
 
]]
 
]]
  +
 
  +
 
-- Get args
+
-- Get template args:
 
local tpl_args = getArgs(frame, {parentFirst = true})
 
local tpl_args = getArgs(frame, {parentFirst = true})
local frame = util.misc.get_frame(frame)
+
local frame = m_util.misc.get_frame(frame)
  +
 
 
-- Parse ascendancy map:
 
-- Parse ascendancy map:
  +
local parsed_map = h.parse_map(tpl_args, frame, tables.ascendancy_classes)
local map = ascendancy_map
 
local parsed_map = h.parse_map(tpl_args, frame, map)
 
 
tpl_args = parsed_map.tpl_args
 
tpl_args = parsed_map.tpl_args
 
local cargo_data = parsed_map.cargo_data
 
local cargo_data = parsed_map.cargo_data
  +
 
 
-- Store cargo fields:
 
-- Store cargo fields:
util.cargo.store(frame, cargo_data)
+
m_cargo.store(frame, cargo_data)
  +
 
 
-- Main sections, loop through
 
-- Main sections, loop through
 
local tbl = mw.html.create('table')
 
local tbl = mw.html.create('table')
for _, key in ipairs(map.main.order) do
+
for _, key in ipairs(tables.ascendancy_classes.order) do
local data = map.main.fields[key]
+
local data = tables.ascendancy_classes.fields[key]
  +
 
 
if data.display == nil then
 
if data.display == nil then
 
text = tpl_args[key]
 
text = tpl_args[key]
Line 409: Line 600:
 
text = data.display(tpl_args, frame, tpl_args[key])
 
text = data.display(tpl_args, frame, tpl_args[key])
 
end
 
end
  +
 
if text ~= nil then
+
if text ~= nil then
 
tbl
 
tbl
 
:tag('tr')
 
:tag('tr')
Line 430: Line 621:
 
end
 
end
 
end
 
end
  +
 
 
-- Output Infocard
 
-- Output Infocard
local infocard_args = {
+
local infocard_args = {
['class'] = 'ascendancy_class',
+
['class'] = 'ascendancy_class',
['header'] = tpl_args.name,
+
['header'] = tpl_args.name,
['subheader'] = string.format('[[%s]]', tpl_args.character),
+
['subheader'] = string.format('[[%s]]', tpl_args.character),
[1] = string.format(
+
[1] = string.format(
 
'[[File:%s ascendancy class.png|250px]]',
 
'[[File:%s ascendancy class.png|250px]]',
 
tpl_args.name
 
tpl_args.name
 
),
 
),
[2] = tostring(tbl),
+
[2] = tostring(tbl),
 
}
 
}
  +
 
-- cats
+
-- Add categories:
 
local cats = {
 
local cats = {
'Ascendancy classes',
+
'Ascendancy classes',
 
tpl_args.character .. ' ascendancy classes',
 
tpl_args.character .. ' ascendancy classes',
 
}
 
}
  +
 
return f_infocard(infocard_args) .. util.misc.add_category(cats)
+
return f_infocard(infocard_args) .. m_util.misc.add_category(cats)
 
end
 
end
   
Line 458: Line 649:
 
-- ---------------------------------------------------------------------
 
-- ---------------------------------------------------------------------
   
local event_map = {
+
tables.events = {
main = {
+
table = 'events',
  +
order = {'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
table = 'events',
 
order = {'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
+
parse_order = {'id', 'name', 'short_name', 'type', 'ordinal', 'standard', 'hardcore', 'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
  +
fields = {
parse_order = {'id', 'name', 'short_name', 'type', 'standard', 'hardcore', 'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
 
fields = {
+
-- Header:
-- Header:
+
name = {
name = {
+
name = 'name',
name = 'name',
+
field = 'name',
field = 'name',
+
type = 'String',
type = 'String',
+
wikitext = i18n.event.name,
wikitext = 'Name',
+
},
},
+
-- Subheader:
-- Subheader:
+
type = {
type = {
+
name = 'type',
name = 'type',
+
field = 'type',
field = 'type',
+
type = 'String',
type = 'String',
+
wikitext = i18n.event.type,
wikitext = 'Type',
+
func = function(tpl_args, frame, value)
func = function(tpl_args, frame, value)
+
local type_tbl = {
local type_tbl = {
+
challenge = i18n.event.type_challenge,
challenge = 'Challenge league',
+
expansion = i18n.event.type_expansion,
expansion = 'Expansion',
+
pvp = i18n.event.type_pvp,
pvp = 'PvP season',
+
race = i18n.event.type_race,
race = 'Race season',
+
}
  +
return type_tbl[value]
  +
end,
  +
},
  +
-- Main text:
  +
release_version = {
  +
name = 'release_version',
  +
field = 'release_version',
  +
type = 'String',
  +
wikitext = i18n.event.release_version,
  +
display = function(tpl_args, frame, value)
  +
if value ~= nil then
  +
return string.format('[[Version %s|%s]]', value, value)
  +
end
  +
end,
  +
},
  +
release_date = {
  +
name = 'release_date',
  +
field = 'release_date',
  +
type = 'Datetime',
  +
wikitext = i18n.event.release_date,
  +
cargo_func = function(tpl_args, frame, value)
  +
return h.date(value, {format='cargo'})
  +
end,
  +
display = function(tpl_args, frame, value)
  +
local out
  +
if value ~= nil then
  +
out = string.format(
  +
'%s %s',
  +
h.date(value),
  +
h.timezone(value)
  +
)
  +
end
  +
  +
return out
  +
end,
  +
},
  +
end_date = {
  +
name = 'end_date',
  +
field = 'end_date',
  +
type = 'Datetime',
  +
wikitext = i18n.event.end_date,
  +
cargo_func = function(tpl_args, frame, value)
  +
return h.date(value, {format='cargo'})
  +
end,
  +
display = function(tpl_args, frame, value)
  +
local out
  +
if value ~= nil then
  +
out = string.format(
  +
'%s %s',
  +
h.date(value),
  +
h.timezone(value)
  +
)
  +
end
  +
  +
return out
  +
end,
  +
},
  +
standard = {
  +
name = 'standard',
  +
field = 'is_standard',
  +
type = 'Boolean',
  +
wikitext = i18n.event.standard,
  +
func = function(tpl_args, frame, value)
  +
local bool_tbl = {
  +
['false'] = 0,
  +
['true'] = 1,
  +
}
  +
return bool_tbl[string.lower(value or '')]
  +
end,
  +
},
  +
hardcore = {
  +
name = 'hardcore',
  +
field = 'is_hardcore',
  +
type = 'Boolean',
  +
wikitext = i18n.event.hardcore,
  +
func = function(tpl_args, frame, value)
  +
local bool_tbl = {
  +
['false'] = 0,
  +
['true'] = 1,
  +
}
  +
return bool_tbl[string.lower(value or '')]
  +
end,
  +
  +
},
  +
number_of_events = {
  +
name = 'number_of_events',
  +
field = 'number_of_events',
  +
type = 'Integer',
  +
wikitext = i18n.event.number_of_events,
  +
},
  +
rewards = {
  +
name = 'rewards',
  +
field = 'rewards',
  +
type = 'Wikitext',
  +
wikitext = 'Rewards',
  +
display = function(tpl_args, frame, value)
  +
local out
  +
if value ~= nil then
  +
out = string.format(
  +
'<div style="text-align: right;">%s</div>',
  +
value
  +
)
  +
end
  +
return out
  +
end,
  +
},
  +
price = {
  +
name = 'price',
  +
field = 'price',
  +
type = 'Wikitext',
  +
wikitext = i18n.event.price,
  +
},
  +
links = {
  +
name = 'links',
  +
field = 'links',
  +
type = 'Wikitext',
  +
wikitext = i18n.event.links,
  +
},
  +
  +
-- Field calculations:
  +
id = {
  +
name = 'id',
  +
field = 'id',
  +
type = 'List (, ) of String',
  +
wikitext = i18n.event.id,
  +
},
  +
short_name = {
  +
name = nil,
  +
field = 'short_name',
  +
type = 'String',
  +
wikitext = i18n.event.short_name,
  +
func = function(tpl_args, frame)
  +
local out = {}
  +
for i,v in pairs(tpl_args) do
  +
local match_tbl = {
  +
challenge = i18n.event.match_challenge,
  +
expansion = i18n.event.match_expansion,
  +
pvp = i18n.event.match_pvp,
  +
race = i18n.event.match_race,
 
}
 
}
+
for ii,vv in pairs(match_tbl) do
return type_tbl[value]
+
if v==ii then
  +
out[#out+1] = tpl_args['name']:lower():gsub(vv, ''):gsub('^%l', string.upper)
end,
 
},
+
break
-- Main text:
 
release_version = {
 
name = 'release_version',
 
field = 'release_version',
 
type = 'String',
 
wikitext = 'Release version',
 
display = function(tpl_args, frame, value)
 
if value ~= nil then
 
return string.format('[[Version %s|%s]]', value, value)
 
end
 
end,
 
},
 
release_date = {
 
name = 'release_date',
 
field = 'release_date',
 
type = 'Datetime',
 
wikitext = 'Release date',
 
cargo_func = function(tpl_args, frame, value)
 
return h.date(value, {format='cargo'})
 
end,
 
display = function(tpl_args, frame, value)
 
local out
 
if value ~= nil then
 
out = string.format(
 
'%s %s',
 
h.date(value),
 
h.timezone(value)
 
)
 
end
 
 
return out
 
end,
 
},
 
end_date = {
 
name = 'end_date',
 
field = 'release_date',
 
type = 'Datetime',
 
wikitext = 'End date',
 
cargo_func = function(tpl_args, frame, value)
 
return h.date(value, {format='cargo'})
 
end,
 
display = function(tpl_args, frame, value)
 
local out
 
if value ~= nil then
 
out = string.format(
 
'%s %s',
 
h.date(value),
 
h.timezone(value)
 
)
 
end
 
 
return out
 
end,
 
},
 
standard = {
 
name = 'standard',
 
field = 'is_standard',
 
type = 'Boolean',
 
wikitext = 'Standard',
 
func = function(tpl_args, frame, value)
 
-- Change to 1 or 0 in templates
 
local tbl = {
 
['True'] = '1',
 
['true'] = '1',
 
['False'] = '0',
 
['false'] = '0',
 
}
 
return tbl[value]
 
end,
 
},
 
hardcore = {
 
name = 'hardcore',
 
field = 'is_hardcore',
 
type = 'Boolean',
 
wikitext = 'Hardcore',
 
func = function(tpl_args, frame, value)
 
-- Change to 1 or 0 in templates
 
local tbl = {
 
['True'] = '1',
 
['true'] = '1',
 
['False'] = '0',
 
['false'] = '0',
 
}
 
return tbl[value]
 
end,
 
 
},
 
number_of_events = {
 
name = 'number_of_events',
 
field = 'number_of_events',
 
type = 'Integer',
 
wikitext = 'Number of events',
 
},
 
rewards = {
 
name = 'rewards',
 
field = 'rewards',
 
type = 'String',
 
wikitext = 'Rewards',
 
display = function(tpl_args, frame, value)
 
local out
 
if value ~= nil then
 
out = string.format(
 
'<div style="text-align: right;">%s</div>',
 
value
 
)
 
end
 
return out
 
end,
 
},
 
price = {
 
name = 'price',
 
field = 'price',
 
type = 'String',
 
wikitext = 'Price',
 
func = function(tpl_args, frame, value)
 
-- Catch spelling error, rename in template eventually:
 
return tpl_args['price'] or tpl_args['prize']
 
end,
 
},
 
links = {
 
name = 'links',
 
field = 'links',
 
type = 'string',
 
wikitext = 'Links',
 
},
 
 
-- Field calculations:
 
id = {
 
name = 'id',
 
field = 'id',
 
type = 'String',
 
wikitext = 'Id',
 
},
 
short_name = {
 
name = nil,
 
field = 'short_name',
 
type = 'String',
 
wikitext = 'Short name',
 
func = function(tpl_args, frame)
 
local out = {}
 
for i,v in pairs(tpl_args) do
 
local tbl = {
 
challenge = 'league',
 
expansion = 'Please, do not match this.',
 
pvp = 'pvp season',
 
race = 'race season',
 
}
 
for ii,vv in pairs(tbl) do
 
if v==ii then
 
out[#out+1] = tpl_args['name']:lower():gsub(vv, ''):gsub('^%l', string.upper)
 
break
 
end
 
 
end
 
end
 
end
 
end
return table.concat(out, ', ')
+
end
end,
+
return table.concat(out, ', ')
},
+
end,
-- ordinal = {
+
},
-- name = nil,
+
ordinal = {
-- field = 'ordinal',
+
name = nil,
-- type = 'String',
+
field = 'ordinal',
-- wikitext = 'Ordinal number',
+
type = 'Integer',
-- func = function(tpl_args, frame)
+
wikitext = i18n.event.ordinal,
-- tpl_args.tables = 'events'
+
func = function(tpl_args, frame)
-- local count = string.format(
+
tpl_args.tables = 'events'
-- 'COUNT(DISTINCT %s._pageName)',
+
local count = string.format(
-- tpl_args.tables
+
'COUNT(DISTINCT %s._pageName)',
-- )
+
tpl_args.tables
-- tpl_args.fields = count
+
)
-- tpl_args.q_where = string.format(
+
tpl_args.fields = count
-- '%s.type = "%s" AND %s.release_date < "%s"',
+
tpl_args.q_where = string.format(
-- tpl_args.tables,
+
'%s.type = "%s" AND %s.release_date < "%s"',
-- tpl_args.type,
+
tpl_args.tables,
-- tpl_args.tables,
+
tpl_args.type or '',
-- tpl_args.release_date
+
tpl_args.tables,
-- )
+
tpl_args.release_date or ''
-- local results = h.cargo_query(tpl_args)
+
)
+
local results = h.cargo_query(tpl_args)
  +
-- if #results > 0 then
 
-- return results[1][count]
+
local out = 1
-- else
+
if #results > 0 then
-- return nil
+
out = out + results[1][count]
-- end
+
end
  +
-- end,
 
-- },
+
return out
  +
end,
 
},
 
},
 
},
 
},
 
}
 
}
   
  +
-- Declare cargo table:
p.declare_events = util.cargo.declare_factory{data=event_map.main}
 
  +
p.declare_events = m_cargo.declare_factory{data=tables.events}
  +
  +
-- Attach cargo table:
  +
p.attach_events = m_cargo.attach_factory{data=tables.events}
   
   
function p.event_box(tpl_args, frame, map)
+
function p.event_box(tpl_args, frame)
 
-- Main sections, loop through
 
-- Main sections, loop through
 
local tbl = mw.html.create('table')
 
local tbl = mw.html.create('table')
for _, key in ipairs(map.main.order) do
+
for _, key in ipairs(tables.events.order) do
local data = map.main.fields[key]
+
local data = tables.events.fields[key]
  +
 
 
if data.display == nil then
 
if data.display == nil then
 
text = tpl_args[key]
 
text = tpl_args[key]
Line 691: Line 874:
 
text = data.display(tpl_args, frame, tpl_args[key])
 
text = data.display(tpl_args, frame, tpl_args[key])
 
end
 
end
  +
 
if text ~= nil then
+
if text ~= nil then
 
tbl
 
tbl
 
:tag('tr')
 
:tag('tr')
Line 712: Line 895:
 
end
 
end
 
end
 
end
  +
 
 
-- Output Infocard
 
-- Output Infocard
local infocard_args = {
+
local infocard_args = {
['class'] = 'event',
+
['class'] = 'event',
['header'] = tpl_args.name,
+
['header'] = tpl_args.name,
['subheader'] = tpl_args.type,
+
['subheader'] = tpl_args.type,
[1] = string.format(
+
[1] = string.format(
'[[File:%s|250px]]',
+
'[[File:%s|250px]]',
tpl_args.image or string.format('%s logo.png', tpl_args.name)
+
tpl_args.image or string.format('%s_logo.png', tpl_args.name)
 
),
 
),
[2] = tostring(tbl),
+
[2] = tostring(tbl),
 
}
 
}
   
Line 728: Line 911:
 
end
 
end
   
-- a=p.event{name='Ascendancy', type = 'expansion', release_version = '2.2.0', release_date = '2016-03-04'}
+
-- =p.event{name='Ascendancy', type = 'expansion', release_version = '2.2.0', release_date = '2016-03-04'}
-- b=p.event{name='Winterheart race season', type='race', release_version = '2.3.0', release_date='2016-01-29', end_date='2016-08-29T22:00:00Z', number_of_events='155', rewards="[[Asphyxia's Wrath]] <br> [[Sapphire Ring]] <br> [[The Whispering Ice]] <br> [[Dyadian Dawn]] <br> [[Call of the Brotherhood]] <br> [[Winterheart]]", prize="[[Demigod's Dominance]]", links='[http://www.pathofexile.com/seasons Schedule and overview]' }
+
-- =p.event{name='Winterheart race season', type='race', release_version = '2.3.0', release_date='2016-01-29', end_date='2016-08-29T22:00:00Z', number_of_events='155', rewards="[[Asphyxia's Wrath]] <br> [[Sapphire Ring]] <br> [[The Whispering Ice]] <br> [[Dyadian Dawn]] <br> [[Call of the Brotherhood]] <br> [[Winterheart]]", prize="[[Demigod's Dominance]]", links='[http://www.pathofexile.com/seasons Schedule and overview]' }
-- c=p.event{name='PvP season 2', type='pvp', release_date='2015-02-15', end_date='2015-03-16', rewards="[[Wanderlust]] <br> [[Coral Ring]] <br> [[Geofri's Baptism]] <br> [[Kikazaru]] <br> [[Meginord's Girdle]] <br> [[Atziri's Foible]]", prize='[[Talisman of the Victor]]', links='[http://www.pathofexile.com/seasons/pvp/season/EUPvPSeason2 EU PvP Ladder] <br> [http://www.pathofexile.com/seasons/pvp/season/USPvPSeason2 US PvP Ladder]' }
+
-- c=p.event{name='PvP season 2', type='pvp', release_date='2015-02-15', end_date='2015-03-16', rewards="[[Wanderlust]] <br> [[Coral Ring]] <br> [[Geofri's Baptism]] <br> [[Kikazaru]] <br> [[Meginord's Girdle]] <br> [[Atziri's Foible]]", prize='[[Talisman of the Victor]]', links='[http://www.pathofexile.com/seasons/pvp/season/EUPvPSeason2 EU PvP Ladder] <br> [http://www.pathofexile.com/seasons/pvp/season/USPvPSeason2 US PvP Ladder]' }
-- d=p.event{name='Perandus league', type='challenge ', release_version = '2.2.0', release_date='2016-03-04', end_date='2016-05-30', standard = 'True', hardcore = 'True'}
+
-- =p.event{name='Perandus league', type='challenge ', release_version = '2.2.0', release_date='2016-03-04', end_date='2016-05-30', standard = 'True', hardcore = 'True'}
  +
   
 
function p.event(frame)
 
function p.event(frame)
-- Get args
+
--[[
  +
Displays a infobox and stores data for various events such as
  +
game expansions, leagues, races, pvp etc.
  +
  +
Examples:
  +
  +
  +
]]
  +
-- Get template args:
 
local tpl_args = getArgs(frame, {parentFirst = true})
 
local tpl_args = getArgs(frame, {parentFirst = true})
local frame = util.misc.get_frame(frame)
+
local frame = m_util.misc.get_frame(frame)
  +
 
 
-- Parse event_map:
 
-- Parse event_map:
local parsed_map = h.parse_map(tpl_args, frame, event_map)
+
local parsed_map = h.parse_map(tpl_args, frame, tables.events)
 
tpl_args = parsed_map.tpl_args
 
tpl_args = parsed_map.tpl_args
 
local cargo_data = parsed_map.cargo_data
 
local cargo_data = parsed_map.cargo_data
  +
 
 
-- Store cargo fields:
 
-- Store cargo fields:
util.cargo.store(frame, cargo_data)
+
m_cargo.store(frame, cargo_data)
  +
 
 
-- Display infobox:
 
-- Display infobox:
local out = p.event_box(tpl_args, frame, event_map)
+
local out = p.event_box(tpl_args, frame)
  +
 
-- Categories
+
-- Add categories:
 
local cats = {
 
local cats = {
tpl_args.type .. 's',
+
tpl_args.type .. 's',
 
}
 
}
  +
 
return out .. util.misc.add_category(cats)
+
return out .. m_util.misc.add_category(cats)
 
end
 
end
   
  +
-- ---------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
 
   
 
return p
 
return p

Latest revision as of 22:29, 19 May 2021

Template info icon Module documentation[view] [edit] [history] [purge]

The data tables module creates infoboxes and stores cargo data.

Subpages[]

--[[
    Module for data tables

    Attempts to create advanced infoboxes in a standardized way.
]]

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_infocard = require('Module:Infocard')._main
local mw_language = mw.getLanguage('en')

local p = {}

-- Internationalization of public strings:
local i18n = {
    character_class = {
        name = 'Name',
        id = 'Id',
    },
    generic_stats = {
        name = 'Name',
        id = 'Id',
        str_id = 'Str_id',
        str = 'Strength',
        dex = 'Dexterity',
        int = 'Intelligence',
        stat_text = 'Text',
        value = 'Value',
    },
    ascendancy_class = {
        name = 'Name',
        id = 'Id',
        flavour_text = 'Flavour text',
        character_id = 'Character id',
        character = 'Character',
    },
    event = {
        name = 'Name',
        id = 'Id',
        type = 'Type',
        type_challenge = 'Challenge league',
        type_expansion = 'Expansion',
        type_pvp = 'PvP season',
        type_race = 'Race season',
        release_version = 'Release version',
        release_date = 'Release date',
        end_date = 'End date',
        standard = 'Standard',
        hardcore = 'Hardcore',
        ordinal = 'Ordinal number',
        short_name = 'Short name',
        match_challenge = 'league',
        match_expansion = 'Please, do not match this.',
        match_pvp = 'pvp season',
        match_race = 'race season',
        number_of_events = 'Number of events',
        price = 'Price',
        rewards = 'Rewards',
        links = 'Links',
    },
}

-- ---------------------------------------------------------------------
-- Utility / Helper functions
-- ---------------------------------------------------------------------
local h = {}

function h.date(value, args)
    --[[
    Format dates in correct and useable form.

    Parameters
    ----------
    value : String, required
        Date
    args : Table
        Table with extra formatting args.

    To do:
    Remove hours if it isn't specified.
    ]]

    local args = args or {}

    -- List of allowed extra arguments:
    local arg_list = {
        format = {
            default = 'Y-m-d H:i:s',
            cargo   = 'Y-m-d H:i:s',
            no_time = 'Y-m-d',
        },
    }

    local date_format = arg_list['format']['default']
    local timestamp = mw_language:formatDate(date_format, value)

    -- If the time is 00:00:00 then assume that the time isn't defined:
    if mw_language:formatDate('H:i:s', timestamp) == '00:00:00' then
        date_format = arg_list['format']['no_time']
    end

    -- Add the extra arguments:
    for i,v in pairs(args) do
        if i == 'format' then
            date_format = arg_list[i][v]
        end
    end

    -- Return the final timestamp format:
    local out
    if value ~= nil then
        out = mw_language:formatDate(date_format, timestamp)
    end

    return out
end

function h.timezone(str)
    --[[
    Check if the string contains Z at the end, if it does it implies
    the time is in UTC and then return UTC.
    ]]

    local out = ''
    if str ~= nil and str:sub(-1,-1) == 'Z' then
        out = 'UTC'
    end

    return out
end

function h.cargo_query(tpl_args)
    --[[
    Returns a Cargo query of all the results.

    tpl_args should include these keys:
    tpl_args.tables
    tpl_args.fields
    tpl_args.q_*

    ]]

    local tables = m_util.string.split(tpl_args.tables, ', ')
    local fields = m_util.string.split(tpl_args.fields, ', ')

    -- Parse query arguments
    local query = {
    }
    for key, value in pairs(tpl_args) do
        if string.sub(key, 0, 2) == 'q_' then
            query[string.sub(key, 3)] = value
        end
    end

    -- Query cargo rows:
    local results = m_cargo.query(tables, fields, query, args)

    return results
end

function h.parse_map(tpl_args, frame, tbldef)
    --[[
        Parse the map

        Input:

    ]]
    local cargo_data = {
        _table = tbldef.table,
    }
    for _, key in pairs(tbldef.parse_order) do
        local data = tbldef.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

    local out = {
        tpl_args = tpl_args,
        cargo_data = cargo_data,
    }

    return out
end

h.parse_stat_args = function(tpl_args, args)
    --[[
    Parse template args that starts with stat.+ and return them as a
    array.

    ]]

    out = {}
    for key, value in pairs(tpl_args) do
        if string.sub(key, 0, 4) == 'stat' then
            local n,k = string.match(key, 'stat(%d+)_(.+)')
            n = tostring(n)
            if out[n] == nil then
                out[n] = {}
            end
            if n ~= nil and k ~= nil then
                out[n][k] = value
            else
                error(string.format(
                    'Wrong stat argument format. The template argument "%s" matched "%s" and "%s".',
                    key or 'n/a', n or 'n/a', k or 'n/a'
                    )
                )
            end
        end
    end

    return out
end


-- ---------------------------------------------------------------------
-- Template: Generic stats
-- ---------------------------------------------------------------------

local tables = {
    generic_stats = {
        table = 'generic_stats',
        order = {},
        parse_order = {'name', 'id', 'stat_text', 'value'},
        fields = {
            name = {
                name = 'name',
                field = 'name',
                type = 'String',
                wikitext = i18n.generic_stats.name,
            },
            id = {
                name = 'row',
                field = 'id',
                type = 'String',
                wikitext = i18n.generic_stats.id,
                func = function(tpl_args, frame, value)
                    return tpl_args.stats[value].id
                end,
            },
            stat_text = {
                name = 'row',
                field = 'stat_text',
                type = 'Wikitext',
                wikitext = i18n.generic_stats.stat_text,
                func = function(tpl_args, frame, value)
                    return tpl_args.stats[value].stat_text
                end,
            },
            value = {
                name = 'row',
                field = 'value',
                type = 'Integer',
                wikitext = i18n.generic_stats.value,
                func = function(tpl_args, frame, val)
                    return tpl_args.stats[val].value
                end,
            },
        },
    },
}

-- Declare cargo table:
p.declare_generic_stats = m_cargo.declare_factory{
    data=tables.generic_stats,
}

-- Attach cargo table:
p.attach_generic_stats = m_cargo.attach_factory{
    data=tables.generic_stats,
}

p.store_data = m_cargo.store_from_lua{tables=tables, module='Data tables'}

-- --------------------------------------------------------------------
-- Template: Character class
-- ---------------------------------------------------------------------
tables.character_classes = {
    table = 'character_classes',
    order = {'flavour_text'},
    parse_order = {'name', 'flavour_text', 'id', 'str_id', 'str', 'dex', 'int'},
    fields = {
        -- Header:
        name = {
            name = 'name',
            field = 'name',
            type = 'String',
            wikitext = i18n.character_class.name,
        },
        -- Main text:
        flavour_text = {
            name = 'flavour_text',
            field = 'flavour_text',
            type = 'String',
            display = function(tpl_args, frame, value)
                return m_util.html.poe_color('unique', value)
            end,
        },
        -- Fields only:
        id = {
            name = nil,
            field = 'id',
            type = 'Integer',
            wikitext = i18n.character_class.id,
            func = function(tpl_args, frame)
                return m_game.constants.characters[tpl_args.name].id
            end,
        },
        str_id = {
            name = nil,
            field = 'str_id',
            type = 'String',
            wikitext = i18n.character_class.str_id,
            func = function(tpl_args, frame)
                return m_game.constants.characters[tpl_args.name].str_id
            end,
        },
        str = {
            name = nil,
            field = 'strength',
            type = 'String',
            wikitext = i18n.character_class.str,
            func = function(tpl_args, frame)
                return m_game.constants.characters[tpl_args.name].str
            end,
        },
        dex = {
            name = nil,
            field = 'dexterity',
            type = 'String',
            wikitext = i18n.character_class.dex,
            func = function(tpl_args, frame)
                return m_game.constants.characters[tpl_args.name].dex
            end,
        },
        int = {
            name = nil,
            field = 'intelligence',
            type = 'String',
            wikitext = i18n.character_class.int,
            func = function(tpl_args, frame)
                return m_game.constants.characters[tpl_args.name].int
            end,
        },
    },
}

tables.character_classes_test = {
    table = 'character_classes_test',
    order = {},
    parse_order = {'flavour_text_author'},
    fields = {
        flavour_text_author = {
            name = nil,
            field = 'flavour_text_author',
            type = 'String',
            func = function(tpl_args, frame, value)
                return 'John (JD) Doe'
            end,
        },
    },
}


tables.character_classes_test2 = {
    table = 'character_classes_test2',
    order = {},
    parse_order = {'flavour_text_author'},
    fields = {
        flavour_text_author = {
            name = nil,
            field = 'flavour_text_author',
            type = 'String',
            func = function(tpl_args, frame, value)
                return 'Jane Smith'
            end,
        },
    },
}

-- Declare cargo table:
p.declare_character_classes = m_cargo.declare_factory{data=tables.character_classes}
p.declare_character_classes_test = m_cargo.declare_factory{data=tables.character_classes_test}
p.declare_character_classes_test2 = m_cargo.declare_factory{data=tables.character_classes_test2}


-- Attach cargo table:
p.attach_character_classes = m_cargo.attach_factory{data=tables.character_classes}
p.attach_character_classes_test = m_cargo.attach_factory{data=tables.character_classes_test}
p.attach_character_classes_test2 = m_cargo.attach_factory{data=tables.character_classes_test2}


function p.character_class(frame)
    --[[
    Displays a infobox and stores cargo data for character classes.

    Examples:
    = p.character_class{
        name='Marauder',
        flavour_text='testing'
    }
    ]]


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

    -- Parse character map:
    local parsed_map = h.parse_map(tpl_args, frame, tables.character_classes)
    tpl_args = parsed_map.tpl_args
    local cargo_data = parsed_map.cargo_data

    -- Store cargo fields:
    m_cargo.store(frame, cargo_data)

    -- Parse and store character test maps:
    m_cargo.store(frame, h.parse_map(tpl_args, frame, tables.character_classes_test).cargo_data)
    m_cargo.store(frame, h.parse_map(tpl_args, frame, tables.character_classes_test2).cargo_data)

    -- Main sections, loop through
    local tbl = mw.html.create('table')
    for _, key in ipairs(tables.character_classes.order) do
        local data = tables.character_classes.fields[key]

        if data.display == nil then
            text = tpl_args[key]
        else
            text = data.display(tpl_args, frame, tpl_args[key])
        end

        if text ~= nil then
            tbl
                :tag('tr')
                    :tag('th')
                        :wikitext(data.wikitext)
                        :done()
                    :tag('td')
                        :wikitext(text)
                        :done()
                    :done()
        elseif text then
            tbl
                :tag('tr')
                    :tag('td')
                        -- :attr('colspan', '2')
                        :wikitext(text)
                        :done()
                    :done()
        end
    end

    -- Output Infocard
    local infocard_args = {
        ['class'] = 'character_class',
        ['header'] = tpl_args.name,
        ['subheader'] = nil,
        [1] = string.format(
            '[[File:%s character class.png|250px]]',
            tpl_args.name
        ),
        [2] = tostring(tbl),
    }

    -- Add categories:
    local cats = {
        'Character classes'
    }

    return f_infocard(infocard_args) .. m_util.misc.add_category(cats)
end

-- ---------------------------------------------------------------------
-- Template: Ascendancy Class
-- ---------------------------------------------------------------------

tables.ascendancy_classes = {
    table = 'ascendancy_classes',
    order = {'flavour_text'},
    parse_order = {'name', 'character', 'flavour_text', 'id', 'character_id'},
    fields = {
        -- Header:
        name = {
            name = 'name',
            field = 'name',
            type = 'String',
            wikitext = i18n.ascendancy_class.name,
        },
        -- Subheader:
        character = {
            name = nil,
            field = 'character_class',
            type = 'String',
            wikitext = i18n.ascendancy_class.character,
            func = function(tpl_args, frame, value)
                local id = m_game.constants.ascendancy[tpl_args.name].id
                local character_id = m_game.constants.ascendancy[tpl_args.name].character

                local character
                for i,v in pairs(m_game.constants.characters) do
                    if v.id == character_id then
                        character = i
                        break
                    end
                end

                return character
            end,
        },
        -- Main text:
        flavour_text = {
            name = 'flavour_text',
            field = 'flavour_text',
            type = 'String',
            display = function(tpl_args, frame, value)
                return m_util.html.poe_color('unique', value)
            end,
        },
        -- Fields only:
        id = {
            name = nil,
            field = 'id',
            type = 'Integer',
            wikitext = i18n.ascendancy_class.id,
            func = function(tpl_args, frame, value)
                return m_game.constants.ascendancy[tpl_args.name].id
            end,
        },
        character_id = {
            name = nil,
            field = 'character_id',
            type = 'Integer',
            wikitext = i18n.ascendancy_class.character_id,
            func = function(tpl_args, frame, value)
                return m_game.constants.ascendancy[tpl_args.name].character
            end,
        },
    },
}

-- Declare cargo table:
p.declare_ascendancy_classes = m_cargo.declare_factory{data=tables.ascendancy_classes}

-- Attach cargo table:
p.attach_ascendancy_classes = m_cargo.attach_factory{data=tables.ascendancy_classes}


function p.ascendancy_class (frame)
    --[[
    Displays a infobox and stores cargo data for ascendancy classes.

    Examples:
    = p.ascendancy_class{
        name='Slayer',
        flavour_text='testing'
    }
    ]]


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

    -- Parse ascendancy map:
    local parsed_map = h.parse_map(tpl_args, frame, tables.ascendancy_classes)
    tpl_args = parsed_map.tpl_args
    local cargo_data = parsed_map.cargo_data

    -- Store cargo fields:
    m_cargo.store(frame, cargo_data)

    -- Main sections, loop through
    local tbl = mw.html.create('table')
    for _, key in ipairs(tables.ascendancy_classes.order) do
        local data = tables.ascendancy_classes.fields[key]

        if data.display == nil then
            text = tpl_args[key]
        else
            text = data.display(tpl_args, frame, tpl_args[key])
        end

        if text ~= nil then
            tbl
                :tag('tr')
                    :tag('th')
                        :wikitext(data.wikitext)
                        :done()
                    :tag('td')
                        :wikitext(text)
                        :done()
                    :done()
        elseif text then
            tbl
                :tag('tr')
                    :tag('td')
                        -- :attr('colspan', '2')
                        :wikitext(text)
                        :done()
                    :done()
        end
    end

    -- Output Infocard
    local infocard_args = {
        ['class'] = 'ascendancy_class',
        ['header'] = tpl_args.name,
        ['subheader'] = string.format('[[%s]]', tpl_args.character),
        [1] = string.format(
            '[[File:%s ascendancy class.png|250px]]',
            tpl_args.name
        ),
        [2] = tostring(tbl),
    }

    -- Add categories:
    local cats = {
        'Ascendancy classes',
        tpl_args.character .. ' ascendancy classes',
    }

    return f_infocard(infocard_args) .. m_util.misc.add_category(cats)
end



-- ---------------------------------------------------------------------
-- Template: Event
-- ---------------------------------------------------------------------

tables.events = {
    table = 'events',
    order = {'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
    parse_order = {'id', 'name', 'short_name', 'type', 'ordinal', 'standard', 'hardcore', 'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
    fields = {
        -- Header:
        name = {
            name = 'name',
            field = 'name',
            type = 'String',
            wikitext = i18n.event.name,
        },
        -- Subheader:
        type = {
            name = 'type',
            field = 'type',
            type = 'String',
            wikitext = i18n.event.type,
            func = function(tpl_args, frame, value)
                local type_tbl = {
                    challenge = i18n.event.type_challenge,
                    expansion = i18n.event.type_expansion,
                    pvp = i18n.event.type_pvp,
                    race = i18n.event.type_race,
                }
                return type_tbl[value]
            end,
        },
        -- Main text:
        release_version = {
            name = 'release_version',
            field = 'release_version',
            type = 'String',
            wikitext = i18n.event.release_version,
            display = function(tpl_args, frame, value)
                if value ~= nil then
                    return string.format('[[Version %s|%s]]', value, value)
                end
            end,
        },
        release_date = {
            name = 'release_date',
            field = 'release_date',
            type = 'Datetime',
            wikitext = i18n.event.release_date,
            cargo_func = function(tpl_args, frame, value)
                return h.date(value, {format='cargo'})
            end,
            display = function(tpl_args, frame, value)
                local out
                if value ~= nil then
                    out = string.format(
                        '%s %s',
                        h.date(value),
                        h.timezone(value)
                    )
                end

                return out
            end,
        },
        end_date = {
            name = 'end_date',
            field = 'end_date',
            type = 'Datetime',
            wikitext = i18n.event.end_date,
            cargo_func = function(tpl_args, frame, value)
                return h.date(value, {format='cargo'})
            end,
            display = function(tpl_args, frame, value)
                local out
                if value ~= nil then
                    out = string.format(
                        '%s %s',
                        h.date(value),
                        h.timezone(value)
                    )
                end

                return out
            end,
        },
        standard = {
            name = 'standard',
            field = 'is_standard',
            type = 'Boolean',
            wikitext = i18n.event.standard,
            func = function(tpl_args, frame, value)
                local bool_tbl = {
                    ['false'] = 0,
                    ['true'] = 1,
                }
                return bool_tbl[string.lower(value or '')]
            end,
        },
        hardcore = {
            name = 'hardcore',
            field = 'is_hardcore',
            type = 'Boolean',
            wikitext = i18n.event.hardcore,
            func = function(tpl_args, frame, value)
                local bool_tbl = {
                    ['false'] = 0,
                    ['true'] = 1,
                }
                return bool_tbl[string.lower(value or '')]
            end,

        },
        number_of_events = {
            name = 'number_of_events',
            field = 'number_of_events',
            type = 'Integer',
            wikitext = i18n.event.number_of_events,
        },
        rewards = {
            name = 'rewards',
            field = 'rewards',
            type = 'Wikitext',
            wikitext = 'Rewards',
            display = function(tpl_args, frame, value)
                local out
                if value ~= nil then
                    out = string.format(
                        '<div style="text-align: right;">%s</div>',
                        value
                    )
                end
                return out
            end,
        },
        price = {
            name = 'price',
            field = 'price',
            type = 'Wikitext',
            wikitext = i18n.event.price,
        },
        links = {
            name = 'links',
            field = 'links',
            type = 'Wikitext',
            wikitext = i18n.event.links,
        },

        -- Field calculations:
        id = {
            name = 'id',
            field = 'id',
            type = 'List (, ) of String',
            wikitext = i18n.event.id,
        },
        short_name = {
            name = nil,
            field = 'short_name',
            type = 'String',
            wikitext = i18n.event.short_name,
            func = function(tpl_args, frame)
                local out = {}
                for i,v in pairs(tpl_args) do
                    local match_tbl = {
                        challenge = i18n.event.match_challenge,
                        expansion = i18n.event.match_expansion,
                        pvp = i18n.event.match_pvp,
                        race = i18n.event.match_race,
                    }
                    for ii,vv in pairs(match_tbl) do
                        if v==ii then
                            out[#out+1] = tpl_args['name']:lower():gsub(vv, ''):gsub('^%l', string.upper)
                            break
                        end
                    end
                end
                return table.concat(out, ', ')
            end,
        },
        ordinal = {
            name = nil,
            field = 'ordinal',
            type = 'Integer',
            wikitext = i18n.event.ordinal,
            func = function(tpl_args, frame)
                tpl_args.tables = 'events'
                local count = string.format(
                    'COUNT(DISTINCT %s._pageName)',
                    tpl_args.tables
                )
                tpl_args.fields = count
                tpl_args.q_where = string.format(
                    '%s.type = "%s" AND %s.release_date < "%s"',
                    tpl_args.tables,
                    tpl_args.type or '',
                    tpl_args.tables,
                    tpl_args.release_date or ''
                )
                local results = h.cargo_query(tpl_args)

                local out = 1
                if #results > 0 then
                    out = out + results[1][count]
                end

                return out
            end,
        },
    },
}

-- Declare cargo table:
p.declare_events = m_cargo.declare_factory{data=tables.events}

-- Attach cargo table:
p.attach_events = m_cargo.attach_factory{data=tables.events}


function p.event_box(tpl_args, frame)
    -- Main sections, loop through
    local tbl = mw.html.create('table')
    for _, key in ipairs(tables.events.order) do
        local data = tables.events.fields[key]

        if data.display == nil then
            text = tpl_args[key]
        else
            text = data.display(tpl_args, frame, tpl_args[key])
        end

        if text ~= nil then
            tbl
                :tag('tr')
                    :tag('th')
                        :wikitext(data.wikitext)
                        :done()
                    :tag('td')
                        :wikitext(text)
                        :done()
                    :done()
        elseif text then
            tbl
                :tag('tr')
                    :tag('td')
                        -- :attr('colspan', '2')
                        :wikitext(text)
                        :done()
                    :done()
        end
    end

    -- Output Infocard
    local infocard_args = {
        ['class'] = 'event',
        ['header'] = tpl_args.name,
        ['subheader'] = tpl_args.type,
        [1] = string.format(
            '[[File:%s|250px]]',
            tpl_args.image or string.format('%s_logo.png', tpl_args.name)
        ),
        [2] = tostring(tbl),
    }

    return f_infocard(infocard_args)
end

    -- =p.event{name='Ascendancy', type = 'expansion', release_version = '2.2.0', release_date = '2016-03-04'}
    -- =p.event{name='Winterheart race season', type='race', release_version = '2.3.0', release_date='2016-01-29', end_date='2016-08-29T22:00:00Z', number_of_events='155', rewards="[[Asphyxia's Wrath]] <br> [[Sapphire Ring]] <br> [[The Whispering Ice]] <br> [[Dyadian Dawn]] <br> [[Call of the Brotherhood]] <br> [[Winterheart]]", prize="[[Demigod's Dominance]]", links='[http://www.pathofexile.com/seasons Schedule and overview]'  }
    -- c=p.event{name='PvP season 2', type='pvp', release_date='2015-02-15', end_date='2015-03-16', rewards="[[Wanderlust]] <br> [[Coral Ring]] <br> [[Geofri's Baptism]] <br> [[Kikazaru]] <br> [[Meginord's Girdle]] <br> [[Atziri's Foible]]", prize='[[Talisman of the Victor]]', links='[http://www.pathofexile.com/seasons/pvp/season/EUPvPSeason2 EU PvP Ladder] <br> [http://www.pathofexile.com/seasons/pvp/season/USPvPSeason2 US PvP Ladder]'  }
    -- =p.event{name='Perandus league', type='challenge ', release_version = '2.2.0', release_date='2016-03-04', end_date='2016-05-30', standard = 'True', hardcore = 'True'}


function p.event(frame)
    --[[
    Displays a infobox and stores data for various events such as
    game expansions, leagues, races, pvp etc.

    Examples:


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

    -- Parse event_map:
    local parsed_map = h.parse_map(tpl_args, frame, tables.events)
    tpl_args = parsed_map.tpl_args
    local cargo_data = parsed_map.cargo_data

    -- Store cargo fields:
    m_cargo.store(frame, cargo_data)

    -- Display infobox:
    local out = p.event_box(tpl_args, frame)

    -- Add categories:
    local cats = {
        tpl_args.type .. 's',
    }

    return out .. m_util.misc.add_category(cats)
end

-- ---------------------------------------------------------------------

return p