Path of Exile Wiki

Please consider helping keep the wiki up to date. Check the to-do list of updates needed for version 3.14.0.

Game data exports will becoming later as the technical changes in addition to regular changes take some more time.

READ MORE

Path of Exile Wiki
Advertisement
Template info icon Module documentation[view] [edit] [history] [purge]

The data tables module creates infoboxes and stores cargo data.

Subpages

--[[
    Module for data tables
    
]]

local getArgs = require('Module:Arguments').getArgs
local util = require('Module:Util')
local game = require('Module:Game')
local f_infocard = require('Module:Infocard')._main
local mw_language = mw.getLanguage('en')

local p = {}

local i18n = {
    ascendancy_class = {
    
    },
    event = {
        
    },
}

-- ---------------------------------------------------------------------
-- Utility / Helper functions
-- ---------------------------------------------------------------------

local h = {}

function h.date(value, args)
    --[[
    Format dates in correct and useable form.
    
    value = date string
    args = table of extra args.
    
    To do:
    Remove hours if it isn't specified.
    ]]
    
    local args = args or {}
    
    -- List of allowed extra arguments:
    local arg_list = {
        format = {
            default = 'Y-m-d H:i:s',
            cargo = 'Y-m-d H:i:s',
        },
    }
    
    local date_format = arg_list.format.default
    for i,v in pairs(args) do
        if i == 'format' then
            date_format = arg_list[i][v]            
        end
    end
    local out
    if value ~= nil then
        out = mw_language:formatDate(date_format, value)
    else
        out =  nil
    end
    
    return out
end

function h.timezone(str)
    --[[
    Check if the string contains Z at the end, if it does it implies 
    the time is in UTC and then return UTC.
    ]]
    
	if str ~= nil and str:sub(-1,-1) == 'Z' then  
		return 'UTC'
	else
		return ''
	end
end

