Module:Item/core: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
Mefisto1029 (talk | contribs) (Added subcat for omens) |
||
(109 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- | -- | ||
-- Core confirguation and functions for Module: | -- Core confirguation and functions for Module:Item and submodules | ||
-- | -- | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
Line 8: | Line 8: | ||
local m_cargo = require('Module:Cargo') | 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('Item') | |||
local m_game = use_sandbox and mw.loadData('Module:Game/sandbox') or mw.loadData('Module:Game') | |||
-- The cfg table contains all localisable strings and configuration, to make it | -- 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: | local cfg = use_sandbox and mw.loadData('Module:Item/config/sandbox') or mw.loadData('Module:Item/config') | ||
local i18n = cfg.i18n | local i18n = cfg.i18n | ||
Line 22: | Line 25: | ||
local h = {} | local h = {} | ||
function | -- ---------------------------------------------------------------------------- | ||
-- Core | |||
-- ---------------------------------------------------------------------------- | |||
if | local core = {} | ||
core.factory = {} | |||
function core.factory.infobox_line(args) | |||
-- args: table | |||
-- type: How to read data from tpl_args using the given keys. nil = Regular, gem = Gem progression, stat = Stats | |||
if | -- parts: table | ||
-- [n]: table | |||
-- 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 | |||
-- ----- params from m_util.html.format_value ----- | |||
if | -- func: Function to transform the value retrieved from the database | ||
table. | -- fmt: Format string (or function that returns format string) to use for the value. | ||
-- Default: '%s' | |||
-- fmt_range: Format string to use for range value. | |||
-- Default: '(%s-%s)' | |||
-- color: poe_color code to use for the value. False for no color. | |||
for _, | -- Default: 'value' if value is unmodified; 'mod' if modified | ||
if | -- class: Additional css class added to color tag | ||
if | -- inline: Format string to use for the output | ||
-- inline_color: poe_color code to use for the output. False for no color. | |||
-- Default: Inherits from value color | |||
-- 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 | |||
end | |||
args.parts = args.parts or {} | |||
return function (tpl_args) | |||
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 | ||
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 stat = tpl_args._stats[data.key] | |||
if stat then | |||
local total = {min=0, max=0} | |||
for _, v in ipairs(stat) do | |||
if v.mod == nil or v.mod.is_implicit or v.mod.is_explicit then | |||
total.min = total.min + v.min | |||
total.max = total.max + v.max | |||
end | |||
end | |||
base_values[i] = total.min | |||
temp_values[#temp_values+1] = {value=total, index=i} | |||
end | |||
end | |||
else | |||
-- Regular. Look for key exactly as written in tpl_args | |||
for i, data in ipairs(args.parts) do | |||
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 and value.max ~= nil then | |||
base_values[i] = value.min | |||
temp_values[#temp_values+1] = {value=value, index=i} | |||
end | |||
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 value ~= nil then | |||
base_values[i] = value | |||
temp_values[#temp_values+1] = {value | |||
min=tpl_args. | |||
max=tpl_args. | |||
} | } | ||
if | if v.min == nil or v.max == nil then | ||
v = tpl_args[opt.hide_key] | |||
end | end | ||
end | end | ||
hide = opt.hide(tpl_args, 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 and opt.hide_default == v.max then | |||
hide = true | |||
end | |||
else | else | ||
local v = data.value | |||
if opt.hide_default == v.min and opt.hide_default == v.max then | |||
hide = true | |||
end | |||
end | end | ||
end | |||
if not hide then | |||
table.insert(final_values, data) | |||
end | end | ||
end | end | ||
-- all zeros = dont display and return early | |||
if #final_values == 0 then | |||
return nil | |||
end | |||
-- all zeros = dont display and return early | |||
if #final_values == 0 then | |||
return nil | |||
end | |||
local parts = {} | local parts = {} | ||
Line 249: | Line 198: | ||
options.color = 'value' | options.color = 'value' | ||
end | end | ||
parts[#parts+1] = m_util.html.format_value(tpl_args, value, options) | |||
parts[#parts+1] = m_util.html.format_value(tpl_args | |||
end | end | ||
if args.sep then | if args.sep then | ||
Line 279: | Line 224: | ||
end | end | ||
function core.factory.damage_html(args) | function core.add_stat(tpl_args, stat_id, value, options) | ||
return function(tpl_args, | options = options or {} | ||
local keys = { | local mod = options.mod | ||
min = args. | local tbl = options.tbl or '_stats' | ||
max = args. | tpl_args[tbl] = tpl_args[tbl] or {} | ||
} | tpl_args[tbl][stat_id] = tpl_args[tbl][stat_id] or { | ||
local | min = 0, | ||
for ktype, key in pairs(keys) do | max = 0, | ||
avg = 0, | |||
parts = { | } | ||
{ | local stat = { | ||
mod = mod, | |||
} | |||
if type(value) == 'table' then | |||
stat.min = value.min | |||
stat.max = value.max | |||
stat.avg = value.avg or (stat.min + stat.max) / 2 | |||
else | |||
stat.min = value | |||
stat.max = value | |||
stat.avg = value | |||
end | |||
table.insert(tpl_args[tbl][stat_id], stat) | |||
-- Totals | |||
tpl_args[tbl][stat_id].min = tpl_args[tbl][stat_id].min + stat.min | |||
tpl_args[tbl][stat_id].max = tpl_args[tbl][stat_id].max + stat.max | |||
tpl_args[tbl][stat_id].avg = tpl_args[tbl][stat_id].avg + stat.avg | |||
end | |||
-- | |||
-- Functions for processing tpl_args | |||
-- | |||
h.proc = {} | |||
h.proc.factory = {} | |||
function h.proc.factory.value(args) | |||
args = args or {} | |||
return function (tpl_args, 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, 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, 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, | key = key, | ||
color = false, | color = false, | ||
Line 295: | Line 301: | ||
} | } | ||
} | } | ||
}(tpl_args | }(tpl_args) | ||
end | end | ||
if | if range.min and range.max then | ||
local color = args. | local color = args.type or false | ||
local range_fmt | 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 | 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 | -- Variable damage range, based on modifier rolls | ||
if args. | if args.type == 'physical' then | ||
color = 'mod' | color = 'mod' | ||
end | end | ||
Line 308: | Line 314: | ||
else | else | ||
-- Standard damage range | -- Standard damage range | ||
if args. | if args.type == 'physical' then | ||
color = 'value' | color = 'value' | ||
end | end | ||
range_fmt = i18n.fmt.standard_damage_range | range_fmt = i18n.fmt.standard_damage_range | ||
end | end | ||
value = string.format(range_fmt, | value = string.format(range_fmt, range.min, range.max) | ||
if color then | if color then | ||
value = m_util.html.poe_color(color, value) | value = m_util.html.poe_color(color, value) | ||
end | end | ||
end | end | ||
return value | |||
end | end | ||
end | end | ||
function | function h.proc.factory.stat_text(args) | ||
return function (tpl_args, value) | |||
local type_map = { | |||
implicit = 'is_implicit', | |||
explicit = 'is_explicit', | |||
} | } | ||
if type_map[args.type] == nil then | |||
if | return nil | ||
end | end | ||
tpl_args | local lines = {} | ||
local random_mods = {} | |||
local skip = cfg.class_specifics[tpl_args.class_id] and cfg.class_specifics[tpl_args.class_id].skip_stat_lines or nil | |||
end | for _, mod_data in ipairs(tpl_args._mods) do | ||
end | if mod_data[type_map[args.type]] then | ||
if mod_data.is_random == true then | |||
random_mods[mod_data.stat_text] = random_mods[mod_data.stat_text] or {} | |||
table.insert(random_mods[mod_data.stat_text], mod_data) | |||
else | |||
if mod_data.stat_text ~= nil then | |||
table.insert(lines, mod_data.stat_text) | |||
else | |||
local text = mod_data.result['mods.stat_text'] | |||
if text and text ~= '' then | |||
for _, line in ipairs(m_util.string.split(text, '<br>')) do | |||
local skipped = false | |||
if skip then | |||
for _, pattern in ipairs(skip) do | |||
if string.match(line, pattern) then | |||
skipped = true | |||
break | |||
end | |||
end | |||
end | |||
if not skipped then | |||
table.insert(lines, line) | |||
end | |||
end | |||
end | |||
end | |||
end | |||
end | |||
end | |||
for stat_text, mod_data_list in pairs(random_mods) do | |||
local text = {} | |||
for _, mod_data in ipairs(mod_data_list) do | |||
table.insert(text, mod_data.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 | |||
return #lines > 0 and table.concat(lines, '<br>') or nil | |||
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.character = h.proc.factory.value{ | |||
validate = m_util.validate.factory.string_length{ | |||
min = 1, | |||
max = 1, | |||
}, | |||
} | |||
h.proc.list = h.proc.factory.list() | |||
-- | -- | ||
-- | -- Argument mapping | ||
-- tpl_args key = { | -- | ||
-- | -- [<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 | |||
-- func | -- default varies Default value if parameter is not set | ||
-- | -- deprecated boolean Set to true for deprecated parameters | ||
-- | |||
-- } | -- } | ||
core.map = { | core.map = { | ||
-- special params | -- special params | ||
html = { | html = { | ||
inherit = false, | |||
field = 'html', | field = 'html', | ||
type = 'Text', | type = 'Text', | ||
func = nil, | func = nil, | ||
}, | }, | ||
infobox_html = { | |||
inherit = false, | |||
field = ' | field = 'infobox_html', | ||
type = 'Text', | |||
func = nil, | |||
}, | |||
metabox_html = { | |||
inherit = false, | |||
field = 'metabox_html', | |||
type = 'Text', | type = 'Text', | ||
func = nil, | func = nil, | ||
}, | }, | ||
implicit_stat_text = { | implicit_stat_text = { | ||
inherit = false, | |||
field = 'implicit_stat_text', | field = 'implicit_stat_text', | ||
type = 'Text', | type = 'Text', | ||
func = | func = h.proc.factory.stat_text{type='implicit'}, | ||
}, | }, | ||
explicit_stat_text = { | explicit_stat_text = { | ||
inherit = false, | |||
field = 'explicit_stat_text', | field = 'explicit_stat_text', | ||
type = 'Text', | type = 'Text', | ||
func = function(tpl_args, | func = h.proc.factory.stat_text{type='explicit'}, | ||
tpl_args.explicit_stat_text = | }, | ||
stat_text = { | |||
inherit = false, | |||
if tpl_args. | field = 'stat_text', | ||
type = 'Text', | |||
func = function (tpl_args, value) | |||
if tpl_args.implicit_stat_text or tpl_args.explicit_stat_text then | |||
local stats = {} | |||
table.insert(stats, tpl_args.implicit_stat_text) -- No-op if value is nil | |||
table.insert(stats, tpl_args.explicit_stat_text) | |||
if tpl_args.is_corrupted then | |||
table.insert(stats, m_util.html.poe_color('corrupted', i18n.tooltips.corrupted)) | |||
elseif tpl_args.is_mirrored then | |||
table.insert(stats, i18n.tooltips.mirrored) | |||
elseif tpl_args.is_unmodifiable then | |||
table.insert(stats, i18n.tooltips.unmodifiable) | |||
end | end | ||
local sep = string.format('<span class="item-stat-separator -%s"></span>', tpl_args.frame_type) | |||
value = table.concat(stats, sep) | |||
end | end | ||
return value | |||
end, | end, | ||
}, | }, | ||
class_id = { | |||
field = ' | inherit = false, | ||
type = ' | field = 'class_id', | ||
func = function(tpl_args, | type = 'String', | ||
func = function (tpl_args, value) | |||
if value == nil then | |||
error(string.format(i18n.errors.generic_required_parameter, 'class_id')) | |||
end | end | ||
if not m_util.table.has_key(m_game.constants.item.classes, value) or m_game.constants.item.classes[value].disabled then | |||
error(string.format(i18n.errors.invalid_class_id, tostring(value))) | |||
end | end | ||
return value | |||
end, | end, | ||
}, | }, | ||
class = { | class = { | ||
inherit = false, | |||
field = 'class', | field = 'class', | ||
type = 'String', | type = 'String', | ||
func = function (tpl_args, | func = function (tpl_args, 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, | ||
deprecated = true, | |||
}, | }, | ||
-- | -- generic | ||
is_in_game = { | |||
inherit = false, | |||
field = ' | field = 'is_in_game', | ||
type = ' | type = 'Boolean', | ||
func = | func = h.proc.boolean, | ||
default = true, | |||
}, | }, | ||
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{ | |||
tbl = m_game.constants.rarities, | |||
errmsg = i18n.errors.invalid_rarity_id, | |||
}, | |||
}, | |||
}, | }, | ||
rarity = { | rarity = { | ||
inherit = false, | |||
field = 'rarity', | field = 'rarity', | ||
type = 'String', | type = 'String', | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
return m_game.constants.rarities[tpl_args.rarity_id].long_upper | |||
end | end, | ||
deprecated = true, | |||
}, | }, | ||
name = { | name = { | ||
inherit = false, | |||
field = 'name', | field = 'name', | ||
type = 'String', | type = 'String', | ||
Line 456: | Line 557: | ||
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 | type = 'List (,) of String', | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
-- Drop rarities only matter for base items | |||
if tpl_args._flags.is_derived then | |||
-- Drop rarities only matter for base items | return nil -- Use default | ||
if tpl_args. | |||
return | |||
end | end | ||
return m_util.cast.table(value, { | |||
callback = m_util.validate.factory.in_table_keys{ | |||
tbl = m_game.constants.rarities, | |||
errmsg = i18n.errors.invalid_rarity_id, | |||
errlvl = 4, | |||
}, | |||
}) | |||
end, | end, | ||
default = {}, | |||
}, | }, | ||
drop_enabled = { | drop_enabled = { | ||
inherit = false, | |||
field = 'drop_enabled', | field = 'drop_enabled', | ||
type = 'Boolean', | type = 'Boolean', | ||
func = m_util.cast | func = function (tpl_args, value) | ||
default = | if value == nil then | ||
return nil -- Use default | |||
end | |||
return tpl_args.is_in_game and m_util.cast.boolean(value) | |||
end, | |||
default = function (tpl_args) | |||
return tpl_args.is_in_game | |||
end, | |||
}, | }, | ||
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, | ||
}, | }, | ||
acquisition_tags = { | |||
inherit = false, | |||
field = ' | field = 'acquisition_tags', | ||
type = 'List (,) of String', | type = 'List (,) of String', | ||
func = m_util. | func = h.proc.factory.list{ | ||
callback = m_util.validate.factory.in_table_keys{ | |||
tbl = cfg.acquisition_tags, | |||
errmsg = i18n.errors.invalid_acquisition_tag, | |||
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, | func = function (tpl_args, value) | ||
value = m_util.cast.table(value) | |||
if type(value) == 'table' and #value > 0 then | |||
tpl_args. | tpl_args._drop_areas_data = m_cargo.array_query{ | ||
tables={'areas'}, | tables = {'areas'}, | ||
fields={'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'}, | fields = { | ||
id_field='areas.id', | 'areas._pageName=_pageName', | ||
id_array= | 'areas.id=id', | ||
query={limit=5000}, | 'areas.name=name', | ||
'areas.main_page=main_page', | |||
'areas.is_legacy_map_area=is_legacy_map_area' | |||
}, | |||
id_field = 'areas.id', | |||
id_array = value, | |||
query = {limit=5000}, | |||
} | } | ||
if tpl_args._drop_areas_data then | |||
tpl_args._legacy_drop_areas = tpl_args._legacy_drop_areas or {} | |||
for _, v in ipairs(tpl_args._drop_areas_data) do | |||
if m_util.cast.boolean(v.is_legacy_map_area) then | |||
tpl_args._flags.has_legacy_drop_areas = true | |||
table.insert(tpl_args._legacy_drop_areas, v.id) | |||
end | |||
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 = {}, | |||
}, | }, | ||
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 629: | Line 680: | ||
field = 'required_level', | field = 'required_level', | ||
type = 'Integer', | type = 'Integer', | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
tpl_args. | value = tpl_args.required_level | ||
if value < cfg.base_item_required_level_threshold and cfg.base_item_required_level_threshold_classes[tpl_args.class_id] then | |||
value = 1 | |||
end | |||
return value | |||
end, | end, | ||
default = 1, | default = 1, | ||
Line 637: | Line 692: | ||
field = 'required_dexterity', | field = 'required_dexterity', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 643: | Line 698: | ||
field = 'required_strength', | field = 'required_strength', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 649: | Line 704: | ||
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, | func = function (tpl_args, value) | ||
if tpl_args.class_id = | if not value then | ||
tpl_args. | -- 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] | |||
else | |||
for k, v in pairs(tpl_args._flags) do | |||
value = v and i18n.default_inventory_icons[k] | |||
end | |||
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, | func = function (tpl_args, 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 | |||
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 = { | ||
field = 'help_text', | field = 'help_text', | ||
type = 'Text', | type = 'Text', | ||
func = h. | func = h.proc.text, | ||
}, | }, | ||
flavour_text = { | is_account_bound = { | ||
inherit = false, | |||
field = 'is_account_bound', | |||
type = 'Boolean', | |||
func = h.proc.boolean, | |||
default = false, | |||
}, | |||
flavour_text = { | |||
inherit = false, | |||
field = 'flavour_text', | field = 'flavour_text', | ||
type = 'Text', | type = 'Text', | ||
func = h.factory. | func = h.proc.factory.value{ | ||
cast = function (value) | |||
value = m_util.cast.text(value) | |||
-- Parse harbinger glyphs | |||
value = string.gsub(value, '<<([Hh][Bb][Gg]%w+)>>', '<span class="glyph %1"></span>') | |||
return value | |||
end, | |||
}, | |||
}, | }, | ||
tags = { | tags = { | ||
field = 'tags', | field = 'tags', | ||
type = 'List (,) of String', | type = 'List (,) of String', | ||
func = m_util. | 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', | ||
func = function (tpl_args, value) | |||
func = function(tpl_args, | if value == nil then | ||
if | return nil | ||
return | |||
end | end | ||
local results = m_cargo.query( | -- 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().prefixedText) | |||
) | |||
} | |||
) | |||
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 = m_util. | 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, | |||
}, | |||
is_searing_exarch_item = { | |||
inherit = false, | |||
field = 'is_searing_exarch_item', | |||
type = 'Boolean', | |||
func = h.proc.boolean, | |||
default = false, | |||
}, | |||
is_eater_of_worlds_item = { | |||
inherit = false, | |||
field = 'is_eater_of_worlds_item', | |||
type = 'Boolean', | |||
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, | func = function (tpl_args, 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_mirrored = { | |||
inherit = false, | |||
field = | field = nil, | ||
type = | type = nil, | ||
func = | func = h.proc.boolean, | ||
default = false, | default = false, | ||
}, | }, | ||
is_unmodifiable = { | |||
inherit = false, | |||
field = ' | field = 'is_unmodifiable', | ||
type = 'Boolean', | type = 'Boolean', | ||
func = | func = h.proc.boolean, | ||
default = false, | |||
default = false, | |||
}, | }, | ||
is_drop_restricted = { | is_drop_restricted = { | ||
inherit = false, | |||
field = 'is_drop_restricted', | field = 'is_drop_restricted', | ||
type = 'Boolean', | type = 'Boolean', | ||
func = m_util.cast | func = function (tpl_args, value) | ||
default = function(tpl_args | if value == nil then | ||
-- | return nil -- Use default | ||
for _, | end | ||
if tpl_args[ | return not tpl_args.drop_enabled or m_util.cast.boolean(value) | ||
end, | |||
default = function (tpl_args) | |||
if not tpl_args.drop_enabled then | |||
return true | |||
end | |||
-- Divination cards have drop restrictions by design. | |||
if tpl_args.class_id == 'DivinationCard' then | |||
return true | |||
end | |||
for _, key in ipairs({'is_replica', '_drop_areas_data', 'drop_monsters'}) do | |||
-- arg 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 | ||
end | end | ||
local flags = { | |||
'is_talisman', | |||
'is_essence', | |||
'is_blight_item', | |||
'is_fossil', | |||
'is_tattoo', | |||
'is_delirium_orb', | |||
'is_catalyst', | |||
'is_omen', | |||
} | |||
for _, flag in ipairs(flags) do | |||
if tpl_args._flags[flag] then | if tpl_args._flags[flag] then | ||
return true | return true | ||
Line 845: | Line 936: | ||
end, | end, | ||
}, | }, | ||
purchase_costs = { | --[[purchase_costs = { | ||
func = function(tpl_args, | field = nil, | ||
type = nil, | |||
func = function (tpl_args, 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 862: | Line 955: | ||
rtbl[#rtbl+1] = values | rtbl[#rtbl+1] = values | ||
i = i + 1 | i = i + 1 | ||
table.insert(tpl_args._store_data, { | |||
_table = 'item_purchase_costs', | _table = 'item_purchase_costs', | ||
amount = values.amount, | amount = values.amount, | ||
name = values.name, | name = values.name, | ||
rarity = values.rarity, | rarity = values.rarity, | ||
} | }) | ||
else | else | ||
i = -1 | i = -1 | ||
end | end | ||
end | end | ||
purchase_costs[rarity_id] = rtbl | purchase_costs[rarity_id] = rtbl | ||
end | end | ||
return purchase_costs | |||
end, | end, | ||
func_fetch = function(tpl_args | func_fetch = function (tpl_args) | ||
if tpl_args.rarity_id ~= 'unique' then | if tpl_args.rarity_id ~= 'unique' then | ||
return | return | ||
Line 901: | Line 991: | ||
local datavar = tpl_args.purchase_costs[string.lower(values.rarity)] | local datavar = tpl_args.purchase_costs[string.lower(values.rarity)] | ||
datavar[#datavar+1] = values | datavar[#datavar+1] = values | ||
table.insert(tpl_args._store_data, { | |||
_table = 'item_purchase_costs', | _table = 'item_purchase_costs', | ||
amount = values.amount, | amount = values.amount, | ||
name = values.name, | name = values.name, | ||
rarity = values.rarity, | rarity = values.rarity, | ||
} | }) | ||
end | end | ||
end, | end, | ||
}, | },--]] | ||
is_sellable = { | |||
inherit = false, | |||
field = nil, | |||
type = nil, | |||
func = function (tpl_args, value) | |||
if value == nil then | |||
return nil -- Use default | |||
end | |||
return tpl_args.is_in_game and m_util.cast.boolean(value) | |||
end, | |||
default = function (tpl_args) | |||
return tpl_args.is_in_game | |||
end, | |||
}, | |||
sell_prices_override = { | sell_prices_override = { | ||
inherit = false, | |||
func = function(tpl_args, | field = nil, | ||
type = nil, | |||
func = function (tpl_args, 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 930: | Line 1,036: | ||
tpl_args.sell_price_order[#tpl_args.sell_price_order+1] = name | tpl_args.sell_price_order[#tpl_args.sell_price_order+1] = name | ||
tpl_args.sell_prices[name] = amount | tpl_args.sell_prices[name] = amount | ||
table.insert(tpl_args._store_data, { | |||
_table = 'item_sell_prices', | _table = 'item_sell_prices', | ||
amount = amount, | amount = amount, | ||
name = name, | name = name, | ||
} | }) | ||
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 943: | Line 1,048: | ||
break | break | ||
end | end | ||
return value | |||
end, | end, | ||
}, | }, | ||
Line 948: | Line 1,054: | ||
-- specific section | -- specific section | ||
-- | -- | ||
-- Most item classes | -- Most item classes | ||
quality = { | quality = { | ||
inherit = false, | |||
field = 'quality', | field = 'quality', | ||
type = 'Integer', | type = 'Integer', | ||
-- | -- Must copy to stat for the stat adjustments to work properly | ||
func = function (tpl_args, value) | |||
func = function(tpl_args, | local value = tonumber(value) | ||
local | if value then | ||
core.add_stat(tpl_args, 'quality', value) | |||
if tpl_args.class_id == 'UtilityFlask' then | |||
if tpl_args. | core.add_stat(tpl_args, 'quality_flask_duration', value) | ||
elseif tpl_args.class_id == 'Map' then | |||
elseif | -- quality is added to quantity for maps | ||
quality | core.add_stat(tpl_args, 'map_item_drop_quantity_+%', value) | ||
end | end | ||
end | end | ||
return value | |||
end, | end, | ||
default = 0, | |||
}, | }, | ||
-- amulets | -- amulets | ||
Line 991: | Line 1,080: | ||
field = 'is_talisman', | field = 'is_talisman', | ||
type = 'Boolean', | type = 'Boolean', | ||
func = m_util.cast | func = function (tpl_args, value) | ||
value = m_util.cast.boolean(value) | |||
tpl_args._flags.is_talisman = value | |||
return value | |||
end, | |||
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 1,035: | Line 1,126: | ||
field = 'buff_values', | field = 'buff_values', | ||
type = 'List (,) of Integer', | type = 'List (,) of Integer', | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
local values = {} | local values = {} | ||
local i = 0 | local i = 0 | ||
Line 1,047: | Line 1,138: | ||
-- 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, | func_copy = function (tpl_args, 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 1,063: | Line 1,155: | ||
field = 'icon', | field = 'icon', | ||
type = 'String', | type = 'String', | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
return string.format(i18n.files.status_icon, tpl_args.name) | |||
end, | end, | ||
}, | }, | ||
Line 1,072: | Line 1,164: | ||
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 = ' | type = 'Float', | ||
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, | ||
default = 0, | |||
}, | }, | ||
physical_damage_max = { | physical_damage_max = { | ||
field = 'physical_damage_max', | field = 'physical_damage_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
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 1,103: | Line 1,197: | ||
field = 'fire_damage_max', | field = 'fire_damage_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 1,109: | Line 1,203: | ||
field = 'cold_damage_min', | field = 'cold_damage_min', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 1,115: | Line 1,209: | ||
field = 'cold_damage_max', | field = 'cold_damage_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 1,121: | Line 1,215: | ||
field = 'lightning_damage_min', | field = 'lightning_damage_min', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 1,127: | Line 1,221: | ||
field = 'lightning_damage_max', | field = 'lightning_damage_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 1,133: | Line 1,227: | ||
field = 'chaos_damage_min', | field = 'chaos_damage_min', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
Line 1,139: | Line 1,233: | ||
field = 'chaos_damage_max', | field = 'chaos_damage_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | |||
spirit = { | |||
field = 'spirit', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
default = 0, | default = 0, | ||
}, | }, | ||
-- armor-type stuff | -- armor-type stuff | ||
armour = { | armour = { | ||
inherit = false, | |||
field = 'armour', | field = 'armour', | ||
type = nil, | |||
func = nil, | |||
}, | |||
armour_min = { | |||
field = 'armour_min', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
armour_max = { | |||
field = ' | field = 'armour_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
evasion = { | evasion = { | ||
inherit = false, | |||
field = 'evasion', | field = 'evasion', | ||
type = nil, | |||
func = nil, | |||
}, | |||
evasion_min = { | |||
field = 'evasion_min', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
evasion_max = { | |||
field = 'evasion_max', | |||
field = ' | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | default = 0, | ||
}, | }, | ||
energy_shield = { | |||
inherit = false, | |||
field = ' | field = 'energy_shield', | ||
type = nil, | |||
func = nil, | |||
}, | |||
energy_shield_min = { | |||
field = 'energy_shield_min', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
energy_shield_max = { | |||
field = ' | field = 'energy_shield_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
ward = { | |||
field = ' | inherit = false, | ||
field = 'ward', | |||
type = nil, | |||
func = nil, | |||
}, | |||
ward_min = { | |||
field = 'ward_min', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
ward_max = { | |||
field = ' | field = 'ward_max', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
-- This is the inherent penality from the armour piece if any | |||
field = ' | movement_speed = { | ||
type = ' | field = 'movement_speed', | ||
func = | type = 'Integer', | ||
func = h.proc.number, | |||
default = 0, | |||
}, | }, | ||
-- shields | |||
field = ' | block = { | ||
type = ' | field = 'block', | ||
type = 'Integer', | |||
func = | func = h.proc.number, | ||
}, | }, | ||
-- | -- skill gem stuff | ||
gem_description = { | |||
field = ' | field = 'gem_description', | ||
type = 'Text', | type = 'Text', | ||
func = | func = h.proc.text, | ||
}, | }, | ||
dexterity_percent = { | |||
field = 'dexterity_percent', | |||
type = 'Integer', | |||
func = h.proc.percentage, | |||
field = ' | default = 0, | ||
}, | |||
strength_percent = { | |||
field = 'strength_percent', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.percentage, | ||
default = 0, | |||
}, | }, | ||
intelligence_percent = { | |||
field = ' | field = 'intelligence_percent', | ||
type = ' | type = 'Integer', | ||
func = | func = h.proc.percentage, | ||
default = 0, | |||
}, | }, | ||
primary_attribute = { | |||
field = ' | field = 'primary_attribute', | ||
type = 'String', | type = 'String', | ||
func = | func = function (tpl_args, 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 = ' | field = 'gem_tags', | ||
type = ' | type = 'List (,) of String', | ||
func = m_util. | 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 = {}, | |||
}, | |||
is_vaal_skill_gem = { | |||
field = 'is_vaal_skill_gem', | |||
type = 'Boolean', | |||
func = h.proc.boolean, | |||
default = false, | |||
}, | }, | ||
vaal_variant_id = { | |||
field = ' | inherit = true, | ||
type = 'String | field = 'vaal_variant_id', | ||
type = 'String', | |||
func = nil, | func = nil, | ||
}, | }, | ||
-- Support gems only | |||
field = ' | support_gem_letter = { | ||
field = 'support_gem_letter', | |||
type = 'String', | type = 'String', | ||
func = | func = h.proc.character, | ||
}, | |||
tpl_args. | support_gem_letter_html = { | ||
field = 'support_gem_letter_html', | |||
type = 'Text', | |||
func = function (tpl_args, 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', v.long_lower) | |||
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, | end, | ||
}, | }, | ||
is_awakened_support_gem = { | |||
field = ' | field = 'is_awakened_support_gem', | ||
type = ' | type = 'Boolean', | ||
func = | func = h.proc.boolean, | ||
default = false, | |||
}, | }, | ||
awakened_variant_id = { | |||
field = ' | field = 'awakened_variant_id', | ||
type = 'String', | type = 'String', | ||
func | func = nil, | ||
}, | }, | ||
-- | -- | ||
-- Jewels | |||
-- | |||
jewel_limit = { | |||
inherit = false, | |||
field = 'jewel_limit', | |||
field = ' | |||
type = 'String', | type = 'String', | ||
func = nil, | func = nil, | ||
}, | }, | ||
-- | |||
field = ' | -- Maps | ||
-- | |||
map_tier = { | |||
field = 'tier', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
map_guild_character = { | |||
field = ' | field = 'guild_character', | ||
type = ' | type = 'String', | ||
func = | func = h.proc.character, | ||
}, | }, | ||
map_area_id = { | |||
field = ' | field = 'area_id', | ||
type = ' | type = 'String', | ||
func = | func = nil, -- TODO: Validate against a query? | ||
}, | }, | ||
map_area_level = { | |||
field = ' | field = 'area_level', | ||
type = ' | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
unique_map_guild_character = { | |||
field = ' | field = 'unique_guild_character', | ||
type = ' | type = 'String', | ||
func = | func = h.proc.character, | ||
func_copy = function (tpl_args, value) | |||
tpl_args.map_guild_character = value | |||
end, | |||
}, | }, | ||
unique_map_area_id = { | |||
field = ' | field = 'unique_area_id', | ||
type = ' | type = 'String', | ||
func = | func = nil, -- TODO: Validate against a query? | ||
func_copy = function (tpl_args, 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, value) | |||
tpl_args.map_area_level = value | |||
end, | |||
}, | |||
map_series = { | |||
field = 'series', | |||
type = 'String', | |||
func = function (tpl_args, 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 | |||
field = ' | atlas_x = { | ||
inherit = false, | |||
field = 'x', | |||
type = 'Float', | type = 'Float', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
atlas_y = { | |||
field = ' | inherit = false, | ||
field = 'y', | |||
type = 'Float', | type = 'Float', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
atlas_region_id = { | |||
field = ' | inherit = false, | ||
field = 'region_id', | |||
type = 'String', | |||
func = nil, | |||
}, | |||
atlas_region_minimum = { | |||
inherit = false, | |||
field = 'region_minimum', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
}, | |||
atlas_x0 = { | |||
inherit = false, | |||
field = 'x0', | |||
type = 'Float', | type = 'Float', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
atlas_x1 = { | |||
field = ' | inherit = false, | ||
field = 'x1', | |||
type = 'Float', | type = 'Float', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
atlas_x2 = { | |||
field = ' | inherit = false, | ||
field = 'x2', | |||
type = 'Float', | type = 'Float', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
atlas_x3 = { | |||
field = ' | inherit = false, | ||
type = ' | field = 'x3', | ||
func = | type = 'Float', | ||
func = h.proc.number, | |||
}, | }, | ||
atlas_map_tier1 = { | atlas_x4 = { | ||
inherit = false, | |||
field = 'x4', | |||
type = 'Float', | |||
func = h.proc.number, | |||
}, | |||
atlas_y0 = { | |||
inherit = false, | |||
field = 'y0', | |||
type = 'Float', | |||
func = h.proc.number, | |||
}, | |||
atlas_y1 = { | |||
inherit = false, | |||
field = 'y1', | |||
type = 'Float', | |||
func = h.proc.number, | |||
}, | |||
atlas_y2 = { | |||
inherit = false, | |||
field = 'y2', | |||
type = 'Float', | |||
func = h.proc.number, | |||
}, | |||
atlas_y3 = { | |||
inherit = false, | |||
field = 'y3', | |||
type = 'Float', | |||
func = h.proc.number, | |||
}, | |||
atlas_y4 = { | |||
inherit = false, | |||
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', | 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 = { | ||
inherit = false, | |||
field = nil, | field = nil, | ||
type = nil, | type = nil, | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
value = {} | |||
local cont = true | local cont = true | ||
local i = 1 | local i = 1 | ||
Line 1,437: | Line 1,629: | ||
end | end | ||
value[data.map2] = data | |||
table.insert(tpl_args. | table.insert(tpl_args._store_data, 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, | ||
}, | }, | ||
-- | -- | ||
-- | -- Map fragments | ||
-- | |||
map_fragment_limit = { | |||
inherit = false, | |||
field = 'map_fragment_limit', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
}, | |||
is_scarab = { | |||
inherit = false, | |||
field = nil, | |||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_scarab = m_util.table.contains(tpl_args.tags, 'scarab') | |||
return value | |||
end, | |||
}, | |||
-- | |||
-- Stackable items | |||
-- | -- | ||
stack_size = { | stack_size = { | ||
inherit = false, | |||
field = 'stack_size', | field = 'stack_size', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
stack_size_currency_tab = { | stack_size_currency_tab = { | ||
inherit = false, | |||
field = 'stack_size_currency_tab', | field = 'stack_size_currency_tab', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
description = { | description = { | ||
inherit = false, | |||
field = 'description', | field = 'description', | ||
type = 'Text', | type = 'Text', | ||
func = h. | func = h.proc.text, | ||
}, | }, | ||
-- Essences | |||
-- | |||
is_essence = { | is_essence = { | ||
inherit = false, | |||
field = nil, | field = nil, | ||
func = m_util.cast | type = nil, | ||
func = function (tpl_args, value) | |||
value = m_util.cast.boolean(value) | |||
tpl_args._flags.is_essence = value | |||
return value | |||
end, | |||
default = false, | default = false, | ||
}, | }, | ||
essence_level_restriction = { | essence_level_restriction = { | ||
inherit = false, | |||
field = 'level_restriction', | field = 'level_restriction', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
essence_level = { | essence_level = { | ||
inherit = false, | |||
field = 'level', | field = 'level', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
essence_type = { | essence_type = { | ||
inherit = false, | |||
field = 'type', | field = 'type', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
essence_category = { | essence_category = { | ||
inherit = false, | |||
field = 'category', | field = 'category', | ||
type = 'String', | type = 'String', | ||
func = nil, | func = nil, | ||
}, | }, | ||
-- | -- Oils | ||
is_blight_item = { | |||
inherit = false, | |||
field = nil, | |||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_blight_item = tpl_args.blight_item_tier ~= nil | |||
return value | |||
end, | |||
}, | |||
blight_item_tier = { | blight_item_tier = { | ||
inherit = false, | |||
field = 'tier', | field = 'tier', | ||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
-- | -- Fossils | ||
is_fossil = { | |||
field = | inherit = false, | ||
type = ' | field = nil, | ||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_fossil = tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'CurrencyDelve', 1, true) ~= nil | |||
return value | |||
end, | |||
}, | }, | ||
-- Tattoos | |||
field = ' | is_tattoo = { | ||
inherit = false, | |||
field = nil, | |||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_tattoo = tpl_args.tattoo_target ~= nil | |||
return value | |||
end, | |||
}, | |||
tattoo_target = { | |||
inherit = false, | |||
field = 'target', | |||
type = 'String', | type = 'String', | ||
func = | func = nil, | ||
}, | }, | ||
tattoo_tribe = { | |||
field = | inherit = false, | ||
type = | field = 'tribe', | ||
func = | type = 'Integer', | ||
func = h.proc.number, | |||
}, | }, | ||
tattoo_limit = { | |||
field = ' | inherit = false, | ||
type = ' | field = 'tattoo_limit', | ||
type = 'String', | |||
func = nil, | |||
}, | }, | ||
tattoo_min_adjacent = { | |||
field = ' | inherit = false, | ||
field = 'min_adjacent', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
tattoo_max_adjacent = { | |||
field = ' | inherit = false, | ||
field = 'max_adjacent', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
tattoo_skill_id = { | |||
field = ' | inherit = false, | ||
type = ' | field = 'skill_id', | ||
func = | type = 'String', | ||
func = nil, | |||
}, | }, | ||
-- Delirium orbs | |||
field = | is_delirium_orb = { | ||
type = | inherit = false, | ||
func = | field = nil, | ||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_delirium_orb = tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'CurrencyAfflictionOrb', 1, true) ~= nil | |||
return value | |||
end, | |||
}, | }, | ||
-- Catalysts | |||
field = | is_catalyst = { | ||
type = | inherit = false, | ||
func = m_util. | field = nil, | ||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_catalyst = m_util.table.contains(tpl_args.tags, 'catalyst') | |||
return value | |||
end, | |||
}, | }, | ||
-- Omens | |||
field = | is_omen = { | ||
type = | inherit = false, | ||
func = m_util. | field = nil, | ||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_omen = m_util.table.contains(tpl_args.tags, 'omen') | |||
return value | |||
end, | |||
}, | }, | ||
-- Cosmetic items | |||
field = ' | cosmetic_type = { | ||
type = ' | inherit = false, | ||
func = m_util. | 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, | |||
}, | |||
}, | |||
}, | }, | ||
cosmetic_theme = { | |||
field = ' | inherit = false, | ||
field = 'theme', | |||
type = 'String', | |||
func = nil, | |||
}, | |||
cosmetic_target = { | |||
inherit = false, | |||
field = 'target', | |||
type = 'List (,) of String', | type = 'List (,) of String', | ||
func = | func = h.proc.list, | ||
default = | default = {}, | ||
}, | }, | ||
-- | -- | ||
-- | -- Harvest seeds | ||
-- | -- | ||
seed_type_id = { | |||
field = ' | inherit = false, | ||
type = ' | field = 'type_id', | ||
func = | type = 'String', | ||
func = nil, | |||
}, | }, | ||
seed_type = { | |||
field = ' | inherit = false, | ||
type = ' | field = 'type', | ||
func = | type = 'String', | ||
func = function (tpl_args, 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 = | inherit = false, | ||
type = | field = nil, | ||
func = m_util. | type = nil, | ||
}, | func = function (tpl_args, value) | ||
if tpl_args.seed_type ~= nil then | |||
field = ' | value = m_util.html.poe_color(tpl_args.seed_type_id, tpl_args.seed_type) | ||
end | |||
return value | |||
end, | |||
}, | |||
seed_effect = { | |||
inherit = false, | |||
field = 'effect', | |||
type = 'Text', | |||
func = nil, | |||
}, | |||
seed_tier = { | |||
inherit = false, | |||
field = 'tier', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
seed_growth_cycles = { | |||
inherit = false, | |||
field = 'growth_cycles', | |||
type = 'Integer', | |||
field = ' | func = h.proc.number, | ||
type = ' | |||
func = h. | |||
}, | }, | ||
seed_required_nearby_seed_tier = { | |||
field = ' | inherit = false, | ||
field = 'required_nearby_seed_tier', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
seed_required_nearby_seed_amount = { | |||
inherit = false, | |||
field = 'required_nearby_seed_amount', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
}, | }, | ||
seed_consumed_wild_lifeforce_percentage = { | |||
inherit = false, | |||
field = 'consumed_wild_lifeforce_percentage', | |||
type = 'Integer', | |||
field = ' | func = h.proc.number, | ||
type = ' | default = 0, | ||
func = | |||
}, | }, | ||
seed_consumed_vivid_lifeforce_percentage = { | |||
field = ' | inherit = false, | ||
type = ' | field = 'consumed_vivid_lifeforce_percentage', | ||
type = 'Integer', | |||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
seed_consumed_primal_lifeforce_percentage = { | |||
field = ' | inherit = false, | ||
field = 'consumed_primal_lifeforce_percentage', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
default = 0, | |||
}, | }, | ||
seed_granted_craft_option_ids = { | |||
field = ' | inherit = false, | ||
field = 'granted_craft_option_ids', | |||
type = 'List (,) of String', | |||
func = h.proc.list, | |||
default = {}, | |||
}, | |||
-- | |||
-- Harvest planet boosters | |||
-- | |||
plant_booster_radius = { | |||
inherit = false, | |||
field = 'radius', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
plant_booster_lifeforce = { | |||
field = ' | inherit = false, | ||
field = 'lifeforce', | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
plant_booster_additional_crafting_options = { | |||
inherit = false, | |||
field = ' | field = 'additional_crafting_options', | ||
type = ' | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
plant_booster_extra_chances = { | |||
inherit = false, | |||
field = 'extra_chances', | |||
field = ' | |||
type = 'Integer', | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
-- | |||
field = ' | -- Heist properties | ||
type = ' | -- | ||
func = h. | heist_required_job_id = { | ||
field = 'required_job_id', | |||
type = 'String', | |||
func = h.proc.text, | |||
}, | }, | ||
heist_required_job_level = { | |||
field = ' | field = 'required_job_level', | ||
type = ' | type = 'Integer', | ||
func = h.proc.number, | |||
}, | }, | ||
heist_data = { | |||
inherit = false, | |||
field = | field = nil, | ||
type = | type = nil, | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
tpl_args. | if tpl_args.heist_required_job_level then | ||
if tpl_args.heist_required_job_id then | |||
local results = m_cargo.query( | |||
{'heist_npc_skills', 'heist_jobs', 'heist_npcs'}, | |||
{'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, | end, | ||
}, | }, | ||
-- | |||
-- | -- Hideout decorations | ||
-- | |||
is_master_doodad = { | |||
inherit = false, | |||
field = 'is_master_doodad', | |||
type = 'Boolean', | |||
field = ' | func = h.proc.boolean, | ||
type = ' | default = false, | ||
func = function(tpl_args, | }, | ||
tpl_args. | variation_count = { | ||
inherit = false, | |||
field = 'variation_count', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
}, | |||
-- | |||
-- Prophecies | |||
-- | |||
is_prophecy = { | |||
inherit = false, | |||
field = nil, | |||
type = nil, | |||
func = function (tpl_args, value) | |||
tpl_args._flags.is_prophecy = tpl_args.prophecy_id ~= nil | |||
return value | |||
end, | end, | ||
default = false, | |||
}, | }, | ||
prophecy_id = { | |||
inherit = false, | |||
field = ' | field = 'prophecy_id', | ||
type = 'String', | type = 'String', | ||
func = | func = nil, | ||
}, | }, | ||
prediction_text = { | |||
inherit = false, | |||
field = ' | field = 'prediction_text', | ||
type = ' | type = 'Text', | ||
func = | func = h.proc.text, | ||
}, | }, | ||
seal_cost = { | |||
inherit = false, | |||
field = ' | field = 'seal_cost', | ||
type = ' | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | |||
prophecy_reward = { | |||
inherit = false, | |||
field = 'reward', | |||
type = 'Text', | |||
func = h.proc.text, | |||
}, | |||
prophecy_objective = { | |||
inherit = false, | |||
field = 'objective', | |||
type = 'Text', | |||
func = h.proc.text, | |||
}, | |||
-- | |||
-- Divination cards | |||
-- | |||
card_art = { | |||
inherit = false, | |||
field = 'card_art', | |||
type = 'Page', | |||
func = function (tpl_args, value) | |||
return string.format(i18n.files.divination_card_art, value or tpl_args.name) | |||
end, | end, | ||
}, | }, | ||
card_background = { | |||
inherit = false, | |||
field = ' | field = 'card_background', | ||
type = ' | type = 'List (,) of Integer', | ||
func = h.proc.factory.list{ | |||
func = | callback = m_util.cast.number, | ||
}, | |||
default = {}, | |||
}, | }, | ||
-- | -- | ||
-- | -- Sentinels | ||
-- | -- | ||
sentinel_duration = { | |||
field = 'duration', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
}, | |||
sentinel_empowers = { | |||
field = 'empowers', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
}, | }, | ||
sentinel_empowerment = { | |||
field = 'empowerment', | |||
field = ' | type = 'Integer', | ||
type = ' | func = h.proc.number, | ||
func = | |||
}, | }, | ||
sentinel_charge = { | |||
field = 'charge', | |||
field = ' | type = 'Integer', | ||
type = ' | func = h.proc.number, | ||
func = | |||
}, | }, | ||
sentinel_monster = { | |||
inherit = false, | |||
field = ' | field = 'monster', | ||
type = ' | type = 'String', | ||
func = | func = nil, | ||
}, | }, | ||
sentinel_monster_level = { | |||
inherit = false, | |||
field = ' | field = 'monster_level', | ||
type = ' | type = 'Integer', | ||
func = | func = h.proc.number, | ||
}, | }, | ||
-- | |||
-- Corpse items | |||
-- | |||
corpse_tier = { | |||
inherit = false, | |||
field = 'tier', | |||
type = 'Integer', | |||
func = function (tpl_args, value) | |||
field = ' | if tpl_args.metadata_id ~= nil then | ||
type = ' | for k, v in ipairs({'Low', 'Mid', 'High'}) do | ||
func = function(tpl_args, | if string.find(tpl_args.metadata_id, 'Metadata/Items/ItemisedCorpses/%w+' .. v) then | ||
return k | |||
end | |||
for | |||
end | end | ||
end | end | ||
return nil | |||
end, | end, | ||
}, | }, | ||
monster_category = { | |||
inherit = false, | |||
field = ' | field = 'monster_category', | ||
type = ' | type = 'String', | ||
func = | func = h.proc.factory.value{ | ||
validate = m_util.validate.factory.in_table_keys{ | |||
tbl = m_game.constants.monster.categories, | |||
errmsg = i18n.errors.invalid_monster_category, | |||
}, | |||
}, | |||
}, | }, | ||
monster_category_html = { | |||
inherit = false, | |||
field = ' | field = 'monster_category_html', | ||
type = 'Text', | type = 'Text', | ||
func = function(tpl_args, | func = function (tpl_args, value) | ||
if tpl_args.monster_category ~= nil then | |||
value = mw.html.create() | |||
:tag('span') | |||
:addClass('mon-cat -' .. m_game.constants.monster.categories[tpl_args.monster_category].long_lower) | |||
:done() | |||
:wikitext(m_game.constants.monster.categories[tpl_args.monster_category].long_upper) | |||
value = m_util.html.poe_color('value', tostring(value)) | |||
end | end | ||
return value | |||
end, | end, | ||
}, | }, | ||
monster_abilities = { | |||
inherit = false, | |||
field = ' | field = 'monster_abilities', | ||
type = 'Text', | type = 'Text', | ||
func = nil, | func = nil, | ||
}, | }, | ||
-- | |||
-- Embers of the Allflame | |||
field = ' | -- | ||
type = ' | pack_id = { | ||
func = | inherit = false, | ||
field = 'pack_id', | |||
type = 'String', | |||
func = nil, | |||
}, | |||
pack_size = { | |||
inherit = false, | |||
field = 'pack_size', | |||
type = nil, | |||
func = nil, | |||
}, | |||
pack_min_size = { | |||
inherit = false, | |||
field = 'pack_min_size', | |||
type = 'Integer', | |||
func = h.proc.number, | |||
default = 1, | |||
}, | }, | ||
pack_max_size = { | |||
inherit = false, | |||
field = ' | field = 'pack_max_size', | ||
type = ' | type = 'Integer', | ||
func = h.proc.number, | |||
default = 1, | |||
}, | }, | ||
pack_leader_chance = { | |||
inherit = false, | |||
field = ' | field = 'pack_leader_chance', | ||
type = ' | type = 'Float', | ||
func = h.proc.number, | |||
}, | }, | ||
-- | -- | ||
-- | -- Tinctures | ||
-- | -- | ||
tincture_mana_burn = { | |||
field = 'debuff_interval', | |||
type = 'Float', | |||
func = | func = h.proc.number, | ||
}, | }, | ||
tincture_cooldown = { | |||
field = 'cooldown', | |||
type = 'Float', | |||
func = | func = h.proc.number, | ||
}, | }, | ||
-- ------------------------------------------------------------------------ | |||
-- derived stats | |||
field = ' | -- ------------------------------------------------------------------------ | ||
-- Populated by processing base item | |||
}, | base_item_id = { | ||
inherit = false, | |||
field = 'base_item_id', | |||
type = 'String', | |||
func = nil, | |||
}, | |||
base_item_page = { | |||
inherit = false, | |||
field = 'base_item_page', | |||
type = 'Page', | |||
func = nil, | |||
}, | |||
base_item = { | |||
inherit = false, | |||
field = 'base_item', | |||
type = 'String', | |||
func = nil, | |||
}, | }, | ||
name_list = { | |||
field = ' | inherit = false, | ||
field = 'name_list', | |||
type = 'List (�) of String', | |||
func = function (tpl_args, value) | |||
value = m_util.cast.table(value) | |||
value[#value+1] = tpl_args.name | |||
return value | |||
}, | end, | ||
default = {}, | |||
}, | }, | ||
frame_type = { | |||
field = ' | inherit = false, | ||
field = 'frame_type', | |||
type = 'String', | |||
func = function (tpl_args, 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 | |||
return tpl_args.rarity_id | |||
end, | |||
}, | }, | ||
-- | |||
-- args populated by mod validation | |||
-- | |||
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 = { | |||
field = ' | inherit = false, | ||
field = 'damage_avg', | |||
type = 'Text', | |||
func = function (tpl_args, value) | |||
local min = 0 | |||
local max = 0 | |||
for _, damage_type in ipairs(m_game.constants.damage_type_order) do | |||
min = min + tpl_args[damage_type .. '_damage_min_range_average'] | |||
max = max + tpl_args[damage_type .. '_damage_max_range_average'] | |||
end | |||
value = (min + max) / 2 | |||
return value | |||
end, | |||
}, | }, | ||
damage_html = { | |||
field = ' | inherit = false, | ||
field = 'damage_html', | |||
type = 'Text', | |||
func = function (tpl_args, 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, | |||
}, | }, | ||
jewel_radius_html = { | |||
field = ' | inherit = false, | ||
field = 'radius_html', | |||
type = 'Text', | |||
func = function (tpl_args, 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, | |||
}, | }, | ||
drop_areas_html = { | |||
field = ' | inherit = false, | ||
field = 'drop_areas_html', | |||
type = 'Text', | |||
func = function (tpl_args, 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.id, '^Map.+') or string.match(data.id, '^MapWorlds.+') or string.match(data.id, '^MapAtziri.+') then | |||
areas[#areas+1] = string.format('[[%s|%s]]', data.main_page or data._pageName, data.main_page or data.name) | |||
end | |||
end | |||
return table.concat(areas, ' • ') | |||
end, | |||
}, | }, | ||
release_version = { | |||
field = ' | 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, | |||
}, | |||
disable_automatic_recipes = { | |||
inherit = false, | |||
field = nil, | |||
func = h.proc.boolean, | |||
default = false, | |||
}, | |||
} | |||
core.stat_map = { | |||
required_level_final = { | |||
field = 'required_level', | |||
stats_add = { | stats_add = { | ||
' | 'local_level_requirement_+', | ||
}, | }, | ||
minimum = 1, | |||
minimum = | |||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '% | fmt = '%i', | ||
}, | }, | ||
}, | }, | ||
weapon_range = { | |||
field = ' | field = 'weapon_range', | ||
stats_add_distance = { | |||
' | 'local_weapon_range_+', | ||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%. | fmt = '%.1f', | ||
}, | }, | ||
}, | }, | ||
physical_damage_min = { | |||
field = ' | field = 'physical_damage_min', | ||
stats_add = { | stats_add = { | ||
' | 'local_minimum_added_physical_damage', | ||
}, | }, | ||
stats_increased = { | stats_increased = { | ||
' | 'local_physical_damage_+%', | ||
'quality', | 'quality', | ||
}, | }, | ||
stats_override = { | |||
['local_weapon_no_physical_damage'] = {min=0, max=0}, | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | fmt = '%i', | ||
}, | }, | ||
}, | }, | ||
physical_damage_max = { | |||
field = ' | field = 'physical_damage_max', | ||
stats_add = { | stats_add = { | ||
' | 'local_maximum_added_physical_damage', | ||
}, | }, | ||
stats_increased = { | stats_increased = { | ||
' | 'local_physical_damage_+%', | ||
'quality', | 'quality', | ||
}, | }, | ||
stats_override = { | |||
['local_weapon_no_physical_damage'] = {min=0, max=0}, | |||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '% | fmt = '%i', | ||
}, | }, | ||
}, | }, | ||
fire_damage_min = { | |||
field = ' | field = 'fire_damage_min', | ||
stats_add = { | |||
' | 'local_minimum_added_fire_damage', | ||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | fmt = '%i', | ||
color = 'fire', | |||
}, | }, | ||
}, | }, | ||
fire_damage_max = { | |||
field = ' | field = 'fire_damage_max', | ||
stats_add = { | stats_add = { | ||
' | 'local_maximum_added_fire_damage', | ||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | fmt = '%i', | ||
color = 'fire', | |||
}, | }, | ||
}, | }, | ||
cold_damage_min = { | |||
field = ' | field = 'cold_damage_min', | ||
stats_add = { | stats_add = { | ||
' | 'local_minimum_added_cold_damage', | ||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i | fmt = '%i', | ||
color = 'cold', | |||
}, | }, | ||
}, | }, | ||
cold_damage_max = { | |||
field = ' | field = 'cold_damage_max', | ||
stats_add = { | stats_add = { | ||
' | 'local_maximum_added_cold_damage', | ||
}, | }, | ||
minimum = 0, | |||
' | html_fmt_options = { | ||
' | fmt = '%i', | ||
color = 'cold', | |||
}, | |||
' | }, | ||
lightning_damage_min = { | |||
field = 'lightning_damage_min', | |||
stats_add = { | |||
'local_minimum_added_lightning_damage', | |||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | fmt = '%i', | ||
color = 'lightning', | |||
}, | }, | ||
}, | }, | ||
lightning_damage_max = { | |||
field = ' | field = 'lightning_damage_max', | ||
stats_add = { | stats_add = { | ||
' | 'local_maximum_added_lightning_damage', | ||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | fmt = '%i', | ||
color = 'lightning', | |||
}, | }, | ||
}, | }, | ||
chaos_damage_min = { | |||
field = ' | field = 'chaos_damage_min', | ||
stats_add = { | stats_add = { | ||
' | 'local_minimum_added_chaos_damage', | ||
}, | }, | ||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
' | color = 'chaos', | ||
' | |||
}, | }, | ||
}, | |||
chaos_damage_max = { | |||
field = 'chaos_damage_max', | |||
stats_add = { | |||
'local_maximum_added_chaos_damage', | |||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | fmt = '%i', | ||
color = 'chaos', | |||
}, | }, | ||
}, | }, | ||
critical_strike_chance = { | |||
field = ' | field = 'critical_strike_chance', | ||
stats_add = { | stats_add = { | ||
' | 'local_critical_strike_chance', | ||
}, | }, | ||
stats_increased = { | stats_increased = { | ||
' | 'local_critical_strike_chance_+%', | ||
}, | }, | ||
stats_override = { | stats_override = { | ||
[' | ['local_weapon_crit_chance_is_100'] = {min=100, max=100}, | ||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '% | fmt = '%.2f', | ||
inline = '%s%%', | |||
}, | }, | ||
}, | }, | ||
attack_speed = { | |||
field = ' | field = 'attack_speed', | ||
stats_increased = { | stats_increased = { | ||
' | 'local_attack_speed_+%', | ||
}, | }, | ||
minimum = 0, | minimum = 0, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '% | fmt = '%.2f', | ||
}, | }, | ||
}, | }, | ||
flask_life = { | |||
field = ' | field = 'life', | ||
stats_add = { | stats_add = { | ||
' | 'local_flask_life_to_recover', | ||
}, | }, | ||
stats_increased = { | stats_increased = { | ||
' | 'local_flask_life_to_recover_+%', | ||
' | 'local_flask_amount_to_recover_+%', | ||
'quality', | |||
}, | }, | ||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | fmt = '%i', | ||
}, | }, | ||
}, | }, | ||
flask_mana = { | |||
field = ' | field = 'mana', | ||
stats_add = { | |||
'local_flask_mana_to_recover', | |||
}, | |||
stats_increased = { | |||
'local_flask_mana_to_recover_+%', | |||
'local_flask_amount_to_recover_+%', | |||
'quality', | |||
}, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | }, | ||
}, | }, | ||
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 = { | html_fmt_options = { | ||
fmt = '%.2f', | |||
fmt = '%. | |||
}, | }, | ||
}, | }, | ||
{ | charges_per_use = { | ||
field = 'charges_per_use', | |||
field = ' | stats_increased = { | ||
'local_charges_used_+%', | |||
}, | }, | ||
minimum = 0, | |||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%i', | |||
fmt = '% | |||
}, | }, | ||
}, | }, | ||
{ | charges_max = { | ||
field = 'charges_max', | |||
field = 'lightning_dps', | stats_add = { | ||
damage_args = {'lightning_damage'}, | 'local_extra_max_charges', | ||
label_infobox = i18n.tooltips.lightning_dps, | }, | ||
stats_increased = { | |||
'local_max_charges_+%', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | |||
}, | |||
armour = { | |||
arg = { | |||
min = 'armour_min', | |||
max = 'armour_max', | |||
}, | |||
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 = { | |||
arg = { | |||
min = 'evasion_min', | |||
max = 'evasion_max', | |||
}, | |||
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 = { | |||
arg = { | |||
min = 'energy_shield_min', | |||
max = 'energy_shield_max', | |||
}, | |||
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_no_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 = { | |||
arg = { | |||
min = 'ward_min', | |||
max = 'ward_max', | |||
}, | |||
field = 'ward', | |||
stats_add = { | |||
'local_ward', | |||
'quality', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | |||
}, | |||
spirit = { | |||
field = 'spirit', | |||
stats_add = { | |||
'local_spirit', | |||
}, | |||
stats_increased = { | |||
'local_spirit_+%', | |||
}, | |||
stats_increased = { | |||
'local_ward_+%', | |||
'quality', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | |||
}, | |||
block = { | |||
field = 'block', | |||
stats_add = { | |||
'local_additional_block_chance_%', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
inline = '%s%%', | |||
}, | |||
}, | |||
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, | |||
}, | |||
}, | |||
sentinel_duration = { | |||
field = 'duration', | |||
stats_add = { | |||
'local_sentinel_duration_+', | |||
}, | |||
stats_increased = { | |||
'local_sentinel_drone_duration_+%', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | |||
}, | |||
sentinel_empowers = { | |||
field = 'empowers', | |||
stats_add = { | |||
'local_sentinel_tag_limit_+', | |||
}, | |||
stats_increased = { | |||
'local_sentinel_tag_limit_+%', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | |||
}, | |||
sentinel_empowerment = { | |||
field = 'empowerment', | |||
stats_add = { | |||
'local_sentinel_drone_difficulty_+', | |||
}, | |||
stats_increased = { | |||
'local_sentinel_drone_difficulty_+%', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | |||
}, | |||
sentinel_charge = { | |||
field = 'charge', | |||
stats_add = { | |||
'local_sentinel_drone_charge_+', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
}, | |||
}, | |||
pack_size = { | |||
arg = { | |||
min = 'pack_min_size', | |||
max = 'pack_max_size', | |||
}, | |||
field = 'pack_size', | |||
minimum = 1, | |||
html_fmt_options = { | |||
fmt = '%i', | |||
fmt_range = '%s-%s', | |||
}, | |||
}, | |||
tincture_mana_burn = { | |||
field = 'debuff_interval', | |||
stats_increased_inverse = { | |||
'local_tincture_toxicity_rate_+%', | |||
}, | |||
stats_override = { | |||
['local_cannot_generate_toxicity_stacks_over_time'] = {min=nil, max=nil}, | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%.2f', | |||
}, | |||
}, | |||
tincture_cooldown = { | |||
field = 'cooldown', | |||
stats_increased_inverse = { | |||
'local_tincture_cooldown_recovery_+%', | |||
}, | |||
minimum = 0, | |||
html_fmt_options = { | |||
fmt = '%.2f', | |||
}, | |||
}, | |||
} | |||
core.dps_map = { | |||
physical_dps = { | |||
field = 'physical_dps', | |||
damage_args = {'physical_damage'}, | |||
label_infobox = i18n.tooltips.physical_dps, | |||
html_fmt_options = { | |||
fmt = '%.1f', | |||
color = 'value', | |||
}, | |||
}, | |||
fire_dps = { | |||
field = 'fire_dps', | |||
damage_args = {'fire_damage'}, | |||
label_infobox = i18n.tooltips.fire_dps, | |||
html_fmt_options = { | |||
fmt = '%.1f', | |||
color = 'fire', | |||
}, | |||
}, | |||
cold_dps = { | |||
field = 'cold_dps', | |||
damage_args = {'cold_damage'}, | |||
label_infobox = i18n.tooltips.cold_dps, | |||
html_fmt_options = { | |||
fmt = '%.1f', | |||
color = 'cold', | |||
}, | |||
}, | |||
lightning_dps = { | |||
field = 'lightning_dps', | |||
damage_args = {'lightning_damage'}, | |||
label_infobox = i18n.tooltips.lightning_dps, | |||
html_fmt_options = { | |||
fmt = '%.1f', | |||
color = 'lightning', | |||
}, | |||
}, | |||
chaos_dps = { | |||
field = 'chaos_dps', | |||
damage_args = {'chaos_damage'}, | |||
label_infobox = i18n.tooltips.chaos_dps, | |||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%.1f', | fmt = '%.1f', | ||
}, | color = 'chaos', | ||
}, | }, | ||
{ | }, | ||
elemental_dps = { | |||
field = ' | field = 'elemental_dps', | ||
damage_args = {'chaos_damage'}, | damage_args = {'fire_damage', 'cold_damage', 'lightning_damage'}, | ||
label_infobox = i18n.tooltips. | label_infobox = i18n.tooltips.elemental_dps, | ||
html_fmt_options = { | |||
fmt = '%.1f', | |||
color = 'value', | |||
}, | |||
}, | |||
poison_dps = { | |||
field = 'poison_dps', | |||
damage_args = {'physical_damage', 'chaos_damage'}, | |||
label_infobox = i18n.tooltips.poison_dps, | |||
html_fmt_options = { | |||
fmt = '%.1f', | |||
color = 'value', | |||
}, | |||
}, | |||
dps = { | |||
field = 'dps', | |||
damage_args = {'physical_damage', 'fire_damage', 'cold_damage', 'lightning_damage', 'chaos_damage'}, | |||
label_infobox = i18n.tooltips.dps, | |||
html_fmt_options = { | html_fmt_options = { | ||
fmt = '%.1f', | fmt = '%.1f', | ||
color = 'value', | color = 'value', | ||
}, | }, | ||
}, | }, |
Latest revision as of 10:27, 24 November 2024
This submodule contains core configuration and functions for use in Module:Item and its other submodules.
The above documentation is transcluded from Module:Item/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:Item and submodules
--
-------------------------------------------------------------------------------
local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Item')
local m_game = use_sandbox and mw.loadData('Module:Game/sandbox') or mw.loadData('Module:Game')
-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = use_sandbox and mw.loadData('Module:Item/config/sandbox') or mw.loadData('Module:Item/config')
local i18n = cfg.i18n
-- ----------------------------------------------------------------------------
-- Helper functions
-- ----------------------------------------------------------------------------
local h = {}
-- ----------------------------------------------------------------------------
-- Core
-- ----------------------------------------------------------------------------
local core = {}
core.factory = {}
function core.factory.infobox_line(args)
-- args: table
-- type: How to read data from tpl_args using the given keys. nil = Regular, gem = Gem progression, stat = Stats
-- parts: table
-- [n]: table
-- 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
-- ----- params 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 range value.
-- Default: '(%s-%s)'
-- color: poe_color code to use for the value. False for no color.
-- Default: 'value' if value is unmodified; 'mod' if modified
-- 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: Inherits from value color
-- 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)
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 stat = tpl_args._stats[data.key]
if stat then
local total = {min=0, max=0}
for _, v in ipairs(stat) do
if v.mod == nil or v.mod.is_implicit or v.mod.is_explicit then
total.min = total.min + v.min
total.max = total.max + v.max
end
end
base_values[i] = total.min
temp_values[#temp_values+1] = {value=total, index=i}
end
end
else
-- Regular. Look for key exactly as written in tpl_args
for i, data in ipairs(args.parts) do
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 and value.max ~= nil then
base_values[i] = value.min
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, 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 and opt.hide_default == v.max then
hide = true
end
else
local v = data.value
if opt.hide_default == v.min and 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, 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.add_stat(tpl_args, stat_id, value, options)
options = options or {}
local mod = options.mod
local tbl = options.tbl or '_stats'
tpl_args[tbl] = tpl_args[tbl] or {}
tpl_args[tbl][stat_id] = tpl_args[tbl][stat_id] or {
min = 0,
max = 0,
avg = 0,
}
local stat = {
mod = mod,
}
if type(value) == 'table' then
stat.min = value.min
stat.max = value.max
stat.avg = value.avg or (stat.min + stat.max) / 2
else
stat.min = value
stat.max = value
stat.avg = value
end
table.insert(tpl_args[tbl][stat_id], stat)
-- Totals
tpl_args[tbl][stat_id].min = tpl_args[tbl][stat_id].min + stat.min
tpl_args[tbl][stat_id].max = tpl_args[tbl][stat_id].max + stat.max
tpl_args[tbl][stat_id].avg = tpl_args[tbl][stat_id].avg + stat.avg
end
--
-- Functions for processing tpl_args
--
h.proc = {}
h.proc.factory = {}
function h.proc.factory.value(args)
args = args or {}
return function (tpl_args, 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, 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, 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)
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
function h.proc.factory.stat_text(args)
return function (tpl_args, value)
local type_map = {
implicit = 'is_implicit',
explicit = 'is_explicit',
}
if type_map[args.type] == nil then
return nil
end
local lines = {}
local random_mods = {}
local skip = cfg.class_specifics[tpl_args.class_id] and cfg.class_specifics[tpl_args.class_id].skip_stat_lines or nil
for _, mod_data in ipairs(tpl_args._mods) do
if mod_data[type_map[args.type]] then
if mod_data.is_random == true then
random_mods[mod_data.stat_text] = random_mods[mod_data.stat_text] or {}
table.insert(random_mods[mod_data.stat_text], mod_data)
else
if mod_data.stat_text ~= nil then
table.insert(lines, mod_data.stat_text)
else
local text = mod_data.result['mods.stat_text']
if text and text ~= '' then
for _, line in ipairs(m_util.string.split(text, '<br>')) do
local skipped = false
if skip then
for _, pattern in ipairs(skip) do
if string.match(line, pattern) then
skipped = true
break
end
end
end
if not skipped then
table.insert(lines, line)
end
end
end
end
end
end
end
for stat_text, mod_data_list in pairs(random_mods) do
local text = {}
for _, mod_data in ipairs(mod_data_list) do
table.insert(text, mod_data.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
return #lines > 0 and table.concat(lines, '<br>') or nil
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.character = h.proc.factory.value{
validate = m_util.validate.factory.string_length{
min = 1,
max = 1,
},
}
h.proc.list = h.proc.factory.list()
--
-- 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
-- deprecated boolean Set to true for deprecated parameters
-- }
core.map = {
-- special params
html = {
inherit = false,
field = 'html',
type = 'Text',
func = nil,
},
infobox_html = {
inherit = false,
field = 'infobox_html',
type = 'Text',
func = nil,
},
metabox_html = {
inherit = false,
field = 'metabox_html',
type = 'Text',
func = nil,
},
implicit_stat_text = {
inherit = false,
field = 'implicit_stat_text',
type = 'Text',
func = h.proc.factory.stat_text{type='implicit'},
},
explicit_stat_text = {
inherit = false,
field = 'explicit_stat_text',
type = 'Text',
func = h.proc.factory.stat_text{type='explicit'},
},
stat_text = {
inherit = false,
field = 'stat_text',
type = 'Text',
func = function (tpl_args, value)
if tpl_args.implicit_stat_text or tpl_args.explicit_stat_text then
local stats = {}
table.insert(stats, tpl_args.implicit_stat_text) -- No-op if value is nil
table.insert(stats, tpl_args.explicit_stat_text)
if tpl_args.is_corrupted then
table.insert(stats, m_util.html.poe_color('corrupted', i18n.tooltips.corrupted))
elseif tpl_args.is_mirrored then
table.insert(stats, i18n.tooltips.mirrored)
elseif tpl_args.is_unmodifiable then
table.insert(stats, i18n.tooltips.unmodifiable)
end
local sep = string.format('<span class="item-stat-separator -%s"></span>', tpl_args.frame_type)
value = table.concat(stats, sep)
end
return value
end,
},
class_id = {
inherit = false,
field = 'class_id',
type = 'String',
func = function (tpl_args, value)
if value == nil then
error(string.format(i18n.errors.generic_required_parameter, 'class_id'))
end
if not m_util.table.has_key(m_game.constants.item.classes, value) or m_game.constants.item.classes[value].disabled then
error(string.format(i18n.errors.invalid_class_id, tostring(value)))
end
return value
end,
},
class = {
inherit = false,
field = 'class',
type = 'String',
func = function (tpl_args, 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,
deprecated = true,
},
-- generic
is_in_game = {
inherit = false,
field = 'is_in_game',
type = 'Boolean',
func = h.proc.boolean,
default = true,
},
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, value)
return m_game.constants.rarities[tpl_args.rarity_id].long_upper
end,
deprecated = true,
},
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 String',
func = function (tpl_args, value)
-- Drop rarities only matter for base items
if tpl_args._flags.is_derived then
return nil -- Use default
end
return m_util.cast.table(value, {
callback = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.rarities,
errmsg = i18n.errors.invalid_rarity_id,
errlvl = 4,
},
})
end,
default = {},
},
drop_enabled = {
inherit = false,
field = 'drop_enabled',
type = 'Boolean',
func = function (tpl_args, value)
if value == nil then
return nil -- Use default
end
return tpl_args.is_in_game and m_util.cast.boolean(value)
end,
default = function (tpl_args)
return tpl_args.is_in_game
end,
},
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,
},
acquisition_tags = {
inherit = false,
field = 'acquisition_tags',
type = 'List (,) of String',
func = h.proc.factory.list{
callback = m_util.validate.factory.in_table_keys{
tbl = cfg.acquisition_tags,
errmsg = i18n.errors.invalid_acquisition_tag,
errlvl = 4,
},
},
default = {},
},
drop_areas = {
inherit = false,
field = 'drop_areas',
type = 'List (,) of String',
func = function (tpl_args, value)
value = m_util.cast.table(value)
if type(value) == 'table' and #value > 0 then
tpl_args._drop_areas_data = m_cargo.array_query{
tables = {'areas'},
fields = {
'areas._pageName=_pageName',
'areas.id=id',
'areas.name=name',
'areas.main_page=main_page',
'areas.is_legacy_map_area=is_legacy_map_area'
},
id_field = 'areas.id',
id_array = value,
query = {limit=5000},
}
if tpl_args._drop_areas_data then
tpl_args._legacy_drop_areas = tpl_args._legacy_drop_areas or {}
for _, v in ipairs(tpl_args._drop_areas_data) do
if m_util.cast.boolean(v.is_legacy_map_area) then
tpl_args._flags.has_legacy_drop_areas = true
table.insert(tpl_args._legacy_drop_areas, v.id)
end
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, value)
value = tpl_args.required_level
if value < cfg.base_item_required_level_threshold and cfg.base_item_required_level_threshold_classes[tpl_args.class_id] 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, 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]
else
for k, v in pairs(tpl_args._flags) do
value = v and i18n.default_inventory_icons[k]
end
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, 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,
},
is_account_bound = {
inherit = false,
field = 'is_account_bound',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
flavour_text = {
inherit = false,
field = 'flavour_text',
type = 'Text',
func = h.proc.factory.value{
cast = function (value)
value = m_util.cast.text(value)
-- Parse harbinger glyphs
value = string.gsub(value, '<<([Hh][Bb][Gg]%w+)>>', '<span class="glyph %1"></span>')
return value
end,
},
},
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',
func = function (tpl_args, 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().prefixedText)
)
}
)
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_searing_exarch_item = {
inherit = false,
field = 'is_searing_exarch_item',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
is_eater_of_worlds_item = {
inherit = false,
field = 'is_eater_of_worlds_item',
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, 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_mirrored = {
inherit = false,
field = nil,
type = nil,
func = h.proc.boolean,
default = false,
},
is_unmodifiable = {
inherit = false,
field = 'is_unmodifiable',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
is_drop_restricted = {
inherit = false,
field = 'is_drop_restricted',
type = 'Boolean',
func = function (tpl_args, value)
if value == nil then
return nil -- Use default
end
return not tpl_args.drop_enabled or m_util.cast.boolean(value)
end,
default = function (tpl_args)
if not tpl_args.drop_enabled then
return true
end
-- Divination cards have drop restrictions by design.
if tpl_args.class_id == 'DivinationCard' then
return true
end
for _, key in ipairs({'is_replica', '_drop_areas_data', 'drop_monsters'}) do
-- arg 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
local flags = {
'is_talisman',
'is_essence',
'is_blight_item',
'is_fossil',
'is_tattoo',
'is_delirium_orb',
'is_catalyst',
'is_omen',
}
for _, flag in ipairs(flags) do
if tpl_args._flags[flag] then
return true
end
end
return false
end,
},
--[[purchase_costs = {
field = nil,
type = nil,
func = function (tpl_args, 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
table.insert(tpl_args._store_data, {
_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)
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
table.insert(tpl_args._store_data, {
_table = 'item_purchase_costs',
amount = values.amount,
name = values.name,
rarity = values.rarity,
})
end
end,
},--]]
is_sellable = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
if value == nil then
return nil -- Use default
end
return tpl_args.is_in_game and m_util.cast.boolean(value)
end,
default = function (tpl_args)
return tpl_args.is_in_game
end,
},
sell_prices_override = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, 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
table.insert(tpl_args._store_data, {
_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',
-- Must copy to stat for the stat adjustments to work properly
func = function (tpl_args, value)
local value = tonumber(value)
if value then
core.add_stat(tpl_args, 'quality', value)
if tpl_args.class_id == 'UtilityFlask' then
core.add_stat(tpl_args, 'quality_flask_duration', value)
elseif tpl_args.class_id == 'Map' then
-- quality is added to quantity for maps
core.add_stat(tpl_args, 'map_item_drop_quantity_+%', value)
end
end
return value
end,
default = 0,
},
-- amulets
is_talisman = {
field = 'is_talisman',
type = 'Boolean',
func = function (tpl_args, value)
value = m_util.cast.boolean(value)
tpl_args._flags.is_talisman = value
return value
end,
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, 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, 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, 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 = 'Float',
func = h.proc.number,
},
physical_damage_min = {
field = 'physical_damage_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
physical_damage_max = {
field = 'physical_damage_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
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,
},
spirit = {
field = 'spirit',
type = 'Integer',
func = h.proc.number,
default = 0,
},
-- armor-type stuff
armour = {
inherit = false,
field = 'armour',
type = nil,
func = nil,
},
armour_min = {
field = 'armour_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
armour_max = {
field = 'armour_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
evasion = {
inherit = false,
field = 'evasion',
type = nil,
func = nil,
},
evasion_min = {
field = 'evasion_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
evasion_max = {
field = 'evasion_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
energy_shield = {
inherit = false,
field = 'energy_shield',
type = nil,
func = nil,
},
energy_shield_min = {
field = 'energy_shield_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
energy_shield_max = {
field = 'energy_shield_max',
type = 'Integer',
func = h.proc.number,
default = 0,
},
ward = {
inherit = false,
field = 'ward',
type = nil,
func = nil,
},
ward_min = {
field = 'ward_min',
type = 'Integer',
func = h.proc.number,
default = 0,
},
ward_max = {
field = 'ward_max',
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,
default = 0,
},
strength_percent = {
field = 'strength_percent',
type = 'Integer',
func = h.proc.percentage,
default = 0,
},
intelligence_percent = {
field = 'intelligence_percent',
type = 'Integer',
func = h.proc.percentage,
default = 0,
},
primary_attribute = {
field = 'primary_attribute',
type = 'String',
func = function (tpl_args, 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 = {},
},
is_vaal_skill_gem = {
field = 'is_vaal_skill_gem',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
vaal_variant_id = {
inherit = true,
field = 'vaal_variant_id',
type = 'String',
func = nil,
},
-- Support gems only
support_gem_letter = {
field = 'support_gem_letter',
type = 'String',
func = h.proc.character,
},
support_gem_letter_html = {
field = 'support_gem_letter_html',
type = 'Text',
func = function (tpl_args, 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', v.long_lower)
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,
},
is_awakened_support_gem = {
field = 'is_awakened_support_gem',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
awakened_variant_id = {
field = 'awakened_variant_id',
type = 'String',
func = nil,
},
--
-- Jewels
--
jewel_limit = {
inherit = false,
field = 'jewel_limit',
type = 'String',
func = nil,
},
--
-- Maps
--
map_tier = {
field = 'tier',
type = 'Integer',
func = h.proc.number,
},
map_guild_character = {
field = 'guild_character',
type = 'String',
func = h.proc.character,
},
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',
func = h.proc.character,
func_copy = function (tpl_args, 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, 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, value)
tpl_args.map_area_level = value
end,
},
map_series = {
field = 'series',
type = 'String',
func = function (tpl_args, 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 = {
inherit = false,
field = 'x',
type = 'Float',
func = h.proc.number,
},
atlas_y = {
inherit = false,
field = 'y',
type = 'Float',
func = h.proc.number,
},
atlas_region_id = {
inherit = false,
field = 'region_id',
type = 'String',
func = nil,
},
atlas_region_minimum = {
inherit = false,
field = 'region_minimum',
type = 'Integer',
func = h.proc.number,
},
atlas_x0 = {
inherit = false,
field = 'x0',
type = 'Float',
func = h.proc.number,
},
atlas_x1 = {
inherit = false,
field = 'x1',
type = 'Float',
func = h.proc.number,
},
atlas_x2 = {
inherit = false,
field = 'x2',
type = 'Float',
func = h.proc.number,
},
atlas_x3 = {
inherit = false,
field = 'x3',
type = 'Float',
func = h.proc.number,
},
atlas_x4 = {
inherit = false,
field = 'x4',
type = 'Float',
func = h.proc.number,
},
atlas_y0 = {
inherit = false,
field = 'y0',
type = 'Float',
func = h.proc.number,
},
atlas_y1 = {
inherit = false,
field = 'y1',
type = 'Float',
func = h.proc.number,
},
atlas_y2 = {
inherit = false,
field = 'y2',
type = 'Float',
func = h.proc.number,
},
atlas_y3 = {
inherit = false,
field = 'y3',
type = 'Float',
func = h.proc.number,
},
atlas_y4 = {
inherit = false,
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 = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, 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._store_data, data)
else
cont = false
if i == 1 then
value = nil
end
end
i = i + 1
end
return value
end,
},
--
-- Map fragments
--
map_fragment_limit = {
inherit = false,
field = 'map_fragment_limit',
type = 'Integer',
func = h.proc.number,
},
is_scarab = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_scarab = m_util.table.contains(tpl_args.tags, 'scarab')
return value
end,
},
--
-- Stackable items
--
stack_size = {
inherit = false,
field = 'stack_size',
type = 'Integer',
func = h.proc.number,
},
stack_size_currency_tab = {
inherit = false,
field = 'stack_size_currency_tab',
type = 'Integer',
func = h.proc.number,
},
description = {
inherit = false,
field = 'description',
type = 'Text',
func = h.proc.text,
},
-- Essences
is_essence = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
value = m_util.cast.boolean(value)
tpl_args._flags.is_essence = value
return value
end,
default = false,
},
essence_level_restriction = {
inherit = false,
field = 'level_restriction',
type = 'Integer',
func = h.proc.number,
},
essence_level = {
inherit = false,
field = 'level',
type = 'Integer',
func = h.proc.number,
},
essence_type = {
inherit = false,
field = 'type',
type = 'Integer',
func = h.proc.number,
},
essence_category = {
inherit = false,
field = 'category',
type = 'String',
func = nil,
},
-- Oils
is_blight_item = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_blight_item = tpl_args.blight_item_tier ~= nil
return value
end,
},
blight_item_tier = {
inherit = false,
field = 'tier',
type = 'Integer',
func = h.proc.number,
},
-- Fossils
is_fossil = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_fossil = tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'CurrencyDelve', 1, true) ~= nil
return value
end,
},
-- Tattoos
is_tattoo = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_tattoo = tpl_args.tattoo_target ~= nil
return value
end,
},
tattoo_target = {
inherit = false,
field = 'target',
type = 'String',
func = nil,
},
tattoo_tribe = {
inherit = false,
field = 'tribe',
type = 'Integer',
func = h.proc.number,
},
tattoo_limit = {
inherit = false,
field = 'tattoo_limit',
type = 'String',
func = nil,
},
tattoo_min_adjacent = {
inherit = false,
field = 'min_adjacent',
type = 'Integer',
func = h.proc.number,
default = 0,
},
tattoo_max_adjacent = {
inherit = false,
field = 'max_adjacent',
type = 'Integer',
func = h.proc.number,
default = 0,
},
tattoo_skill_id = {
inherit = false,
field = 'skill_id',
type = 'String',
func = nil,
},
-- Delirium orbs
is_delirium_orb = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_delirium_orb = tpl_args.metadata_id and string.find(tpl_args.metadata_id, 'CurrencyAfflictionOrb', 1, true) ~= nil
return value
end,
},
-- Catalysts
is_catalyst = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_catalyst = m_util.table.contains(tpl_args.tags, 'catalyst')
return value
end,
},
-- Omens
is_omen = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_omen = m_util.table.contains(tpl_args.tags, 'omen')
return value
end,
},
-- Cosmetic items
cosmetic_type = {
inherit = false,
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,
},
},
},
cosmetic_theme = {
inherit = false,
field = 'theme',
type = 'String',
func = nil,
},
cosmetic_target = {
inherit = false,
field = 'target',
type = 'List (,) of String',
func = h.proc.list,
default = {},
},
--
-- Harvest seeds
--
seed_type_id = {
inherit = false,
field = 'type_id',
type = 'String',
func = nil,
},
seed_type = {
inherit = false,
field = 'type',
type = 'String',
func = function (tpl_args, 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 = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, 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 = {
inherit = false,
field = 'effect',
type = 'Text',
func = nil,
},
seed_tier = {
inherit = false,
field = 'tier',
type = 'Integer',
func = h.proc.number,
},
seed_growth_cycles = {
inherit = false,
field = 'growth_cycles',
type = 'Integer',
func = h.proc.number,
},
seed_required_nearby_seed_tier = {
inherit = false,
field = 'required_nearby_seed_tier',
type = 'Integer',
func = h.proc.number,
},
seed_required_nearby_seed_amount = {
inherit = false,
field = 'required_nearby_seed_amount',
type = 'Integer',
func = h.proc.number,
},
seed_consumed_wild_lifeforce_percentage = {
inherit = false,
field = 'consumed_wild_lifeforce_percentage',
type = 'Integer',
func = h.proc.number,
default = 0,
},
seed_consumed_vivid_lifeforce_percentage = {
inherit = false,
field = 'consumed_vivid_lifeforce_percentage',
type = 'Integer',
func = h.proc.number,
default = 0,
},
seed_consumed_primal_lifeforce_percentage = {
inherit = false,
field = 'consumed_primal_lifeforce_percentage',
type = 'Integer',
func = h.proc.number,
default = 0,
},
seed_granted_craft_option_ids = {
inherit = false,
field = 'granted_craft_option_ids',
type = 'List (,) of String',
func = h.proc.list,
default = {},
},
--
-- Harvest planet boosters
--
plant_booster_radius = {
inherit = false,
field = 'radius',
type = 'Integer',
func = h.proc.number,
},
plant_booster_lifeforce = {
inherit = false,
field = 'lifeforce',
type = 'Integer',
func = h.proc.number,
},
plant_booster_additional_crafting_options = {
inherit = false,
field = 'additional_crafting_options',
type = 'Integer',
func = h.proc.number,
},
plant_booster_extra_chances = {
inherit = false,
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 = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
if tpl_args.heist_required_job_level then
if tpl_args.heist_required_job_id then
local results = m_cargo.query(
{'heist_npc_skills', 'heist_jobs', 'heist_npcs'},
{'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 decorations
--
is_master_doodad = {
inherit = false,
field = 'is_master_doodad',
type = 'Boolean',
func = h.proc.boolean,
default = false,
},
variation_count = {
inherit = false,
field = 'variation_count',
type = 'Integer',
func = h.proc.number,
},
--
-- Prophecies
--
is_prophecy = {
inherit = false,
field = nil,
type = nil,
func = function (tpl_args, value)
tpl_args._flags.is_prophecy = tpl_args.prophecy_id ~= nil
return value
end,
default = false,
},
prophecy_id = {
inherit = false,
field = 'prophecy_id',
type = 'String',
func = nil,
},
prediction_text = {
inherit = false,
field = 'prediction_text',
type = 'Text',
func = h.proc.text,
},
seal_cost = {
inherit = false,
field = 'seal_cost',
type = 'Integer',
func = h.proc.number,
},
prophecy_reward = {
inherit = false,
field = 'reward',
type = 'Text',
func = h.proc.text,
},
prophecy_objective = {
inherit = false,
field = 'objective',
type = 'Text',
func = h.proc.text,
},
--
-- Divination cards
--
card_art = {
inherit = false,
field = 'card_art',
type = 'Page',
func = function (tpl_args, value)
return string.format(i18n.files.divination_card_art, value or tpl_args.name)
end,
},
card_background = {
inherit = false,
field = 'card_background',
type = 'List (,) of Integer',
func = h.proc.factory.list{
callback = m_util.cast.number,
},
default = {},
},
--
-- Sentinels
--
sentinel_duration = {
field = 'duration',
type = 'Integer',
func = h.proc.number,
},
sentinel_empowers = {
field = 'empowers',
type = 'Integer',
func = h.proc.number,
},
sentinel_empowerment = {
field = 'empowerment',
type = 'Integer',
func = h.proc.number,
},
sentinel_charge = {
field = 'charge',
type = 'Integer',
func = h.proc.number,
},
sentinel_monster = {
inherit = false,
field = 'monster',
type = 'String',
func = nil,
},
sentinel_monster_level = {
inherit = false,
field = 'monster_level',
type = 'Integer',
func = h.proc.number,
},
--
-- Corpse items
--
corpse_tier = {
inherit = false,
field = 'tier',
type = 'Integer',
func = function (tpl_args, value)
if tpl_args.metadata_id ~= nil then
for k, v in ipairs({'Low', 'Mid', 'High'}) do
if string.find(tpl_args.metadata_id, 'Metadata/Items/ItemisedCorpses/%w+' .. v) then
return k
end
end
end
return nil
end,
},
monster_category = {
inherit = false,
field = 'monster_category',
type = 'String',
func = h.proc.factory.value{
validate = m_util.validate.factory.in_table_keys{
tbl = m_game.constants.monster.categories,
errmsg = i18n.errors.invalid_monster_category,
},
},
},
monster_category_html = {
inherit = false,
field = 'monster_category_html',
type = 'Text',
func = function (tpl_args, value)
if tpl_args.monster_category ~= nil then
value = mw.html.create()
:tag('span')
:addClass('mon-cat -' .. m_game.constants.monster.categories[tpl_args.monster_category].long_lower)
:done()
:wikitext(m_game.constants.monster.categories[tpl_args.monster_category].long_upper)
value = m_util.html.poe_color('value', tostring(value))
end
return value
end,
},
monster_abilities = {
inherit = false,
field = 'monster_abilities',
type = 'Text',
func = nil,
},
--
-- Embers of the Allflame
--
pack_id = {
inherit = false,
field = 'pack_id',
type = 'String',
func = nil,
},
pack_size = {
inherit = false,
field = 'pack_size',
type = nil,
func = nil,
},
pack_min_size = {
inherit = false,
field = 'pack_min_size',
type = 'Integer',
func = h.proc.number,
default = 1,
},
pack_max_size = {
inherit = false,
field = 'pack_max_size',
type = 'Integer',
func = h.proc.number,
default = 1,
},
pack_leader_chance = {
inherit = false,
field = 'pack_leader_chance',
type = 'Float',
func = h.proc.number,
},
--
-- Tinctures
--
tincture_mana_burn = {
field = 'debuff_interval',
type = 'Float',
func = h.proc.number,
},
tincture_cooldown = {
field = 'cooldown',
type = 'Float',
func = h.proc.number,
},
-- ------------------------------------------------------------------------
-- derived stats
-- ------------------------------------------------------------------------
-- Populated by processing base item
base_item_id = {
inherit = false,
field = 'base_item_id',
type = 'String',
func = nil,
},
base_item_page = {
inherit = false,
field = 'base_item_page',
type = 'Page',
func = nil,
},
base_item = {
inherit = false,
field = 'base_item',
type = 'String',
func = nil,
},
name_list = {
inherit = false,
field = 'name_list',
type = 'List (�) of String',
func = function (tpl_args, 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, 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
return tpl_args.rarity_id
end,
},
--
-- args populated by mod validation
--
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, value)
local min = 0
local max = 0
for _, damage_type in ipairs(m_game.constants.damage_type_order) do
min = min + tpl_args[damage_type .. '_damage_min_range_average']
max = max + tpl_args[damage_type .. '_damage_max_range_average']
end
value = (min + max) / 2
return value
end,
},
damage_html = {
inherit = false,
field = 'damage_html',
type = 'Text',
func = function (tpl_args, 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,
},
jewel_radius_html = {
inherit = false,
field = 'radius_html',
type = 'Text',
func = function (tpl_args, 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,
},
drop_areas_html = {
inherit = false,
field = 'drop_areas_html',
type = 'Text',
func = function (tpl_args, 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.id, '^Map.+') or string.match(data.id, '^MapWorlds.+') or string.match(data.id, '^MapAtziri.+') then
areas[#areas+1] = string.format('[[%s|%s]]', data.main_page or data._pageName, data.main_page or data.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,
},
disable_automatic_recipes = {
inherit = false,
field = nil,
func = h.proc.boolean,
default = false,
},
}
core.stat_map = {
required_level_final = {
field = 'required_level',
stats_add = {
'local_level_requirement_+',
},
minimum = 1,
html_fmt_options = {
fmt = '%i',
},
},
weapon_range = {
field = 'weapon_range',
stats_add_distance = {
'local_weapon_range_+',
},
minimum = 0,
html_fmt_options = {
fmt = '%.1f',
},
},
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 = {
fmt = '%i',
color = 'fire',
},
},
fire_damage_max = {
field = 'fire_damage_max',
stats_add = {
'local_maximum_added_fire_damage',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
color = 'fire',
},
},
cold_damage_min = {
field = 'cold_damage_min',
stats_add = {
'local_minimum_added_cold_damage',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
color = 'cold',
},
},
cold_damage_max = {
field = 'cold_damage_max',
stats_add = {
'local_maximum_added_cold_damage',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
color = 'cold',
},
},
lightning_damage_min = {
field = 'lightning_damage_min',
stats_add = {
'local_minimum_added_lightning_damage',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
color = 'lightning',
},
},
lightning_damage_max = {
field = 'lightning_damage_max',
stats_add = {
'local_maximum_added_lightning_damage',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
color = 'lightning',
},
},
chaos_damage_min = {
field = 'chaos_damage_min',
stats_add = {
'local_minimum_added_chaos_damage',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
color = 'chaos',
},
},
chaos_damage_max = {
field = 'chaos_damage_max',
stats_add = {
'local_maximum_added_chaos_damage',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
color = 'chaos',
},
},
critical_strike_chance = {
field = 'critical_strike_chance',
stats_add = {
'local_critical_strike_chance',
},
stats_increased = {
'local_critical_strike_chance_+%',
},
stats_override = {
['local_weapon_crit_chance_is_100'] = {min=100, max=100},
},
minimum = 0,
html_fmt_options = {
fmt = '%.2f',
inline = '%s%%',
},
},
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',
},
html_fmt_options = {
fmt = '%i',
},
},
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',
},
},
armour = {
arg = {
min = 'armour_min',
max = 'armour_max',
},
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 = {
arg = {
min = 'evasion_min',
max = 'evasion_max',
},
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 = {
arg = {
min = 'energy_shield_min',
max = 'energy_shield_max',
},
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_no_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 = {
arg = {
min = 'ward_min',
max = 'ward_max',
},
field = 'ward',
stats_add = {
'local_ward',
'quality',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
spirit = {
field = 'spirit',
stats_add = {
'local_spirit',
},
stats_increased = {
'local_spirit_+%',
},
stats_increased = {
'local_ward_+%',
'quality',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
block = {
field = 'block',
stats_add = {
'local_additional_block_chance_%',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
inline = '%s%%',
},
},
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,
},
},
sentinel_duration = {
field = 'duration',
stats_add = {
'local_sentinel_duration_+',
},
stats_increased = {
'local_sentinel_drone_duration_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
sentinel_empowers = {
field = 'empowers',
stats_add = {
'local_sentinel_tag_limit_+',
},
stats_increased = {
'local_sentinel_tag_limit_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
sentinel_empowerment = {
field = 'empowerment',
stats_add = {
'local_sentinel_drone_difficulty_+',
},
stats_increased = {
'local_sentinel_drone_difficulty_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
sentinel_charge = {
field = 'charge',
stats_add = {
'local_sentinel_drone_charge_+',
},
minimum = 0,
html_fmt_options = {
fmt = '%i',
},
},
pack_size = {
arg = {
min = 'pack_min_size',
max = 'pack_max_size',
},
field = 'pack_size',
minimum = 1,
html_fmt_options = {
fmt = '%i',
fmt_range = '%s-%s',
},
},
tincture_mana_burn = {
field = 'debuff_interval',
stats_increased_inverse = {
'local_tincture_toxicity_rate_+%',
},
stats_override = {
['local_cannot_generate_toxicity_stacks_over_time'] = {min=nil, max=nil},
},
minimum = 0,
html_fmt_options = {
fmt = '%.2f',
},
},
tincture_cooldown = {
field = 'cooldown',
stats_increased_inverse = {
'local_tincture_cooldown_recovery_+%',
},
minimum = 0,
html_fmt_options = {
fmt = '%.2f',
},
},
}
core.dps_map = {
physical_dps = {
field = 'physical_dps',
damage_args = {'physical_damage'},
label_infobox = i18n.tooltips.physical_dps,
html_fmt_options = {
fmt = '%.1f',
color = 'value',
},
},
fire_dps = {
field = 'fire_dps',
damage_args = {'fire_damage'},
label_infobox = i18n.tooltips.fire_dps,
html_fmt_options = {
fmt = '%.1f',
color = 'fire',
},
},
cold_dps = {
field = 'cold_dps',
damage_args = {'cold_damage'},
label_infobox = i18n.tooltips.cold_dps,
html_fmt_options = {
fmt = '%.1f',
color = 'cold',
},
},
lightning_dps = {
field = 'lightning_dps',
damage_args = {'lightning_damage'},
label_infobox = i18n.tooltips.lightning_dps,
html_fmt_options = {
fmt = '%.1f',
color = 'lightning',
},
},
chaos_dps = {
field = 'chaos_dps',
damage_args = {'chaos_damage'},
label_infobox = i18n.tooltips.chaos_dps,
html_fmt_options = {
fmt = '%.1f',
color = 'chaos',
},
},
elemental_dps = {
field = 'elemental_dps',
damage_args = {'fire_damage', 'cold_damage', 'lightning_damage'},
label_infobox = i18n.tooltips.elemental_dps,
html_fmt_options = {
fmt = '%.1f',
color = 'value',
},
},
poison_dps = {
field = 'poison_dps',
damage_args = {'physical_damage', 'chaos_damage'},
label_infobox = i18n.tooltips.poison_dps,
html_fmt_options = {
fmt = '%.1f',
color = 'value',
},
},
dps = {
field = 'dps',
damage_args = {'physical_damage', 'fire_damage', 'cold_damage', 'lightning_damage', 'chaos_damage'},
label_infobox = i18n.tooltips.dps,
html_fmt_options = {
fmt = '%.1f',
color = 'value',
},
},
}
return core