Path of Exile Wiki

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

ПОДРОБНЕЕ

Path of Exile Wiki
Нет описания правки
(Отмена правки 518514, сделанной Ruba159753 (обсуждение))
Метка: отмена
Строка 1: Строка 1:
-------------------------------------------------------------------------------
+
-- ----------------------------------------------------------------------------
--
+
-- Imports
 
-- ----------------------------------------------------------------------------
-- Module:Item acquisition
 
--
 
-- This module implements Template:Item acquisition.
 
-------------------------------------------------------------------------------
 
   
require('Module:No globals')
 
 
local getArgs = require('Module:Arguments').getArgs
 
local getArgs = require('Module:Arguments').getArgs
 
local m_util = require('Module:Util')
 
local m_util = require('Module:Util')
Строка 14: Строка 10:
 
local m_game = mw.loadData('Module:Game')
 
local m_game = mw.loadData('Module:Game')
   
 
local f_item_link = require('Module:Item link').item_link
-- Should we use the sandbox version of our submodules?
 
  +
local f_message_box = require('Module:Message box').main
local use_sandbox = m_util.misc.maybe_sandbox('Item acquisition')
 
   
  +
-- ----------------------------------------------------------------------------
-- Lazy loading
 
  +
-- Strings
local f_item_link -- require('Module:Item link').item_link
 
  +
-- ----------------------------------------------------------------------------
  +
-- 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.
 
--
  +
-- TODO: Maybe move this out to a separate sub-page module
 
local i18n = {
  +
acquisition = {
  +
header = 'Получение предмета',
  +
link = '[[File:Questionmark.png|right|24px|link=Path_of_Exile_Wiki:Как_редактировать_получение_предмета]]',
 
  +
drop_leagues = 'После изменений [[Версия 3.14.0#Баланс уникальных предметов|версии 3.14.0]] неясно, какие именно [[Предметы с ограниченным доступом#Предметы, относящиеся к конкретной лиге|предметы, относящиеся к конкретной лиге]], были добавлены в основной список выпадающих предметов. Если этот предмет не существует в основном списке выпадающих предметов, он может выпадать только в областях с активным флагом лиги %s. Предметы, относящиеся к конкретной лиге, также могут быть приобретены [[Предметы с ограниченным доступом#Предметы, относящиеся к конкретной лиге|другими способами]].',
  +
drop_disabled = 'Этот предмет не выпадает.',
  +
area_header = 'Ограничения на получение в областях',
  +
area_legacy_header = 'Ограничения на получение в устаревших областях',
  +
area = 'Этот предмет можно получить в следующих областях:',
  +
monster = 'Этот предмет может выпасть из следующих монстров:',
  +
monster_header = 'Ограничения на получение из монстров',
 
  +
upgraded_from_header = 'Способы получения',
  +
upgraded_from = 'Этот предмет можно получить следующими способами:',
 
  +
ingredient_header = 'Используется для получения',
  +
ingredient = 'Этот предмет используется для получения следующих предметов:',
 
},
 
  +
upgraded_from_table = {
  +
outcome = 'Результат',
  +
ingredient = 'Ингредиент',
  +
ingredient_amount = 'Кол-во',
  +
ingredient_notes = 'Примечания<br>по ингредиентам',
  +
recipe_notes = 'Общие примечания',
 
type = 'Тип',
  +
automatic = m_util.html.abbr('Автоматически', 'Автоматически добавлено шаблоном на основе характеристик предмета.'),
  +
manual = m_util.html.abbr('Вручную', 'Вручную добавлено на вики-страницу предмета.'),
  +
old_data = m_util.html.abbr('Устаревшие данные', 'Устаревшие данные - пожалуйста, сделайте пустое редактирование вики-страницы предмета.'),
 
},
 
  +
quest_reward = {
  +
quest_rewards_header = 'Награда за задание',
  +
quest_rewards_intro = 'Дается в качестве награды за следующие задания:',
  +
vendor_rewards_header = 'Награда торговца',
  +
vendor_rewards_intro = 'Можно приобрести у перечисленных торговцев после выполнения следующих заданий:',
 
},
  +
}
   
  +
-- ----------------------------------------------------------------------------
-- The cfg table contains all localisable strings and configuration, to make it
 
  +
-- Globals
-- easier to port this module to another wiki.
 
  +
-- ----------------------------------------------------------------------------
local cfg = use_sandbox and mw.loadData('Module:Item acquisition/config/sandbox') or mw.loadData('Module:Item acquisition/config')
 
   
local i18n = cfg.i18n
+
local c = {}
  +
  +
c.MAX_ITEMS = 100
  +
c.COLLAPSE_TABLE = 30
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
Строка 31: Строка 76:
   
 
local h = {}
 
local h = {}
 
-- Lazy loading for Module:Item link
 
function h.item_link(args)
 
if not f_item_link then
 
f_item_link = require('Module:Item link').item_link
 
end
 
return f_item_link(args)
 
end
 
 
 
function h.head(str, level)
 
function h.head(str, level)
 
local head = mw.html.create('h' .. (level or 3))
 
local head = mw.html.create('h' .. (level or 3))
Строка 46: Строка 82:
 
end
 
end
   
function h.fetch_recipes(where_set, where_group)
+
function h.fetch_upgraded_from_sets(where_set, where_group)
 
if where_set == "" or where_group == "" then
 
if where_set == "" or where_group == "" then
 
return {}, {}
 
return {}, {}
Строка 53: Строка 89:
 
local sets = {}
 
local sets = {}
 
