(Created page with "------------------------------------------------------------------------------- -- -- Core confirguation and functions for Module:Item2 and submodules -- -------------------...") |
No edit summary |
||
(28 intermediate revisions by the same user not shown) | |||
Line 9: | Line 9: | ||
local m_game = mw.loadData('Module:Game') |
local m_game = mw.loadData('Module:Game') |
||
+ | |||
+ | -- Should we use the sandbox version of our submodules? |
||
+ | local use_sandbox = m_util.misc.maybe_sandbox('Item2') |
||
-- The cfg table contains all localisable strings and configuration, to make it |
-- The cfg table contains all localisable strings and configuration, to make it |
||
-- easier to port this module to another wiki. |
-- easier to port this module to another wiki. |
||
− | local cfg = mw.loadData('Module:Item2/config') |
+ | local cfg = use_sandbox and mw.loadData('Module:Item2/config/sandbox') or mw.loadData('Module:Item2/config') |
local i18n = cfg.i18n |
local i18n = cfg.i18n |
||
Line 20: | Line 23: | ||
-- ---------------------------------------------------------------------------- |
-- ---------------------------------------------------------------------------- |
||
+ | local h = {} |
||
+ | |||
+ | -- ---------------------------------------------------------------------------- |
||
+ | -- Core |
||
+ | -- ---------------------------------------------------------------------------- |
||
+ | |||
+ | local core = {} |
||
+ | |||
+ | core.factory = {} |
||
+ | |||
+ | function core.factory.infobox_line(args) |
||
+ | --[[ |
||
+ | args |
||
+ | type How to read data from tpl_args using the given keys. nil = Regular, gem = Skill progression, stat = Stats |
||
+ | parts |
||
+ | [n] |
||
+ | key key to use. If type = gem and table is given, parse for subfield along path |
||
+ | hide Hide part if this function returns true |
||
+ | hide_key Alternate key to use to retrieve the value |
||
+ | hide_default hide the value if this is set |
||
+ | hide_default_key key to use if it isn't equal to the key parameter |
||
+ | -- from m_util.html.format_value -- |
||
+ | func Function to transform the value retrieved from the database |
||
+ | fmt Format string (or function that returns format string) to use for the value. Default: '%s' |
||
+ | fmt_range Format string to use for the value range. Default: '(%s-%s)' |
||
+ | color poe_color code to use for the value range. False for no color. Default: 'mod' |
||
+ | class Additional css class added to color tag |
||
+ | inline Format string to use for the output |
||
+ | inline_color poe_color code to use for the output. False for no color. Default: 'default' |
||
+ | inline_class Additional css class added to inline color tag |
||
+ | sep If specified, parts are joined with this separator before being formatted for output |
||
+ | fmt Format string to use for output. If not specified, parts are simply concatenated |
||
+ | color poe_color code to use for output. Default: no color |
||
+ | class Additional css class added to output |
||
+ | --]] |
||
+ | |||
+ | args.parts = args.parts or {} |
||
+ | return function (tpl_args, frame) |
||
+ | local base_values = {} |
||
+ | local temp_values = {} |
||
+ | if args.type == 'gem' then |
||
+ | -- Skill progression. Look for keys in tpl_args.skill_levels |
||
+ | if not cfg.class_groups.gems.keys[tpl_args.class_id] then |
||
+ | -- Skip if this item is not actually a gem |
||
+ | return |
||
+ | end |
||
+ | for i, data in ipairs(args.parts) do |
||
+ | if data.key then |
||
+ | local path = type(data.key) == 'table' and data.key or {data.key} |
||
+ | -- Check for static value |
||
+ | local value = tpl_args.skill_levels[0] |
||
+ | for _, p in ipairs(path) do -- Parse for subfield along path |
||
+ | if value[p] == nil then |
||
+ | value = nil |
||
+ | break |
||
+ | else |
||
+ | value = value[p] |
||
+ | end |
||
+ | end |
||
+ | if value ~= nil then |
||
+ | base_values[i] = value |
||
+ | temp_values[#temp_values+1] = {value={min=value,max=value}, index=i} |
||
+ | else -- Check for leveled values |
||
+ | value = { |
||
+ | min = tpl_args.skill_levels[1], |
||
+ | max = tpl_args.skill_levels[tpl_args.max_level], |
||
+ | } |
||
+ | for k, _ in pairs(value) do |
||
+ | for _, p in ipairs(path) do -- Parse for subfield along path |
||
+ | if value[k][p] == nil then |
||
+ | value[k] = nil |
||
+ | break |
||
+ | else |
||
+ | value[k] = value[k][p] |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | if value.min ~= nil and value.max ~= nil then |
||
+ | base_values[i] = value.min |
||
+ | temp_values[#temp_values+1] = {value=value, index=i} |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | elseif args.type == 'stat' then |
||
+ | -- Stats. Look for key in tpl_args._stats |
||
+ | for i, data in ipairs(args.parts) do |
||
+ | local value = tpl_args._stats[data.key] |
||
+ | if value ~= nil then |
||
+ | base_values[i] = value.min |
||
+ | temp_values[#temp_values+1] = {value=value, index=i} |
||
+ | end |
||
+ | end |
||
+ | else |
||
+ | -- Regular. Look for key exactly as written in tpl_args |
||
+ | for i, data in ipairs(args.parts) do |
||
+ | base_values[i] = tpl_args[data.key] |
||
+ | local value = {} |
||
+ | if tpl_args[data.key .. '_range_minimum'] ~= nil then |
||
+ | value.min = tpl_args[data.key .. '_range_minimum'] |
||
+ | value.max = tpl_args[data.key .. '_range_maximum'] |
||
+ | elseif tpl_args[data.key] ~= nil then |
||
+ | value.min = tpl_args[data.key] |
||
+ | value.max = tpl_args[data.key] |
||
+ | end |
||
+ | if value.min == nil then |
||
+ | else |
||
+ | temp_values[#temp_values+1] = {value=value, index=i} |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | |||
+ | local final_values = {} |
||
+ | for i, data in ipairs(temp_values) do |
||
+ | local opt = args.parts[data.index] |
||
+ | local hide = false |
||
+ | if type(opt.hide) == 'function' then |
||
+ | local v = data.value |
||
+ | if opt.hide_key then |
||
+ | v = { |
||
+ | min = tpl_args[opt.hide_key .. '_range_minimum'], |
||
+ | max = tpl_args[opt.hide_key .. '_range_maximum'], |
||
+ | } |
||
+ | if v.min == nil or v.max == nil then |
||
+ | v = tpl_args[opt.hide_key] |
||
+ | end |
||
+ | end |
||
+ | hide = opt.hide(tpl_args, frame, v) |
||
+ | elseif opt.hide_default ~= nil then |
||
+ | if opt.hide_default_key then |
||
+ | local v = { |
||
+ | min = tpl_args[opt.hide_default_key .. '_range_minimum'], |
||
+ | max = tpl_args[opt.hide_default_key .. '_range_maximum'], |
||
+ | } |
||
+ | if v.min == nil or v.max == nil then |
||
+ | if opt.hide_default == tpl_args[opt.hide_default_key] then |
||
+ | hide = true |
||
+ | end |
||
+ | elseif opt.hide_default == v.min or opt.hide_default == v.max then |
||
+ | hide = true |
||
+ | end |
||
+ | else |
||
+ | local v = data.value |
||
+ | if opt.hide_default == v.min or opt.hide_default == v.max then |
||
+ | hide = true |
||
+ | end |
||
+ | end |
||
+ | end |
||
+ | if not hide then |
||
+ | table.insert(final_values, data) |
||
+ | end |
||
+ | end |
||
+ | |||
+ | -- all zeros = dont display and return early |
||
+ | if #final_values == 0 then |
||
+ | return nil |
||
+ | end |
||
+ | |||
+ | local parts = {} |
||
+ | for i, data in ipairs(final_values) do |
||
+ | local value = data.value |
||
+ | value.base = base_values[data.index] |
||
+ | local options = args.parts[data.index] |
||
+ | if args.type == 'gem' and options.color == nil then |
||
+ | -- Display skill progression range values as unmodified (white) |
||
+ | options.color = 'value' |
||
+ | end |
||
+ | parts[#parts+1] = m_util.html.format_value(tpl_args, frame, value, options) |
||
+ | end |
||
+ | if args.sep then |
||
+ | -- Join parts with separator before formatting |
||
+ | parts = {table.concat(parts, args.sep)} |
||
+ | end |
||
+ | |||
+ | -- Build output string |
||
+ | local out |
||
+ | if args.fmt then |
||
+ | out = string.format(args.fmt, unpack(parts)) |
||
+ | else |
||
+ | out = table.concat(parts) |
||
+ | end |
||
+ | if args.color then |
||
+ | out = m_util.html.poe_color(args.color, out, args.class) |
||
+ | elseif args.class then |
||
+ | out = tostring(mw.html.create('em') |
||
+ | :attr('class', class) |
||
+ | :wikitext(out) |
||
+ | ) |
||
+ | end |
||
+ | return out |
||
+ | end |
||
+ | end |
||
+ | |||
+ | function core.stats_update(tpl_args, id, value, modid, key) |
||
+ | if tpl_args[key][id] == nil then |
||
+ | tpl_args[key][id] = { |
||
+ | references = {modid}, |
||
+ | min = value.min, |
||
+ | max = value.max, |
||
+ | avg = value.avg, |
||
+ | } |
||
+ | else |
||
+ | if modid ~= nil then |
||
+ | table.insert(tpl_args[key][id].references, modid) |
||
+ | end |
||
+ | tpl_args[key][id].min = tpl_args[key][id].min + value.min |
||
+ | tpl_args[key][id].max = tpl_args[key][id].max + value.max |
||
+ | tpl_args[key][id].avg = tpl_args[key][id].avg + value.avg |
||
+ | end |
||
+ | end |
||
+ | |||
+ | -- |
||
+ | -- Functions for processing tpl_args |
||
+ | -- |
||
+ | h.proc = {} |
||
+ | h.proc.factory = {} |
||
+ | |||
+ | function h.proc.factory.value(args) |
||
+ | args = args or {} |
||
+ | return function (tpl_args, frame, value) |
||
+ | if value == nil then |
||
+ | return nil |
||
+ | end |
||
+ | if args.cast then |
||
+ | value = args.cast(value) |
||
+ | end |
||
+ | if args.validate then |
||
+ | value = args.validate(value) |
||
+ | end |
||
+ | return value |
||
+ | end |
||
+ | end |
||
+ | |||
+ | function h.proc.factory.list(args) |
||
+ | args = args or {} |
||
+ | return function (tpl_args, frame, value) |
||
+ | return m_util.cast.table(value, { |
||
+ | pattern = args.pattern, |
||
+ | callback = args.callback, |
||
+ | }) |
||
+ | end |
||
+ | end |
||
+ | |||
+ | function h.proc.factory.damage_html(args) |
||
+ | return function (tpl_args, frame, value) |
||
+ | local keys = { |
||
+ | min = args.type .. '_damage_min', |
||
+ | max = args.type .. '_damage_max', |
||
+ | } |
||
+ | local range = {} |
||
+ | for ktype, key in pairs(keys) do |
||
+ | range[ktype] = core.factory.infobox_line{ |
||
+ | parts = { |
||
+ | { |
||
+ | key = key, |
||
+ | color = false, |
||
+ | hide_default = 0, |
||
+ | } |
||
+ | } |
||
+ | }(tpl_args, frame) |
||
+ | end |
||
+ | if range.min and range.max then |
||
+ | local color = args.type or false |
||
+ | local range_fmt |
||
+ | if tpl_args[keys.min .. '_range_minimum'] ~= tpl_args[keys.min .. '_range_maximum'] or tpl_args[keys.max .. '_range_minimum'] ~= tpl_args[keys.max .. '_range_maximum'] then |
||
+ | -- Variable damage range, based on modifier rolls |
||
+ | if args.type == 'physical' then |
||
+ | color = 'mod' |
||
+ | end |
||
+ | range_fmt = i18n.fmt.variable_damage_range |
||
+ | else |
||
+ | -- Standard damage range |
||
+ | if args.type == 'physical' then |
||
+ | color = 'value' |
||
+ | end |
||
+ | range_fmt = i18n.fmt.standard_damage_range |
||
+ | end |
||
+ | value = string.format(range_fmt, range.min, range.max) |
||
+ | if color then |
||
+ | value = m_util.html.poe_color(color, value) |
||
+ | end |
||
+ | end |
||
+ | return value |
||
+ | end |
||
+ | end |
||
+ | |||
+ | h.proc.text = h.proc.factory.value{cast = m_util.cast.text} |
||
+ | h.proc.boolean = h.proc.factory.value{cast = m_util.cast.boolean} |
||
+ | h.proc.number = h.proc.factory.value{cast = m_util.cast.number} |
||
+ | |||
+ | h.proc.percentage = h.proc.factory.value{ |
||
+ | cast = m_util.cast.number, |
||
+ | validate = m_util.validate.factory.number_in_range{ |
||
+ | min = 0, |
||
+ | max = 100, |
||
+ | }, |
||
+ | } |
||
+ | |||
+ | h.proc.size = h.proc.factory.value{ |
||
+ | cast = m_util.cast.number, |
||
+ | validate = m_util.validate.factory.number_in_range{ |
||
+ | min = 1, |
||
+ | max = 4, |
||
+ | }, |
||
+ | } |
||
+ | |||
+ | h.proc.list = h.proc.factory.list() |
||
+ | |||
+ | -- Process mod stats |
||
function h.process_mod_stats(tpl_args, args) |
function h.process_mod_stats(tpl_args, args) |
||
local lines = {} |
local lines = {} |
||
Line 100: | Line 412: | ||
end |
end |
||
end |
end |
||
− | |||
− | -- |
||
− | -- Factory |
||
− | -- |
||
− | |||
− | h.factory = {} |
||
− | |||
− | function h.factory.cast_text(k, args) |
||
− | args = args or {} |
||
− | return function (tpl_args, frame) |
||
− | tpl_args[args.key_out or k] = m_util.cast.text(tpl_args[k]) |
||
− | end |
||
− | end |
||
− | |||
− | function h.factory.damage_html(args) |
||
− | return function(tpl_args, frame) |
||
− | local keys = { |
||
− | min = args.key .. '_damage_min', |
||
− | max = args.key .. '_damage_max', |
||
− | } |
||
− | local value = {} |
||
− | for ktype, key in pairs(keys) do |
||
− | value[ktype] = h.factory.infobox_line{ |
||
− | parts = { |
||
− | { |
||
− | key = key, |
||
− | color = false, |
||
− | hide_default = 0, |
||
− | } |
||
− | } |
||
− | }(tpl_args, frame) |
||
− | end |
||
− | if value.min and value.max then |
||
− | local color = args.key or false |
||
− | local range_fmt |
||
− | if tpl_args[keys.min .. '_range_minimum'] ~= tpl_args[keys.min .. '_range_maximum'] or tpl_args[keys.max .. '_range_minimum'] ~= tpl_args[keys.max .. '_range_maximum'] then |
||
− | -- Variable damage range, based on modifier rolls |
||
− | if args.key == 'physical' then |
||
− | color = 'mod' |
||
− | end |
||
− | range_fmt = i18n.fmt.variable_damage_range |
||
− | else |
||
− | -- Standard damage range |
||
− | if args.key == 'physical' then |
||
− | color = 'value' |
||
− | end |
||
− | range_fmt = i18n.fmt.standard_damage_range |
||
− | end |
||
− | value = string.format(range_fmt, value.min, value.max) |
||
− | if color then |
||
− | value = m_util.html.poe_color(color, value) |
||
− | end |
||
− | tpl_args[args.key .. '_damage_html'] = value |
||
− | end |
||
− | end |
||
− | end |
||
− | |||
− | -- ---------------------------------------------------------------------------- |
||
− | -- Core |
||
− | -- ---------------------------------------------------------------------------- |
||
− | |||
− | local core = {} |
||
-- |
-- |
||
− | -- |
+ | -- Argument mapping |
-- |
-- |
||
+ | -- [<tpl_args key>] = { |
||
− | -- format: |
||
+ | -- inherit boolean Whether the item will inherit this key from its base item. Default: true |
||
− | -- tpl_args key = { |
||
+ | -- field string Cargo field name |
||
− | -- no_copy = true or nil -- When loading an base item, dont copy this key |
||
+ | -- type string Cargo field type |
||
− | -- property = 'prop', -- Property associated with this key |
||
− | -- |
+ | -- func function Function to unpack the argument into a native lua value and validate it |
+ | -- default varies Default value if parameter is not set |
||
− | -- If not specified, func is used. |
||
− | -- If neither is specified, value is copied as string |
||
− | -- func = function or nil -- Function to unpack the argument into a native lua value and validate it. |
||
− | -- If not specified, value will not be set. |
||
− | -- default = object -- Default value if the parameter is nil |
||
-- } |
-- } |
||
core.map = { |
core.map = { |
||
-- special params |
-- special params |
||
html = { |
html = { |
||
− | + | inherit = false, |
|
field = 'html', |
field = 'html', |
||
type = 'Text', |
type = 'Text', |
||
Line 186: | Line 432: | ||
}, |
}, |
||
html_extra = { |
html_extra = { |
||
− | + | inherit = false, |
|
field = 'html_extra', |
field = 'html_extra', |
||
type = 'Text', |
type = 'Text', |
||
Line 194: | Line 440: | ||
field = 'implicit_stat_text', |
field = 'implicit_stat_text', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return h.process_mod_stats(tpl_args, {is_implicit=true}) |
|
end, |
end, |
||
}, |
}, |
||
Line 201: | Line 447: | ||
field = 'explicit_stat_text', |
field = 'explicit_stat_text', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | local explicit = h.process_mod_stats(tpl_args, {is_implicit=false}) |
|
− | |||
if tpl_args.is_talisman or tpl_args.is_corrupted then |
if tpl_args.is_talisman or tpl_args.is_corrupted then |
||
− | + | explicit = explicit or '' |
|
− | + | if explicit ~= '' then |
|
− | + | explicit = explicit .. '<br> ' |
|
− | tpl_args.explicit_stat_text = (tpl_args.explicit_stat_text or '') .. '<br>' .. i18n.tooltips.corrupted |
||
end |
end |
||
+ | explicit = explicit .. i18n.tooltips.corrupted |
||
end |
end |
||
+ | return explicit |
||
end, |
end, |
||
}, |
}, |
||
Line 216: | Line 462: | ||
field = 'stat_text', |
field = 'stat_text', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
local sep = '' |
local sep = '' |
||
if tpl_args.implicit_stat_text and tpl_args.explicit_stat_text then |
if tpl_args.implicit_stat_text and tpl_args.explicit_stat_text then |
||
Line 222: | Line 468: | ||
end |
end |
||
local text = (tpl_args.implicit_stat_text or '') .. sep .. (tpl_args.explicit_stat_text or '') |
local text = (tpl_args.implicit_stat_text or '') .. sep .. (tpl_args.explicit_stat_text or '') |
||
− | |||
if string.len(text) > 0 then |
if string.len(text) > 0 then |
||
− | + | value = text |
|
end |
end |
||
+ | return value |
||
end, |
end, |
||
+ | }, |
||
+ | class_id = { |
||
+ | inherit = false, |
||
+ | field = 'class_id', |
||
+ | type = 'String', |
||
+ | func = h.proc.factory.value{ |
||
+ | validate = m_util.validate.factory.in_table_keys{ |
||
+ | tbl = m_game.constants.item.classes, |
||
+ | errmsg = i18n.errors.invalid_class_id, |
||
+ | }, |
||
+ | }, |
||
}, |
}, |
||
class = { |
class = { |
||
− | + | inherit = false, |
|
field = 'class', |
field = 'class', |
||
type = 'String', |
type = 'String', |
||
− | func = function (tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | local class = m_game.constants.item.classes[tpl_args.class_id]['long_upper'] |
|
-- Avoids errors with empty item class names later on |
-- Avoids errors with empty item class names later on |
||
− | if |
+ | if class == '' then |
− | + | class = nil |
|
end |
end |
||
+ | return class |
||
end, |
end, |
||
− | }, |
||
− | -- processed in build_item_classes |
||
− | class_id = { |
||
− | no_copy = true, |
||
− | field = 'class_id', |
||
− | type = 'String', |
||
− | func = function (tpl_args, frame) |
||
− | if m_game.constants.item.classes[tpl_args.class_id] == nil then |
||
− | error(string.format(i18n.errors.invalid_class_id, tostring(tpl_args.class_id))) |
||
− | end |
||
− | end |
||
}, |
}, |
||
-- generic |
-- generic |
||
rarity_id = { |
rarity_id = { |
||
− | + | inherit = false, |
|
field = 'rarity_id', |
field = 'rarity_id', |
||
type = 'String', |
type = 'String', |
||
− | func = |
+ | func = h.proc.factory.value{ |
+ | validate = m_util.validate.factory.in_table_keys{ |
||
− | if m_game.constants.rarities[tpl_args.rarity_id] == nil then |
||
+ | tbl = m_game.constants.rarities, |
||
− | error(string.format(i18n.errors.invalid_rarity_id, tostring(tpl_args.rarity_id))) |
||
− | + | errmsg = i18n.errors.invalid_rarity_id, |
|
− | + | }, |
|
+ | }, |
||
}, |
}, |
||
rarity = { |
rarity = { |
||
− | + | inherit = false, |
|
field = 'rarity', |
field = 'rarity', |
||
type = 'String', |
type = 'String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return m_game.constants.rarities[tpl_args.rarity_id]['long_upper'] |
|
− | end |
+ | end, |
}, |
}, |
||
name = { |
name = { |
||
− | + | inherit = false, |
|
field = 'name', |
field = 'name', |
||
type = 'String', |
type = 'String', |
||
Line 279: | Line 527: | ||
field = 'size_x', |
field = 'size_x', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.size, |
+ | default = 1, |
||
}, |
}, |
||
size_y = { |
size_y = { |
||
field = 'size_y', |
field = 'size_y', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.size, |
+ | default = 1, |
||
}, |
}, |
||
drop_rarities_ids = { |
drop_rarities_ids = { |
||
− | + | inherit = false, |
|
field = 'drop_rarity_ids', |
field = 'drop_rarity_ids', |
||
type = 'List (,) of Text', |
type = 'List (,) of Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
tpl_args.drop_rarities_ids = nil |
tpl_args.drop_rarities_ids = nil |
||
if true then return end |
if true then return end |
||
Line 297: | Line 547: | ||
return |
return |
||
end |
end |
||
− | |||
if tpl_args.drop_rarities_ids == nil then |
if tpl_args.drop_rarities_ids == nil then |
||
tpl_args.drop_rarities_ids = {} |
tpl_args.drop_rarities_ids = {} |
||
return |
return |
||
end |
end |
||
− | |||
tpl_args.drop_rarities_ids = m_util.string.split(tpl_args.drop_rarities_ids, ',%s*') |
tpl_args.drop_rarities_ids = m_util.string.split(tpl_args.drop_rarities_ids, ',%s*') |
||
for _, rarity_id in ipairs(tpl_args.drop_rarities_ids) do |
for _, rarity_id in ipairs(tpl_args.drop_rarities_ids) do |
||
Line 312: | Line 560: | ||
}, |
}, |
||
drop_rarities = { |
drop_rarities = { |
||
− | + | inherit = false, |
|
field = nil, |
field = nil, |
||
type = 'List (,) of Text', |
type = 'List (,) of Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
tpl_args.drop_rarities = nil |
tpl_args.drop_rarities = nil |
||
if true then return end |
if true then return end |
||
Line 331: | Line 579: | ||
}, |
}, |
||
drop_enabled = { |
drop_enabled = { |
||
− | + | inherit = false, |
|
field = 'drop_enabled', |
field = 'drop_enabled', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
default = true, |
default = true, |
||
}, |
}, |
||
drop_level = { |
drop_level = { |
||
− | + | inherit = false, |
|
field = 'drop_level', |
field = 'drop_level', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
drop_level_maximum = { |
drop_level_maximum = { |
||
− | + | inherit = false, |
|
field = 'drop_level_maximum', |
field = 'drop_level_maximum', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
drop_leagues = { |
drop_leagues = { |
||
− | + | inherit = false, |
|
field = 'drop_leagues', |
field = 'drop_leagues', |
||
type = 'List (,) of String', |
type = 'List (,) of String', |
||
+ | func = h.proc.factory.list{ |
||
− | func = m_util.cast.factory.assoc_table('drop_leagues', {tbl=m_game.constants.leagues, errmsg=i18n.errors.invalid_league}), |
||
+ | callback = m_util.validate.factory.in_table_keys{ |
||
+ | tbl = m_game.constants.leagues, |
||
+ | errmsg = i18n.errors.invalid_league, |
||
+ | errlvl = 4, |
||
+ | }, |
||
+ | }, |
||
+ | default = {}, |
||
}, |
}, |
||
drop_areas = { |
drop_areas = { |
||
− | + | inherit = false, |
|
field = 'drop_areas', |
field = 'drop_areas', |
||
type = 'List (,) of String', |
type = 'List (,) of String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | value = m_util.cast.table(value) |
|
+ | if value then |
||
− | tpl_args.drop_areas = m_util.string.split(tpl_args.drop_areas, ',%s*') |
||
tpl_args.drop_areas_data = m_cargo.array_query{ |
tpl_args.drop_areas_data = m_cargo.array_query{ |
||
tables={'areas'}, |
tables={'areas'}, |
||
fields={'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'}, |
fields={'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'}, |
||
id_field='areas.id', |
id_field='areas.id', |
||
− | id_array= |
+ | id_array=value, |
query={limit=5000}, |
query={limit=5000}, |
||
} |
} |
||
end |
end |
||
− | |||
-- find areas based on item tags for atlas bases |
-- find areas based on item tags for atlas bases |
||
local query_data |
local query_data |
||
Line 399: | Line 653: | ||
if query_data ~= nil then |
if query_data ~= nil then |
||
-- in case no manual drop areas have been set |
-- in case no manual drop areas have been set |
||
− | if |
+ | if value == nil then |
− | + | value = {} |
|
tpl_args.drop_areas_data = {} |
tpl_args.drop_areas_data = {} |
||
end |
end |
||
local drop_areas_assoc = {} |
local drop_areas_assoc = {} |
||
− | for _, id in ipairs( |
+ | for _, id in ipairs(value) do |
drop_areas_assoc[id] = true |
drop_areas_assoc[id] = true |
||
end |
end |
||
Line 412: | Line 666: | ||
for _, row in ipairs(query_data) do |
for _, row in ipairs(query_data) do |
||
if drop_areas_assoc[row['areas.id']] == nil then |
if drop_areas_assoc[row['areas.id']] == nil then |
||
− | + | value[#value+1] = row['areas.id'] |
|
tpl_args.drop_areas_data[#tpl_args.drop_areas_data+1] = row |
tpl_args.drop_areas_data[#tpl_args.drop_areas_data+1] = row |
||
else |
else |
||
Line 425: | Line 679: | ||
end |
end |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
+ | default = {}, |
||
}, |
}, |
||
drop_monsters = { |
drop_monsters = { |
||
− | + | inherit = false, |
|
field = 'drop_monsters', |
field = 'drop_monsters', |
||
type = 'List (,) of Text', |
type = 'List (,) of Text', |
||
− | func = |
+ | func = h.proc.list, |
+ | default = {}, |
||
− | if tpl_args.drop_monsters ~= nil then |
||
− | tpl_args.drop_monsters = m_util.string.split(tpl_args.drop_monsters, ',%s*') |
||
− | end |
||
− | end, |
||
}, |
}, |
||
drop_text = { |
drop_text = { |
||
− | + | inherit = false, |
|
field = 'drop_text', |
field = 'drop_text', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
required_level = { |
required_level = { |
||
field = 'required_level_base', |
field = 'required_level_base', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 1, |
default = 1, |
||
}, |
}, |
||
Line 452: | Line 705: | ||
field = 'required_level', |
field = 'required_level', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | value = tpl_args.required_level |
|
+ | if value < cfg.base_item_required_level_threshold then |
||
+ | value = 1 |
||
+ | end |
||
+ | return value |
||
end, |
end, |
||
default = 1, |
default = 1, |
||
Line 460: | Line 717: | ||
field = 'required_dexterity', |
field = 'required_dexterity', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 466: | Line 723: | ||
field = 'required_strength', |
field = 'required_strength', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 472: | Line 729: | ||
field = 'required_intelligence', |
field = 'required_intelligence', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
inventory_icon = { |
inventory_icon = { |
||
− | + | inherit = false, |
|
field = 'inventory_icon', |
field = 'inventory_icon', |
||
type = 'String', |
type = 'String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | if |
+ | if not value then |
+ | -- Certain types of items have default inventory icons |
||
− | tpl_args.inventory_icon = tpl_args.inventory_icon or 'Divination card' |
||
+ | if i18n.default_inventory_icons[tpl_args.class_id] then |
||
+ | value = i18n.default_inventory_icons[tpl_args.class_id] |
||
+ | elseif tpl_args.base_item_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy' then |
||
+ | value = i18n.default_inventory_icons['Prophecy'] |
||
+ | end |
||
end |
end |
||
− | tpl_args.inventory_icon_id = |
+ | tpl_args.inventory_icon_id = value or tpl_args.name |
− | + | return string.format(i18n.files.inventory_icon, tpl_args.inventory_icon_id) |
|
end, |
end, |
||
}, |
}, |
||
− | -- note: this must be called after |
+ | -- note: this must be called after inventory_icon to work correctly as it depends on tpl_args.inventory_icon_id being set |
alternate_art_inventory_icons = { |
alternate_art_inventory_icons = { |
||
− | + | inherit = false, |
|
field = 'alternate_art_inventory_icons', |
field = 'alternate_art_inventory_icons', |
||
type = 'List (,) of String', |
type = 'List (,) of String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return m_util.cast.table(value, { |
|
− | + | callback = function (value) |
|
− | + | return string.format(i18n.files.inventory_icon, string.format('%s %s', tpl_args.inventory_icon_id, tostring(value))) |
|
− | + | end, |
|
− | + | }) |
|
− | icons[#icons+1] = string.format(i18n.inventory_icon, string.format('%s %s', tpl_args.inventory_icon_id, name)) |
||
− | end |
||
− | end |
||
− | tpl_args.alternate_art_inventory_icons = icons |
||
end, |
end, |
||
− | default = |
+ | default = {}, |
}, |
}, |
||
cannot_be_traded_or_modified = { |
cannot_be_traded_or_modified = { |
||
− | + | inherit = false, |
|
field = 'cannot_be_traded_or_modified', |
field = 'cannot_be_traded_or_modified', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
help_text = { |
help_text = { |
||
− | debug_ignore_nil = true, |
||
field = 'help_text', |
field = 'help_text', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
flavour_text = { |
flavour_text = { |
||
− | + | inherit = false, |
|
field = 'flavour_text', |
field = 'flavour_text', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
flavour_text_id = { |
flavour_text_id = { |
||
− | + | inherit = false, |
|
field = 'flavour_text_id', |
field = 'flavour_text_id', |
||
type = 'String', |
type = 'String', |
||
Line 533: | Line 790: | ||
field = 'tags', |
field = 'tags', |
||
type = 'List (,) of String', |
type = 'List (,) of String', |
||
− | func = |
+ | func = h.proc.factory.list{ |
− | + | callback = m_util.validate.factory.in_table_keys{ |
|
− | + | tbl = m_game.constants.tags, |
|
+ | errmsg = i18n.errors.invalid_tag, |
||
− | }), |
||
+ | errlvl = 4, |
||
+ | }, |
||
+ | }, |
||
+ | default = {}, |
||
}, |
}, |
||
metadata_id = { |
metadata_id = { |
||
− | + | inherit = false, |
|
field = 'metadata_id', |
field = 'metadata_id', |
||
type = 'String', |
type = 'String', |
||
--type = 'String(unique; size=200)', |
--type = 'String(unique; size=200)', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | if |
+ | if value == nil then |
− | return |
+ | return nil |
end |
end |
||
+ | -- Unless we're in testing mode, validate that metadata_id is unique |
||
− | local results = m_cargo.query( |
||
− | + | if not tpl_args.test then |
|
− | + | local results = m_cargo.query( |
|
− | { |
+ | {'items'}, |
− | + | {'items._pageName'}, |
|
− | + | { |
|
− | + | where=string.format( |
|
− | + | 'items.metadata_id = "%s" AND items._pageName != "%s"', |
|
+ | value, |
||
− | error(string.format(i18n.errors.duplicate_metadata, tpl_args.metadata_id, results[1]['items._pageName'])) |
||
+ | m_cargo.addslashes(mw.title.getCurrentTitle().fullText) |
||
+ | ) |
||
+ | } |
||
+ | ) |
||
+ | if #results > 0 then |
||
+ | error(string.format(i18n.errors.duplicate_metadata, value, results[1]['items._pageName'])) |
||
+ | end |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
}, |
}, |
||
influences = { |
influences = { |
||
− | + | inherit = false, |
|
field = 'influences', |
field = 'influences', |
||
type = 'List (,) of String', |
type = 'List (,) of String', |
||
− | func = |
+ | func = h.proc.factory.list{ |
− | + | callback = m_util.validate.factory.in_table_keys{ |
|
− | + | tbl = m_game.constants.influences, |
|
+ | errmsg = i18n.errors.invalid_influence, |
||
− | }), |
||
+ | errlvl = 4, |
||
+ | }, |
||
+ | }, |
||
+ | default = {}, |
||
}, |
}, |
||
is_fractured = { |
is_fractured = { |
||
− | + | inherit = false, |
|
field = 'is_fractured', |
field = 'is_fractured', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
is_synthesised = { |
is_synthesised = { |
||
− | + | inherit = false, |
|
field = 'is_synthesised', |
field = 'is_synthesised', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
is_veiled = { |
is_veiled = { |
||
− | + | inherit = false, |
|
field = 'is_veiled', |
field = 'is_veiled', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
is_replica = { |
is_replica = { |
||
− | + | inherit = false, |
|
field = 'is_replica', |
field = 'is_replica', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | m_util.cast |
+ | value = m_util.cast.boolean(value) |
− | if |
+ | if value == true and tpl_args.rarity_id ~= 'unique' then |
error(string.format(i18n.errors.non_unique_flag, 'is_replica')) |
error(string.format(i18n.errors.non_unique_flag, 'is_replica')) |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
default = false, |
default = false, |
||
}, |
}, |
||
is_corrupted = { |
is_corrupted = { |
||
− | + | inherit = false, |
|
field = 'is_corrupted', |
field = 'is_corrupted', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
is_relic = { |
is_relic = { |
||
− | + | inherit = false, |
|
field = 'is_relic', |
field = 'is_relic', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | m_util.cast |
+ | value = m_util.cast.boolean(value) |
− | if |
+ | if value == true and tpl_args.rarity_id ~= 'unique' then |
error(string.format(i18n.errors.non_unique_flag, 'is_relic')) |
error(string.format(i18n.errors.non_unique_flag, 'is_relic')) |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
default = false, |
default = false, |
||
}, |
}, |
||
is_fated = { |
is_fated = { |
||
− | + | inherit = false, |
|
field = 'is_fated', |
field = 'is_fated', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | m_util.cast |
+ | value = m_util.cast.boolean(value) |
− | if |
+ | if value == true and tpl_args.rarity_id ~= 'unique' then |
error(string.format(i18n.errors.non_unique_flag, 'is_fated')) |
error(string.format(i18n.errors.non_unique_flag, 'is_fated')) |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
default = false, |
default = false, |
||
}, |
}, |
||
is_prophecy = { |
is_prophecy = { |
||
− | + | inherit = false, |
|
field = nil, |
field = nil, |
||
type = nil, |
type = nil, |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | tpl_args._flags.is_prophecy = (tpl_args.metadata_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy' or tpl_args.base_item == |
+ | tpl_args._flags.is_prophecy = (tpl_args.metadata_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy' or tpl_args.base_item == cfg.prophecy_base_item or tpl_args.base_item_page == cfg.prophecy_base_item_page or tpl_args.base_item_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy') |
+ | return value |
||
end |
end |
||
}, |
}, |
||
is_blight_item = { |
is_blight_item = { |
||
− | + | inherit = false, |
|
field = nil, |
field = nil, |
||
type = nil, |
type = nil, |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
tpl_args._flags.is_blight_item = (tpl_args.blight_item_tier ~= nil) |
tpl_args._flags.is_blight_item = (tpl_args.blight_item_tier ~= nil) |
||
+ | return value |
||
end |
end |
||
}, |
}, |
||
is_drop_restricted = { |
is_drop_restricted = { |
||
− | + | inherit = false, |
|
field = 'is_drop_restricted', |
field = 'is_drop_restricted', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
− | default = function(tpl_args, frame) |
+ | default = function (tpl_args, frame) |
-- Generally items that are obtained only from specific monsters can't be obtained via cards or other means unless specifically specified |
-- Generally items that are obtained only from specific monsters can't be obtained via cards or other means unless specifically specified |
||
− | for _, |
+ | for _, key in ipairs({'is_talisman', 'is_essence', 'is_fated', 'is_replica', 'is_relic', 'drop_monsters'}) do |
− | + | -- key must be truthy and NOT an empty table |
|
+ | if tpl_args[key] and not (type(tpl_args[key]) == 'table' and #tpl_args[key] == 0) then |
||
return true |
return true |
||
end |
end |
||
Line 669: | Line 948: | ||
}, |
}, |
||
purchase_costs = { |
purchase_costs = { |
||
− | + | field = nil, |
|
+ | type = nil, |
||
+ | func = function (tpl_args, frame, value) |
||
local purchase_costs = {} |
local purchase_costs = {} |
||
for _, rarity_id in ipairs(m_game.constants.rarity_order) do |
for _, rarity_id in ipairs(m_game.constants.rarity_order) do |
||
Line 696: | Line 977: | ||
end |
end |
||
end |
end |
||
− | |||
purchase_costs[rarity_id] = rtbl |
purchase_costs[rarity_id] = rtbl |
||
end |
end |
||
− | + | return purchase_costs |
|
− | tpl_args.purchase_costs = purchase_costs |
||
end, |
end, |
||
− | func_fetch = function(tpl_args, frame) |
+ | func_fetch = function (tpl_args, frame) |
if tpl_args.rarity_id ~= 'unique' then |
if tpl_args.rarity_id ~= 'unique' then |
||
return |
return |
||
Line 733: | Line 1,012: | ||
end |
end |
||
end, |
end, |
||
+ | }, |
||
+ | is_sellable = { |
||
+ | inherit = false, |
||
+ | field = nil, |
||
+ | type = nil, |
||
+ | func = h.proc.boolean, |
||
+ | default = true, |
||
}, |
}, |
||
sell_prices_override = { |
sell_prices_override = { |
||
− | + | inherit = false, |
|
− | + | field = nil, |
|
+ | type = nil, |
||
+ | func = function (tpl_args, frame, value) |
||
-- these variables are also used by mods when setting automatic sell prices |
-- these variables are also used by mods when setting automatic sell prices |
||
tpl_args.sell_prices = {} |
tpl_args.sell_prices = {} |
||
tpl_args.sell_price_order = {} |
tpl_args.sell_price_order = {} |
||
− | + | if not tpl_args.is_sellable then |
|
− | + | return nil |
|
+ | end |
||
local name |
local name |
||
local amount |
local amount |
||
Line 760: | Line 1,049: | ||
end |
end |
||
until name == nil or amount == nil |
until name == nil or amount == nil |
||
− | |||
-- if sell prices are set, the override is active |
-- if sell prices are set, the override is active |
||
for _, _ in pairs(tpl_args.sell_prices) do |
for _, _ in pairs(tpl_args.sell_prices) do |
||
Line 766: | Line 1,054: | ||
break |
break |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
}, |
}, |
||
Line 771: | Line 1,060: | ||
-- specific section |
-- specific section |
||
-- |
-- |
||
+ | |||
− | |||
-- Most item classes |
-- Most item classes |
||
quality = { |
quality = { |
||
− | + | inherit = false, |
|
field = 'quality', |
field = 'quality', |
||
type = 'Integer', |
type = 'Integer', |
||
-- Can be set manually, but default to Q20 for unique weapons/body armours |
-- Can be set manually, but default to Q20 for unique weapons/body armours |
||
-- Also must copy to stat for the stat adjustments to work properly |
-- Also must copy to stat for the stat adjustments to work properly |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | local quality = tonumber( |
+ | local quality = tonumber(value) |
− | -- |
||
if quality == nil then |
if quality == nil then |
||
if tpl_args.rarity_id ~= 'unique' then |
if tpl_args.rarity_id ~= 'unique' then |
||
Line 791: | Line 1,079: | ||
end |
end |
||
end |
end |
||
− | |||
− | tpl_args.quality = quality |
||
− | |||
local stat = { |
local stat = { |
||
min = quality, |
min = quality, |
||
Line 799: | Line 1,084: | ||
avg = quality, |
avg = quality, |
||
} |
} |
||
+ | core.stats_update(tpl_args, 'quality', stat, nil, '_stats') |
||
− | |||
− | h.stats_update(tpl_args, 'quality', stat, nil, '_stats') |
||
− | |||
if tpl_args.class_id == 'UtilityFlask' or tpl_args.class_id == 'UtilityFlaskCritical' then |
if tpl_args.class_id == 'UtilityFlask' or tpl_args.class_id == 'UtilityFlaskCritical' then |
||
− | + | core.stats_update(tpl_args, 'quality_flask_duration', stat, nil, '_stats') |
|
-- quality is added to quantity for maps |
-- quality is added to quantity for maps |
||
elseif tpl_args.class_id == 'Map' then |
elseif tpl_args.class_id == 'Map' then |
||
− | + | core.stats_update(tpl_args, 'map_item_drop_quantity_+%', stat, nil, '_stats') |
|
end |
end |
||
+ | return quality |
||
end, |
end, |
||
}, |
}, |
||
Line 814: | Line 1,098: | ||
field = 'is_talisman', |
field = 'is_talisman', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
− | |||
talisman_tier = { |
talisman_tier = { |
||
field = 'talisman_tier', |
field = 'talisman_tier', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
− | |||
-- flasks |
-- flasks |
||
charges_max = { |
charges_max = { |
||
field = 'charges_max', |
field = 'charges_max', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
charges_per_use = { |
charges_per_use = { |
||
field = 'charges_per_use', |
field = 'charges_per_use', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
flask_mana = { |
flask_mana = { |
||
field = 'mana', |
field = 'mana', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
flask_life = { |
flask_life = { |
||
field = 'life', |
field = 'life', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
flask_duration = { |
flask_duration = { |
||
field = 'duration', |
field = 'duration', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
buff_id = { |
buff_id = { |
||
Line 858: | Line 1,140: | ||
field = 'buff_values', |
field = 'buff_values', |
||
type = 'List (,) of Integer', |
type = 'List (,) of Integer', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
local values = {} |
local values = {} |
||
local i = 0 |
local i = 0 |
||
Line 870: | Line 1,152: | ||
-- needed so the values copyied from unique item base isn't overriden |
-- needed so the values copyied from unique item base isn't overriden |
||
if #values >= 1 then |
if #values >= 1 then |
||
− | + | value = values |
|
end |
end |
||
+ | return value |
||
end, |
end, |
||
− | func_copy = function(tpl_args, frame) |
+ | func_copy = function (tpl_args, frame, value) |
− | tpl_args.buff_values = m_util.string.split( |
+ | tpl_args.buff_values = m_util.string.split(value, ',%s*') |
end, |
end, |
||
− | default = |
+ | default = {}, |
}, |
}, |
||
buff_stat_text = { |
buff_stat_text = { |
||
Line 886: | Line 1,169: | ||
field = 'icon', |
field = 'icon', |
||
type = 'String', |
type = 'String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return string.format(i18n.files.status_icon, tpl_args.name) |
|
end, |
end, |
||
}, |
}, |
||
Line 895: | Line 1,178: | ||
field = 'critical_strike_chance', |
field = 'critical_strike_chance', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
attack_speed = { |
attack_speed = { |
||
field = 'attack_speed', |
field = 'attack_speed', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
weapon_range = { |
weapon_range = { |
||
field = 'weapon_range', |
field = 'weapon_range', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
physical_damage_min = { |
physical_damage_min = { |
||
field = 'physical_damage_min', |
field = 'physical_damage_min', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
physical_damage_max = { |
physical_damage_max = { |
||
field = 'physical_damage_max', |
field = 'physical_damage_max', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
fire_damage_min = { |
fire_damage_min = { |
||
field = 'fire_damage_min', |
field = 'fire_damage_min', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 926: | Line 1,209: | ||
field = 'fire_damage_max', |
field = 'fire_damage_max', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 932: | Line 1,215: | ||
field = 'cold_damage_min', |
field = 'cold_damage_min', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 938: | Line 1,221: | ||
field = 'cold_damage_max', |
field = 'cold_damage_max', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 944: | Line 1,227: | ||
field = 'lightning_damage_min', |
field = 'lightning_damage_min', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 950: | Line 1,233: | ||
field = 'lightning_damage_max', |
field = 'lightning_damage_max', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 956: | Line 1,239: | ||
field = 'chaos_damage_min', |
field = 'chaos_damage_min', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 962: | Line 1,245: | ||
field = 'chaos_damage_max', |
field = 'chaos_damage_max', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 969: | Line 1,252: | ||
field = 'armour', |
field = 'armour', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 975: | Line 1,258: | ||
field = 'energy_shield', |
field = 'energy_shield', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 981: | Line 1,264: | ||
field = 'evasion', |
field = 'evasion', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
+ | default = 0, |
||
+ | }, |
||
+ | ward = { |
||
+ | field = 'ward', |
||
+ | type = 'Integer', |
||
+ | func = h.proc.number, |
||
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 988: | Line 1,277: | ||
field = 'movement_speed', |
field = 'movement_speed', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 995: | Line 1,284: | ||
field = 'block', |
field = 'block', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
-- skill gem stuff |
-- skill gem stuff |
||
Line 1,001: | Line 1,290: | ||
field = 'gem_description', |
field = 'gem_description', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
dexterity_percent = { |
dexterity_percent = { |
||
field = 'dexterity_percent', |
field = 'dexterity_percent', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.percentage, |
}, |
}, |
||
strength_percent = { |
strength_percent = { |
||
field = 'strength_percent', |
field = 'strength_percent', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.percentage, |
}, |
}, |
||
intelligence_percent = { |
intelligence_percent = { |
||
field = 'intelligence_percent', |
field = 'intelligence_percent', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.percentage, |
}, |
}, |
||
primary_attribute = { |
primary_attribute = { |
||
field = 'primary_attribute', |
field = 'primary_attribute', |
||
type = 'String', |
type = 'String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
for _, attr in ipairs(m_game.constants.attribute_order) do |
for _, attr in ipairs(m_game.constants.attribute_order) do |
||
local val = tpl_args[attr .. '_percent'] |
local val = tpl_args[attr .. '_percent'] |
||
if val and val >= 60 then |
if val and val >= 60 then |
||
− | + | return attr |
|
− | return |
||
end |
end |
||
end |
end |
||
− | + | return 'none' |
|
end, |
end, |
||
}, |
}, |
||
Line 1,035: | Line 1,323: | ||
field = 'gem_tags', |
field = 'gem_tags', |
||
type = 'List (,) of String', |
type = 'List (,) of String', |
||
− | + | func = h.proc.factory.list{ |
|
+ | callback = m_util.validate.factory.in_table_keys{ |
||
− | func = function(tpl_args, frame) |
||
+ | tbl = m_game.constants.item.gem_tags_lookup, |
||
− | if tpl_args.gem_tags then |
||
− | + | errmsg = i18n.errors.invalid_gem_tag, |
|
− | + | errlvl = 4, |
|
− | + | }, |
|
+ | }, |
||
− | default = function (tpl_args, frame) return {} end, |
||
+ | default = {}, |
||
}, |
}, |
||
-- Support gems only |
-- Support gems only |
||
Line 1,052: | Line 1,341: | ||
field = 'support_gem_letter_html', |
field = 'support_gem_letter_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
if tpl_args.support_gem_letter == nil then |
if tpl_args.support_gem_letter == nil then |
||
− | return |
+ | return nil |
end |
end |
||
+ | for k, v in pairs(m_game.constants.attributes) do |
||
− | |||
− | + | local key = string.format('%s_percent', k) |
|
− | + | if tpl_args[key] and tpl_args[key] > 50 then |
|
− | + | value = tostring( |
|
− | + | mw.html.create('span') |
|
− | + | :attr('class', string.format('support-gem-id-%s', v.color)) |
|
+ | :wikitext(tpl_args.support_gem_letter) |
||
− | } |
||
− | + | ) |
|
− | for k, v in pairs(css_map) do |
||
− | k = string.format('%s_percent', k) |
||
− | if tpl_args[k] and tpl_args[k] > 50 then |
||
− | id = v |
||
break |
break |
||
end |
end |
||
end |
end |
||
− | + | return value |
|
− | if id ~= nil then |
||
− | local container = mw.html.create('span') |
||
− | container |
||
− | :attr('class', string.format('support-gem-id-%s', id)) |
||
− | :wikitext(tpl_args.support_gem_letter) |
||
− | :done() |
||
− | tpl_args.support_gem_letter_html = tostring(container) |
||
− | end |
||
end, |
end, |
||
}, |
}, |
||
Line 1,088: | Line 1,365: | ||
field = 'tier', |
field = 'tier', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
map_guild_character = { |
map_guild_character = { |
||
Line 1,103: | Line 1,380: | ||
field = 'area_level', |
field = 'area_level', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
unique_map_guild_character = { |
unique_map_guild_character = { |
||
field = 'unique_guild_character', |
field = 'unique_guild_character', |
||
type = 'String(size=1)', |
type = 'String(size=1)', |
||
− | func_copy = function(tpl_args, frame) |
||
− | tpl_args.map_guild_character = tpl_args.unique_map_guild_character |
||
− | end, |
||
func = nil, |
func = nil, |
||
+ | func_copy = function (tpl_args, frame, value) |
||
+ | tpl_args.map_guild_character = value |
||
+ | end, |
||
}, |
}, |
||
unique_map_area_id = { |
unique_map_area_id = { |
||
Line 1,117: | Line 1,394: | ||
type = 'String', |
type = 'String', |
||
func = nil, -- TODO: Validate against a query? |
func = nil, -- TODO: Validate against a query? |
||
− | func_copy = function(tpl_args, frame) |
+ | func_copy = function (tpl_args, frame, value) |
− | tpl_args.map_area_id = |
+ | tpl_args.map_area_id = value |
end, |
end, |
||
}, |
}, |
||
Line 1,124: | Line 1,401: | ||
field = 'unique_area_level', |
field = 'unique_area_level', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
− | func_copy = function(tpl_args, frame) |
+ | func_copy = function (tpl_args, frame, value) |
− | tpl_args.map_area_level = |
+ | tpl_args.map_area_level = value |
end, |
end, |
||
}, |
}, |
||
Line 1,132: | Line 1,409: | ||
field = 'series', |
field = 'series', |
||
type = 'String', |
type = 'String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | if tpl_args.rarity == 'normal' and |
+ | if tpl_args.rarity == 'normal' and value == nil then |
error(string.format(i18n.errors.generic_required_parameter, 'map_series')) |
error(string.format(i18n.errors.generic_required_parameter, 'map_series')) |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
}, |
}, |
||
Line 1,142: | Line 1,420: | ||
field = 'x', |
field = 'x', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_y = { |
atlas_y = { |
||
field = 'y', |
field = 'y', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_region_id = { |
atlas_region_id = { |
||
Line 1,157: | Line 1,435: | ||
field = 'region_minimum', |
field = 'region_minimum', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_x0 = { |
atlas_x0 = { |
||
field = 'x0', |
field = 'x0', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_x1 = { |
atlas_x1 = { |
||
field = 'x1', |
field = 'x1', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_x2 = { |
atlas_x2 = { |
||
field = 'x2', |
field = 'x2', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_x3 = { |
atlas_x3 = { |
||
field = 'x3', |
field = 'x3', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_x4 = { |
atlas_x4 = { |
||
field = 'x4', |
field = 'x4', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_y0 = { |
atlas_y0 = { |
||
field = 'y0', |
field = 'y0', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_y1 = { |
atlas_y1 = { |
||
field = 'y1', |
field = 'y1', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_y2 = { |
atlas_y2 = { |
||
field = 'y2', |
field = 'y2', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_y3 = { |
atlas_y3 = { |
||
field = 'y3', |
field = 'y3', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_y4 = { |
atlas_y4 = { |
||
field = 'y4', |
field = 'y4', |
||
type = 'Float', |
type = 'Float', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_map_tier0 = { |
atlas_map_tier0 = { |
||
field = 'map_tier0', |
field = 'map_tier0', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_map_tier1 = { |
atlas_map_tier1 = { |
||
field = 'map_tier1', |
field = 'map_tier1', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_map_tier2 = { |
atlas_map_tier2 = { |
||
field = 'map_tier2', |
field = 'map_tier2', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_map_tier3 = { |
atlas_map_tier3 = { |
||
field = 'map_tier3', |
field = 'map_tier3', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_map_tier4 = { |
atlas_map_tier4 = { |
||
field = 'map_tier4', |
field = 'map_tier4', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
atlas_connections = { |
atlas_connections = { |
||
field = nil, |
field = nil, |
||
type = nil, |
type = nil, |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | value = {} |
|
− | |||
local cont = true |
local cont = true |
||
local i = 1 |
local i = 1 |
||
Line 1,260: | Line 1,537: | ||
end |
end |
||
− | + | value[data.map2] = data |
|
table.insert(tpl_args._subobjects, data) |
table.insert(tpl_args._subobjects, data) |
||
else |
else |
||
cont = false |
cont = false |
||
if i == 1 then |
if i == 1 then |
||
− | + | value = nil |
|
end |
end |
||
end |
end |
||
− | |||
i = i + 1 |
i = i + 1 |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
− | default = nil, |
||
}, |
}, |
||
-- |
-- |
||
Line 1,280: | Line 1,556: | ||
field = 'stack_size', |
field = 'stack_size', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
stack_size_currency_tab = { |
stack_size_currency_tab = { |
||
field = 'stack_size_currency_tab', |
field = 'stack_size_currency_tab', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
description = { |
description = { |
||
field = 'description', |
field = 'description', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
cosmetic_type = { |
cosmetic_type = { |
||
field = 'cosmetic_type', |
field = 'cosmetic_type', |
||
type = 'String', |
type = 'String', |
||
− | func = h.factory. |
+ | func = h.proc.factory.value{ |
+ | validate = m_util.validate.factory.in_table_keys{ |
||
+ | tbl = m_game.constants.item.cosmetic_item_types, |
||
+ | errmsg = i18n.errors.invalid_cosmetic_type, |
||
+ | }, |
||
+ | }, |
||
}, |
}, |
||
-- for essences |
-- for essences |
||
is_essence = { |
is_essence = { |
||
field = nil, |
field = nil, |
||
− | + | type = nil, |
|
+ | func = h.proc.boolean, |
||
default = false, |
default = false, |
||
}, |
}, |
||
Line 1,306: | Line 1,588: | ||
field = 'level_restriction', |
field = 'level_restriction', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
essence_level = { |
essence_level = { |
||
field = 'level', |
field = 'level', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
essence_type = { |
essence_type = { |
||
field = 'type', |
field = 'type', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
essence_category = { |
essence_category = { |
||
Line 1,327: | Line 1,609: | ||
field = 'tier', |
field = 'tier', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
-- harvest seeds |
-- harvest seeds |
||
Line 1,333: | Line 1,615: | ||
field = 'type_id', |
field = 'type_id', |
||
type = 'String', |
type = 'String', |
||
+ | func = nil, |
||
}, |
}, |
||
seed_type = { |
seed_type = { |
||
field = 'type', |
field = 'type', |
||
type = 'String', |
type = 'String', |
||
− | func = function (tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
if tpl_args.seed_type_id ~= 'none' or tpl_args.seed_type_id ~= nil then |
if tpl_args.seed_type_id ~= 'none' or tpl_args.seed_type_id ~= nil then |
||
− | + | value = m_game.seed_types[tpl_args.seed_type_id] |
|
end |
end |
||
+ | return value |
||
end |
end |
||
}, |
}, |
||
Line 1,346: | Line 1,630: | ||
field = nil, |
field = nil, |
||
type = nil, |
type = nil, |
||
− | func = function (tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
if tpl_args.seed_type ~= nil then |
if tpl_args.seed_type ~= nil then |
||
− | + | value = m_util.html.poe_color(tpl_args.seed_type_id, tpl_args.seed_type) |
|
end |
end |
||
+ | return value |
||
end |
end |
||
}, |
}, |
||
Line 1,355: | Line 1,640: | ||
field = 'effect', |
field = 'effect', |
||
type = 'Text', |
type = 'Text', |
||
+ | func = nil, |
||
}, |
}, |
||
seed_tier = { |
seed_tier = { |
||
field = 'tier', |
field = 'tier', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
seed_growth_cycles = { |
seed_growth_cycles = { |
||
field = 'growth_cycles', |
field = 'growth_cycles', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
seed_required_nearby_seed_tier = { |
seed_required_nearby_seed_tier = { |
||
field = 'required_nearby_seed_tier', |
field = 'required_nearby_seed_tier', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
seed_required_nearby_seed_amount = { |
seed_required_nearby_seed_amount = { |
||
field = 'required_nearby_seed_amount', |
field = 'required_nearby_seed_amount', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
seed_consumed_wild_lifeforce_percentage = { |
seed_consumed_wild_lifeforce_percentage = { |
||
field = 'consumed_wild_lifeforce_percentage', |
field = 'consumed_wild_lifeforce_percentage', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 1,385: | Line 1,671: | ||
field = 'consumed_vivid_lifeforce_percentage', |
field = 'consumed_vivid_lifeforce_percentage', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 1,391: | Line 1,677: | ||
field = 'consumed_primal_lifeforce_percentage', |
field = 'consumed_primal_lifeforce_percentage', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
default = 0, |
default = 0, |
||
}, |
}, |
||
Line 1,397: | Line 1,683: | ||
field = 'granted_craft_option_ids', |
field = 'granted_craft_option_ids', |
||
type = 'List (,) of String', |
type = 'List (,) of String', |
||
− | func = |
+ | func = h.proc.list, |
− | default = |
+ | default = {}, |
}, |
}, |
||
-- |
-- |
||
Line 1,406: | Line 1,692: | ||
field = 'radius', |
field = 'radius', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
plant_booster_lifeforce = { |
plant_booster_lifeforce = { |
||
field = 'lifeforce', |
field = 'lifeforce', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
plant_booster_additional_crafting_options = { |
plant_booster_additional_crafting_options = { |
||
field = 'additional_crafting_options', |
field = 'additional_crafting_options', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
plant_booster_extra_chances = { |
plant_booster_extra_chances = { |
||
field = 'extra_chances', |
field = 'extra_chances', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
-- |
-- |
||
Line 1,429: | Line 1,715: | ||
field = 'required_job_id', |
field = 'required_job_id', |
||
type = 'String', |
type = 'String', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
heist_required_job_level = { |
heist_required_job_level = { |
||
field = 'required_job_level', |
field = 'required_job_level', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
heist_data = { |
heist_data = { |
||
− | + | field = nil, |
|
+ | type = nil, |
||
+ | func = function (tpl_args, frame, value) |
||
if tpl_args.heist_required_job_level then |
if tpl_args.heist_required_job_level then |
||
if tpl_args.heist_required_job_id then |
if tpl_args.heist_required_job_id then |
||
Line 1,448: | Line 1,736: | ||
} |
} |
||
) |
) |
||
− | |||
local npcs = {} |
local npcs = {} |
||
− | |||
for _, row in ipairs(results) do |
for _, row in ipairs(results) do |
||
npcs[#npcs+1] = row['heist_npcs.name'] |
npcs[#npcs+1] = row['heist_npcs.name'] |
||
end |
end |
||
− | |||
tpl_args.heist_required_npcs = table.concat(npcs, ', ') |
tpl_args.heist_required_npcs = table.concat(npcs, ', ') |
||
tpl_args.heist_required_job = results[1]['heist_jobs.name'] |
tpl_args.heist_required_job = results[1]['heist_jobs.name'] |
||
Line 1,461: | Line 1,746: | ||
end |
end |
||
end |
end |
||
+ | return value |
||
end, |
end, |
||
}, |
}, |
||
Line 1,469: | Line 1,755: | ||
field = 'is_master_doodad', |
field = 'is_master_doodad', |
||
type = 'Boolean', |
type = 'Boolean', |
||
− | func = |
+ | func = h.proc.boolean, |
}, |
}, |
||
master = { |
master = { |
||
field = 'master', |
field = 'master', |
||
type = 'String', |
type = 'String', |
||
+ | func = h.proc.factory.value{ |
||
− | -- todo validate against list of master names |
||
− | + | validate = m_util.validate.factory.in_table_keys{ |
|
+ | tbl = m_util.table.column(m_game.constants.masters, 'long_upper', 'full'), |
||
+ | errmsg = i18n.errors.invalid_master, |
||
+ | }, |
||
+ | }, |
||
}, |
}, |
||
master_level_requirement = { |
master_level_requirement = { |
||
field = 'level_requirement', |
field = 'level_requirement', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
master_favour_cost = { |
master_favour_cost = { |
||
field = 'favour_cost', |
field = 'favour_cost', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
variation_count = { |
variation_count = { |
||
field = 'variation_count', |
field = 'variation_count', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
-- Propehcy |
-- Propehcy |
||
Line 1,501: | Line 1,791: | ||
field = 'prediction_text', |
field = 'prediction_text', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
seal_cost = { |
seal_cost = { |
||
field = 'seal_cost', |
field = 'seal_cost', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
prophecy_reward = { |
prophecy_reward = { |
||
field = 'reward', |
field = 'reward', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
prophecy_objective = { |
prophecy_objective = { |
||
field = 'objective', |
field = 'objective', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h. |
+ | func = h.proc.text, |
}, |
}, |
||
-- Divination cards |
-- Divination cards |
||
Line 1,522: | Line 1,812: | ||
field = 'card_art', |
field = 'card_art', |
||
type = 'Page', |
type = 'Page', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return string.format(i18n.files.divination_card_art, value or tpl_args.name) |
|
end, |
end, |
||
}, |
}, |
||
Line 1,532: | Line 1,822: | ||
-- For rarity != normal, rarity already verified |
-- For rarity != normal, rarity already verified |
||
base_item = { |
base_item = { |
||
− | + | inherit = false, |
|
field = 'base_item', |
field = 'base_item', |
||
type = 'String', |
type = 'String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return tpl_args.base_item_data['items.name'] |
|
end, |
end, |
||
}, |
}, |
||
base_item_id = { |
base_item_id = { |
||
− | + | inherit = false, |
|
field = 'base_item_id', |
field = 'base_item_id', |
||
type = 'String', |
type = 'String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return tpl_args.base_item_data['items.metadata_id'] |
|
end, |
end, |
||
}, |
}, |
||
base_item_page = { |
base_item_page = { |
||
− | + | inherit = false, |
|
field = 'base_item_page', |
field = 'base_item_page', |
||
type = 'Page', |
type = 'Page', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | return tpl_args.base_item_data['items._pageName'] |
|
end, |
end, |
||
}, |
}, |
||
name_list = { |
name_list = { |
||
− | + | inherit = false, |
|
field = 'name_list', |
field = 'name_list', |
||
type = 'List (�) of String', |
type = 'List (�) of String', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
− | + | value = m_util.cast.table(value) |
|
− | + | value[#value+1] = tpl_args.name |
|
+ | return value |
||
− | tpl_args.name_list[#tpl_args.name_list+1] = tpl_args.name |
||
− | else |
||
− | tpl_args.name_list = {tpl_args.name} |
||
− | end |
||
end, |
end, |
||
+ | default = {}, |
||
}, |
}, |
||
frame_type = { |
frame_type = { |
||
− | + | inherit = false, |
|
field = 'frame_type', |
field = 'frame_type', |
||
type = 'String', |
type = 'String', |
||
− | + | func = function (tpl_args, frame, value) |
|
− | + | if value then |
|
+ | return value |
||
+ | end |
||
if tpl_args._flags.is_prophecy then |
if tpl_args._flags.is_prophecy then |
||
− | + | return 'prophecy' |
|
− | return |
||
end |
end |
||
− | |||
local var = cfg.class_specifics[tpl_args.class_id] |
local var = cfg.class_specifics[tpl_args.class_id] |
||
if var ~= nil and var.frame_type ~= nil then |
if var ~= nil and var.frame_type ~= nil then |
||
− | + | return var.frame_type |
|
− | return |
||
end |
end |
||
− | |||
if tpl_args.is_relic then |
if tpl_args.is_relic then |
||
− | + | return 'relic' |
|
− | return |
||
end |
end |
||
− | + | return tpl_args.rarity_id |
|
− | tpl_args.frame_type = tpl_args.rarity_id |
||
end, |
end, |
||
}, |
}, |
||
Line 1,597: | Line 1,881: | ||
-- |
-- |
||
mods = { |
mods = { |
||
− | + | field = nil, |
|
+ | type = nil, |
||
+ | func = nil, |
||
+ | default = {}, |
||
func_fetch = function (tpl_args, frame) |
func_fetch = function (tpl_args, frame) |
||
+ | -- Fetch implicit mods from base item |
||
local results = m_cargo.query( |
local results = m_cargo.query( |
||
{'items' ,'item_mods'}, |
{'items' ,'item_mods'}, |
||
Line 1,613: | Line 1,901: | ||
result = row['item_mods.text'] |
result = row['item_mods.text'] |
||
end |
end |
||
− | tpl_args. |
+ | tpl_args._base_implicit_mods[#tpl_args._base_implicit_mods+1] = { |
result=result, |
result=result, |
||
id=row['item_mods.id'], |
id=row['item_mods.id'], |
||
Line 1,624: | Line 1,912: | ||
}, |
}, |
||
physical_damage_html = { |
physical_damage_html = { |
||
− | + | inherit = false, |
|
field = 'physical_damage_html', |
field = 'physical_damage_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h.factory.damage_html{ |
+ | func = h.proc.factory.damage_html{type = 'physical'}, |
}, |
}, |
||
fire_damage_html = { |
fire_damage_html = { |
||
− | + | inherit = false, |
|
field = 'fire_damage_html', |
field = 'fire_damage_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h.factory.damage_html{ |
+ | func = h.proc.factory.damage_html{type = 'fire'}, |
}, |
}, |
||
cold_damage_html = { |
cold_damage_html = { |
||
− | + | inherit = false, |
|
field = 'cold_damage_html', |
field = 'cold_damage_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h.factory.damage_html{ |
+ | func = h.proc.factory.damage_html{type = 'cold'}, |
}, |
}, |
||
lightning_damage_html = { |
lightning_damage_html = { |
||
− | + | inherit = false, |
|
field = 'lightning_damage_html', |
field = 'lightning_damage_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h.factory.damage_html{ |
+ | func = h.proc.factory.damage_html{type = 'lightning'}, |
}, |
}, |
||
chaos_damage_html = { |
chaos_damage_html = { |
||
− | + | inherit = false, |
|
field = 'chaos_damage_html', |
field = 'chaos_damage_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = h.factory.damage_html{ |
+ | func = h.proc.factory.damage_html{type = 'chaos'}, |
}, |
}, |
||
damage_avg = { |
damage_avg = { |
||
− | + | inherit = false, |
|
field = 'damage_avg', |
field = 'damage_avg', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
local dmg = {min=0, max=0} |
local dmg = {min=0, max=0} |
||
for key, _ in pairs(dmg) do |
for key, _ in pairs(dmg) do |
||
Line 1,664: | Line 1,952: | ||
end |
end |
||
end |
end |
||
− | |||
dmg = (dmg.min + dmg.max) / 2 |
dmg = (dmg.min + dmg.max) / 2 |
||
− | + | return dmg |
|
− | tpl_args.damage_avg = dmg |
||
end, |
end, |
||
}, |
}, |
||
damage_html = { |
damage_html = { |
||
− | + | inherit = false, |
|
field = 'damage_html', |
field = 'damage_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
local text = {} |
local text = {} |
||
for _, dkey in ipairs(m_game.constants.damage_type_order) do |
for _, dkey in ipairs(m_game.constants.damage_type_order) do |
||
− | local |
+ | local range = tpl_args[dkey .. '_damage_html'] |
− | if |
+ | if range ~= nil then |
− | text[#text+1] = |
+ | text[#text+1] = range |
end |
end |
||
end |
end |
||
if #text > 0 then |
if #text > 0 then |
||
− | + | value = table.concat(text, '<br>') |
|
end |
end |
||
+ | return value |
||
end, |
end, |
||
}, |
}, |
||
item_limit = { |
item_limit = { |
||
− | + | inherit = false, |
|
field = 'item_limit', |
field = 'item_limit', |
||
type = 'Integer', |
type = 'Integer', |
||
− | func = |
+ | func = h.proc.number, |
}, |
}, |
||
jewel_radius_html = { |
jewel_radius_html = { |
||
− | + | inherit = false, |
|
field = 'radius_html', |
field = 'radius_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
-- Get radius from stats |
-- Get radius from stats |
||
local radius = tpl_args._stats.local_jewel_effect_base_radius |
local radius = tpl_args._stats.local_jewel_effect_base_radius |
||
Line 1,704: | Line 1,991: | ||
local size = m_game.constants.item.jewel_radius_to_size[radius] or radius |
local size = m_game.constants.item.jewel_radius_to_size[radius] or radius |
||
local color = radius == 0 and 'mod' or 'value' |
local color = radius == 0 and 'mod' or 'value' |
||
− | + | value = m_util.html.poe_color(color, size) |
|
end |
end |
||
+ | return value |
||
end, |
end, |
||
}, |
}, |
||
incubator_effect = { |
incubator_effect = { |
||
− | + | inherit = false, |
|
field = 'effect', |
field = 'effect', |
||
type = 'Text', |
type = 'Text', |
||
Line 1,715: | Line 2,003: | ||
}, |
}, |
||
drop_areas_html = { |
drop_areas_html = { |
||
− | + | inherit = false, |
|
field = 'drop_areas_html', |
field = 'drop_areas_html', |
||
type = 'Text', |
type = 'Text', |
||
− | func = function(tpl_args, frame) |
+ | func = function (tpl_args, frame, value) |
if tpl_args.drop_areas_data == nil then |
if tpl_args.drop_areas_data == nil then |
||
− | return |
+ | return value |
end |
end |
||
− | + | if value ~= nil then |
|
− | + | return value |
|
− | return |
||
end |
end |
||
− | |||
local areas = {} |
local areas = {} |
||
for _, data in pairs(tpl_args.drop_areas_data) do |
for _, data in pairs(tpl_args.drop_areas_data) do |
||
Line 1,734: | Line 2,020: | ||
end |
end |
||
end |
end |
||
− | + | return table.concat(areas, ' • ') |
|
− | tpl_args.drop_areas_html = table.concat(areas, ' • ') |
||
end, |
end, |
||
}, |
}, |
||
release_version = { |
release_version = { |
||
− | + | inherit = false, |
|
field = 'release_version', |
field = 'release_version', |
||
− | type = 'String' |
+ | type = 'String', |
+ | func = nil, |
||
}, |
}, |
||
removal_version = { |
removal_version = { |
||
− | + | inherit = false, |
|
field = 'removal_version', |
field = 'removal_version', |
||
type = 'String', |
type = 'String', |
||
+ | func = nil, |
||
}, |
}, |
||
-- |
-- |
||
Line 1,752: | Line 2,039: | ||
-- |
-- |
||
suppress_improper_modifiers_category = { |
suppress_improper_modifiers_category = { |
||
− | + | inherit = false, |
|
field = nil, |
field = nil, |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
upgraded_from_disabled = { |
upgraded_from_disabled = { |
||
− | + | inherit = false, |
|
field = nil, |
field = nil, |
||
− | func = |
+ | func = h.proc.boolean, |
default = false, |
default = false, |
||
}, |
}, |
||
Line 2,060: | Line 2,347: | ||
stats_override = { |
stats_override = { |
||
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0}, |
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0}, |
||
+ | }, |
||
+ | minimum = 0, |
||
+ | html_fmt_options = { |
||
+ | fmt = '%i', |
||
+ | }, |
||
+ | }, |
||
+ | ward = { |
||
+ | field = 'ward', |
||
+ | stats_add = { |
||
+ | 'local_ward', |
||
+ | }, |
||
+ | stats_increased = { |
||
+ | 'local_ward_+%', |
||
+ | 'quality', |
||
}, |
}, |
||
minimum = 0, |
minimum = 0, |
||
Line 2,129: | Line 2,430: | ||
core.dps_map = { |
core.dps_map = { |
||
− | { |
+ | physical_dps = { |
− | name = 'physical_dps', |
||
field = 'physical_dps', |
field = 'physical_dps', |
||
− | damage_args = {'physical_damage' |
+ | damage_args = {'physical_damage'}, |
label_infobox = i18n.tooltips.physical_dps, |
label_infobox = i18n.tooltips.physical_dps, |
||
html_fmt_options = { |
html_fmt_options = { |
||
Line 2,139: | Line 2,439: | ||
}, |
}, |
||
}, |
}, |
||
− | { |
+ | fire_dps = { |
− | name = 'fire_dps', |
||
field = 'fire_dps', |
field = 'fire_dps', |
||
damage_args = {'fire_damage'}, |
damage_args = {'fire_damage'}, |
||
Line 2,149: | Line 2,448: | ||
}, |
}, |
||
}, |
}, |
||
− | { |
+ | cold_dps = { |
− | name = 'cold_dps', |
||
field = 'cold_dps', |
field = 'cold_dps', |
||
damage_args = {'cold_damage'}, |
damage_args = {'cold_damage'}, |
||
Line 2,159: | Line 2,457: | ||
}, |
}, |
||
}, |
}, |
||
− | { |
+ | lightning_dps = { |
− | name = 'lightning_dps', |
||
field = 'lightning_dps', |
field = 'lightning_dps', |
||
damage_args = {'lightning_damage'}, |
damage_args = {'lightning_damage'}, |
||
Line 2,169: | Line 2,466: | ||
}, |
}, |
||
}, |
}, |
||
− | { |
+ | chaos_dps = { |
− | name = 'chaos_dps', |
||
field = 'chaos_dps', |
field = 'chaos_dps', |
||
damage_args = {'chaos_damage'}, |
damage_args = {'chaos_damage'}, |
||
Line 2,179: | Line 2,475: | ||
}, |
}, |
||
}, |
}, |
||
− | { |
+ | elemental_dps = { |
− | name = 'elemental_dps', |
||
field = 'elemental_dps', |
field = 'elemental_dps', |
||
damage_args = {'fire_damage', 'cold_damage', 'lightning_damage'}, |
damage_args = {'fire_damage', 'cold_damage', 'lightning_damage'}, |
||
Line 2,189: | Line 2,484: | ||
}, |
}, |
||
}, |
}, |
||
− | { |
+ | poison_dps = { |
− | name = 'poison_dps', |
||
field = 'poison_dps', |
field = 'poison_dps', |
||
damage_args = {'physical_damage', 'chaos_damage'}, |
damage_args = {'physical_damage', 'chaos_damage'}, |
||
Line 2,199: | Line 2,493: | ||
}, |
}, |
||
}, |
}, |
||
− | { |
+ | dps = { |
− | name = 'dps', |
||
field = 'dps', |
field = 'dps', |
||
damage_args = {'physical_damage', 'fire_damage', 'cold_damage', 'lightning_damage', 'chaos_damage'}, |
damage_args = {'physical_damage', 'fire_damage', 'cold_damage', 'lightning_damage', 'chaos_damage'}, |
Revision as of 01:07, 16 July 2021
This module depends on the following other modules: |
This submodule contains core configuration and functions for use in Module:Item2 and its other submodules.
The above documentation is transcluded from Module:Item2/core/doc.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
-------------------------------------------------------------------------------
--
-- Core confirguation and functions for Module:Item2 and submodules
--
-------------------------------------------------------------------------------
local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local m_game = mw.loadData('Module:Game')
-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Item2')
-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = use_sandbox and mw.loadData('Module:Item2/config/sandbox') or mw.loadData('Module:Item2/config')
local i18n = cfg.i18n
-- ----------------------------------------------------------------------------
-- Helper functions
-- ----------------------------------------------------------------------------
local h = {}
-- ----------------------------------------------------------------------------
-- Core
-- ----------------------------------------------------------------------------
local core = {}
core.factory = {}
function core.factory.infobox_line(args)
--[[
args
type How to read data from tpl_args using the given keys. nil = Regular, gem = Skill progression, stat = Stats
parts
[n]
key key to use. If type = gem and table is given, parse for subfield along path
hide Hide part if this function returns true
hide_key Alternate key to use to retrieve the value
hide_default hide the value if this is set
hide_default_key key to use if it isn't equal to the key parameter
-- from m_util.html.format_value --
func Function to transform the value retrieved from the database
fmt Format string (or function that returns format string) to use for the value. Default: '%s'
fmt_range Format string to use for the value range. Default: '(%s-%s)'
color poe_color code to use for the value range. False for no color. Default: 'mod'
class Additional css class added to color tag
inline Format string to use for the output
inline_color poe_color code to use for the output. False for no color. Default: 'default'
inline_class Additional css class added to inline color tag
sep If specified, parts are joined with this separator before being formatted for output
fmt Format string to use for output. If not specified, parts are simply concatenated
color poe_color code to use for output. Default: no color
class Additional css class added to output
--]]
args.parts = args.parts or {}
return function (tpl_args, frame)
local base_values = {}
local temp_values = {}
if args.type == 'gem' then
-- Skill progression. Look for keys in tpl_args.skill_levels
if not cfg.class_groups.gems.keys[tpl_args.class_id] then
-- Skip if this item is not actually a gem
return
end
for i, data in ipairs(args.parts) do
if data.key then
local path = type(data.key) == 'table' and data.key or {data.key}
-- Check for static value
local value = tpl_args.skill_levels[0]
for _, p in ipairs(path) do -- Parse for subfield along path
if value[p] == nil then
value = nil
break
else
value = value[p]
end
end
if value ~= nil then
base_values[i] = value
temp_values[#temp_values+1] = {value={min=value,max=value}, index=i}
else -- Check for leveled values
value = {
min = tpl_args.skill_levels[1],
max = tpl_args.skill_levels[tpl_args.max_level],
}
for k, _ in pairs(value) do
for _, p in ipairs(path) do -- Parse for subfield along path
if value[k][p] == nil then
value[k] = nil
break
else
value[k] = value[k][p]
end
end
end
if value.min ~= nil and value.max ~= nil then
base_values[i] = value.min
temp_values[#temp_values+1] = {value=value, index=i}
end
end
end
end
elseif args.type == 'stat' then
-- Stats. Look for key in tpl_args._stats
for i, data in ipairs(args.parts) do
local value = tpl_args._stats[data.key]
if value ~= nil then
base_values[i] = value.min
temp_values[#temp_values+1] = {value=value, index=i}
end
end
else
-- Regular. Look for key exactly as written in tpl_args
for i, data in ipairs(args.parts) do
base_values[i] = tpl_args[data.key]
local value = {}
if tpl_args[data.key .. '_range_minimum'] ~= nil then
value.min = tpl_args[data.key .. '_range_minimum']
value.max = tpl_args[data.key .. '_range_maximum']
elseif tpl_args[data.key] ~= nil then
value.min = tpl_args[data.key]
value.max = tpl_args[data.key]
end
if value.min == nil then
else
temp_values[#temp_values+1] = {value=value, index=i}
end
end
end
local final_values = {}
for i, data in ipairs(temp_values) do
local opt = args.parts[data.index]
local hide = false
if type(opt.hide) == 'function' then
local v = data.value
if opt.hide_key then
v = {
min = tpl_args[opt.hide_key .. '_range_minimum'],
max = tpl_args[opt.hide_key .. '_range_maximum'],
}
if v.min == nil or v.max == nil then
v = tpl_args[opt.hide_key]
end
end
hide = opt.hide(tpl_args, frame, v)
elseif opt.hide_default ~= nil then
if opt.hide_default_key then
local v = {
min = tpl_args[opt.hide_default_key .. '_range_minimum'],
max = tpl_args[opt.hide_default_key .. '_range_maximum'],
}
if v.min == nil or v.max == nil then
if opt.hide_default == tpl_args[opt.hide_default_key] then
hide = true
end
elseif opt.hide_default == v.min or opt.hide_default == v.max then
hide = true
end
else
local v = data.value
if opt.hide_default == v.min or opt.hide_default == v.max then
hide = true
end
end
end
if not hide then
table.insert(final_values, data)
end
end
-- all zeros = dont display and return early
if #final_values == 0 then
return nil
end
local parts = {}
for i, data in ipairs(final_values) do
local value = data.value
value.base = base_values[data.index]
local options = args.parts[data.index]
if args.type == 'gem' and options.color == nil then
-- Display skill progression range values as unmodified (white)
options.color = 'value'
end
parts[#parts+1] = m_util.html.format_value(tpl_args, frame, value, options)
end
if args.sep then
-- Join parts with separator before formatting
parts = {table.concat(parts, args.sep)}
end
-- Build output string
local out
if args.fmt then
out = string.format(args.fmt, unpack(parts))
else
out = table.concat(parts)
end
if args.color then
out = m_util.html.poe_color(args.color, out, args.class)
elseif args.class then
out = tostring(mw.html.create('em')
:attr('class', class)
:wikitext(out)
)
end
return out
end
end
function core.stats_update(tpl_args, id, value, modid, key)
if tpl_args[key][id] == nil then
tpl_args[key][id] = {
references = {modid},
min = value.min,
max = value.max,
avg = value.avg,
}
else
if modid ~= nil then
table.insert(tpl_args[key][id].references, modid)
end
tpl_args[key][id].min = tpl_args[key][id].min + value.min
tpl_args[key][id].max = tpl_args[key][id].max + value.max
tpl_args[key][id].avg = tpl_args[key][id].avg + value.avg
end
end
--
-- Functions for processing tpl_args
--
h.proc = {}
h.proc.factory = {}
function h.proc.factory.value(args)
args = args or {}
return function (tpl_args, frame, value)
if value == nil then
return nil
end
if args.cast then
value = args.cast(value)
end
if args.validate then
value = args.validate(value)
end
return value
end
end
function h.proc.factory.list(args)
args = args or {}
return function (tpl_args, frame, value)
return m_util.cast.table(value, {
pattern = args.pattern,
callback = args.callback,
})
end
end
function h.proc.factory.damage_html(args)
return function (tpl_args, frame, value)
local keys = {
min = args.type .. '_damage_min',
max = args.type .. '_damage_max',
}
local range = {}
for ktype, key in pairs(keys) do
range[ktype] = core.factory.infobox_line{
parts = {
{
key = key,
color = false,
hide_default = 0,
}
}
}(tpl_args, frame)
end
if range.min and range.max then
local color = args.type or false
local range_fmt
if tpl_args[keys.min .. '_range_minimum'] ~= tpl_args[keys.min .. '_range_maximum'] or tpl_args[keys.max .. '_range_minimum'] ~= tpl_args[keys.max .. '_range_maximum'] then
-- Variable damage range, based on modifier rolls
if args.type == 'physical' then
color = 'mod'
end
range_fmt = i18n.fmt.variable_damage_range
else
-- Standard damage range
if args.type == 'physical' then
color = 'value'
end
range_fmt = i18n.fmt.standard_damage_range
end
value = string.format(range_fmt, range.min, range.max)
if color then
value = m_util.html.poe_color(color, value)
end
end
return value
end
end
h.proc.text = h.proc.factory.value{cast = m_util.cast.text}
h.proc.boolean = h.proc.factory.value{cast = m_util.cast.boolean}
h.proc.number = h.proc.factory.value{cast = m_util.cast.number}
h.proc.percentage = h.proc.factory.value{
cast = m_util.cast.number,
validate = m_util.validate.factory.number_in_range{
min = 0,
max = 100,
},
}
h.proc.size = h.proc.factory.value{
cast = m_util.cast.number,
validate = m_util.validate.factory.number_in_range{
min = 1,
max = 4,
},
}
h.proc.list = h.proc.factory.list()
-- Process mod stats
function h.process_mod_stats(tpl_args, args)
local lines = {}
local skip = cfg.class_specifics[tpl_args.class_id]
if skip then
skip = skip.skip_stat_lines
end
local random_mods = {}
for _, modinfo in ipairs(tpl_args._mods) do
if modinfo.is_implicit == args.is_implicit then
if modinfo.is_random == true then
if random_mods[modinfo.stat_text] then
table.insert(random_mods[modinfo.stat_text], modinfo)
else
random_mods[modinfo.stat_text] = {modinfo}
end
else
if modinfo.id == nil then
table.insert(lines, modinfo.result)
-- Allows the override of the SMW fetched mod texts for this modifier via <modtype><id>_text parameter
elseif modinfo.text ~= nil then
table.insert(lines, modinfo.text)
else
for _, line in ipairs(m_util.string.split(modinfo.result['mods.stat_text'] or '', '<br>')) do
if line ~= '' then
if skip == nil then
table.insert(lines, line)
else
local skipped = false
for _, pattern in ipairs(skip) do
if string.match(line, pattern) then
skipped = true
break
end
end
if not skipped then
table.insert(lines, line)
end
end
end
end
end
end
end
end
for stat_text, modinfo_list in pairs(random_mods) do
local text = {}
for _, modinfo in ipairs(modinfo_list) do
table.insert(text, modinfo.result['mods.stat_text'])
end
local tbl = mw.html.create('table')
tbl
:attr('class', 'random-modifier-stats mw-collapsed')
:attr('style', 'text-align: left')
:tag('tr')
:tag('th')
:attr('class', 'mw-customtoggle-31')
:wikitext(stat_text)
:done()
:done()
:tag('tr')
:attr('class', 'mw-collapsible mw-collapsed')
:attr('id', 'mw-customcollapsible-31')
:tag('td')
:wikitext(table.concat(text, '<hr style="width: 20%">'))
:done()
:done()
table.insert(lines, tostring(tbl))
end
if #lines == 0 then
return
else
return table.concat(lines, '<br>')
end
end
--
-- Argument mapping
--
-- [<tpl_args key>] = {
-- inherit boolean Whether the item will inherit this key from its base item. Default: true
-- field string Cargo field name
-- type string Cargo field type
-- func function Function to unpack the argument into a native lua value and validate it
-- default varies Default value if parameter is not set
-- }
core.map = {
-- special params
html = {
inherit = false,
field = 'html',
type = 'Text',
func = nil,
},
html_extra = {
inherit = false,
field = 'html_extra',
type = 'Text',
func = nil,
},
implicit_stat_text = {
field = 'implicit_stat_text',
type = 'Text',
func = function (tpl_args, frame, value)
return h.process_mod_stats(tpl_args, {is_implicit=true})
end,
},
explicit_stat_text = {
field = 'explicit_stat_text',
type = 'Text',
func = function (tpl_args, frame, value)
local explicit = h.process_mod_stats(tpl_args, {is_implicit=false})
if tpl_args.is_talisman or tpl_args.is_corrupted then
explicit = explicit or ''
if explicit ~= '' then
explicit = explicit .. '<br> '
end
explicit = explicit .. i18n.tooltips.corrupted
end
return explicit
end,
},
stat_text = {
field = 'stat_text',
type = 'Text',
func = function (tpl_args, frame, value)
local sep = ''
if tpl_args.implicit_stat_text and tpl_args.explicit_stat_text then
sep = string.format('<span class="item-stat-separator -%s"></span>', tpl_args.frame_type)
end
local text = (tpl_args.implicit_stat_text or '') .. sep .. (tpl_args.explicit_stat_text or '')
if string.len(text) > 0 then
value = text
end
return value
end,
},
class_id = {
inherit = false,
field = 'class_id',
type = 'String',
func = h.proc.factory.value{
validate = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.item.classes,
errmsg = i18n.errors.invalid_class_id,
},
},
},
class = {
inherit = false,
field = 'class',
type = 'String',
func = function (tpl_args, frame, value)
local class = m_game.constants.item.classes[tpl_args.class_id]['long_upper']
-- Avoids errors with empty item class names later on
if class == '' then
class = nil
end
return class
end,
},
-- generic
rarity_id = {
inherit = false,
field = 'rarity_id',
type = 'String',
func = h.proc.factory.value{
validate = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.rarities,
errmsg = i18n.errors.invalid_rarity_id,
},
},
},
rarity = {
inherit = false,
field = 'rarity',
type = 'String',
func = function (tpl_args, frame, value)
return m_game.constants.rarities[tpl_args.rarity_id]['long_upper']
end,
},
name = {
inherit = false,
field = 'name',
type = 'String',
func = nil,
},
size_x = {
field = 'size_x',
type = 'Integer',
func = h.proc.size,
default = 1,
},
size_y = {
field = 'size_y',
type = 'Integer',
func = h.proc.size,
default = 1,
},
drop_rarities_ids = {
inherit = false,
field = 'drop_rarity_ids',
type = 'List (,) of Text',
func = function (tpl_args, frame, value)
tpl_args.drop_rarities_ids = nil
if true then return end
-- Drop rarities only matter for base items.
if tpl_args.rarity_id ~= 'normal' then
return
end
if tpl_args.drop_rarities_ids == nil then
tpl_args.drop_rarities_ids = {}
return
end
tpl_args.drop_rarities_ids = m_util.string.split(tpl_args.drop_rarities_ids, ',%s*')
for _, rarity_id in ipairs(tpl_args.drop_rarities_ids) do
if m_game.constants.rarities[rarity_id] == nil then
error(string.format(i18n.errors.invalid_rarity_id, tostring(rarity_id)))
end
end
end,
},
drop_rarities = {
inherit = false,
field = nil,
type = 'List (,) of Text',
func = function (tpl_args, frame, value)
tpl_args.drop_rarities = nil
if true then return end
-- Drop rarities only matter for base items.
if tpl_args.rarity_id ~= 'normal' then
return
end
local rarities = {}
for _, rarity_id in ipairs(tpl_args.drop_rarities_ids) do
rarities[#rarities+1] = m_game.constants.rarities[rarity_id].full
end
tpl_args.drop_rarities = rarities
end,
},
drop_enabled = {
inherit = false,
field = 'drop_enabled',
type = 'Boolean',
func = h.proc.boolean,
default = true,
},
drop_level = {
inherit = false,
field = 'drop_level',
type = 'Integer',
func = h.proc.number,
},
drop_level_maximum = {
inherit = false,
field = 'drop_level_maximum',
type = 'Integer',
func = h.proc.number,
},
drop_leagues = {
inherit = false,
field = 'drop_leagues',
type = 'List (,) of String',
func = h.proc.factory.list{
callback = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.leagues,
errmsg = i18n.errors.invalid_league,
errlvl = 4,
},
},
default = {},
},
drop_areas = {
inherit = false,
field = 'drop_areas',
type = 'List (,) of String',
func = function (tpl_args, frame, value)
value = m_util.cast.table(value)
if value then
tpl_args.drop_areas_data = m_cargo.array_query{
tables={'areas'},
fields={'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'},
id_field='areas.id',
id_array=value,
query={limit=5000},
}
end
-- find areas based on item tags for atlas bases
local query_data
for _, tag in ipairs(tpl_args.tags or {}) do
query_data = nil
if string.match(tag, '[%w_]*atlas[%w_]*') ~= nil and tag ~= 'atlas_base_type' then
query_data = m_cargo.query(
{'atlas_maps', 'maps', 'areas', 'atlas_base_item_types'},
{'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'},
{
join='atlas_maps._pageID=maps._pageID, maps.area_id=areas.id, atlas_maps.region_id=atlas_base_item_types.region_id',
where=string.format([[
atlas_base_item_types.tag = "%s"
AND atlas_base_item_types.weight > 0
AND (
atlas_maps.map_tier0 >= tier_min AND atlas_maps.map_tier0 <= atlas_base_item_types.tier_max
OR atlas_maps.map_tier1 >= tier_min AND atlas_maps.map_tier1 <= atlas_base_item_types.tier_max
OR atlas_maps.map_tier2 >= tier_min AND atlas_maps.map_tier2 <= atlas_base_item_types.tier_max
OR atlas_maps.map_tier3 >= tier_min AND atlas_maps.map_tier3 <= atlas_base_item_types.tier_max
OR atlas_maps.map_tier4 >= tier_min AND atlas_maps.map_tier4 <= atlas_base_item_types.tier_max
)]],
tag),
groupBy='areas.id',
}
)
end
if query_data ~= nil then
-- in case no manual drop areas have been set
if value == nil then
value = {}
tpl_args.drop_areas_data = {}
end
local drop_areas_assoc = {}
for _, id in ipairs(value) do
drop_areas_assoc[id] = true
end
local duplicates = {}
for _, row in ipairs(query_data) do
if drop_areas_assoc[row['areas.id']] == nil then
value[#value+1] = row['areas.id']
tpl_args.drop_areas_data[#tpl_args.drop_areas_data+1] = row
else
duplicates[#duplicates+1] = row['areas.id']
end
end
if #duplicates > 0 then
tpl_args._errors[#tpl_args._errors+1] = string.format(i18n.errors.duplicate_area_id_from_query, table.concat(duplicates, ', '))
tpl_args._flags.duplicate_query_area_ids = true
end
end
end
return value
end,
default = {},
},
drop_monsters = {
inherit = false,
field = 'drop_monsters',
type = 'List (,) of Text',
func = h.proc.list,
default = {},
},
drop_text = {
inherit = false,
field = 'drop_text',
type = 'Text',
func = h.proc.text,
},
required_level = {
field = 'required_level_base',
type = 'Integer',
func = h.proc.number,
default = 1,
},
required_level_final = {
field = 'required_level',
type = 'Integer',
func = function (tpl_args, frame, value)
value = tpl_args.required_level
if value < cfg.base_item_required_level_threshold then
value = 1
end
return value
end,
default = 1,
},
required_dexterity = {
field = 'required_dexterity',
type = 'Integer',
func = h.proc.number,
default = 0,
},
required_strength = {
field = 'required_strength',
type = 'Integer',
func = h.proc.number,
default = 0,
},
required_intelligence = {
field = 'required_intelligence',
type = 'Integer',
func = h.proc.number,
default = 0,
},
inventory_icon = {
inherit = false,
field = 'inventory_icon',
type = 'String',
func = function (tpl_args, frame, value)
if not value then
-- Certain types of items have default inventory icons
if i18n.default_inventory_icons[tpl_args.class_id] then
value = i18n.default_inventory_icons[tpl_args.class_id]
elseif tpl_args.base_item_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy' then
value = i18n.default_inventory_icons['Prophecy']
end
end
tpl_args.inventory_icon_id = value or tpl_args.name
return string.format(i18n.files.inventory_icon, tpl_args.inventory_icon_id)
end,
},
-- note: this must be called after inventory_icon to work correctly as it depends on tpl_args.inventory_icon_id being set
alternate_art_inventory_icons = {
inherit = false,
field = 'alternate_art_inventory_icons',
type = 'List (,) of String',
func = function (tpl_args, frame, value)
return m_util.cast.table(value, {
callback = function (value)
return string.format(i18n.files.inventory_icon, string.format('%s %s', tpl_args.inventory_icon_id, tostring(value)))
end,
})
end,
default = {},
},
cannot_be_traded_or_modified = {
inherit = false,
field = 'cannot_be_traded_or_modified',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
help_text = {
field = 'help_text',
type = 'Text',
func = h.proc.text,
},
flavour_text = {
inherit = false,
field = 'flavour_text',
type = 'Text',
func = h.proc.text,
},
flavour_text_id = {
inherit = false,
field = 'flavour_text_id',
type = 'String',
func = nil,
},
tags = {
field = 'tags',
type = 'List (,) of String',
func = h.proc.factory.list{
callback = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.tags,
errmsg = i18n.errors.invalid_tag,
errlvl = 4,
},
},
default = {},
},
metadata_id = {
inherit = false,
field = 'metadata_id',
type = 'String',
--type = 'String(unique; size=200)',
func = function (tpl_args, frame, value)
if value == nil then
return nil
end
-- Unless we're in testing mode, validate that metadata_id is unique
if not tpl_args.test then
local results = m_cargo.query(
{'items'},
{'items._pageName'},
{
where=string.format(
'items.metadata_id = "%s" AND items._pageName != "%s"',
value,
m_cargo.addslashes(mw.title.getCurrentTitle().fullText)
)
}
)
if #results > 0 then
error(string.format(i18n.errors.duplicate_metadata, value, results[1]['items._pageName']))
end
end
return value
end,
},
influences = {
inherit = false,
field = 'influences',
type = 'List (,) of String',
func = h.proc.factory.list{
callback = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.influences,
errmsg = i18n.errors.invalid_influence,
errlvl = 4,
},
},
default = {},
},
is_fractured = {
inherit = false,
field = 'is_fractured',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
is_synthesised = {
inherit = false,
field = 'is_synthesised',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
is_veiled = {
inherit = false,
field = 'is_veiled',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
is_replica = {
inherit = false,
field = 'is_replica',
type = 'Boolean',
func = function (tpl_args, frame, value)
value = m_util.cast.boolean(value)
if value == true and tpl_args.rarity_id ~= 'unique' then
error(string.format(i18n.errors.non_unique_flag, 'is_replica'))
end
return value
end,
default = false,
},
is_corrupted = {
inherit = false,
field = 'is_corrupted',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
is_relic = {
inherit = false,
field = 'is_relic',
type = 'Boolean',
func = function (tpl_args, frame, value)
value = m_util.cast.boolean(value)
if value == true and tpl_args.rarity_id ~= 'unique' then
error(string.format(i18n.errors.non_unique_flag, 'is_relic'))
end
return value
end,
default = false,
},
is_fated = {
inherit = false,
field = 'is_fated',
type = 'Boolean',
func = function (tpl_args, frame, value)
value = m_util.cast.boolean(value)
if value == true and tpl_args.rarity_id ~= 'unique' then
error(string.format(i18n.errors.non_unique_flag, 'is_fated'))
end
return value
end,
default = false,
},
is_prophecy = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, frame, value)
tpl_args._flags.is_prophecy = (tpl_args.metadata_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy' or tpl_args.base_item == cfg.prophecy_base_item or tpl_args.base_item_page == cfg.prophecy_base_item_page or tpl_args.base_item_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy')
return value
end
},
is_blight_item = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, frame, value)
tpl_args._flags.is_blight_item = (tpl_args.blight_item_tier ~= nil)
return value
end
},
is_drop_restricted = {
inherit = false,
field = 'is_drop_restricted',
type = 'Boolean',
func = h.proc.boolean,
default = function (tpl_args, frame)
-- Generally items that are obtained only from specific monsters can't be obtained via cards or other means unless specifically specified
for _, key in ipairs({'is_talisman', 'is_essence', 'is_fated', 'is_replica', 'is_relic', 'drop_monsters'}) do
-- key must be truthy and NOT an empty table
if tpl_args[key] and not (type(tpl_args[key]) == 'table' and #tpl_args[key] == 0) then
return true
end
end
for _, flag in ipairs({'is_prophecy', 'is_blight_item'}) do
if tpl_args._flags[flag] then
return true
end
end
return false
end,
},
purchase_costs = {
field = nil,
type = nil,
func = function (tpl_args, frame, value)
local purchase_costs = {}
for _, rarity_id in ipairs(m_game.constants.rarity_order) do
local rtbl = {}
local prefix = string.format('purchase_cost_%s', rarity_id)
local i = 1
while i ~= -1 do
local iprefix = prefix .. i
local values = {
name = tpl_args[iprefix .. '_name'],
amount = tonumber(tpl_args[iprefix .. '_amount']),
rarity = rarity_id,
}
if values.name ~= nil and values.amount ~= nil then
rtbl[#rtbl+1] = values
i = i + 1
tpl_args._subobjects[#tpl_args._subobjects+1] = {
_table = 'item_purchase_costs',
amount = values.amount,
name = values.name,
rarity = values.rarity,
}
else
i = -1
end
end
purchase_costs[rarity_id] = rtbl
end
return purchase_costs
end,
func_fetch = function (tpl_args, frame)
if tpl_args.rarity_id ~= 'unique' then
return
end
local results = m_cargo.query(
{'items' ,'item_purchase_costs'},
{'item_purchase_costs.amount', 'item_purchase_costs.name', 'item_purchase_costs.rarity'},
{
join = 'items._pageID=item_purchase_costs._pageID',
where = string.format('items._pageName="%s" AND item_purchase_costs.rarity="unique"', tpl_args.base_item_page),
}
)
for _, row in ipairs(results) do
local values = {
rarity = row['item_purchase_costs.rarity'],
name = row['item_purchase_costs.name'],
amount = tonumber(row['item_purchase_costs.amount']),
}
local datavar = tpl_args.purchase_costs[string.lower(values.rarity)]
datavar[#datavar+1] = values
tpl_args._subobjects[#tpl_args._subobjects+1] = {
_table = 'item_purchase_costs',
amount = values.amount,
name = values.name,
rarity = values.rarity,
}
end
end,
},
is_sellable = {
inherit = false,
field = nil,
type = nil,
func = h.proc.boolean,
default = true,
},
sell_prices_override = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, frame, value)
-- these variables are also used by mods when setting automatic sell prices
tpl_args.sell_prices = {}
tpl_args.sell_price_order = {}
if not tpl_args.is_sellable then
return nil
end
local name
local amount
local i = 0
repeat
i = i + 1
name = tpl_args[string.format('sell_price%s_name', i)]
amount = tpl_args[string.format('sell_price%s_amount', i)]
if name ~= nil and amount ~= nil then
tpl_args.sell_price_order[#tpl_args.sell_price_order+1] = name
tpl_args.sell_prices[name] = amount
tpl_args._subobjects[#tpl_args._subobjects+1] = {
_table = 'item_sell_prices',
amount = amount,
name = name,
}
end
until name == nil or amount == nil
-- if sell prices are set, the override is active
for _, _ in pairs(tpl_args.sell_prices) do
tpl_args._flags.sell_prices_override = true
break
end
return value
end,
},
--
-- specific section
--
-- Most item classes
quality = {
inherit = false,
field = 'quality',
type = 'Integer',
-- Can be set manually, but default to Q20 for unique weapons/body armours
-- Also must copy to stat for the stat adjustments to work properly
func = function (tpl_args, frame, value)
local quality = tonumber(value)
if quality == nil then
if tpl_args.rarity_id ~= 'unique' then
quality = 0
elseif cfg.class_groups.weapons.keys[tpl_args.class_id] or cfg.class_groups.armor.keys[tpl_args.class_id] then
quality = 20
else
quality = 0
end
end
local stat = {
min = quality,
max = quality,
avg = quality,
}
core.stats_update(tpl_args, 'quality', stat, nil, '_stats')
if tpl_args.class_id == 'UtilityFlask' or tpl_args.class_id == 'UtilityFlaskCritical' then
core.stats_update(tpl_args, 'quality_flask_duration', stat, nil, '_stats')
-- quality is added to quantity for maps
elseif tpl_args.class_id == 'Map' then
core.stats_update(tpl_args, 'map_item_drop_quantity_+%', stat, nil, '_stats')
end
return quality
end,
},
-- amulets
is_talisman = {
field = 'is_talisman',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
talisman_tier = {
field = 'talisman_tier',
type = 'Integer',
func = h.proc.number,
},
-- flasks
charges_max = {
field = 'charges_max',
type = 'Integer',
func = h.proc.number,
},
charges_per_use = {
field = 'charges_per_use',
type = 'Integer',
func = h.proc.number,
},
flask_mana = {
field = 'mana',
type = 'Integer',
func = h.proc.number,
},
flask_life = {
field = 'life',
type = 'Integer',
func = h.proc.number,
},
flask_duration = {
field = 'duration',
type = 'Float',
func = h.proc.number,
},
buff_id = {
field = 'id',
type = 'String',
func = nil,
},
buff_values = {
field = 'buff_values',
type = 'List (,) of Integer',
func = function (tpl_args, frame, value)
local values = {}
local i = 0
repeat
i = i + 1
local key = 'buff_value' .. i
values[i] = tonumber(tpl_args[key])
tpl_args[key] = nil
until values[i] == nil
-- needed so the values copyied from unique item base isn't overriden
if #values >= 1 then
value = values
end
return value
end,
func_copy = function (tpl_args, frame, value)
tpl_args.buff_values = m_util.string.split(value, ',%s*')
end,
default = {},
},
buff_stat_text = {
field = 'stat_text',
type = 'String',
func = nil,
},
buff_icon = {
field = 'icon',
type = 'String',
func = function (tpl_args, frame, value)
return string.format(i18n.files.status_icon, tpl_args.name)
end,
},
-- weapons
critical_strike_chance = {
field = 'critical_strike_chance',
type = 'Float',
func = h.proc.number,
},
attack_speed = {
field = 'attack_speed',
type = 'Float',
func = h.proc.number,
},
weapon_range = {
field = 'weapon_range',
type = 'Integer',
func = h.proc.number,
},
physical_damage_min = {
field = 'physical_damage_min',
type = 'Integer',
func = h.proc.number,
},
physical_damage_max = {
field = 'physical_damage_max',
type = 'Integer',
func = h.proc.number,
},
fire_damage_min = {
field = 'fire_damage_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
fire_damage_max = {
field = 'fire_damage_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
cold_damage_min = {
field = 'cold_damage_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
cold_damage_max = {
field = 'cold_damage_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
lightning_damage_min = {
field = 'lightning_damage_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
lightning_damage_max = {
field = 'lightning_damage_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
chaos_damage_min = {
field = 'chaos_damage_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
chaos_damage_max = {
field = 'chaos_damage_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
-- armor-type stuff
armour = {
field = 'armour',
type = 'Integer',
func = h.proc.number,
default = 0,
},
energy_shield = {
field = 'energy_shield',
type = 'Integer',
func = h.proc.number,
default = 0,
},
evasion = {
field = 'evasion',
type = 'Integer',
func = h.proc.number,
default = 0,
},
ward = {
field = 'ward',
type = 'Integer',
func = h.proc.number,
default = 0,
},
-- This is the inherent penality from the armour piece if any
movement_speed = {
field = 'movement_speed',
type = 'Integer',
func = h.proc.number,
default = 0,
},
-- shields
block = {
field = 'block',
type = 'Integer',
func = h.proc.number,
},
-- skill gem stuff
gem_description = {
field = 'gem_description',
type = 'Text',
func = h.proc.text,
},
dexterity_percent = {
field = 'dexterity_percent',
type = 'Integer',
func = h.proc.percentage,
},
strength_percent = {
field = 'strength_percent',
type = 'Integer',
func = h.proc.percentage,
},
intelligence_percent = {
field = 'intelligence_percent',
type = 'Integer',
func = h.proc.percentage,
},
primary_attribute = {
field = 'primary_attribute',
type = 'String',
func = function (tpl_args, frame, value)
for _, attr in ipairs(m_game.constants.attribute_order) do
local val = tpl_args[attr .. '_percent']
if val and val >= 60 then
return attr
end
end
return 'none'
end,
},
gem_tags = {
field = 'gem_tags',
type = 'List (,) of String',
func = h.proc.factory.list{
callback = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.item.gem_tags_lookup,
errmsg = i18n.errors.invalid_gem_tag,
errlvl = 4,
},
},
default = {},
},
-- Support gems only
support_gem_letter = {
field = 'support_gem_letter',
type = 'String(size=1)',
func = nil,
},
support_gem_letter_html = {
field = 'support_gem_letter_html',
type = 'Text',
func = function (tpl_args, frame, value)
if tpl_args.support_gem_letter == nil then
return nil
end
for k, v in pairs(m_game.constants.attributes) do
local key = string.format('%s_percent', k)
if tpl_args[key] and tpl_args[key] > 50 then
value = tostring(
mw.html.create('span')
:attr('class', string.format('support-gem-id-%s', v.color))
:wikitext(tpl_args.support_gem_letter)
)
break
end
end
return value
end,
},
--
-- Maps
--
map_tier = {
field = 'tier',
type = 'Integer',
func = h.proc.number,
},
map_guild_character = {
field = 'guild_character',
type = 'String(size=1)',
func = nil,
},
map_area_id = {
field = 'area_id',
type = 'String',
func = nil, -- TODO: Validate against a query?
},
map_area_level = {
field = 'area_level',
type = 'Integer',
func = h.proc.number,
},
unique_map_guild_character = {
field = 'unique_guild_character',
type = 'String(size=1)',
func = nil,
func_copy = function (tpl_args, frame, value)
tpl_args.map_guild_character = value
end,
},
unique_map_area_id = {
field = 'unique_area_id',
type = 'String',
func = nil, -- TODO: Validate against a query?
func_copy = function (tpl_args, frame, value)
tpl_args.map_area_id = value
end,
},
unique_map_area_level = {
field = 'unique_area_level',
type = 'Integer',
func = h.proc.number,
func_copy = function (tpl_args, frame, value)
tpl_args.map_area_level = value
end,
},
map_series = {
field = 'series',
type = 'String',
func = function (tpl_args, frame, value)
if tpl_args.rarity == 'normal' and value == nil then
error(string.format(i18n.errors.generic_required_parameter, 'map_series'))
end
return value
end,
},
-- atlas info is only for the current map series
atlas_x = {
field = 'x',
type = 'Float',
func = h.proc.number,
},
atlas_y = {
field = 'y',
type = 'Float',
func = h.proc.number,
},
atlas_region_id = {
field = 'region_id',
type = 'String',
func = nil,
},
atlas_region_minimum = {
field = 'region_minimum',
type = 'Integer',
func = h.proc.number,
},
atlas_x0 = {
field = 'x0',
type = 'Float',
func = h.proc.number,
},
atlas_x1 = {
field = 'x1',
type = 'Float',
func = h.proc.number,
},
atlas_x2 = {
field = 'x2',
type = 'Float',
func = h.proc.number,
},
atlas_x3 = {
field = 'x3',
type = 'Float',
func = h.proc.number,
},
atlas_x4 = {
field = 'x4',
type = 'Float',
func = h.proc.number,
},
atlas_y0 = {
field = 'y0',
type = 'Float',
func = h.proc.number,
},
atlas_y1 = {
field = 'y1',
type = 'Float',
func = h.proc.number,
},
atlas_y2 = {
field = 'y2',
type = 'Float',
func = h.proc.number,
},
atlas_y3 = {
field = 'y3',
type = 'Float',
func = h.proc.number,
},
atlas_y4 = {
field = 'y4',
type = 'Float',
func = h.proc.number,
},
atlas_map_tier0 = {
field = 'map_tier0',
type = 'Integer',
func = h.proc.number,
},
atlas_map_tier1 = {
field = 'map_tier1',
type = 'Integer',
func = h.proc.number,
},
atlas_map_tier2 = {
field = 'map_tier2',
type = 'Integer',
func = h.proc.number,
},
atlas_map_tier3 = {
field = 'map_tier3',
type = 'Integer',
func = h.proc.number,
},
atlas_map_tier4 = {
field = 'map_tier4',
type = 'Integer',
func = h.proc.number,
},
atlas_connections = {
field = nil,
type = nil,
func = function (tpl_args, frame, value)
value = {}
local cont = true
local i = 1
while cont do
local prefix = string.format('atlas_connection%s_', i)
local regions = tpl_args[prefix .. 'tier']
local data = {
_table = 'atlas_connections',
map1 = string.format('%s (%s)', tpl_args.name, tpl_args.map_series or ''),
map2 = tpl_args[prefix .. 'target'],
}
if regions and data.map2 then
regions = m_util.string.split(regions, ',%s*')
if #regions ~= 5 then
error(string.format(i18n.errors.invalid_region_upgrade_count, i, #regions))
end
for index, value in ipairs(regions) do
data['region' .. (index - 1)] = m_util.cast.boolean(value)
end
value[data.map2] = data
table.insert(tpl_args._subobjects, data)
else
cont = false
if i == 1 then
value = nil
end
end
i = i + 1
end
return value
end,
},
--
-- Currency-like items
--
stack_size = {
field = 'stack_size',
type = 'Integer',
func = h.proc.number,
},
stack_size_currency_tab = {
field = 'stack_size_currency_tab',
type = 'Integer',
func = h.proc.number,
},
description = {
field = 'description',
type = 'Text',
func = h.proc.text,
},
cosmetic_type = {
field = 'cosmetic_type',
type = 'String',
func = h.proc.factory.value{
validate = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.item.cosmetic_item_types,
errmsg = i18n.errors.invalid_cosmetic_type,
},
},
},
-- for essences
is_essence = {
field = nil,
type = nil,
func = h.proc.boolean,
default = false,
},
essence_level_restriction = {
field = 'level_restriction',
type = 'Integer',
func = h.proc.number,
},
essence_level = {
field = 'level',
type = 'Integer',
func = h.proc.number,
},
essence_type = {
field = 'type',
type = 'Integer',
func = h.proc.number,
},
essence_category = {
field = 'category',
type = 'String',
func = nil,
},
-- blight crafting items (i.e. oils)
blight_item_tier = {
field = 'tier',
type = 'Integer',
func = h.proc.number,
},
-- harvest seeds
seed_type_id = {
field = 'type_id',
type = 'String',
func = nil,
},
seed_type = {
field = 'type',
type = 'String',
func = function (tpl_args, frame, value)
if tpl_args.seed_type_id ~= 'none' or tpl_args.seed_type_id ~= nil then
value = m_game.seed_types[tpl_args.seed_type_id]
end
return value
end
},
seed_type_html = {
field = nil,
type = nil,
func = function (tpl_args, frame, value)
if tpl_args.seed_type ~= nil then
value = m_util.html.poe_color(tpl_args.seed_type_id, tpl_args.seed_type)
end
return value
end
},
seed_effect = {
field = 'effect',
type = 'Text',
func = nil,
},
seed_tier = {
field = 'tier',
type = 'Integer',
func = h.proc.number,
},
seed_growth_cycles = {
field = 'growth_cycles',
type = 'Integer',
func = h.proc.number,
},
seed_required_nearby_seed_tier = {
field = 'required_nearby_seed_tier',
type = 'Integer',
func = h.proc.number,
},
seed_required_nearby_seed_amount = {
field = 'required_nearby_seed_amount',
type = 'Integer',
func = h.proc.number,
},
seed_consumed_wild_lifeforce_percentage = {
field = 'consumed_wild_lifeforce_percentage',
type = 'Integer',
func = h.proc.number,
default = 0,
},
seed_consumed_vivid_lifeforce_percentage = {
field = 'consumed_vivid_lifeforce_percentage',
type = 'Integer',
func = h.proc.number,
default = 0,
},
seed_consumed_primal_lifeforce_percentage = {
field = 'consumed_primal_lifeforce_percentage',
type = 'Integer',
func = h.proc.number,
default = 0,
},
seed_granted_craft_option_ids = {
field = 'granted_craft_option_ids',
type = 'List (,) of String',
func = h.proc.list,
default = {},
},
--
-- harvest planet boosters
--
plant_booster_radius = {
field = 'radius',
type = 'Integer',
func = h.proc.number,
},
plant_booster_lifeforce = {
field = 'lifeforce',
type = 'Integer',
func = h.proc.number,
},
plant_booster_additional_crafting_options = {
field = 'additional_crafting_options',
type = 'Integer',
func = h.proc.number,
},
plant_booster_extra_chances = {
field = 'extra_chances',
type = 'Integer',
func = h.proc.number,
},
--
-- Heist properties
--
heist_required_job_id = {
field = 'required_job_id',
type = 'String',
func = h.proc.text,
},
heist_required_job_level = {
field = 'required_job_level',
type = 'Integer',
func = h.proc.number,
},
heist_data = {
field = nil,
type = nil,
func = function (tpl_args, frame, value)
if tpl_args.heist_required_job_level then
if tpl_args.heist_required_job_id then
local results = m_cargo.query(
{'heist_jobs', 'heist_npcs', 'heist_npc_skills'},
{'heist_npcs.name', 'heist_jobs.name'},
{
join = 'heist_npc_skills.job_id=heist_jobs.id, heist_npc_skills.npc_id=heist_npcs.id',
where = string.format('heist_npc_skills.job_id = "%s" AND heist_npc_skills.level >= %s', tpl_args.heist_required_job_id, tpl_args.heist_required_job_level),
}
)
local npcs = {}
for _, row in ipairs(results) do
npcs[#npcs+1] = row['heist_npcs.name']
end
tpl_args.heist_required_npcs = table.concat(npcs, ', ')
tpl_args.heist_required_job = results[1]['heist_jobs.name']
else
tpl_args.heist_required_job = i18n.tooltips.heist_any_job
end
end
return value
end,
},
--
-- hideout doodads (HideoutDoodads.dat)
--
is_master_doodad = {
field = 'is_master_doodad',
type = 'Boolean',
func = h.proc.boolean,
},
master = {
field = 'master',
type = 'String',
func = h.proc.factory.value{
validate = m_util.validate.factory.in_table_keys{
tbl = m_util.table.column(m_game.constants.masters, 'long_upper', 'full'),
errmsg = i18n.errors.invalid_master,
},
},
},
master_level_requirement = {
field = 'level_requirement',
type = 'Integer',
func = h.proc.number,
},
master_favour_cost = {
field = 'favour_cost',
type = 'Integer',
func = h.proc.number,
},
variation_count = {
field = 'variation_count',
type = 'Integer',
func = h.proc.number,
},
-- Propehcy
prophecy_id = {
field = 'prophecy_id',
type = 'String',
func = nil,
},
prediction_text = {
field = 'prediction_text',
type = 'Text',
func = h.proc.text,
},
seal_cost = {
field = 'seal_cost',
type = 'Integer',
func = h.proc.number,
},
prophecy_reward = {
field = 'reward',
type = 'Text',
func = h.proc.text,
},
prophecy_objective = {
field = 'objective',
type = 'Text',
func = h.proc.text,
},
-- Divination cards
card_art = {
field = 'card_art',
type = 'Page',
func = function (tpl_args, frame, value)
return string.format(i18n.files.divination_card_art, value or tpl_args.name)
end,
},
-- ------------------------------------------------------------------------
-- derived stats
-- ------------------------------------------------------------------------
-- For rarity != normal, rarity already verified
base_item = {
inherit = false,
field = 'base_item',
type = 'String',
func = function (tpl_args, frame, value)
return tpl_args.base_item_data['items.name']
end,
},
base_item_id = {
inherit = false,
field = 'base_item_id',
type = 'String',
func = function (tpl_args, frame, value)
return tpl_args.base_item_data['items.metadata_id']
end,
},
base_item_page = {
inherit = false,
field = 'base_item_page',
type = 'Page',
func = function (tpl_args, frame, value)
return tpl_args.base_item_data['items._pageName']
end,
},
name_list = {
inherit = false,
field = 'name_list',
type = 'List (�) of String',
func = function (tpl_args, frame, value)
value = m_util.cast.table(value)
value[#value+1] = tpl_args.name
return value
end,
default = {},
},
frame_type = {
inherit = false,
field = 'frame_type',
type = 'String',
func = function (tpl_args, frame, value)
if value then
return value
end
if tpl_args._flags.is_prophecy then
return 'prophecy'
end
local var = cfg.class_specifics[tpl_args.class_id]
if var ~= nil and var.frame_type ~= nil then
return var.frame_type
end
if tpl_args.is_relic then
return 'relic'
end
return tpl_args.rarity_id
end,
},
--
-- args populated by mod validation
--
mods = {
field = nil,
type = nil,
func = nil,
default = {},
func_fetch = function (tpl_args, frame)
-- Fetch implicit mods from base item
local results = m_cargo.query(
{'items' ,'item_mods'},
{'item_mods.id', 'item_mods.is_implicit', 'item_mods.is_random', 'item_mods.text'},
{
join = 'items._pageID=item_mods._pageID',
where = string.format('items._pageName="%s" AND item_mods.is_implicit=1', tpl_args.base_item_page),
}
)
for _, row in ipairs(results) do
-- Handle text-only mods
local result
if row['item_mods.id'] == nil then
result = row['item_mods.text']
end
tpl_args._base_implicit_mods[#tpl_args._base_implicit_mods+1] = {
result=result,
id=row['item_mods.id'],
stat_text=row['item_mods.text'],
is_implicit=m_util.cast.boolean(row['item_mods.is_implicit']),
is_random=m_util.cast.boolean(row['item_mods.is_random']),
}
end
end,
},
physical_damage_html = {
inherit = false,
field = 'physical_damage_html',
type = 'Text',
func = h.proc.factory.damage_html{type = 'physical'},
},
fire_damage_html = {
inherit = false,
field = 'fire_damage_html',
type = 'Text',
func = h.proc.factory.damage_html{type = 'fire'},
},
cold_damage_html = {
inherit = false,
field = 'cold_damage_html',
type = 'Text',
func = h.proc.factory.damage_html{type = 'cold'},
},
lightning_damage_html = {
inherit = false,
field = 'lightning_damage_html',
type = 'Text',
func = h.proc.factory.damage_html{type = 'lightning'},
},
chaos_damage_html = {
inherit = false,
field = 'chaos_damage_html',
type = 'Text',
func = h.proc.factory.damage_html{type = 'chaos'},
},
damage_avg = {
inherit = false,
field = 'damage_avg',
type = 'Text',
func = function (tpl_args, frame, value)
local dmg = {min=0, max=0}
for key, _ in pairs(dmg) do
for _, dkey in ipairs(m_game.constants.damage_type_order) do
dmg[key] = dmg[key] + tpl_args[string.format('%s_damage_%s_range_average', dkey, key)]
end
end
dmg = (dmg.min + dmg.max) / 2
return dmg
end,
},
damage_html = {
inherit = false,
field = 'damage_html',
type = 'Text',
func = function (tpl_args, frame, value)
local text = {}
for _, dkey in ipairs(m_game.constants.damage_type_order) do
local range = tpl_args[dkey .. '_damage_html']
if range ~= nil then
text[#text+1] = range
end
end
if #text > 0 then
value = table.concat(text, '<br>')
end
return value
end,
},
item_limit = {
inherit = false,
field = 'item_limit',
type = 'Integer',
func = h.proc.number,
},
jewel_radius_html = {
inherit = false,
field = 'radius_html',
type = 'Text',
func = function (tpl_args, frame, value)
-- Get radius from stats
local radius = tpl_args._stats.local_jewel_effect_base_radius
if radius then
radius = radius.min
local size = m_game.constants.item.jewel_radius_to_size[radius] or radius
local color = radius == 0 and 'mod' or 'value'
value = m_util.html.poe_color(color, size)
end
return value
end,
},
incubator_effect = {
inherit = false,
field = 'effect',
type = 'Text',
func = nil,
},
drop_areas_html = {
inherit = false,
field = 'drop_areas_html',
type = 'Text',
func = function (tpl_args, frame, value)
if tpl_args.drop_areas_data == nil then
return value
end
if value ~= nil then
return value
end
local areas = {}
for _, data in pairs(tpl_args.drop_areas_data) do
-- skip legacy maps in the drop html listing
if not string.match(data['areas.id'], '^Map.*') or string.match(data['areas.id'], '^MapWorlds.*') or string.match(data['areas.id'], '^MapAtziri.*') then
areas[#areas+1] = string.format('[[%s|%s]]', data['areas.main_page'] or data['areas._pageName'], data['areas.main_page'] or data['areas.name'])
end
end
return table.concat(areas, ' • ')
end,
},
release_version = {
inherit = false,
field = 'release_version',
type = 'String',
func = nil,
},
removal_version = {
inherit = false,
field = 'removal_version',
type = 'String',
func = nil,
},
--
-- args governing use of the template itself
--
suppress_improper_modifiers_category = {
inherit = false,
field = nil,
func = h.proc.boolean,
default = false,
},
upgraded_from_disabled = {
inherit = false,
field = nil,
func = h.proc.boolean,
default = false,
},
}
core.stat_map = {
required_level_final = {
field = 'required_level',
stats_add = {
'local_level_requirement_+',
},
stats_override = {
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=1, max=1},
},
minimum = 1,
html_fmt_options = {
fmt = '%i',
},
},
weapon_range = {
field = 'weapon_range',
stats_add = {
'local_weapon_range_+',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
physical_damage_min = {
field = 'physical_damage_min',
stats_add = {
'local_minimum_added_physical_damage',
},
stats_increased = {
'local_physical_damage_+%',
'quality',
},
stats_override = {
['local_weapon_no_physical_damage'] = {min=0, max=0},
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
physical_damage_max = {
field = 'physical_damage_max',
stats_add = {
'local_maximum_added_physical_damage',
},
stats_increased = {
'local_physical_damage_+%',
'quality',
},
stats_override = {
['local_weapon_no_physical_damage'] = {min=0, max=0},
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
fire_damage_min = {
field = 'fire_damage_min',
stats_add = {
'local_minimum_added_fire_damage',
},
minimum = 0,
html_fmt_options = {
color = 'fire',
fmt = '%i',
},
},
fire_damage_max = {
field = 'fire_damage_max',
stats_add = {
'local_maximum_added_fire_damage',
},
minimum = 0,
html_fmt_options = {
color = 'fire',
fmt = '%i',
},
},
cold_damage_min = {
field = 'cold_damage_min',
stats_add = {
'local_minimum_added_cold_damage',
},
minimum = 0,
html_fmt_options = {
color = 'cold',
fmt = '%i',
},
},
cold_damage_max = {
field = 'cold_damage_max',
stats_add = {
'local_maximum_added_cold_damage',
},
minimum = 0,
html_fmt_options = {
color = 'cold',
fmt = '%i',
},
},
lightning_damage_min = {
field = 'lightning_damage_min',
stats_add = {
'local_minimum_added_lightning_damage',
},
minimum = 0,
html_fmt_options = {
color = 'lightning',
fmt = '%i',
},
},
lightning_damage_max = {
field = 'lightning_damage_max',
stats_add = {
'local_maximum_added_lightning_damage',
},
minimum = 0,
html_fmt_options = {
color = 'lightning',
fmt = '%i',
},
},
chaos_damage_min = {
field = 'chaos_damage_min',
stats_add = {
'local_minimum_added_chaos_damage',
},
minimum = 0,
html_fmt_options = {
color = 'chaos',
fmt = '%i',
},
},
chaos_damage_max = {
field = 'chaos_damage_max',
stats_add = {
'local_maximum_added_chaos_damage',
},
minimum = 0,
html_fmt_options = {
color = 'chaos',
fmt = '%i',
},
},
critical_strike_chance = {
field = 'critical_strike_chance',
stats_add = {
'local_critical_strike_chance',
},
stats_increased = {
'local_critical_strike_chance_+%',
},
stats_override = {
['local_weapon_always_crit'] = {min=100, max=100},
},
minimum = 0,
html_fmt_options = {
fmt = '%.2f%%',
},
},
attack_speed = {
field = 'attack_speed',
stats_increased = {
'local_attack_speed_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%.2f',
},
},
flask_life = {
field = 'life',
stats_add = {
'local_flask_life_to_recover',
},
stats_increased = {
'local_flask_life_to_recover_+%',
'local_flask_amount_to_recover_+%',
'quality',
},
html_fmt_options = {
fmt = '%i',
},
},
flask_mana = {
field = 'mana',
stats_add = {
'local_flask_mana_to_recover',
},
stats_increased = {
'local_flask_mana_to_recover_+%',
'local_flask_amount_to_recover_+%',
'quality',
},
},
flask_duration = {
field = 'duration',
stats_increased = {
'local_flask_duration_+%',
-- regular quality isn't used here because it doesn't increase duration of life/mana/hybrid flasks
'quality_flask_duration',
},
stats_increased_inverse = {
'local_flask_recovery_speed_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%.2f',
},
},
charges_per_use = {
field = 'charges_per_use',
stats_increased = {
'local_charges_used_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
charges_max = {
field = 'charges_max',
stats_add = {
'local_extra_max_charges',
},
stats_increased = {
'local_max_charges_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
block = {
field = 'block',
stats_add = {
'local_additional_block_chance_%',
},
minimum = 0,
html_fmt_options = {
fmt = '%i%%',
},
},
armour = {
field = 'armour',
stats_add = {
'local_base_physical_damage_reduction_rating',
},
stats_increased = {
'local_physical_damage_reduction_rating_+%',
'local_armour_and_energy_shield_+%',
'local_armour_and_evasion_+%',
'local_armour_and_evasion_and_energy_shield_+%',
'quality',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
evasion = {
field = 'evasion',
stats_add = {
'local_base_evasion_rating',
'local_evasion_rating_and_energy_shield',
},
stats_increased = {
'local_evasion_rating_+%',
'local_evasion_and_energy_shield_+%',
'local_armour_and_evasion_+%',
'local_armour_and_evasion_and_energy_shield_+%',
'quality',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
energy_shield = {
field = 'energy_shield',
stats_add = {
'local_energy_shield',
'local_evasion_rating_and_energy_shield',
},
stats_increased = {
'local_energy_shield_+%',
'local_armour_and_energy_shield_+%',
'local_evasion_and_energy_shield_+%',
'local_armour_and_evasion_and_energy_shield_+%',
'quality',
},
stats_override = {
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
ward = {
field = 'ward',
stats_add = {
'local_ward',
},
stats_increased = {
'local_ward_+%',
'quality',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
required_dexterity = {
field = 'required_dexterity',
stats_add = {
'local_dexterity_requirement_+'
},
stats_increased = {
'local_dexterity_requirement_+%',
'local_attribute_requirements_+%',
},
stats_override = {
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
['local_no_attribute_requirements'] = {min=0, max=0},
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
required_intelligence = {
field = 'required_intelligence',
stats_add = {
'local_intelligence_requirement_+'
},
stats_increased = {
'local_intelligence_requirement_+%',
'local_attribute_requirements_+%',
},
stats_override = {
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
['local_no_attribute_requirements'] = {min=0, max=0},
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
required_strength = {
field = 'required_strength',
stats_add = {
'local_strength_requirement_+'
},
stats_increased = {
'local_strength_requirement_+%',
'local_attribute_requirements_+%',
},
stats_override = {
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
['local_no_attribute_requirements'] = {min=0, max=0},
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
map_area_level = {
field = 'map_area_level',
stats_override = {
['map_item_level_override'] = true,
},
},
}
core.dps_map = {
physical_dps = {
field = 'physical_dps',
damage_args = {'physical_damage'},
label_infobox = i18n.tooltips.physical_dps,
html_fmt_options = {
color = 'value',
fmt = '%.1f',
},
},
fire_dps = {
field = 'fire_dps',
damage_args = {'fire_damage'},
label_infobox = i18n.tooltips.fire_dps,
html_fmt_options = {
color = 'fire',
fmt = '%.1f',
},
},
cold_dps = {
field = 'cold_dps',
damage_args = {'cold_damage'},
label_infobox = i18n.tooltips.cold_dps,
html_fmt_options = {
color = 'cold',
fmt = '%.1f',
},
},
lightning_dps = {
field = 'lightning_dps',
damage_args = {'lightning_damage'},
label_infobox = i18n.tooltips.lightning_dps,
html_fmt_options = {
color = 'lightning',
fmt = '%.1f',
},
},
chaos_dps = {
field = 'chaos_dps',
damage_args = {'chaos_damage'},
label_infobox = i18n.tooltips.chaos_dps,
html_fmt_options = {
color = 'chaos',
fmt = '%.1f',
},
},
elemental_dps = {
field = 'elemental_dps',
damage_args = {'fire_damage', 'cold_damage', 'lightning_damage'},
label_infobox = i18n.tooltips.elemental_dps,
html_fmt_options = {
color = 'value',
fmt = '%.1f',
},
},
poison_dps = {
field = 'poison_dps',
damage_args = {'physical_damage', 'chaos_damage'},
label_infobox = i18n.tooltips.poison_dps,
html_fmt_options = {
color = 'value',
fmt = '%.1f',
},
},
dps = {
field = 'dps',
damage_args = {'physical_damage', 'fire_damage', 'cold_damage', 'lightning_damage', 'chaos_damage'},
label_infobox = i18n.tooltips.dps,
html_fmt_options = {
color = 'value',
fmt = '%.1f',
},
},
}
return core