function h.cargo_query(tpl_args)
    --[[
    Returns a Cargo query of all the results, even if there are more
    results than the maximum query limit. It also adds popular fields. 
    
    tpl_args should include these keys:
    tpl_args.tables
    tpl_args.fields
    tpl_args.q_*
    
    ]]
    
    local tables = util.string.split(tpl_args.tables, ', ')
    local fields = util.string.split(tpl_args.fields, ', ')
    
    -- Parse query arguments
    local query = {
        -- Workaround: Fix duplicates but removes other rows as well. 
        groupBy = tables[1] .. '._pageID',
        limit = 5000,
        offset = 0,
    }
    for key, value in pairs(tpl_args) do 
        if string.sub(key, 0, 2) == 'q_' then
            query[string.sub(key, 3)] = value
        end
    end
    
    -- Add commonly used fields:
    fields_base = {
        '_pageNamespace', 
        '_pageTitle',
        '_ID',
        '_rowID',
        '_pageID',
        '_pageName'
        -- '_value'
    }
    for _, tbl in ipairs(tables) do
        for _, fld in ipairs(fields_base) do
            fields[#fields+1] = string.format('%s.%s', tbl, fld)
        end
    end
    
    -- Query cargo table. If there are too many results then repeat, 
    -- offset, re-query and add the remaining results:
    local results = {}      
    repeat
        local result = mw.ext.cargo.query(
            table.concat(tables, ', '),
            table.concat(fields, ', '),
            query
        )
        query.offset = query.offset + #result

        for _,v in ipairs(result) do
            results[#results + 1] = v
        end
    until #result < query.limit
    
    return results
end

function h.parse_map(tpl_args, frame, map)
    --[[
        Parse the map
        
        Input:
        
    ]]
    local cargo_data = {
        _table = map.main.table,
    }
    for _, key in pairs(map.main.parse_order) do
        local data = map.main.fields[key]
        local value 
        if data.func ~= nil then
            if data.name then
                value = data.func(tpl_args, frame, tpl_args[data.name])
            else
                value = data.func(tpl_args, frame)
            end
        else
            value = tpl_args[data.name]
        end
        
        tpl_args[key] = value

        if data.field ~= nil then
            if data.func_cargo then
                cargo_data[data.field] = data.func_cargo(tpl_args, frame)
            else
                cargo_data[data.field] = value
            end
        end
    end
    
    local out = {
        tpl_args = tpl_args,
        cargo_data = cargo_data,
    }
    
    return out
end

-- ---------------------------------------------------------------------
-- Template: Character classes
-- ---------------------------------------------------------------------
local character_map = {
    main = {
        table = 'character_classes',
        order = {'flavour_text'},
        parse_order = {'name', 'flavour_text', 'id'},
        fields = {
            -- Header:
            name = {
                name = 'name',
                field = 'name',
                type = 'String',
                wikitext = 'Name',
            },
            -- Main text:
            flavour_text = {
                name = 'flavour_text',
                field = 'flavour_text',
                type = 'String',
                display = function(tpl_args, frame, value)
                    return util.html.poe_color('unique', value)
                end,
            },
            -- Fields only:
            id = {
                name = nil,
                field = 'id',
                type = 'String',
                wikitext = 'Id',
                func = function(tpl_args, frame)
                    return game.constants.characters[tpl_args.name].id
                end,
            },
        },
    },
}

p.declare_character_classes = util.cargo.declare_factory{data=character_map.main}

function p.character_class(frame)
    --[[
    Displays a infobox and stores cargo data for character classes.
    
    Examples:
    = p.character_class{
        name='Marauder',
        flavour_text='testing'
    }
    ]]
    
    
    -- Get args
    local tpl_args = getArgs(frame, {parentFirst = true})
    local frame = util.misc.get_frame(frame)
	    
    -- Parse character map:
    local map = character_map
    local parsed_map = h.parse_map(tpl_args, frame, map)
    tpl_args = parsed_map.tpl_args
    local cargo_data = parsed_map.cargo_data
    
    
    -- Store cargo fields:
    util.cargo.store(frame, cargo_data)  
 
    -- Main sections, loop through
    local tbl = mw.html.create('table')
    for _, key in ipairs(map.main.order) do
        local data = map.main.fields[key]
        
        if data.display == nil then
            text = tpl_args[key]
        else
            text = data.display(tpl_args, frame, tpl_args[key])
        end
        
        if text ~= nil then           
            tbl
                :tag('tr')
                    :tag('th')
                        :wikitext(data.wikitext)
                        :done()
                    :tag('td')
                        :wikitext(text)
                        :done()
                    :done()
        elseif text then
            tbl
                :tag('tr')
                    :tag('td')
                        -- :attr('colspan', '2')
                        :wikitext(text)
                        :done()
                    :done()
        end
    end
    
    -- Output Infocard
	local infocard_args = {
		['class'] = 'character_class',
		['header'] = tpl_args.name,
		['subheader'] = nil,
		[1] = string.format(
            '[[File:%s character class.png|250px]]',
            tpl_args.name
        ),
		[2] = tostring(tbl),
    }
    
    -- cats
    local cats = {
        'Character Classes'
    }
    
    return f_infocard(infocard_args) .. util.misc.add_category(cats)
end

-- ---------------------------------------------------------------------
-- Template: Ascendancy Class
-- ---------------------------------------------------------------------

local ascendancy_map = {
    main = {
        table = 'ascendancy_classes',
        order = {'flavour_text'},
        parse_order = {'name', 'character', 'flavour_text', 'id', 'character_id'},
        fields = {
            -- Header:
            name = {
                name = 'name',
                field = 'name',
                type = 'String',
                wikitext = 'Name',
            },
            -- Subheader:
            character = {
                name = nil,
                field = 'character',
                type = 'String',
                wikitext = 'Character',
                func = function(tpl_args, frame, value)
                    local id = game.constants.ascendancy[tpl_args.name].id
                    local character_id = game.constants.ascendancy[tpl_args.name].character
                    
                    local character
                    for i,v in pairs(game.constants.characters) do
                        if v.id == character_id then 
                            character = i
                            break
                        end
                    end
                    
                    return character 
                end,
            },
            -- Main text:
            flavour_text = {
                name = 'flavour_text',
                field = 'flavour_text',
                type = 'String',
                display = function(tpl_args, frame, value)
                    return util.html.poe_color('unique', value)
                end,
            },
            -- Fields only:
            id = {
                name = nil,
                field = 'id',
                type = 'Integer',
                wikitext = 'Id',
                func = function(tpl_args, frame, value)
                    return game.constants.ascendancy[tpl_args.name].id
                end,
            },
            character_id = {
                name = nil,
                field = 'character_id',
                type = 'Integer',
                wikitext = 'Character id',
                func = function(tpl_args, frame, value)
                    return game.constants.ascendancy[tpl_args.name].character
                end,
            },
        },
    },
}

p.declare_ascendancy_classes = util.cargo.declare_factory{data=ascendancy_map.main}


function p.ascendancy_class (frame)
    --[[
    Displays a infobox and stores cargo data for ascendancy classes.
    
    Examples:
    = p.ascendancy_class{
        name='Slayer',
        flavour_text='testing'
    }
    ]]
    
    
    -- Get args
    local tpl_args = getArgs(frame, {parentFirst = true})
    local frame = util.misc.get_frame(frame)
	    
    -- Parse ascendancy map:
    local map = ascendancy_map
    local parsed_map = h.parse_map(tpl_args, frame, map)
    tpl_args = parsed_map.tpl_args
    local cargo_data = parsed_map.cargo_data
    
    -- Store cargo fields:
    util.cargo.store(frame, cargo_data)  
 
    -- Main sections, loop through
    local tbl = mw.html.create('table')
    for _, key in ipairs(map.main.order) do
        local data = map.main.fields[key]
        
        if data.display == nil then
            text = tpl_args[key]
        else
            text = data.display(tpl_args, frame, tpl_args[key])
        end
        
        if text ~= nil then           
            tbl
                :tag('tr')
                    :tag('th')
                        :wikitext(data.wikitext)
                        :done()
                    :tag('td')
                        :wikitext(text)
                        :done()
                    :done()
        elseif text then
            tbl
                :tag('tr')
                    :tag('td')
                        -- :attr('colspan', '2')
                        :wikitext(text)
                        :done()
                    :done()
        end
    end
    
    -- Output Infocard
	local infocard_args = {
		['class'] = 'ascendancy_class',
		['header'] = tpl_args.name,
		['subheader'] = string.format('[[%s]]', tpl_args.character),
		[1] = string.format(
            '[[File:%s ascendancy class.png|250px]]',
            tpl_args.name
        ),
		[2] = tostring(tbl),
    }
    
    -- cats
    local cats = {
        'Ascendancy classes', 
        tpl_args.character .. ' ascendancy classes',
    }
    
    return f_infocard(infocard_args) .. util.misc.add_category(cats)
end



-- ---------------------------------------------------------------------
-- Template: Event
-- ---------------------------------------------------------------------

local event_map = {
    main = {
        table = 'events',
        order = {'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
        parse_order = {'id', 'name', 'short_name', 'type', 'standard', 'hardcore', 'release_version', 'release_date', 'end_date', 'number_of_events', 'rewards', 'price', 'links'},
        fields = {
            -- Header:
            name = {
                name = 'name',
                field = 'name',
                type = 'String',
                wikitext = 'Name',
            },      
            -- Subheader:
            type = {
                name = 'type',
                field = 'type',
                type = 'String',
                wikitext = 'Type',
                func = function(tpl_args, frame, value)
                    local type_tbl = {
                        challenge = 'Challenge league',
                        expansion = 'Expansion',
                        pvp = 'PvP season',
                        race = 'Race season',
                    }
                    
                    return type_tbl[value]
                end, 
            },            
            -- Main text:
			release_version = { 
				name = 'release_version',
                field = 'release_version',
                type = 'String',
                wikitext = 'Release version',
                display = function(tpl_args, frame, value)
                    if value ~= nil then
                        return string.format('[[Version %s|%s]]', value, value)
                    end 
                end,
			},
			release_date = { 
				name = 'release_date',
                field = 'release_date',
                type = 'Datetime',
                wikitext = 'Release date',
                cargo_func = function(tpl_args, frame, value)
                    return h.date(value, {format='cargo'})
                end,
                display = function(tpl_args, frame, value)
                    local out 
                    if value ~= nil then
                        out = string.format(
                            '%s %s', 
                            h.date(value), 
                            h.timezone(value)
                        )
                    end
                    
                    return out
                end,
			},
			end_date = { 
				name = 'end_date',
                field = 'release_date',
                type = 'Datetime',
                wikitext = 'End date',
                cargo_func = function(tpl_args, frame, value)
                    return h.date(value, {format='cargo'})
                end,
                display = function(tpl_args, frame, value)
                    local out 
                    if value ~= nil then
                        out = string.format(
                            '%s %s', 
                            h.date(value), 
                            h.timezone(value)
                        )
                    end
                    
                    return out
                end,
			},
			standard = { 
				name = 'standard',
                field = 'is_standard',
                type = 'Boolean',
                wikitext = 'Standard',
                func = function(tpl_args, frame, value)
                    -- Change to 1 or 0 in templates
                    local tbl = {
                        ['True'] = '1',
                        ['true'] = '1',
                        ['False'] = '0',
                        ['false'] = '0',
                    }
                    return tbl[value]
                end,
			},
			hardcore = { 
				name = 'hardcore',
                field = 'is_hardcore',
                type = 'Boolean',
                wikitext = 'Hardcore',
                func = function(tpl_args, frame, value)
                    -- Change to 1 or 0 in templates
                    local tbl = {
                        ['True'] = '1',
                        ['true'] = '1',
                        ['False'] = '0',
                        ['false'] = '0',
                    }
                    return tbl[value]
                end,
                
            },            
			number_of_events = { 
				name = 'number_of_events',
                field = 'number_of_events',
                type = 'Integer',
                wikitext = 'Number of events',
			},	
			rewards = { 
				name = 'rewards',
                field = 'rewards',
                type = 'String',
                wikitext = 'Rewards',
                display = function(tpl_args, frame, value)
                    local out
                    if value ~= nil then
                        out = string.format(
                            '<div style="text-align: right;">%s</div>', 
                            value
                        )
                    end
                    return out
                end,
			},
			price = { 
				name = 'price',
                field = 'price',
                type = 'String',
                wikitext = 'Price',
                func = function(tpl_args, frame, value)
                    -- Catch spelling error, rename in template eventually:
                    return tpl_args['price'] or tpl_args['prize'] 
                end,
			},
			links = { 
				name = 'links',
                field = 'links',
                type = 'string', 
                wikitext = 'Links',
			},
            
            -- Field calculations:
            id = {
                name = 'id',
                field = 'id',
                type = 'String',
                wikitext = 'Id', 
            },
            short_name = {
                name = nil,
                field = 'short_name',
                type = 'String',
                wikitext = 'Short name', 
                func = function(tpl_args, frame)
                    local out = {}
                    for i,v in pairs(tpl_args) do
                        local tbl = {
                            challenge = 'league',
                            expansion = 'Please, do not match this.',
                            pvp = 'pvp season',
                            race = 'race season',
                        }
                        for ii,vv in pairs(tbl) do
                            if v==ii then
                                out[#out+1] = tpl_args['name']:lower():gsub(vv, ''):gsub('^%l', string.upper)
                                break
                            end
                        end
                    end
                    return table.concat(out, ', ')
                end,
            },
            -- ordinal = {
                -- name = nil,
                -- field = 'ordinal',
                -- type = 'String',
                -- wikitext = 'Ordinal number', 
                -- func = function(tpl_args, frame)
                    -- tpl_args.tables = 'events'
                    -- local count = string.format(
                        -- 'COUNT(DISTINCT %s._pageName)', 
                        -- tpl_args.tables
                    -- )
                    -- tpl_args.fields = count
                    -- tpl_args.q_where = string.format(
                        -- '%s.type = "%s" AND %s.release_date < "%s"', 
                        -- tpl_args.tables,
                        -- tpl_args.type, 
                        -- tpl_args.tables,
                        -- tpl_args.release_date
                    -- )
                    -- local results = h.cargo_query(tpl_args)
                    
                    -- if #results > 0 then 
                        -- return results[1][count]
                    -- else
                        -- return nil
                    -- end
                -- end,
            -- },
        },
    },
}

p.declare_events = util.cargo.declare_factory{data=event_map.main}


function p.event_box(tpl_args, frame, map)
    -- Main sections, loop through
    local tbl = mw.html.create('table')
    for _, key in ipairs(map.main.order) do
        local data = map.main.fields[key]
        
        if data.display == nil then
            text = tpl_args[key]
        else
            text = data.display(tpl_args, frame, tpl_args[key])
        end
        
        if text ~= nil then           
            tbl
                :tag('tr')
                    :tag('th')
                        :wikitext(data.wikitext)
                        :done()
                    :tag('td')
                        :wikitext(text)
                        :done()
                    :done()
        elseif text then
            tbl
                :tag('tr')
                    :tag('td')
                        -- :attr('colspan', '2')
                        :wikitext(text)
                        :done()
                    :done()
        end
    end
    
    -- Output Infocard
	local infocard_args = {
		['class'] = 'event',
		['header'] = tpl_args.name,
		['subheader'] = tpl_args.type,
		[1] = string.format(
            '[[File:%s|250px]]', 
            tpl_args.image or string.format('%s logo.png', tpl_args.name)
        ),
		[2] = tostring(tbl),
    }

    return f_infocard(infocard_args)
end

-- a=p.event{name='Ascendancy', type = 'expansion', release_version = '2.2.0', release_date = '2016-03-04'}
-- b=p.event{name='Winterheart race season', type='race', release_version = '2.3.0', release_date='2016-01-29', end_date='2016-08-29T22:00:00Z', number_of_events='155', rewards="[[Asphyxia's Wrath]] <br> [[Sapphire Ring]] <br> [[The Whispering Ice]] <br> [[Dyadian Dawn]] <br> [[Call of the Brotherhood]] <br> [[Winterheart]]", prize="[[Demigod's Dominance]]", links='[http://www.pathofexile.com/seasons Schedule and overview]'  }
-- c=p.event{name='PvP season 2', type='pvp', release_date='2015-02-15', end_date='2015-03-16', rewards="[[Wanderlust]] <br> [[Coral Ring]] <br> [[Geofri's Baptism]] <br> [[Kikazaru]] <br> [[Meginord's Girdle]] <br> [[Atziri's Foible]]", prize='[[Talisman of the Victor]]', links='[http://www.pathofexile.com/seasons/pvp/season/EUPvPSeason2 EU PvP Ladder] <br> [http://www.pathofexile.com/seasons/pvp/season/USPvPSeason2 US PvP Ladder]'  }
-- d=p.event{name='Perandus league', type='challenge ', release_version = '2.2.0', release_date='2016-03-04', end_date='2016-05-30', standard = 'True', hardcore = 'True'}

function p.event(frame)
    -- Get args
    local tpl_args = getArgs(frame, {parentFirst = true})
    local frame = util.misc.get_frame(frame)
	
    -- Parse event_map:
    local parsed_map = h.parse_map(tpl_args, frame, event_map)
    tpl_args = parsed_map.tpl_args
    local cargo_data = parsed_map.cargo_data
    
    -- Store cargo fields:
    util.cargo.store(frame, cargo_data)   
    
    -- Display infobox:
    local out = p.event_box(tpl_args, frame, event_map)
    
    -- Categories
    local cats = {
		tpl_args.type .. 's',
    }
    
    return out .. util.misc.add_category(cats)
end


-- ----------------------------------------------------------------------------

return p
Advertisement