local results = m_cargo.query(
 
local results = m_cargo.query(
{'acquisition_recipes'},
+
{'upgraded_from_sets'},
 
{
 
{
'acquisition_recipes._pageName',
+
'upgraded_from_sets._pageName',
'acquisition_recipes.recipe_id',
+
'upgraded_from_sets.set_id',
'acquisition_recipes.result_amount',
+
'upgraded_from_sets.text',
'acquisition_recipes.description',
+
'upgraded_from_sets.automatic',
'acquisition_recipes.automatic',
 
 
},
 
},
 
{
 
{
Строка 68: Строка 103:
 
for _, row in ipairs(results) do
 
for _, row in ipairs(results) do
 
row.groups = {}
 
row.groups = {}
sets[row['acquisition_recipes._pageName'] .. tonumber(row['acquisition_recipes.recipe_id'])] = row
+
sets[row['upgraded_from_sets._pageName'] .. tonumber(row['upgraded_from_sets.set_id'])] = row
 
end
 
end
 
 
 
results = m_cargo.query(
 
results = m_cargo.query(
{'acquisition_recipe_parts'},
+
{'upgraded_from_groups'},
 
{
 
{
'acquisition_recipe_parts._pageName',
+
'upgraded_from_groups._pageName',
'acquisition_recipe_parts.recipe_id',
+
'upgraded_from_groups.set_id',
'acquisition_recipe_parts.part_id',
+
'upgraded_from_groups.group_id',
'acquisition_recipe_parts.notes',
+
'upgraded_from_groups.notes',
'acquisition_recipe_parts.amount',
+
'upgraded_from_groups.amount',
'acquisition_recipe_parts.item_name',
+
'upgraded_from_groups.item_name',
'acquisition_recipe_parts.item_page',
+
'upgraded_from_groups.item_page',
 
},
 
},
 
{
 
{
Строка 88: Строка 123:
 
 
 
for _, row in ipairs(results) do
 
for _, row in ipairs(results) do
sets[row['acquisition_recipe_parts._pageName'] .. tonumber(row['acquisition_recipe_parts.recipe_id'])].groups[tonumber(row['acquisition_recipe_parts.part_id'])] = row
+
sets[row['upgraded_from_groups._pageName'] .. tonumber(row['upgraded_from_groups.set_id'])].groups[tonumber(row['upgraded_from_groups.group_id'])] = row
 
end
 
end
 
 
Строка 97: Строка 132:
 
 
 
table.sort(sets_sort, function (a, b)
 
table.sort(sets_sort, function (a, b)
return tonumber(sets[a]['acquisition_recipes.recipe_id']) < tonumber(sets[b]['acquisition_recipes.recipe_id'])
+
return tonumber(sets[a]['upgraded_from_sets.set_id']) < tonumber(sets[b]['upgraded_from_sets.set_id'])
 
end)
 
end)
 
 
Строка 103: Строка 138:
 
end
 
end
   
function h.recipe_table(tpl_args, item, sets, set_order, data_type, out, item_pages)
+
function h.upgraded_from_table(tpl_args, sets, set_order, data_type, out, item_pages)
 
 
 
-- Count the number of item pages:
 
-- Count the number of item pages:
Строка 124: Строка 159:
 
end
 
end
 
local set = sets[set_key]
 
local set = sets[set_key]
if set['acquisition_recipes.description'] ~= nil then
+
if set['upgraded_from_sets.text'] ~= nil then
 
set_notes = true
 
set_notes = true
 
end
 
end
Строка 130: Строка 165:
 
if #set.groups > 0 then
 
if #set.groups > 0 then
 
for i, group in ipairs(set.groups) do
 
for i, group in ipairs(set.groups) do
if group['acquisition_recipe_parts.notes'] ~= nil then
+
if group['upgraded_from_groups.notes'] ~= nil then
 
group_notes = true
 
group_notes = true
 
break
 
break
Строка 142: Строка 177:
 
-- sorting will mess up the table because of the rowspawns
 
-- sorting will mess up the table because of the rowspawns
 
local table_class = 'wikitable mw-collapsible mw-expanded'
 
local table_class = 'wikitable mw-collapsible mw-expanded'
if item_pages_count > cfg.COLLAPSE_TABLE then
+
if item_pages_count > c.COLLAPSE_TABLE then
 
table_class = 'wikitable mw-collapsible mw-collapsed'
 
table_class = 'wikitable mw-collapsible mw-collapsed'
 
end
 
end
Строка 154: Строка 189:
 
tr
 
tr
 
:tag('th')
 
:tag('th')
:wikitext(i18n.recipe_table.outcome)
+
:wikitext(i18n.upgraded_from_table.outcome)
 
end
 
end
 
 
 
tr
 
tr
 
:tag('th')
 
:tag('th')
:wikitext(i18n.recipe_table.ingredient_amount)
+
:wikitext(i18n.upgraded_from_table.ingredient_amount)
 
:done()
 
:done()
 
:tag('th')
 
:tag('th')
:wikitext(i18n.recipe_table.ingredient)
+
:wikitext(i18n.upgraded_from_table.ingredient)
 
:done()
 
:done()
 
if group_notes then
 
if group_notes then
 
tr
 
tr
 
:tag('th')
 
:tag('th')
:wikitext(i18n.recipe_table.ingredient_notes)
+
:wikitext(i18n.upgraded_from_table.ingredient_notes)
 
:done()
 
:done()
 
end
 
end
Строка 173: Строка 208:
 
tr
 
tr
 
:tag('th')
 
:tag('th')
:wikitext(i18n.recipe_table.recipe_notes)
+
:wikitext(i18n.upgraded_from_table.recipe_notes)
 
:done()
 
:done()
 
end
 
end
 
tr
 
tr
 
:tag('th')
 
:tag('th')
:wikitext(i18n.recipe_table.type)
+
:wikitext(i18n.upgraded_from_table.type)
 
:done()
 
:done()
 
--
 
--
Строка 193: Строка 228:
 
if data_type == 'ingredient' then
 
if data_type == 'ingredient' then
 
local str
 
local str
if tpl_args.no_link == nil and item_pages_count < cfg.MAX_ITEMS then
+
if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
local item_data = item_pages[set['acquisition_recipes._pageName']][1]
+
local item_data = item_pages[set['upgraded_from_sets._pageName']][1]
str = h.item_link{page=set['acquisition_recipes._pageName'], name=item_data['items.name'], inventory_icon=item_data['items.inventory_icon'] or '', html=item_data['items.html'] or '', skip_query=true}
+
str = f_item_link{page=set['upgraded_from_sets._pageName'], name=item_data['items.name'], inventory_icon=item_data['items.inventory_icon'] or '', html=item_data['items.html'] or '', skip_query=true}
 
else
 
else
str = string.format('[[%s]]', set['acquisition_recipes._pageName'])
+
str = string.format('[[%s]]', set['upgraded_from_sets._pageName'])
 
end
 
end
 
 
Строка 215: Строка 250:
 
end
 
end
 
local str
 
local str
if tpl_args.no_link == nil and item_pages_count < cfg.MAX_ITEMS then
+
if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
local item_data = item_pages[group['acquisition_recipe_parts.item_page']][1]
+
local item_data = item_pages[group['upgraded_from_groups.item_page']][1]
str = h.item_link{
+
str = f_item_link{
page=group['acquisition_recipe_parts.item_page'],
+
page=group['upgraded_from_groups.item_page'],
 
name=item_data['items.name'],
 
name=item_data['items.name'],
 
inventory_icon=item_data['items.inventory_icon'] or '',
 
inventory_icon=item_data['items.inventory_icon'] or '',
Строка 225: Строка 260:
 
}
 
}
 
else
 
else
str = string.format('[[%s]]', group['acquisition_recipe_parts.item_page'])
+
str = string.format('[[%s]]', group['upgraded_from_groups.item_page'])
 
end
 
end
 
 
Строка 231: Строка 266:
 
:tag('td')
 
:tag('td')
 
:attr('data-sort-type', 'number')
 
:attr('data-sort-type', 'number')
:wikitext(group['acquisition_recipe_parts.amount'])
+
:wikitext(group['upgraded_from_groups.amount'])
 
:done()
 
:done()
 
:tag('td')
 
:tag('td')
Строка 238: Строка 273:
 
 
 
if group_notes then
 
if group_notes then
if group['acquisition_recipe_parts.notes'] then
+
if group['upgraded_from_groups.notes'] then
 
tr2
 
tr2
 
:tag('td')
 
:tag('td')
:wikitext(group['acquisition_recipe_parts.notes'])
+
:wikitext(group['upgraded_from_groups.notes'])
 
else
 
else
 
tr2:node(m_util.html.td.na{as_tag=true})
 
tr2:node(m_util.html.td.na{as_tag=true})
Строка 249: Строка 284:
 
 
 
if set_notes then
 
if set_notes then
if set['acquisition_recipes.description'] then
+
if set['upgraded_from_sets.text'] then
 
tr
 
tr
 
:tag('td')
 
:tag('td')
 
:attr('rowspan', #set.groups)
 
:attr('rowspan', #set.groups)
:wikitext(set['acquisition_recipes.description'])
+
:wikitext(set['upgraded_from_sets.text'])
 
else
 
else
 
tr
 
tr
Строка 265: Строка 300:
 
 
 
local t
 
local t
if set['acquisition_recipes.automatic'] == nil then
+
if set['upgraded_from_sets.automatic'] == nil then
t = i18n.recipe_table.old_data
+
t = i18n.upgraded_from_table.old_data
elseif set['acquisition_recipes.automatic'] == '1' then
+
elseif set['upgraded_from_sets.automatic'] == '1' then
t = i18n.recipe_table.automatic
+
t = i18n.upgraded_from_table.automatic
 
else
 
else
t = i18n.recipe_table.manual
+
t = i18n.upgraded_from_table.manual
 
end
 
end
 
 
Строка 286: Строка 321:
 
 
 
if data_type == 'ingredient' then
 
if data_type == 'ingredient' then
out[#out+1] = h.head(i18n.acquisition.recipe_usage_heading)
+
out[#out+1] = h.head(i18n.acquisition.ingredient_header)
out[#out+1] = string.format(i18n.acquisition.recipe_usage_text, item['items.name'])
+
out[#out+1] = i18n.acquisition.ingredient
 
else
 
else
out[#out+1] = h.head(i18n.acquisition.recipes_heading)
+
out[#out+1] = h.head(i18n.acquisition.upgraded_from_header)
out[#out+1] = string.format(i18n.acquisition.recipes_text, item['items.name'])
+
out[#out+1] = i18n.acquisition.upgraded_from
 
end
 
end
 
out[#out+1] = '<br>'
 
out[#out+1] = '<br>'
Строка 366: Строка 401:
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
  +
-- Templates
-- Exported functions
 
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
   
Строка 383: Строка 418:
 
= p.item_acquisition{page='The Rite of Elements'}
 
= p.item_acquisition{page='The Rite of Elements'}
 
]]
 
]]
  +
   
 
-- Get args
 
-- Get args
Строка 389: Строка 425:
 
})
 
})
 
frame = m_util.misc.get_frame(frame)
 
frame = m_util.misc.get_frame(frame)
 
 
 
tpl_args.page = tpl_args.page or tostring(mw.title.getCurrentTitle())
 
 
local out = {}
 
local out = {}
 
local results
 
local query
 
 
out[#out+1] = tpl_args.acquisition_insert
 
out[#out+1] = tpl_args.acquisition_insert
 
 
 
-- fetch general item drop information that is used in multiple places in a
 
-- fetch general item drop information that is used in multiple places in a
 
-- single query to reduce performance hit
 
-- single query to reduce performance hit
local tables = {'items'}
+
local item_data = m_cargo.query(
local fields = {
+
{'items'},
'items._pageName',
+
{
'items.name',
+
'items.drop_text',
'items.rarity_id',
+
'items.drop_leagues',
'items.drop_text',
+
'items.drop_areas__full',
'items.acquisition_tags',
+
'items.drop_monsters',
'items.drop_areas__full',
+
'items.drop_enabled',
'items.drop_monsters',
+
},
'items.drop_enabled',
+
{
'items.is_drop_restricted',
+
where=string.format('items._pageName="%s"', tpl_args.page),
 
limit=1,
}
 
local query = {
+
}
limit = 1,
+
)
}
 
if tpl_args.page then
 
-- Join with _pageData in order to check for page redirect
 
tables[#tables+1] = '_pageData'
 
fields[#fields+1] = '_pageData._pageNameOrRedirect'
 
query.where = string.format(
 
'_pageData._pageName="%s"',
 
tpl_args.page
 
)
 
query.join = 'items._pageName = _pageData._pageNameOrRedirect'
 
else
 
query.where = string.format(
 
'items._pageName="%s"',
 
tostring(mw.title.getCurrentTitle())
 
)
 
end
 
local item_data = m_cargo.query(tables, fields, query)
 
 
if #item_data > 0 then
 
if #item_data > 0 then
 
item_data = item_data[1]
 
item_data = item_data[1]
Строка 431: Строка 455:
 
 
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
-- General drop restrictions
+
-- Drop disabled item
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
 
local drop_enabled = m_util.cast.boolean(item_data['items.drop_enabled'])
 
local drop_enabled = m_util.cast.boolean(item_data['items.drop_enabled'])
local drop_restricted = m_util.cast.boolean(item_data['items.is_drop_restricted'])
 
local is_unique = item_data['items.rarity_id'] == 'unique'
 
 
if not drop_enabled then
 
if not drop_enabled then
out[#out+1] = string.format(i18n.acquisition.drop_disabled, item_data['items.name'])
+
out[#out+1] = i18n.acquisition.drop_disabled
 
out[#out+1] = ' '
elseif drop_restricted then
 
  +
end
out[#out+1] = string.format(i18n.acquisition.drop_restricted, item_data['items.name'])
 
if is_unique then
 
out[#out+1] = ' '
 
out[#out+1] = i18n.acquisition.cannot_be_chanced
 
end
 
else
 
if not item_data['items.drop_areas__full'] then
 
out[#out+1] = string.format(i18n.acquisition.drop_anywhere, item_data['items.name'])
 
end
 
if is_unique then
 
out[#out+1] = ' '
 
out[#out+1] = i18n.acquisition.can_be_chanced
 
end
 
end
 
 
 
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
-- League-specific
+
-- Drop restrictions by league
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
 
if item_data['items.drop_leagues'] and drop_enabled then
local acquisition_tags
 
if item_data['items.acquisition_tags'] then
+
local text = string.format(i18n.acquisition.drop_leagues, item_data['items.drop_leagues'])
  +
local mbox = f_message_box('ambox', {
acquisition_tags = m_util.string.split(item_data['items.acquisition_tags'], ',')
 
  +
type = 'notice',
else
 
acquisition_tags = {}
+
text = tostring(text),
end
+
})
 
out[#out+1] = '\n\n'
if m_util.table.contains(acquisition_tags, 'league-specific') and drop_enabled and is_unique then
 
 
out[#out+1] = mbox
 
out[#out+1] = '\n\n'
 
out[#out+1] = '\n\n'
out[#out+1] = string.format(i18n.acquisition.league_specific_unique, item_data['items.name'])
 
 
end
 
end
 
 
Строка 472: Строка 481:
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
 
if item_data['items.drop_text'] and drop_enabled then
 
if item_data['items.drop_text'] and drop_enabled then
out[#out+1] = '\n\n'
 
 
out[#out+1] = item_data['items.drop_text']
 
out[#out+1] = item_data['items.drop_text']
 
end
 
end
Строка 546: Строка 554:
 
ul:tag('li')
 
ul:tag('li')
 
:wikitext(string.format('[[%s|%s]]', row['areas.main_page'] or row['areas._pageName'], row['areas.name']))
 
:wikitext(string.format('[[%s|%s]]', row['areas.main_page'] or row['areas._pageName'], row['areas.name']))
end
+
end
 
out[#out+1] = h.head(query_set.header)
 
out[#out+1] = h.head(query_set.header)
 
out[#out+1] = i18n.acquisition.area
 
out[#out+1] = i18n.acquisition.area
Строка 592: Строка 600:
 
row['monsters.name']
 
row['monsters.name']
 
))
 
))
end
+
end
 
out[#out+1] = h.head(i18n.acquisition.monster_header)
 
out[#out+1] = h.head(i18n.acquisition.monster_header)
 
out[#out+1] = i18n.acquisition.monster
 
out[#out+1] = i18n.acquisition.monster
Строка 601: Строка 609:
 
 
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
  +
-- Vendor recipes/upgrades handling
-- Recipes section
 
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
 
 
 
--
 
--
-- Query recipe data
+
-- Query set data
 
--
 
--
local obtained_sets, obtained_sets_order = h.fetch_recipes(
+
local obtained_sets, obtained_sets_order = h.fetch_upgraded_from_sets(
string.format('acquisition_recipes._pageName="%s"', item_data['items._pageName']),
+
string.format('upgraded_from_sets._pageName="%s"', tpl_args.page),
string.format('acquisition_recipe_parts._pageName="%s"', item_data['items._pageName'])
+
string.format('upgraded_from_groups._pageName="%s"', tpl_args.page)
 
)
 
)
 
 
  +
results = m_cargo.query(
-- Find recipes that item is used in
 
  +
{'upgraded_from_groups'},
local results = m_cargo.query(
 
{'acquisition_recipe_parts'},
 
 
{
 
{
'_pageID',
+
'upgraded_from_groups._pageID',
'recipe_id',
+
'upgraded_from_groups.set_id',
 
},
 
},
 
{
 
{
where = string.format('item_page="%s"', item_data['items._pageName']),
+
where=string.format('upgraded_from_groups.item_page="%s"', tpl_args.page),
groupBy = '_pageID, recipe_id',
+
-- only need one result set for the where clause
  +
groupBy='upgraded_from_groups._pageID, upgraded_from_groups.set_id',
 
}
 
}
 
)
 
)
  +
local where = {sets={}, groups={}}
 
 
for key, data in pairs(where) do
local recipes = {}
 
  +
for _, row in ipairs(results) do
local parts = {}
 
  +
data[#data+1] = string.format('upgraded_from_%s.set_id="%s" AND upgraded_from_%s._pageID="%s"', key, row['upgraded_from_groups.set_id'], key, row['upgraded_from_groups._pageID'])
for _, row in ipairs(results) do
 
 
end
recipes[#recipes+1] = string.format('acquisition_recipes.recipe_id="%s" AND acquisition_recipes._pageID="%s"', row.recipe_id, row._pageID)
 
 
where[key] = table.concat(data, ' OR ')
parts[#parts+1] = string.format('acquisition_recipe_parts.recipe_id="%s" AND acquisition_recipe_parts._pageID="%s"', row.recipe_id, row._pageID)
 
 
end
 
end
 
local ingredient_sets, ingredient_sets_order = h.fetch_upgraded_from_sets(where.sets, where.groups)
parts = table.concat(parts, ' OR ')
 
recipes = table.concat(recipes, ' OR ')
 
 
local ingredient_sets, ingredient_sets_order = h.fetch_recipes(recipes, parts)
 
 
--
 
--
 
-- Query bulk item info for item linking
 
-- Query bulk item info for item linking
Строка 643: Строка 648:
 
local set = set_data[1][set_key]
 
local set = set_data[1][set_key]
 
for _, group in ipairs(set.groups) do
 
for _, group in ipairs(set.groups) do
item_pages.assoc[group['acquisition_recipe_parts.item_page']] = true
+
item_pages.assoc[group['upgraded_from_groups.item_page']] = true
 
end
 
end
item_pages.assoc[set['acquisition_recipes._pageName']] = true
+
item_pages.assoc[set['upgraded_from_sets._pageName']] = true
 
end
 
end
 
end
 
end
Строка 653: Строка 658:
 
end
 
end
 
 
if #item_pages < cfg.MAX_ITEMS then
+
if #item_pages < c.MAX_ITEMS then
 
item_pages = m_cargo.map_results_to_id{
 
item_pages = m_cargo.map_results_to_id{
 
results=m_cargo.array_query{
 
results=m_cargo.array_query{
Строка 673: Строка 678:
 
--
 
--
 
 
h.recipe_table(tpl_args, item_data, obtained_sets, obtained_sets_order, 'obtained', out, item_pages)
+
h.upgraded_from_table(tpl_args, obtained_sets, obtained_sets_order, 'obtained', out, item_pages)
 
 
 
--
 
--
Строка 679: Строка 684:
 
--
 
--
 
 
h.recipe_table(tpl_args, item_data, ingredient_sets, ingredient_sets_order, 'ingredient', out, item_pages)
+
h.upgraded_from_table(tpl_args, ingredient_sets, ingredient_sets_order, 'ingredient', out, item_pages)
 
 
 
out[#out+1] = tpl_args.ingredient_append
 
out[#out+1] = tpl_args.ingredient_append
Строка 698: Строка 703:
 
},
 
},
 
{
 
{
where=string.format('quest_rewards._pageName="%s"', item_data['items._pageName']),
+
where=string.format('quest_rewards._pageName="%s"', tpl_args.page),
 
orderBy='quest_rewards.act ASC, quest_rewards.quest_id ASC',
 
orderBy='quest_rewards.act ASC, quest_rewards.quest_id ASC',
 
}
 
}
Строка 713: Строка 718:
 
},
 
},
 
{
 
{
where=string.format('vendor_rewards._pageName="%s"', item_data['items._pageName']),
+
where=string.format('vendor_rewards._pageName="%s"', tpl_args.page),
 
orderBy='vendor_rewards.act ASC, vendor_rewards.quest_id ASC',
 
orderBy='vendor_rewards.act ASC, vendor_rewards.quest_id ASC',
 
}
 
}
Строка 727: Строка 732:
 
return tostring(head) .. table.concat(out)
 
return tostring(head) .. table.concat(out)
 
end
 
end
  +
  +
-- ----------------------------------------------------------------------------
  +
-- Return
  +
-- ----------------------------------------------------------------------------
   
 
return p
 
return p

Версия от 15:44, 20 октября 2021

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

Предоставляет функциональные возможности для отображения получения предмета.

Описание

Шаблоны Item

Модуль:Item2

Все шаблоны, определенные в Модуль:Item2:

Модуль:Item table

Все шаблоны, определенные в Модуль:Item table:

Модуль:Item link

Все шаблоны, определенные в Модуль:Item link:

Модуль:Item acquisition

-- ----------------------------------------------------------------------------
-- Imports
-- ----------------------------------------------------------------------------

local getArgs = require('Module:Arguments').getArgs
local m_util = require('Module:Util')
local m_cargo = require('Module:Cargo')
local m_quest_reward = require('Module:Quest reward')._shared

local m_game = mw.loadData('Module:Game')

local f_item_link = require('Module:Item link').item_link
local f_message_box = require('Module:Message box').main

-- ----------------------------------------------------------------------------
-- 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.
--
-- TODO: Maybe move this out to a separate sub-page module
local i18n = {
    acquisition = {
        header = 'Получение предмета',
        link = '[[File:Questionmark.png|right|24px|link=Path_of_Exile_Wiki:Как_редактировать_получение_предмета]]',
        
        drop_leagues = 'После изменений [[Версия 3.14.0#Баланс уникальных предметов|версии 3.14.0]] неясно, какие именно [[Предметы с ограниченным доступом#Предметы, относящиеся к конкретной лиге|предметы, относящиеся к конкретной лиге]], были добавлены в основной список выпадающих предметов. Если этот предмет не существует в основном списке выпадающих предметов, он может выпадать только в областях с активным флагом лиги %s. Предметы, относящиеся к конкретной лиге, также могут быть приобретены [[Предметы с ограниченным доступом#Предметы, относящиеся к конкретной лиге|другими способами]].',
        drop_disabled = 'Этот предмет не выпадает.',
        area_header = 'Ограничения на получение в областях',
        area_legacy_header = 'Ограничения на получение в устаревших областях',
        area = 'Этот предмет можно получить в следующих областях:',
        monster = 'Этот предмет может выпасть из следующих монстров:',
        monster_header = 'Ограничения на получение из монстров',
        
        upgraded_from_header = 'Способы получения',
        upgraded_from = 'Этот предмет можно получить следующими способами:',
        
        ingredient_header = 'Используется для получения',
        ingredient = 'Этот предмет используется для получения следующих предметов:',
    },
    
    upgraded_from_table = {
        outcome = 'Результат',
        ingredient = 'Ингредиент',
        ingredient_amount = 'Кол-во',
        ingredient_notes = 'Примечания<br>по ингредиентам',
        recipe_notes = 'Общие примечания',
        type = 'Тип',
        automatic = m_util.html.abbr('Автоматически', 'Автоматически добавлено шаблоном на основе характеристик предмета.'),
        manual = m_util.html.abbr('Вручную', 'Вручную добавлено на вики-страницу предмета.'),
        old_data = m_util.html.abbr('Устаревшие данные', 'Устаревшие данные - пожалуйста, сделайте пустое редактирование вики-страницы предмета.'),
    },
    
    quest_reward = {
        quest_rewards_header = 'Награда за задание',
        quest_rewards_intro = 'Дается в качестве награды за следующие задания:',
        vendor_rewards_header = 'Награда торговца',
        vendor_rewards_intro = 'Можно приобрести у перечисленных торговцев после выполнения следующих заданий:',
    },
}

-- ----------------------------------------------------------------------------
-- Globals
-- ----------------------------------------------------------------------------

local c = {}

c.MAX_ITEMS = 100
c.COLLAPSE_TABLE = 30

-- ----------------------------------------------------------------------------
-- Helper functions
-- ----------------------------------------------------------------------------

local h = {}
function h.head(str, level)
    local head = mw.html.create('h' .. (level or 3))
    head:wikitext(str)
    return tostring(head)
end

function h.fetch_upgraded_from_sets(where_set, where_group)
    if where_set == "" or where_group == "" then
        return {}, {}
    end
    
    local sets = {}
    local results = m_cargo.query(
        {'upgraded_from_sets'},
        {
            'upgraded_from_sets._pageName',
            'upgraded_from_sets.set_id',
            'upgraded_from_sets.text',
            'upgraded_from_sets.automatic',
        },
        {
            where=where_set,
        }
    )
    
    for _, row in ipairs(results) do
        row.groups = {}
        sets[row['upgraded_from_sets._pageName'] .. tonumber(row['upgraded_from_sets.set_id'])] = row
    end
    
    results = m_cargo.query(
        {'upgraded_from_groups'},
        {
            'upgraded_from_groups._pageName',
            'upgraded_from_groups.set_id',
            'upgraded_from_groups.group_id',
            'upgraded_from_groups.notes',
            'upgraded_from_groups.amount',
            'upgraded_from_groups.item_name',
            'upgraded_from_groups.item_page',
        },
        {
            where=where_group,
        }
    )
    
    for _, row in ipairs(results) do
        sets[row['upgraded_from_groups._pageName'] .. tonumber(row['upgraded_from_groups.set_id'])].groups[tonumber(row['upgraded_from_groups.group_id'])] = row
    end
    
    local sets_sort = {}
    for key, _ in pairs(sets) do
        sets_sort[#sets_sort+1] = key
    end
    
    table.sort(sets_sort, function (a, b)
        return tonumber(sets[a]['upgraded_from_sets.set_id']) < tonumber(sets[b]['upgraded_from_sets.set_id'])
    end)
    
    return sets, sets_sort
end

function h.upgraded_from_table(tpl_args, sets, set_order, data_type, out, item_pages)
    
    -- Count the number of item pages:
    local item_pages_count = 0
    for _,__ in pairs(item_pages) do 
        item_pages_count = item_pages_count + 1
    end
    
    -- Avoid creating headers only when no data is given
    if #set_order <= 0 then
        return
    end
    
    -- Prevent showing either group or set notes when no rows have any to save a bit of vertical space
    local set_notes = false
    local group_notes = false
    for _, set_key in ipairs(set_order) do
        if set_notes and group_notes then
            break
        end
        local set = sets[set_key]
        if set['upgraded_from_sets.text'] ~= nil then
            set_notes = true
        end
        
        if #set.groups > 0 then
            for i, group in ipairs(set.groups) do
                if group['upgraded_from_groups.notes'] ~= nil then
                    group_notes = true
                    break
                end
            end
        end
    end
    
    local tbl = mw.html.create('table')
    
    -- sorting will mess up the table because of the rowspawns
    local table_class = 'wikitable mw-collapsible mw-expanded'
    if item_pages_count > c.COLLAPSE_TABLE then
        table_class = 'wikitable mw-collapsible mw-collapsed'
    end
    tbl:attr('class', table_class)
    
    --
    -- Header
    -- 
    local tr = tbl:tag('tr')
    if data_type == 'ingredient' then
        tr
            :tag('th')
                :wikitext(i18n.upgraded_from_table.outcome)
    end
    
    tr
        :tag('th')
            :wikitext(i18n.upgraded_from_table.ingredient_amount)
            :done()
        :tag('th')
            :wikitext(i18n.upgraded_from_table.ingredient)
            :done()
    if group_notes then
        tr
            :tag('th')
                :wikitext(i18n.upgraded_from_table.ingredient_notes)
                :done()
    end
    if set_notes then
         tr
            :tag('th')
                :wikitext(i18n.upgraded_from_table.recipe_notes)
                :done()
    end
    tr
        :tag('th')
            :wikitext(i18n.upgraded_from_table.type)
            :done()
    --
    -- Rows
    --
    
    for _, set_key in ipairs(set_order) do
        local set = sets[set_key]
        
        if #set.groups > 0 then
            tr = tbl:tag('tr')
            tr:attr('class', 'upgraded-from-set')
            
            if data_type == 'ingredient' then
                local str
                if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
                    local item_data = item_pages[set['upgraded_from_sets._pageName']][1]
                    str = f_item_link{page=set['upgraded_from_sets._pageName'], name=item_data['items.name'], inventory_icon=item_data['items.inventory_icon'] or '', html=item_data['items.html'] or '', skip_query=true}
                else
                    str = string.format('[[%s]]', set['upgraded_from_sets._pageName'])
                end
                
                tr
                    :tag('td')
                        :attr('rowspan', #set.groups)
                        :wikitext(str)
                        :done()
            end
            
            local tr2
            for i, group in ipairs(set.groups) do
                if i <= 1 then
                    tr2 = tr
                else
                    tr2 = tbl:tag('tr')
                end
                local str
                if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
                    local item_data = item_pages[group['upgraded_from_groups.item_page']][1]
                    str = f_item_link{
                        page=group['upgraded_from_groups.item_page'], 
                        name=item_data['items.name'], 
                        inventory_icon=item_data['items.inventory_icon'] or '', 
                        html=item_data['items.html'] or '', 
                        skip_query=true
                    }
                else
                    str = string.format('[[%s]]', group['upgraded_from_groups.item_page'])
                end
                
                tr2
                    :tag('td')
                        :attr('data-sort-type', 'number')
                        :wikitext(group['upgraded_from_groups.amount'])
                        :done()
                    :tag('td')
                        :wikitext(str)
                        :done()
                
                if group_notes then
                    if group['upgraded_from_groups.notes'] then
                        tr2
                            :tag('td')
                                :wikitext(group['upgraded_from_groups.notes'])
                    else
                        tr2:node(m_util.html.td.na{as_tag=true})
                    end
                end
            end
            
            if set_notes then
                if set['upgraded_from_sets.text'] then
                    tr
                        :tag('td')
                            :attr('rowspan', #set.groups)
                            :wikitext(set['upgraded_from_sets.text'])
                else
                    tr
                        :tag('td')
                            :attr('class', 'table-na')
                            :attr('rowspan', #set.groups)
                            :wikitext('N/A')
                            :done()
                end
            end
            
            local t
            if set['upgraded_from_sets.automatic'] == nil then
                t = i18n.upgraded_from_table.old_data
            elseif set['upgraded_from_sets.automatic'] == '1' then
                t = i18n.upgraded_from_table.automatic
            else
                t = i18n.upgraded_from_table.manual
            end
            
            tr
                :tag('td')
                    :attr('rowspan', #set.groups)
                    :wikitext(t)
        end
    end
    
    
    --
    -- print
    --
    
    if data_type == 'ingredient' then
        out[#out+1] = h.head(i18n.acquisition.ingredient_header)
        out[#out+1] = i18n.acquisition.ingredient
    else
        out[#out+1] = h.head(i18n.acquisition.upgraded_from_header)
        out[#out+1] = i18n.acquisition.upgraded_from
    end
    out[#out+1] = '<br>'
    out[#out+1] = tostring(tbl)
end

function h.reward_table(data, rtbl)
    if #data == 0 then
        return
    end
    
    local tbl = m_quest_reward.reward_tbl_head()
            
    for _, row in ipairs(data) do
        local classes
        if row[rtbl .. '.classes'] then
            classes = {}
            for _, class in ipairs(m_util.string.split(row[rtbl .. '.classes'], ',')) do
                classes[class] = true
            end
        end
        
        local tr = tbl:tag('tr')
        m_quest_reward.reward_tbl_row_head(tr, rtbl, row)
                
        local cell = {
            [0] = {
                value = '✗',
                sort = 0,
                class = 'table-cell-xmark',
            },
            [1] = {
                value = '✓',
                sort = 1,
                class = 'table-cell-checkmark',
            },
        }
        if rtbl == 'quest_rewards' then
            local value = m_quest_reward.reward_tbl_extra_info(row)
            
            -- If there isn't any extra information the checkmark will do
            if value ~= '' then
                cell[1].value = value
                cell[1].class = nil
                cell[1].css = 'text-align: center;'
            end
        end
        
        if classes then
            for _, class in ipairs(m_game.constants.characters_order) do
                local cell_value
                if classes[m_game.constants.characters[class].name] then
                    cell_value = cell[1]
                else
                    cell_value = cell[0]
                end
                tr:tag('td')
                    :attr('class', cell_value.class or '')
                    :attr('style', cell_value.css or '')
                    :attr('table-sort-value', cell_value.sort)
                    :wikitext(cell_value.value)
            end
        else
            tr:tag('td')
                :attr('colspan', 7)
                :attr('class', cell[1].class or '')
                :attr('style', cell[1].css or '')
                :attr('table-sort-value', cell[1].sort)
                :wikitext(cell[1].value)
        end
    end
    
    return h.head(i18n.quest_reward[rtbl .. '_header']) .. i18n.quest_reward[rtbl .. '_intro'] .. tostring(tbl)
end

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

local p = {}

--
-- Template: Item acquisition
--
function p.item_acquisition (frame)
    --[[
    Duplicates the information from the infobox in a more readable 
    manner on the page.
    
    Example
    -------
    = p.item_acquisition{page='The Rite of Elements'}
    ]]


    -- Get args
    local tpl_args = getArgs(frame, {
        parentFirst = true
    })
    frame = m_util.misc.get_frame(frame)
    
    tpl_args.page = tpl_args.page or tostring(mw.title.getCurrentTitle())
    
    local out = {}
    local results
    local query
    
    out[#out+1] = tpl_args.acquisition_insert
    
    -- fetch general item drop information that is used in multiple places in a
    -- single query to reduce performance hit
    local item_data = m_cargo.query(
        {'items'},
        {
            'items.drop_text',
            'items.drop_leagues',
            'items.drop_areas__full',
            'items.drop_monsters',
            'items.drop_enabled',
        },
        {
            where=string.format('items._pageName="%s"', tpl_args.page),
            limit=1,
        }
    )
    if #item_data > 0 then
        item_data = item_data[1]
    end
    
    -- ------------------------------------------------------------------------
    -- Drop disabled item
    -- ------------------------------------------------------------------------
    local drop_enabled = m_util.cast.boolean(item_data['items.drop_enabled'])
    if not drop_enabled then
        out[#out+1] = i18n.acquisition.drop_disabled
        out[#out+1] = ' '
    end 
    
    -- ------------------------------------------------------------------------
    -- Drop restrictions by league
    -- ------------------------------------------------------------------------
    if item_data['items.drop_leagues'] and drop_enabled then
        local text = string.format(i18n.acquisition.drop_leagues, item_data['items.drop_leagues'])
        local mbox = f_message_box('ambox', {
            type = 'notice',
            text = tostring(text),
        })
        out[#out+1] = '\n\n'
        out[#out+1] = mbox
        out[#out+1] = '\n\n'
    end
    
    -- ------------------------------------------------------------------------
    -- Drop restrictions by text
    -- ------------------------------------------------------------------------
    if item_data['items.drop_text'] and drop_enabled then
        out[#out+1] = item_data['items.drop_text']
    end
    
    -- ------------------------------------------------------------------------
    -- Drop restrictions by area
    -- ------------------------------------------------------------------------
    
    local area_ids
    if item_data['items.drop_areas__full'] then
        area_ids = m_util.string.split(item_data['items.drop_areas__full'], ',')
    else
        area_ids = {}
    end
    
    -- Handle legacy areas:
    local legacy_area_ids = {
        -- 'MapWar%',
        'MapAtlas%',
        'Map2%',
        'MapTier%',
    }
    local condition_current = {}
    local condition_legacy = {}
    local order_legacy = {}
    for i,v in ipairs(legacy_area_ids) do 
        condition_current[#condition_current+1] = string.format('areas.id NOT LIKE "%s"', v)
        condition_legacy[#condition_legacy+1] = string.format('areas.id LIKE "%s"', v)
        order_legacy[#order_legacy+1] = string.format('WHEN areas.id LIKE "%s" THEN %d', v,i)        
    end
    
    local query_sets = {
        {
            header=i18n.acquisition.area_header,
            condition=string.format('%s', table.concat(condition_current, ' AND ')),
            order='areas.name ASC',
        },
        {
            header=i18n.acquisition.area_legacy_header,
            condition=string.format('%s', table.concat(condition_legacy, ' OR ')),
            order=string.format([[
                CASE 
                    %s
                    ELSE %d 
                END ASC, 
                areas.name ASC
            ]], 
            table.concat(order_legacy, ' '), 
            #order_legacy+1
            ),
        },
    }
        
    if #area_ids > 0 then
        for _, query_set in ipairs(query_sets) do
            local results = m_cargo.query(
                {'areas'},
                {
                    'areas._pageName',
                    'areas.id',
                    'areas.name',
                    'areas.main_page',
                },
                {
                    where=string.format('(%s) AND areas.id IN ("%s")', query_set.condition, table.concat(area_ids, '","')),
                    orderBy=query_set.order,
                    groupBy='areas.id',
                }
            )
            if #results > 0 then
                local ul = mw.html.create('ul')
                for _, row in ipairs(results) do
                    ul:tag('li')
                        :wikitext(string.format('[[%s|%s]]', row['areas.main_page'] or row['areas._pageName'], row['areas.name']))
                end            
                out[#out+1] = h.head(query_set.header)
                out[#out+1] = i18n.acquisition.area
                out[#out+1]= '<br>'
                out[#out+1] = tostring(ul)
            end
        end
    end
    
    -- ------------------------------------------------------------------------
    -- Drop restrictions by monster
    -- ------------------------------------------------------------------------

    local monster_metadata_ids = {}
    if item_data['items.drop_monsters'] then
        monster_metadata_ids = m_util.string.split(item_data['items.drop_monsters'], ',%s*')
    end
            
    if #monster_metadata_ids > 0 then
        local results = m_cargo.query(
            {'monsters', 'main_pages'},
            {
                'monsters._pageName',
                'monsters.metadata_id',
                'monsters.name',
                -- 'monsters.main_page',
                'main_pages._pageName',
            },
            {
                join='monsters.metadata_id=main_pages.id',
                where=string.format('monsters.metadata_id IN ("%s")', table.concat(monster_metadata_ids, '","')),
                orderBy='monsters.name',
                groupBy='monsters.metadata_id',
            }
        )
        if #results > 0 then
            local ul = mw.html.create('ul')
            for _, row in ipairs(results) do
                ul:tag('li')
                    :wikitext(string.format(
                        '[[%s|%s]]', 
                           row['monsters.main_page'] 
                        or row['main_pages._pageName'] 
                        or row['monsters._pageName'], 
                        row['monsters.name']
                    ))
            end            
            out[#out+1] = h.head(i18n.acquisition.monster_header)
            out[#out+1] = i18n.acquisition.monster
            out[#out+1]= '<br>'
            out[#out+1] = tostring(ul)
        end
    end
    
    -- ------------------------------------------------------------------------
    -- Vendor recipes/upgrades handling
    -- ------------------------------------------------------------------------
    
    --
    -- Query set data
    --
    local obtained_sets, obtained_sets_order = h.fetch_upgraded_from_sets(
        string.format('upgraded_from_sets._pageName="%s"', tpl_args.page),
        string.format('upgraded_from_groups._pageName="%s"', tpl_args.page)
    )
    
    results = m_cargo.query(
        {'upgraded_from_groups'},
        {
            'upgraded_from_groups._pageID',
            'upgraded_from_groups.set_id',
        },
        {
            where=string.format('upgraded_from_groups.item_page="%s"', tpl_args.page),
            -- only need one result set for the where clause
            groupBy='upgraded_from_groups._pageID, upgraded_from_groups.set_id',
        }
    )
    local where = {sets={}, groups={}}
    for key, data in pairs(where) do
        for _, row in ipairs(results) do
            data[#data+1] = string.format('upgraded_from_%s.set_id="%s" AND upgraded_from_%s._pageID="%s"', key, row['upgraded_from_groups.set_id'], key, row['upgraded_from_groups._pageID'])
        end
        where[key] = table.concat(data, ' OR ')
    end
    local ingredient_sets, ingredient_sets_order = h.fetch_upgraded_from_sets(where.sets, where.groups)
    --
    -- Query bulk item info for item linking
    --
    local item_pages = {assoc={}}
    for _, set_data in ipairs({{obtained_sets, obtained_sets_order}, {ingredient_sets, ingredient_sets_order}}) do
        for _, set_key in ipairs(set_data[2]) do
            local set = set_data[1][set_key]
            for _, group in ipairs(set.groups) do
                item_pages.assoc[group['upgraded_from_groups.item_page']] = true
            end
            item_pages.assoc[set['upgraded_from_sets._pageName']] = true
        end
    end
    -- remove duplicates
    for name, _ in pairs(item_pages.assoc) do
        item_pages[#item_pages+1] = name
    end
    
    if #item_pages < c.MAX_ITEMS then
        item_pages = m_cargo.map_results_to_id{
            results=m_cargo.array_query{
                tables={'items'},
                fields={'items.name', 'items.inventory_icon', 'items.html'},
                id_array = item_pages,
                id_field = 'items._pageName',
                query = {
                    limit=5000
                },
            },
            field='items._pageName',
            keep_id_field=true,
        }
    end
    
    -- 
    -- Output for being obtained via vendor recipe
    --
    
    h.upgraded_from_table(tpl_args, obtained_sets, obtained_sets_order, 'obtained', out, item_pages)
    
    -- 
    -- Ingredient of vendor recipes/upgrades
    -- 
    
    h.upgraded_from_table(tpl_args, ingredient_sets, ingredient_sets_order, 'ingredient', out, item_pages)
    
    out[#out+1] = tpl_args.ingredient_append
    
    -- ------------------------------------------------------------------------
    -- Obtained via quest or vendor reward
    -- ------------------------------------------------------------------------
    
    local quest_rewards = m_cargo.query(
        {'quest_rewards'},
        {
            'quest_rewards.quest',
            'quest_rewards.act',
            'quest_rewards.classes',
            'quest_rewards.sockets',
            'quest_rewards.item_level',
            'quest_rewards.rarity',
        },
        {
            where=string.format('quest_rewards._pageName="%s"', tpl_args.page),
            orderBy='quest_rewards.act ASC, quest_rewards.quest_id ASC',
        }
    )
    out[#out+1] = h.reward_table(quest_rewards, 'quest_rewards')
    
    local vendor_rewards = m_cargo.query(
        {'vendor_rewards'},
        {
            'vendor_rewards.quest',
            'vendor_rewards.act',
            'vendor_rewards.classes',
            'vendor_rewards.npc',
        },
        {
            where=string.format('vendor_rewards._pageName="%s"', tpl_args.page),
            orderBy='vendor_rewards.act ASC, vendor_rewards.quest_id ASC',
        }
    )
    out[#out+1] = h.reward_table(vendor_rewards, 'vendor_rewards')
    
    -- ------------------------------------
    -- output
    -- ------------------------------------
    
    local head = mw.html.create('h2')
    head:wikitext(i18n.acquisition.header .. i18n.acquisition.link)
    return tostring(head) .. table.concat(out)
end

-- ----------------------------------------------------------------------------
-- Return
-- ----------------------------------------------------------------------------

return p