Module:Quest reward

From Path of Exile Wiki
Jump to: navigation, search
--
-- Module for bestiary templates
--

local m_game = require('Module:Game')
local m_util = require('Module:Util')
local f_item_link = require('Module:Item link').item_link
local getArgs = require('Module:Arguments').getArgs
local m_cargo = require('Module:Cargo')

local p = {}
p._shared = {}

-- ----------------------------------------------------------------------------
-- Strings
-- ----------------------------------------------------------------------------

local i18n = {
    errors = {
        invalid_table = 'Invalid table selected. Valid choices are either quest or vendor',
        invalid_type = 'type must be either quest_rewards or vendor_rewards',
    },
    messages = {
        storage = 'Attempted to store rows %s to %s in "%s_rewards" table',
    },
    quest_reward = {
        character_class = 'Class →',
        quest = 'Quest ↓',
        row_header = '[[%s]]<br>Act %s',
        item_level = 'iLvl %s',
        links = '%s-linked',
    },
}

-- ----------------------------------------------------------------------------
-- Cargo
-- ----------------------------------------------------------------------------

local tables = {}

tables.quest_rewards = {
    table = 'quest_rewards',
    fields = {
        quest = {
            field = 'quest',
            type = 'String',
        },
        quest_id = {
            field = 'quest_id',
            type = 'Integer',
        },
        -- still needed?
        act = {
            field = 'act',
            type = 'Integer',
        },
        classes = {
            field = 'classes',
            type = 'String',
        },
        sockets = {
            field = 'sockets',
            type = 'Integer',
        },
        item_level = {
            field = 'item_level',
            type = 'Integer',
        },
        rarity = {
            field = 'rarity',
            type = 'String',
        },
        reward = {
            field = 'reward',
            type = 'Page',
        },
    },
}

tables.vendor_rewards = {
    table = 'vendor_rewards',
    fields = {
        quest = {
            field = 'quest',
            type = 'String',
        },
        quest_id = {
            field = 'quest_id',
            type = 'Integer',
        },
        act = {
            field = 'act',
            type = 'Integer',
        },
        reward = {
            field = 'reward',
            type = 'Page',
        },
        npc = {
            field = 'npc',
            type = 'String',
        },
        classes = {
            field = 'classes',
            type = 'String',
        },
    }
}

-- ----------------------------------------------------------------------------
-- Helper functions and globals
-- ----------------------------------------------------------------------------

local h = {}

-- ----------------------------------------------------------------------------
-- Page functions
-- ----------------------------------------------------------------------------

p.table_quest_rewards = m_cargo.declare_factory{data=tables.quest_rewards}
p.table_vendor_rewards = m_cargo.declare_factory{data=tables.vendor_rewards}

p.store_data = m_cargo.store_from_lua{tables=tables, module='Quest reward/data'}

function p._shared.reward_tbl_head()
    local tbl = mw.html.create('table')
    tbl:attr('class', 'wikitable sortable')
    local tr = tbl:tag('tr')
    tr
        :tag('th')
            :attr('class', 'unsortable')
            :wikitext(i18n.quest_reward.character_class)
    for _, class in ipairs(m_game.constants.characters_order) do
        tr:tag('th')
            :attr('rowspan', 2)
            :wikitext(string.format('[[%s]]', m_game.constants.characters[class].name))
    end
    
    tbl
        :tag('tr')
            :tag('th')
                :wikitext(i18n.quest_reward.quest)
    return tbl
end

function p._shared.reward_tbl_row_head(tr, rtbl, row)
    local npc = ''
    if row[rtbl .. '.npc'] then
        npc = string.format('<br>[[%s]]', row[rtbl .. '.npc'])
    end
    
    tr
        :tag('th')
            :wikitext(string.format(i18n.quest_reward.row_header, row[rtbl .. '.quest'], row[rtbl .. '.act']))
            :wikitext(npc)
end

