Path of Exile Wiki

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

ПОДРОБНЕЕ

Path of Exile Wiki
Нет описания правки
Нет описания правки
(не показано 26 промежуточных версий 2 участников)
Строка 3: Строка 3:
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
   
local getArgs = require('Модуль:Arguments').getArgs
+
local getArgs = require('Module:Arguments').getArgs
local m_game = require('Модуль:Game')
+
local m_util = require('Module:Util')
local m_util = require('Модуль:Util')
+
local m_cargo = require('Module:Cargo')
local m_quest_reward = require('Модуль:Quest reward')._shared
+
local m_quest_reward = require('Module:Quest reward')._shared
  +
local f_item_link = require('Модуль:Item link').item_link
 
  +
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
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
Строка 21: Строка 25:
 
acquisition = {
 
acquisition = {
 
header = 'Получение предмета',
 
header = 'Получение предмета',
  +
link = '[[File:Questionmark.png|right|24px|link=Path_of_Exile_Wiki:Как_редактировать_получение_предмета]]',
area_header = 'Список областей',
 
 
area_legacy_header = 'Список устаревших областей',
 
  +
drop_leagues = 'После изменений [[Версия 3.14.0#Баланс уникальных предметов|версии 3.14.0]] неясно, какие именно [[Предметы с ограниченным доступом#Предметы, относящиеся к конкретной лиге|предметы, относящиеся к конкретной лиге]], были добавлены в основной список выпадающих предметов. Если этот предмет не существует в основном списке выпадающих предметов, он может выпадать только в областях с активным флагом лиги %s. Предметы, относящиеся к конкретной лиге, также могут быть приобретены [[Предметы с ограниченным доступом#Предметы, относящиеся к конкретной лиге|другими способами]].',
  +
drop_disabled = 'Этот предмет не выпадает.',
  +
area_header = 'Ограничения на получение в областях',
 
area_legacy_header = 'Ограничения на получение в устаревших областях',
 
area = 'Этот предмет можно получить в следующих областях:',
 
area = 'Этот предмет можно получить в следующих областях:',
  +
monster = 'Этот предмет может выпасть из следующих монстров:',
  +
monster_header = 'Ограничения на получение из монстров',
 
 
 
upgraded_from_header = 'Способы получения',
 
upgraded_from_header = 'Способы получения',
Строка 38: Строка 48:
 
ingredient_notes = 'Примечания<br>по ингредиентам',
 
ingredient_notes = 'Примечания<br>по ингредиентам',
 
recipe_notes = 'Общие примечания',
 
recipe_notes = 'Общие примечания',
  +
type = 'Тип',
  +
automatic = m_util.html.abbr('Автоматически', 'Автоматически добавлено шаблоном на основе характеристик предмета.'),
  +
manual = m_util.html.abbr('Вручную', 'Вручную добавлено на вики-страницу предмета.'),
  +
old_data = m_util.html.abbr('Устаревшие данные', 'Устаревшие данные - пожалуйста, сделайте пустое редактирование вики-страницы предмета.'),
 
},
 
},
 
 
 
quest_reward = {
 
quest_reward = {
quest_rewards_header = 'Quest reward',
+
quest_rewards_header = 'Награда за задание',
quest_rewards_intro = 'This skill is given as quest reward for the following quests:',
+
quest_rewards_intro = 'Дается в качестве награды за следующие задания:',
vendor_rewards_header = 'Vendor reward',
+
vendor_rewards_header = 'Награда торговца',
  +
vendor_rewards_intro = 'Можно приобрести у перечисленных торговцев после выполнения следующих заданий:',
vendor_rewards_intro = 'This skill can be bought at the listed npc vendors after completing the following quests:',
 
 
},
 
},
 
}
 
}
Строка 74: Строка 88:
 
 
 
local sets = {}
 
