Module:Mod: Difference between revisions
Jump to navigation
Jump to search
>OmegaK2 (The replacement for Template:SMW mod table is handled in Module:Modifier table) |
>OmegaK2 (remove property links) |
||
Line 504: | Line 504: | ||
:tag('tr') | :tag('tr') | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Tags') | ||
:done() | :done() | ||
:tag('td') | :tag('td') | ||
Line 525: | Line 525: | ||
:tag('tr') | :tag('tr') | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('#') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Stat Id') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Min') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Max') | ||
:done() | :done() | ||
:done() | :done() | ||
Line 579: | Line 579: | ||
:tag('tr') | :tag('tr') | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('#') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Tag') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Weight') | ||
:done() | :done() | ||
:done() | :done() | ||
Line 629: | Line 629: | ||
:tag('tr') | :tag('tr') | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('#') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Tag') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Weight') | ||
:done() | :done() | ||
:done() | :done() | ||
Line 678: | Line 678: | ||
:tag('tr') | :tag('tr') | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('#') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:wikitext(' | :wikitext('Item') | ||
:done() | :done() | ||
:done() | :done() |
Revision as of 20:15, 10 February 2018
This module is used on 34000+ pages.
To avoid major disruption and server load, do not make unnecessary edits to this module. Test changes to this module first using its /sandbox and /testcases subpages or your user space. All of the changes can then be applied to this module in a single edit.
Consider discussing changes on the talk page or on Discord before implementing them.
Module for handling for modifiers with Cargo support.
List of currently implemented templates
The above documentation is transcluded from Module:Mod/doc.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
--
-- Module for mod related templates
--
local m_util = require('Module:Util')
local getArgs = require('Module:Arguments').getArgs
local game = require('Module:Game')
local f_item_link = require('Module:Item link').item_link
local cargo = mw.ext.cargo
local p = {}
-- ----------------------------------------------------------------------------
-- Strings
-- ----------------------------------------------------------------------------
-- This section contains strings used by this module.
-- Add new strings here instead of in-code directly, this will help other
-- people to correct spelling mistakes easier and help with translation to
-- other PoE wikis.
local i18n = {
args = {
--
-- Mod template
--
-- main
id = 'id',
name = 'name',
mod_group = 'mod_group',
mod_type = 'mod_type',
domain = 'domain',
generation_type = 'generation_type',
required_level = 'required_level',
stat_text = 'stat_text',
granted_buff_id = 'granted_buff_id',
granted_buff_value = 'granted_buff_value',
granted_skill = 'granted_skill',
tags = 'tags',
-- sell price
sell_price_prefix = 'sell_price',
item_name = 'name',
amount = 'amount',
},
errors = {
--
-- Mod template
--
sell_price_duplicate_name = 'Do not specify a sell price item name multiple times. Adjust the amount instead.',
sell_price_missing_argument = 'Both %s and %s must be specified',
},
drop_down_table = {
collapse_all = 'Collapse all',
expand_all = 'Expand all',
table_intro = 'The table below displays the available [[modifiers]] for [[item]]s such as',
prefix = 'Prefix',
suffix = 'Suffix',
corrupted = 'Corrupted'
},
}
-- ----------------------------------------------------------------------------
-- m_utility / Helper functions
-- ----------------------------------------------------------------------------
local h = {}
-- Validate single value properties and set them
h.validate = {}
function h.validate.not_nil (args)
return function (arg)
if g_args[arg] == nil then
error(string.format('%s must not be nil', arg))
end
end
end
function h.validate.number (args)
return function (tpl_args, frame, value)
return m_util.cast.number(value, args)
end
end
function h.create_header(row)
local stat = mw.html.create('span')
local text, nsub = mw.ustring.gsub(row['Has stat text'], '%d+', '?')
stat
:attr('class', 'mod-table-header-stat')
:wikitext(text)
:done()
local mgroup = mw.html.create('span')
mgroup
:attr('class', 'mod-table-header-modgroup')
:wikitext(row['Has mod group'])
:done()
local tbl = mw.html.create('table')
tbl
:attr('class', 'wikitable mw-collapsible mw-collapsed mod-table')
:tag('tr')
:tag('th')
:attr('class', 'mod-table-header')
:attr('colspan', g_args.colspan)
:tag('span')
:attr('class', 'mod-table-header-container')
:wikitext(tostring(stat) .. tostring(mgroup))
:done()
:done()
return tbl
end
function h.format_mod(tbl, row, tags)
local tr = tbl:tag('tr')
tr
:tag('td')
:wikitext(string.format('[[%s|%s]]', row[1], row['Has name']))
:attr('class', 'mod-table-cell-name')
:done()
:tag('td')
:wikitext(row['Has level requirement'])
:attr('class', 'mod-table-cell-level')
:done()
:tag('td')
:wikitext(row['Has stat text'])
:attr('class', 'mod-table-cell-stat')
:done()
:tag('td')
:wikitext(table.concat(tags, ', '))
:attr('class', 'mod-table-cell-tags')
:done()
end
function h.cargo_query(tpl_args)
--[[
Returns a Cargo query of all the results, even if there are more
results than the maximum query limit. It also adds popular fields.
tpl_args should include these keys:
tpl_args.tables
tpl_args.fields
tpl_args.q_*
]]
local tables = m_util.string.split(tpl_args.tables, ', ')
local fields = m_util.string.split(tpl_args.fields, ', ')
-- Parse query arguments
local query = {
-- Workaround: Fix duplicates but removes other rows as well.
groupBy = tables[1] .. '._pageID',
limit = 5000,
offset = 0,
}
for key, value in pairs(tpl_args) do
if string.sub(key, 0, 2) == 'q_' then
query[string.sub(key, 3)] = value
end
end
-- Add commonly used fields:
local fields_base = {
'_pageNamespace',
'_pageTitle',
'_ID',
'_rowID',
'_pageID',
'_pageName'
-- '_value'
}
for _, tbl in ipairs(tables) do
for _, fld in ipairs(fields_base) do
fields[#fields+1] = string.format('%s.%s', tbl, fld)
end
end
-- Query cargo table. If there are too many results then repeat,
-- offset, re-query and add the remaining results:
local results = {}
repeat
local result = mw.ext.cargo.query(
table.concat(tables, ', '),
table.concat(fields, ', '),
query
)
query.offset = query.offset + #result
for _,v in ipairs(result) do
results[#results + 1] = v
end
until #result < query.limit
return results
end
-- ----------------------------------------------------------------------------
-- Templates
-- ----------------------------------------------------------------------------
--
-- Template: Mod
--
local mod_map = {
main = {
table = 'mods',
order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags'},
parse_order = {'id', 'name', 'mod_group', 'mod_type', 'domain', 'generation_type', 'required_level', 'stat_text', 'stat_text_raw', 'granted_buff_id', 'granted_buff_value', 'granted_skill', 'tags'},
fields = {
id = {
name = i18n.args.id,
field = i18n.args.id,
type = 'String',
wikitext = 'Mod Id',
},
name = {
name = i18n.args.name,
field = i18n.args.name,
type = 'String',
wikitext = 'Name',
},
mod_group = {
name = i18n.args.mod_group,
field = i18n.args.mod_group,
type = 'String',
wikitext = 'Group',
},
mod_type = {
name = i18n.args.mod_type,
field = i18n.args.mod_type,
type = 'String',
wikitext = 'Mod type',
},
domain = {
name = i18n.args.domain,
field = i18n.args.domain,
type = 'Integer',
func = h.validate.number{min=1, max=15},
wikitext = 'Mod domain',
display = function (value)
return game.constants.mod.domains[value]['short_upper'] .. ' (Id: ' .. value .. ')'
end,
},
generation_type = {
name = i18n.args.generation_type,
field = i18n.args.generation_type,
type = 'Integer',
func = h.validate.number{min=1, max=12},
wikitext = 'Generation type',
display = function (value)
return game.constants.mod.generation_types[value]['short_upper'] .. ' (Id: ' .. value .. ')'
end,
},
required_level = {
name = i18n.args.required_level,
field = i18n.args.required_level,
type = 'Integer',
func = h.validate.number{min=0, max=100},
wikitext = 'Req. level',
},
stat_text = {
name = i18n.args.stat_text,
field = i18n.args.stat_text,
type = 'Text',
wikitext = 'Effect',
},
stat_text_raw = {
name = nil,
field = 'stat_text_raw',
type = 'Text',
func = function(tpl_args, frame)
if tpl_args.stat_text then
tpl_args.stat_text_raw = string.gsub(
-- [[x]] -> x
string.gsub(
tpl_args.stat_text, '%[%[([^%]|]+)%]%]', '%1'
),
-- [[x|y]] -> y
'%[%[[^|]+|([^%]|]+)%]%]', '%1'
)
end
return tpl_args.stat_text_raw
end
},
granted_buff_id = {
name = i18n.args.granted_buff_id,
field = i18n.args.granted_buff_id,
type = 'String',
wikitext = 'Granted Buff Id',
},
granted_buff_value = {
name = i18n.args.granted_buff_value,
field = i18n.args.granted_buff_value,
type = 'Integer',
wikitext = 'Granted Buff Value',
},
granted_skill = {
name = i18n.args.granted_skill,
field = i18n.args.granted_skill,
type = 'String',
wikitext = 'Granted Skill',
},
tags = {
name = i18n.args.tags,
field = i18n.args.tags,
type = 'List (,) of String',
wikitext = 'Tags',
func = function (tpl_args, frame, value)
if value == nil then
return {}
else
return m_util.string.split(value, ', ')
end
end,
func_cargo = function(tpl_args, frame)
return table.concat(tpl_args.tags, ',')
end,
display = function(value)
return table.concat(value, ', ')
end,
},
},
},
mod_sell_prices = {
table = 'mod_sell_prices',
order = {'name', 'amount'},
fields = {
name = {
name = i18n.args.item_name,
field = i18n.args.item_name,
type = 'String',
func = function (value) return value end,
},
amount = {
name = i18n.args.amount,
field = i18n.args.amount,
type = 'Integer',
func = tonumber,
},
},
},
}
p.table_main = m_util.cargo.declare_factory{data=mod_map.main}
p.table_mod_sell_prices = m_util.cargo.declare_factory{data=mod_map.mod_sell_prices}
function p.table_mod_stats(frame)
m_util.cargo.declare(frame, {
_table = 'mod_stats',
id = 'String',
min = 'Integer',
max = 'Integer',
})
end
-- p.mod{id = "LocalIncreasedPhysicalDamagePercentUniqueOneHandSword2", name = "", mod_group = "LocalPhysicalDamagePercent", domain = "1", generation_type = "3", required_level = "1", mod_type = "LocalPhysicalDamagePercent", stat_text = "150% increased Physical Damage", stat1_id = "local_physical_damage_+%", stat1_min = "150", stat1_max = "150"}
function p.mod(frame)
-- Get args
tpl_args = getArgs(frame, {
parentFirst = true
})
frame = m_util.misc.get_frame(frame)
--
-- Validation & semantic properties
--
-- Validate single value properties and set them
local cargo_data = {
_table = mod_map.main.table,
}
for _, key in pairs(mod_map.main.parse_order) do
data = mod_map.main.fields[key]
local value
if data.func ~= nil then
if data.name then
value = data.func(tpl_args, frame, tpl_args[data.name])
else
value = data.func(tpl_args, frame)
end
else
value = tpl_args[data.name]
end
tpl_args[key] = value
if data.field ~= nil then
if data.func_cargo then
cargo_data[data.field] = data.func_cargo(tpl_args, frame)
else
cargo_data[data.field] = value
end
end
end
m_util.cargo.store(frame, cargo_data)
-- Validate % set the stat subobjects
m_util.args.stats(tpl_args, {frame=frame})
for _, stat_data in pairs(tpl_args.stats) do
m_util.cargo.store(frame, {
_table = 'mod_stats',
id = stat_data.id,
min = stat_data.min,
max = stat_data.max,
})
end
-- Validate & set spawn weight subobjects
m_util.args.spawn_weight_list(tpl_args, {
frame=frame,
})
-- Validate & set generation weight subobjects
m_util.args.generation_weight_list(tpl_args, {
frame=frame,
})
-- Validate & set mod sell values
i = 0
local names = {}
local sell_prices = {}
repeat
i = i + 1
local id = {}
value = {}
for key, data in pairs(mod_map.mod_sell_prices.fields) do
id[key] = string.format('%s%s_%s', i18n.args.sell_price_prefix, i, data.name)
value[key] = data.func(tpl_args[id[key]])
end
if value.name == nil and value.amount == nil then
value = nil
elseif value.name ~= nil and value.amount ~= nil then
if names[value.name] then
error(i18n.errors.sell_price_duplicate_name)
else
names[value.name] = true
end
local cargo_data = {
_table = mod_map.mod_sell_prices.table,
}
for key, data in pairs(mod_map.mod_sell_prices.fields) do
cargo_data[data.field] = value[key]
end
m_util.cargo.store(frame, cargo_data)
sell_prices[#sell_prices+1] = value
else
error (string.format(i18n.errors.sell_price_missing_arguments, id.name, id.amount))
end
until value == nil
--
-- Display
--
local container = mw.html.create('div')
container
:attr('class', 'modbox')
-- core stats
local tbl = container:tag('table')
tbl
:attr('class', 'wikitable')
for _, key in ipairs(mod_map.main.order) do
local data = mod_map.main.fields[key]
local text
if data.display == nil then
text = tpl_args[key]
else
text = data.display(tpl_args[key])
end
tbl
:tag('tr')
:tag('th')
:wikitext(data.wikitext)
:done()
:tag('td')
:wikitext(text)
:done()
:done()
:done()
end
tbl
:tag('tr')
:tag('th')
:wikitext('Tags')
:done()
:tag('td')
:wikitext(table.concat(tpl_args['tags'], ', '))
:done()
:done()
:done()
-- stat table
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 4)
:wikitext('Stats')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Stat Id')
:done()
:tag('th')
:wikitext('Min')
:done()
:tag('th')
:wikitext('Max')
:done()
:done()
:done()
for i=1, #tpl_args.stats do
local value = {
id = tpl_args['stat' .. i .. '_id'],
min = tpl_args['stat' .. i .. '_min'],
max = tpl_args['stat' .. i .. '_max'],
}
if value.id then
tbl
:tag('tr')
:tag('td')
:wikitext(i)
:done()
:tag('td')
:wikitext(value.id)
:done()
:tag('td')
:wikitext(value.min)
:done()
:tag('td')
:wikitext(value.max)
:done()
:done()
:done()
end
end
-- spawn weight table
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 3)
:wikitext('Spawn Weights')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Tag')
:done()
:tag('th')
:wikitext('Weight')
:done()
:done()
:done()
i = 0
value = nil
repeat
i = i + 1
value = {
tag = tpl_args[string.format('spawn_weight%s_tag', i)],
value = tpl_args[string.format('spawn_weight%s_value', i)],
}
if value.tag then
tbl
:tag('tr')
:tag('td')
:wikitext(i)
:done()
:tag('td')
:wikitext(value.tag)
:done()
:tag('td')
:wikitext(value.value)
:done()
:done()
:done()
end
until value.tag == nil
-- generation weight table
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 3)
:wikitext('Generation Weights')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Tag')
:done()
:tag('th')
:wikitext('Weight')
:done()
:done()
:done()
i = 0
value = nil
repeat
i = i + 1
value = {
tag = tpl_args[string.format('generation_weight%s_tag', i)],
value = tpl_args[string.format('generation_weight%s_value', i)],
}
if value.tag then
tbl
:tag('tr')
:tag('td')
:wikitext(i)
:done()
:tag('td')
:wikitext(value.tag)
:done()
:tag('td')
:wikitext(value.value)
:done()
:done()
:done()
end
until value.tag == nil
-- Sell prices
tbl = container:tag('table')
tbl
:attr('class', 'wikitable sortable')
:tag('tr')
:tag('th')
:attr('colspan', 2)
:wikitext('Modifier sell price')
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('#')
:done()
:tag('th')
:wikitext('Item')
:done()
:done()
:done()
for i, value in ipairs(sell_prices) do
tbl
:tag('tr')
:tag('td')
:wikitext(value.amount)
:done()
:tag('td')
:wikitext(string.format('[[%s]]', value.name))
:done()
:done()
end
-- Generic messages on the page
out = {}
if mw.ustring.find(tpl_args['id'], '_') then
out[#out+1] = frame:expandTemplate{ title = 'Incorrect title', args = { title=tpl_args['id'] } } .. '\n\n\n'
end
if tpl_args['name'] then
out[#out+1] = string.format("'''%s''' is the internal id of modifier '''%s'''.\n", tpl_args['id'], tpl_args['name'])
else
out[#out+1] = string.format("'''%s''' is the internal id of an unnamed modifier.\n", tpl_args['id'], tpl_args['name'])
end
-- Categories
cats = {'Mods'}
-- Done -> output
return tostring(container) .. m_util.misc.add_category(cats) .. '\n' .. table.concat(out)
end
--
-- Template: SMW query mods
--
function p.query_mods(frame)
-- Args
g_args = getArgs(frame, {
parentFirst = true
})
g_frame = m_util.misc.get_frame(frame)
g_args.colspan = 4
local conditions = {}
conditions[#conditions+1] = 'concept'
if g_args.tag then
conditions[#conditions+1] = string.format('[[Has subobject::<q>[[-Has subobject::+]] [[Has spawn weight::>>0]] [[Has tag::%s]]</q>]]', g_args.tag)
end
g_args.header_level = g_args.header_level or 2
-- Fields
local fields = {}
fields[#fields+1] = '?Is mod'
fields[#fields+1] = '?Has name'
fields[#fields+1] = '?Has level requirement'
fields[#fields+1] = '?Has mod group'
fields[#fields+1] = '?Has stat text'
-- parameters
local parameters = {}
parameters.sort = 'Has mod group, '
parameters.limit = 1000 -- lets see
local data = {}
data.header = {
prefix = 'Prefix',
suffix = 'Suffix',
}
local out = {}
for _, v in ipairs({'prefix', 'suffix'}) do
out[#out+1] = string.format('<h%i>%s</h%i>', g_args.header_level, data.header[v], g_args.header_level)
conditions[1] = string.format('[[Concept:Spawnable named %s item mods]]', v)
local query
local results
--
-- Query tags
--
query = {}
query[#query+1] = string.format('[[-Has subobject::<q>%s</q>]]', table.concat(conditions, ' '))
query[#query+1] = '[[Has tag::+]]'
query[#query+1] = '[[Has spawn weight::+]]'
--query[#query+1] = '[[Has spawn weight::>>0]]'
query[#query+1] = '?Has tag'
query[#query+1] = '?Has spawn weight#' -- need native number
query.limit = 1000
query.offset = 0
-- Tag order is very important
query.sort = ', Is tag number'
local tags = {}
-- this works because lua only considers nil to be false >_>
while query.offset do
results = m_util.smw.query(query, g_frame)
query.offset = query.offset + #results
-- terminates the while if enough reuslts have been fetched
if query.offset % 1000 ~= 0 then
query.offset = nil
end
for _, row in ipairs(results) do
local page, _ = string.gsub(row[1], '#_[%x]+', '')
if tags[page] == nil then
tags[page] = {}
end
local text
if tonumber(row['Has spawn weight']) > 0 then
text = '[[File:Yes.png|yes|link=]]'
else
text = '[[File:No.png|no|link=]]'
end
tags[page][#tags[page]+1] = string.format('%s %s', row['Has tag'], text)
end
end
--
-- Query mods
--
query = {}
for _, v in ipairs(conditions) do
query[#query+1] = v
end
for _, v in ipairs(fields) do
query[#query+1] = v
end
for k, v in pairs(parameters) do
query[k] = v
end
results = m_util.smw.query(query, g_frame)
local last = ''
local tbl = ''
for _, row in ipairs(results) do
local current = string.gsub(row['Is mod'], '%d+.*', '%%d.*')
if string.match(last, current) then
h.format_mod(tbl, row, tags[row[1]])
else
out[#out+1] = tostring(tbl)
tbl = h.create_header(row)
h.format_mod(tbl, row, tags[row[1]])
end
last = row['Is mod']
end
-- add the last table
out[#out+1] = tostring(tbl)
end
return table.concat(out, '')
end
function p.get_mod_domain(cargo_query)
--[[
Gets the mod domain based on the item class.
]]
local out = cargo_query
local mod_domains = game.constants.mod.domains
-- Set item class as key and the mod domain as value:
local class_to_domain = {
['Life Flasks']=2,
['Mana Flasks']=2,
['Hybrid Flasks']=2,
['Utility Flasks']=2,
['Critical Utility Flasks']=2,
['Maps']=5,
['Jewel']=11,
['Leaguestones']=13,
['Abyss Jewel']=14,
}
for i,_ in ipairs(out) do
-- Get the domain, if it's not defined in the table assume it's
-- in the item domain.
out[i]['items.domain'] = class_to_domain[out[i]['items.class']] or 1
-- Convert the mod domain number to understandable text:
out[i]['items.domain_text'] = mod_domains[out[i]['items.domain']]['short_lower']
end
return out
end
function p.get_item_tags(frame)
--[[
This function queries for the tags of a specific item.
]]
-- Args
local tpl_args = getArgs(frame, {parentFirst=true})
local frame = m_util.misc.get_frame(frame)
tpl_args.tables = 'items'
tpl_args.fields = 'items.name, items.tags, items.class'
local tbl = {
{tpl_args.page, 'items._pageName = "%s"'},
{tpl_args.item, 'items.name = "%s"'},
}
for _,v in ipairs(tbl) do
if v[1] ~= nil then
condition = string.format(v[2], v[1])
break
end
end
tpl_args.q_where = condition
tpl_args.q_groupBy = 'items._pageID'
tpl_args.q_orderBy = 'items.name'
-- Query mods with cargo:
results = h.cargo_query(tpl_args)
-- -- SMW workaround, remove when module:item2 is ready:
-- local tbl = {
-- {tpl_args.page, '[[%s]]'},
-- {tpl_args.item, '[[Has name::%s]]'},
-- }
-- for _,v in ipairs(tbl) do
-- if v[1] ~= nil then
-- condition = string.format(v[2], v[1])
-- break
-- end
-- end
-- local results = m_util.smw.query(
-- {
-- condition,
-- '?Has name',
-- '?Has tags',
-- '?Has item class'
-- },
-- frame
-- )
-- for i,_ in ipairs(results) do
-- results[i]['items.tags'] = results[i]['Has tags']:gsub('(<MANY>)', ', ')
-- results[i]['items.class'] = results[i]['Has item class']
-- results[i]['items.name'] = results[i]['Has name']
-- results[i]['items._pageName'] = results[i][1]
-- end
-- --
results = p.get_mod_domain(results)
return results
end
function p.header(str)
--[[
This function replace specific numbers with a generic #.
]]
local s = table.concat(m_util.string.split(str, '%(%d+%.*%d*%-%d+%.*%d*%)'), '#')
s = table.concat(m_util.string.split(s, '%d+%.*%d*'), '#')
s = table.concat(m_util.string.split(s, '<br>'), ', ')
return s
end
function p.get_spawn_chance(frame)
--[[
Calculates the spawn chance of a set of mods that all have a
spawn weight.
]]
-- Args
local tpl_args = getArgs(frame, {parentFirst=true})
local frame = m_util.misc.get_frame(frame)
local tbl = tpl_args['tbl']
-- Probabilities affecting the result besides the spawn weight:
local chance_multiplier = tonumber(tpl_args['chance_multiplier']) or 1
local N = 0
for i,_ in ipairs(tbl) do
-- Total number of outcomes.
N = N + tbl[i]['spawn_weights.weight']
end
for i,_ in ipairs(tbl) do
-- Number of ways it can happen:
local n = tbl[i]['spawn_weights.weight']
-- Truncated value:
tbl[i]['spawn_weights.chance'] = string.format(
"%0.2f%%",
n/N * chance_multiplier*100
)
end
return tbl
end
function p.drop_down_table(frame)
--[[
This function queries mods that can spawn on an item. It compares
the item tags and the spawn weight tags. If there's a match and
the spawn weight is larger than zero, then that mod is added to a
drop down list.
To Do
* Misses forsaken masters currently.
* Add a proper expand/collapse toggle for the entire header row so
it reacts together with mw-collapsible.
* Show Mod group in a better way perhaps:
Mod group (expanded)
# to Damage (Collapsed)
3 to Damage
5 to Damage
Examples:
Weapons
p.drop_down_table{item = 'Rusted Hatchet', header = 'One Handed Axes'}
p.drop_down_table{item = 'Stone Axe', header = 'Two Handed Axes'}
Accessories
p.drop_down_table{item = 'Amber Amulet', header = 'Amulets'}
Jewels
p.drop_down_table{item = 'Cobalt Jewel', header = 'Jewels'}
Armour
p.drop_down_table{item = 'Plate Vest', header = 'Armour body armours'}
p.drop_down_table{item = 'Iron Greaves', header = 'Armour boots'}
p.drop_down_table{item = 'Iron Gauntlets', header = 'Armour gloves'}
p.drop_down_table{item = 'Iron Hat', header = 'Armour helmets'}
p.drop_down_table{item = 'Splintered Tower Shield', header = 'Armour shields'}
p.drop_down_table{
item = 'Fishing Rod',
header = 'FISH PLEASE',
item_tags = 'fishing_rod',
extra_fields = 'Has spawn weight, Has spawn chance'
}
= p.drop_down_table{
item = 'Fishing Rod',
item_tags = 'axe, one_hand_weapon, onehand, weapon, default'
}
= p.drop_down_table{
item = 'Vaal Blade',
}
]]
-- Get template args:
local tpl_args = getArgs(frame, {parentFirst=true})
local frame = m_util.misc.get_frame(frame)
-- Get the items tags:
local get_item_tags = p.get_item_tags(tpl_args)[1]
-- For some reason cargo queried item tags, are not comma-space
-- separated.
local item_tags = {}
if tpl_args.item_tags ~= nil then
item_tags = m_util.string.split(tpl_args.item_tags, ', ')
else
item_tags = m_util.string.split(get_item_tags['items.tags'], ',')
end
-- local item_tags = m_util.string.split(
-- tpl_args.item_tags or get_item_tags['items.tags'],
-- ', '
-- )
-- Create drop down lists in these sections and query in these
-- generation types.
local section = {}
section = {
[1] = {
header = i18n.drop_down_table.prefix,
generation_type = 1,
},
[2] = {
header = i18n.drop_down_table.suffix,
generation_type = 2,
},
[3] = {
header = i18n.drop_down_table.corrupted,
generation_type = 5,
chance_multiplier = 1/4, -- See Vaal orb, for the 4 possible events.
},
-- [4] = {
-- header = 'Forsaken masters',
-- generation_type = 'master',
-- },
}
-- Introductory text:
local out = {}
out[#out+1] = string.format(
'==%s== \n',
tpl_args['header'] or table.concat(item_tags, ', ')
)
out[#out+1] = string.format(
'<div style="float: right; text-align:center"><div class="mw-collapsible-collapse-all" style="cursor:pointer;">[%s]</div><hr><div class="mw-collapsible-expand-all" style="cursor:pointer;">[%s]</div></div>',
i18n.drop_down_table.collapse_all,
i18n.drop_down_table.expand_all
)
out[#out+1] = string.format('%s %s.<br><br><br>',
i18n.drop_down_table.table_intro,
f_item_link{page=get_item_tags['items._pageName']}
)
local item_mods = {}
local tableIndex = -1
for _, sctn in ipairs(section) do
local container = mw.html.create('div')
:attr('style', 'vertical-align:top; display:inline-block;')
-- Format the where condition:
generation_type = sctn['generation_type']
local where = {}
for _, item_tag in ipairs(item_tags) do
where[#where+1] = string.format(
'(spawn_weights.tag="%s" AND mods.generation_type=%s AND mods.domain=%s)',
item_tag,
sctn['generation_type'],
get_item_tags['items.domain']
)
end
tpl_args.tables = 'mods, spawn_weights, mod_stats'
tpl_args.fields = 'mods.name, mods.id, mods.required_level, mods.generation_type, mods.domain, mods.mod_group, mods.mod_type, mods.stat_text, mod_stats.id, spawn_weights.tag, spawn_weights.weight, spawn_weights.ordinal'
tpl_args.q_join = 'mods._pageID=spawn_weights._pageID, mods._pageID=mod_stats._pageID'
tpl_args.q_where = table.concat(where, ' OR ')
tpl_args.q_groupBy = 'mods._pageID, spawn_weights.tag, spawn_weights.weight'
tpl_args.q_orderBy = 'mods.generation_type, mods.mod_group, mods.mod_type, mods._pageName, mods.required_level, spawn_weights.ordinal'
local extra_fields = {}
if tpl_args.extra_fields ~= nil then
extra_fields = m_util.string.split(tpl_args.extra_fields, ', ')
tpl_args.fields = string.format(
'%s, %s',
tpl_args.fields,
table.concat(extra_fields, ', ')
)
end
-- Query mods:
results = h.cargo_query(tpl_args)
-- Create own list for spawn weights and group by page name:
local spawn_weights = {}
local results_unique = {}
local hash = {}
for _,v in ipairs(results) do
if spawn_weights[v['mods._pageName']] == nil then
spawn_weights[v['mods._pageName']] = {}
end
local n = #spawn_weights[v['mods._pageName']] or 0
spawn_weights[v['mods._pageName']][n+1] = v
-- Get a sorted list that only has unique page names:
if hash[v['mods._pageName']] ~= true then
results_unique[#results_unique+1] = v
hash[v['mods._pageName']] = true
end
end
if #results_unique > 0 then
item_mods[generation_type] = {}
-- Loop through all the modifiers from the concept pages:
local last
for _, v in ipairs(results_unique) do
local pagename = v['spawn_weights._pageName']
-- Loop through all the modifier tags until they match
-- the item tags:
local j = 0
local tag_match_stop
repeat
j = j+1
local mod_tag = spawn_weights[pagename][j]['spawn_weights.tag']
local mod_tag_weight = tonumber(
spawn_weights[pagename][j]['spawn_weights.weight']
)
-- Loop through the item tags until it matches the
-- spawn weight tag and the mod tag has a value larger than
-- zero:
local y = 0
local tag_match_add = false
repeat
y = y+1
tag_match_stop = ((mod_tag == item_tags[y]) and ((mod_tag_weight or -1) >= 0)) or (spawn_weights[pagename][j] == nil)
tag_match_add = (mod_tag == item_tags[y]) and ((mod_tag_weight or -1) > 0)
until tag_match_stop or y == #item_tags
-- If there's a match then save that mod and other
-- interesting information:
if tag_match_add then
-- Assume that the mod is global then go through
-- all the stat ids and check if any of the
-- stats are local:
local mod_scope = 'Global'
for _, vv in ipairs(spawn_weights[pagename]) do
if vv['mod_stats.id']:find('.*local.*') ~= nil then
mod_scope = 'Local'
end
end
-- Save the matching modifier tag:
local a = #item_mods[generation_type]
item_mods[generation_type][a+1] = spawn_weights[pagename][j]
-- Save other interesting fields:
item_mods[generation_type][a+1]['mods.scope'] = mod_scope
item_mods[generation_type][a+1]['spawn_weight.idx_match'] = j
item_mods[generation_type][a+1]['mods.add'] = tag_match_add
item_mods[generation_type][a+1]['mods.stop'] = tag_match_stop
end
until tag_match_stop
end
-- If the user wants to see the spawn chance then do the
-- calculations and save that result as well:
if tpl_args.spawn_chance ~= nil then
extra_fields[#extra_fields+1] = 'spawn_weights.chance'
item_mods[generation_type] = p.get_spawn_chance{
tbl = item_mods[generation_type],
chance_multiplier = sctn['chance_multiplier']
}
end
-- Create the drop down table with <table></table>:
local headers = container
headers
:tag('h3')
:wikitext(string.format(
'%s',
sctn['header']
)
)
:done()
:done()
-- Loop through and add all matching mods to the <table>.
local tbl, last
for _, rows in ipairs(item_mods[generation_type]) do
-- If the last mod group is different to the current
-- mod group then assume the mod isn't related and start
-- a new drop down list:
if rows['mods.mod_group'] ~= last then
-- Check through all the mods and see if there are
-- multiple mod types within the same mod group:
local count = {}
for _, n in ipairs(item_mods[generation_type]) do
-- If the mod has the same mod group, then add
-- the mod type to the counter. Only unique mod
-- types matter so the number is just a dummy
-- value:
if n['mods.mod_group'] == rows['mods.mod_group'] then
count[n['mods.mod_type']] = 1
end
end
-- Calculate how many unique mod types with the
-- same mod group there are:
number_of_mod_types = 0
for _ in pairs(count) do
number_of_mod_types = number_of_mod_types + 1
end
-- If there are multiple unique mod types with the
-- same mod group then change the style of the drop
-- down list to indicate it:
if number_of_mod_types > 1 then
tbl_caption = string.format(
'%s',
m_util.html.poe_color(
'mod',
'Mod group: ' .. rows['mods.mod_group']
)
)
else
tbl_caption = string.format(
'%s (%s)',
m_util.html.poe_color(
'mod',
p.header(rows['mods.stat_text'])
),
rows['mods.scope']
)
end
-- Add class and style to the <table>:
tableIndex = tableIndex+1
tbl = container:tag('table')
tbl
:attr('class', 'mw-collapsible mw-collapsed')
:attr('style',
'text-align:left; line-height:1.60em; width:810px;'
)
:tag('th')
:attr('class',
string.format(
'mw-customtoggle-%s',
tableIndex
)
)
:attr('style',
'text-align:left; line-height:1.40em; border-bottom:1pt solid dimgrey;'
)
:attr('colspan', '3' .. #extra_fields)
:wikitext(tbl_caption)
:done()
:done()
end
-- If the mod has no name then use the mod id:
local mod_name = rows['mods.name']
if mod_name == '' or mod_name == nil then
mod_name = rows['mods.id']
end
-- Check if there are any extra properties to show in
-- the drop down list and then add a cell for that,
-- add this node at the end of the table row:
local td = mw.html.create('td')
if extra_fields ~= nil then
for _, extra_field in ipairs(extra_fields) do
td
:attr('width', '*')
:wikitext(string.format(
'%s: %s ',
extra_field,
rows[extra_field]
)
)
:done()
end
end
-- Add a table row with the interesting properties that
-- modifier has:
tbl
:tag('tr')
:attr('class', 'mw-collapsible mw-collapsed')
:attr(
'id',
string.format(
'mw-customcollapsible-%s',
tableIndex
)
)
:tag('td')
:attr('width', '160')
:wikitext(
string.format(
' [[%s|%s]]',
rows['mods._pageName'],
mod_name:gsub('%s', ' ')
)
)
:done()
:tag('td')
:attr('width', '1')
:wikitext(
string.format(
'%s %s',
game.level_requirement['short_upper']:gsub('%s', ' '),
rows['mods.required_level']
)
)
:done()
:tag('td')
:attr('width', '*')
:wikitext(
string.format(
'%s',
m_util.html.poe_color(
'mod',
rows['mods.stat_text']:gsub('<br>', ', ')
)
)
)
:done()
:node(td)
:done()
:done()
-- Save the last mod group for later comparison:
last = rows['mods.mod_group']
end
end
out[#out+1] = tostring(container)
end
return table.concat(out,'')
end
return p