function p._shared.reward_tbl_extra_info(row)
    local value = {}
    if row['quest_rewards.item_level'] then
        value[#value+1] = string.format(i18n.quest_reward.item_level, row['quest_rewards.item_level'])
    end
    -- TODO: i18n rarity name?
    if row['quest_rewards.rarity'] then
        value[#value+1] = m_util.html.poe_color(string.lower(row['quest_rewards.rarity']), row['quest_rewards.rarity'])
    end
    if row['quest_rewards.sockets'] then
        value[#value+1] = string.format(i18n.quest_reward.links, row['quest_rewards.sockets'])
    end
    
    return table.concat(value, ', ')
end

function p.quest_reward_table(frame)
    --[[
    Displays a table of quest rewards from a certain quest.
    
    Examples
    --------
    = p.quest_reward_table{type='vendor_rewards', q_where='quest="A Fixture of Fate"'}
    ]]
    
    -- Get args
    tpl_args = getArgs(frame, {
        parentFirst = true
    })
    frame = m_util.misc.get_frame(frame)
    local q_where = tpl_args.q_where
    if tpl_args.item_link then
        tpl_args.item_link = m_util.cast.boolean(tpl_args.item_link)
    else
        tpl_args.item_link = true
    end

    local data
    if tpl_args.type == 'quest_rewards' then
        data = m_cargo.query(
            {'quest_rewards'},
            {
                'quest_rewards.quest',
                'quest_rewards.act',
                'quest_rewards.classes',
                'quest_rewards.sockets',
                'quest_rewards.item_level',
                'quest_rewards.rarity',
                'quest_rewards.reward',
            },
            {
                where=q_where,
                orderBy='quest_rewards.act ASC, quest_rewards.quest_id ASC, quest_rewards.reward ASC',
                limit=5000,
            }
        )
    elseif tpl_args.type == 'vendor_rewards' then
        data = m_cargo.query(
            {'vendor_rewards'},
            {
                'vendor_rewards.quest',
                'vendor_rewards.act',
                'vendor_rewards.classes',
                'vendor_rewards.npc',
                'vendor_rewards.reward',
            },
            {
                where=q_where,
                orderBy='vendor_rewards.act ASC, vendor_rewards.quest_id ASC, vendor_rewards.reward ASC',
                limit=5000,
            }
        )
    else
        error(i18n.errors.invalid_type, tpl_args.type)
    end
    
    -- ------------------------------------------------------------------------
    -- Build output table
    -- ------------------------------------------------------------------------
    local tbl = p._shared.reward_tbl_head()
    
    if #data == 0 then
        return tostring(tbl)
    end
    
    local quest_order = {}
    local quests = {}
    local pages = {}
    
    --
    -- remap data to quests[questid].classes[class]
    --
    for _, row in ipairs(data) do
        local classes = quests[row[tpl_args.type .. '.quest']]
        if classes == nil then
            table.insert(quest_order, row[tpl_args.type .. '.quest'])
            classes = {}
            quests[row[tpl_args.type .. '.quest']] = classes
        end
        
        if row[tpl_args.type .. '.classes'] then
            classes[-1] = {}
            for _, class in ipairs(m_util.string.split(row[tpl_args.type .. '.classes'], '�')) do
                if classes[class] == nil then
                    classes[class] = {}
                end
                table.insert(classes[class], row)
            end
        else
            if classes[0] == nil then
                    classes[0] = {}
                end
            table.insert(classes[0], row)
        end
        
        pages[row[tpl_args.type .. '.reward']] = true
    end
    --
    -- Cache item data
    --
    local item_data
    if tpl_args.item_link then
        local pages_array = {}
        for page, _ in pairs(pages) do
            pages_array[#pages_array+1] = page
        end
        
        local fields = {
            'items.name',
            'items.inventory_icon',
        }
        
        if m_util.cast.boolean(tpl_args.no_html) ~= true then
            fields[#fields+1] = 'items.html'
        end
        
        item_data = m_cargo.map_results_to_id{
            results=m_cargo.array_query{
                tables={'items'},
                fields=fields,
                id_field='items._pageName',
                id_array=pages_array,
                query={
                    limit=5000,
                },
            }, 
            field='items._pageName',
        }
    end
    --
    -- Output rows
    --
    
    function element(rows)
        if rows == nil then
            return ''
        end
        local out = {}
        for _, row in ipairs(rows) do
            local reward = row[tpl_args.type .. '.reward']
            if tpl_args.item_link then
                local idata = item_data[reward][1]
                reward = f_item_link{page=reward, name=idata['items.name'], inventory_icon=idata['items.inventory_icon'] or '', html=idata['items.html'] or '', skip_query=true}
            else
                reward = string.format('[[%s]]', reward)
            end
            local info = p._shared.reward_tbl_extra_info(row)
            if info ~= '' then
                out[#out+1] = string.format('%s (%s)', reward, info)
            else
                out[#out+1] = reward
            end
        end
        return table.concat(out, '<br>')
    end
    
    for _, quest_key in ipairs(quest_order) do
        local classes = quests[quest_key]
        
        if classes[0] then
            local tr = tbl:tag('tr')
            for _, class in pairs(classes) do
                if class[1] then
                    p._shared.reward_tbl_row_head(tr, tpl_args.type, class[1])
                    break
                end
            end
            tr:tag('td')
                :attr('colspan', 7)
                :attr('style', 'text-align: center;')
                :wikitext(element(classes[0]))
        end
        if classes[-1] then
            local tr = tbl:tag('tr')
            for _, class in pairs(classes) do
                if class[1] then
                    p._shared.reward_tbl_row_head(tr, tpl_args.type, class[1])
                    break
                end
            end
            for _, class in ipairs(m_game.constants.characters_order) do
                 tr:tag('td')
                    :wikitext(element(classes[m_game.constants.characters[class].name]))
            end
        end
    end
    
    return tostring(tbl)
end

-- ----------------------------------------------------------------------------
-- End
-- ----------------------------------------------------------------------------

return p