local sets = {}
local results = m_util.cargo.query(
+
local results = m_cargo.query(
 
{'upgraded_from_sets'},
 
{'upgraded_from_sets'},
 
{
 
{
Строка 80: Строка 94:
 
'upgraded_from_sets.set_id',
 
'upgraded_from_sets.set_id',
 
'upgraded_from_sets.text',
 
'upgraded_from_sets.text',
  +
'upgraded_from_sets.automatic',
 
},
 
},
 
{
 
{
Строка 91: Строка 106:
 
end
 
end
 
 
results = m_util.cargo.query(
+
results = m_cargo.query(
 
{'upgraded_from_groups'},
 
{'upgraded_from_groups'},
 
{
 
{
Строка 196: Строка 211:
 
:done()
 
:done()
 
end
 
end
 
tr
 
:tag('th')
  +
:wikitext(i18n.upgraded_from_table.type)
 
:done()
 
--
 
--
 
-- Rows
 
-- Rows
Строка 210: Строка 229:
 
local str
 
local str
 
if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
 
if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
item_data = item_pages[set['upgraded_from_sets._pageName']][1]
+
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}
 
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
Строка 223: Строка 242:
 
end
 
end
 
 
  +
local tr2
 
for i, group in ipairs(set.groups) do
 
for i, group in ipairs(set.groups) do
 
if i <= 1 then
 
if i <= 1 then
Строка 231: Строка 251:
 
local str
 
local str
 
if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
 
if tpl_args.no_link == nil and item_pages_count < c.MAX_ITEMS then
item_data = item_pages[group['upgraded_from_groups.item_page']][1]
+
local item_data = item_pages[group['upgraded_from_groups.item_page']][1]
 
str = f_item_link{
 
str = f_item_link{
 
page=group['upgraded_from_groups.item_page'],
 
page=group['upgraded_from_groups.item_page'],
Строка 278: Строка 298:
 
end
 
end
 
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
 
end
 
end
Строка 308: Строка 342:
 
if row[rtbl .. '.classes'] then
 
if row[rtbl .. '.classes'] then
 
classes = {}
 
classes = {}
for _, class in ipairs(m_util.string.split(row[rtbl .. '.classes'], '')) do
+
for _, class in ipairs(m_util.string.split(row[rtbl .. '.classes'], ',')) do
 
classes[class] = true
 
classes[class] = true
 
end
 
end
Строка 342: Строка 376:
 
for _, class in ipairs(m_game.constants.characters_order) do
 
for _, class in ipairs(m_game.constants.characters_order) do
 
local cell_value
 
local cell_value
if classes[class] then
+
if classes[m_game.constants.characters[class].name] then
 
cell_value = cell[1]
 
cell_value = cell[1]
 
else
 
else
Строка 380: Строка 414:
 
manner on the page.
 
manner on the page.
 
 
Example:
+
Example
  +
-------
 
= p.item_acquisition{page='The Rite of Elements'}
 
= p.item_acquisition{page='The Rite of Elements'}
 
]]
 
]]
Строка 399: Строка 434:
 
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
-- ------------------------------------------------------------------------
 
  +
-- single query to reduce performance hit
-- Drop restrictions by text
 
  +
local item_data = m_cargo.query(
-- ------------------------------------------------------------------------
 
results = m_util.cargo.query(
 
 
{'items'},
 
{'items'},
 
{
 
{
 
'items.drop_text',
 
'items.drop_text',
  +
'items.drop_leagues',
 
'items.drop_areas__full',
  +
'items.drop_monsters',
  +
'items.drop_enabled',
 
},
 
},
 
{
 
{
Строка 412: Строка 450:
 
}
 
}
 
)
 
)
+
if #item_data > 0 then
 
item_data = item_data[1]
if #results > 0 then
 
  +
end
results = results[1]
 
  +
if results['items.drop_text'] then
 
 
-- ------------------------------------------------------------------------
out[#out+1] = results['items.drop_text']
 
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
 
end
 
 
Строка 424: Строка 488:
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
 
 
local area_ids = m_util.cargo.query(
+
local area_ids
{'items'},
+
if item_data['items.drop_areas__full'] then
{'items.drop_areas__full'},
+
area_ids = m_util.string.split(item_data['items.drop_areas__full'], ',')
{
 
where=string.format('items._pageName="%s"', tpl_args.page),
 
}
 
)[1]
 
if area_ids and area_ids['items.drop_areas__full'] then
 
area_ids = m_util.string.split(area_ids['items.drop_areas__full'], ',')
 
 
else
 
else
 
area_ids = {}
 
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
 
end
 
 
Строка 440: Строка 514:
 
{
 
{
 
header=i18n.acquisition.area_header,
 
header=i18n.acquisition.area_header,
condition='areas.id NOT LIKE "MapAtlas%" AND areas.id NOT LIKE "Map2%"',
+
condition=string.format('%s', table.concat(condition_current, ' AND ')),
 
order='areas.name ASC',
 
order='areas.name ASC',
 
},
 
},
 
{
 
{
 
header=i18n.acquisition.area_legacy_header,
 
header=i18n.acquisition.area_legacy_header,
condition='areas.id LIKE "MapAtlas%" OR areas.id LIKE "Map2%"',
+
condition=string.format('%s', table.concat(condition_legacy, ' OR ')),
order=[[
+
order=string.format([[
 
CASE
 
CASE
WHEN areas.id LIKE "MapAtlas%" THEN 1
+
%s
WHEN areas.id LIKE "Map2%" THEN 2
+
ELSE %d
ELSE 3
 
 
END ASC,
 
END ASC,
 
areas.name ASC
 
areas.name ASC
]],
+
]],
  +
table.concat(order_legacy, ' '),
  +
#order_legacy+1
  +
),
 
},
 
},
 
}
 
}
+
 
if #area_ids > 0 then
 
if #area_ids > 0 then
 
for _, query_set in ipairs(query_sets) do
 
for _, query_set in ipairs(query_sets) do
results = m_util.cargo.query(
+
local results = m_cargo.query(
 
{'areas'},
 
{'areas'},
 
{
 
{
Строка 484: Строка 560:
 
out[#out+1] = tostring(ul)
 
out[#out+1] = tostring(ul)
 
end
 
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
 
end
 
end
Строка 499: Строка 620:
 
)
 
)
 
 
results = m_util.cargo.query(
+
results = m_cargo.query(
 
{'upgraded_from_groups'},
 
{'upgraded_from_groups'},
 
{
 
{
Строка 538: Строка 659:
 
 
 
if #item_pages < c.MAX_ITEMS then
 
if #item_pages < c.MAX_ITEMS then
item_pages = m_util.cargo.map_results_to_id{
+
item_pages = m_cargo.map_results_to_id{
results=m_util.cargo.array_query{
+
results=m_cargo.array_query{
 
tables={'items'},
 
tables={'items'},
 
fields={'items.name', 'items.inventory_icon', 'items.html'},
 
fields={'items.name', 'items.inventory_icon', 'items.html'},
Строка 571: Строка 692:
 
-- ------------------------------------------------------------------------
 
-- ------------------------------------------------------------------------
 
 
local quest_rewards = m_util.cargo.query(
+
local quest_rewards = m_cargo.query(
 
{'quest_rewards'},
 
{'quest_rewards'},
 
{
 
{
Строка 582: Строка 703:
 
},
 
},
 
{
 
{
where=string.format('quest_rewards.reward="%s"', tpl_args.page),
+
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',
 
}
 
}
Строка 588: Строка 709:
 
out[#out+1] = h.reward_table(quest_rewards, 'quest_rewards')
 
out[#out+1] = h.reward_table(quest_rewards, 'quest_rewards')
 
 
local vendor_rewards = m_util.cargo.query(
+
local vendor_rewards = m_cargo.query(
 
{'vendor_rewards'},
 
{'vendor_rewards'},
 
{
 
{
Строка 597: Строка 718:
 
},
 
},
 
{
 
{
where=string.format('vendor_rewards.reward="%s"', tpl_args.page),
+
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',
 
}
 
}
Строка 608: Строка 729:
 
 
 
local head = mw.html.create('h2')
 
local head = mw.html.create('h2')
head:wikitext(i18n.acquisition.header .. '[[File:Questionmark.png|right|24px|link=Path_of_Exile_Wiki:How_to_edit_item_acquisition]]')
+
head:wikitext(i18n.acquisition.header .. i18n.acquisition.link)
 
return tostring(head) .. table.concat(out)
 
return tostring(head) .. table.concat(out)
 
end
 
end

Версия от 16:22, 13 июля 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