Module:Sandbox: Difference between revisions

From Path of Exile 2 Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 969: Line 969:
p.itemRangeAverage = makeInvokeFunc('_itemRangeAverage')
p.itemRangeAverage = makeInvokeFunc('_itemRangeAverage')
function p._itemRangeAverage(args)
function p._itemRangeAverage(args)
local prop = args[1]
local s = {}
return prop
s.mod = string.match(args[1], '>([^><]+)</') or args[1]
s.sign = string.find(s.mod, '&minus;', 0, true) and -1 or 1
s.min = string.match(s.mod, '%((%S+)%s*to') or s.mod
s.max = string.match(s.mod, 'to%s*(%S+)%)') or s.min
s.minLow = tonumber( string.match(s.min, '(%d+)') )
s.minHigh = tonumber( string.match(s.min, '&ndash;(%d+)') or s.minLow )
s.maxLow = tonumber( string.match(s.max, '(%d+)') )
s.maxHigh = tonumber( string.match(s.max, '&ndash;(%d+)') or s.maxLow )
if #{s.minLow, s.minHigh, s.maxLow, s.maxHigh} > 0 then
return nil
end
return ( ( (s.minLow + s.minHigh) / 2 ) + ( (s.maxLow + s.maxHigh) / 2 ) ) / 2 * s.sign
end
end



Revision as of 14:54, 24 April 2015

Module documentation[view] [edit] [history] [purge]


This page is not an actual Scribunto module. It exists to provide editors a place to create experimental modules.

Naming your modules

To keep things tidy, please use the following format to name your experimental modules:

Module:Sandbox/Your username/Module name

Cleaning up unused modules

Experimental modules may be deleted by admins upon request or after a long period of inactivity.

List of modules in this area

For a list of the experimental modules under Module:Sandbox, see Special:PrefixIndex/Module:Sandbox/.

local p = {}
local views = {}
local getArgs, mathModule

---------------------------------------------------------------------
-- Argument processing
---------------------------------------------------------------------
local function makeInvokeFunc(funcName)
	return function (frame)
		if not getArgs then
			getArgs = require('Module:Arguments').getArgs
		end
		local args = getArgs(frame)
		return p[funcName](args)
	end
end

---------------------------------------------------------------------
-- Implements {{item}}
---------------------------------------------------------------------
p.item = makeInvokeFunc('_item')
function p._item(args)
	local cleanArgs = {}
	cleanArgs.view = args.view or args.View or 'full'
	cleanArgs.format = args.format or args.Format
	cleanArgs.name = args.name or args.Name
	cleanArgs.sortKey = args.sortKey or args.SortKey or cleanArgs.name
	cleanArgs.pageName = args.pageName or args.PageName or cleanArgs.name
	cleanArgs.image = args.image or args.Image or cleanArgs.pageName .. '.png'
	cleanArgs.size = args.size or args.Size or '2x_'
	cleanArgs.rarity = args.rarity or args.Rarity or 'Normal'
	cleanArgs.type = args.type or args.Type
	cleanArgs.subtype = args.subtype or args.Subtype
	cleanArgs.baseItem = args.baseItem or args.BaseItem
	cleanArgs.baseItemPage = args.baseItemPage or args.BaseItemPage or cleanArgs.baseItem
	cleanArgs.level = args.level or args.RequiredLevel
	cleanArgs.strength = args.strength or args.RequiredStrength
	cleanArgs.dexterity = args.dexterity or args.RequiredDexterity
	cleanArgs.intelligence = args.intelligence or args.RequiredIntelligence
	cleanArgs.physical = args.physicalDamage or args.PhysicalDamage
	cleanArgs.fire = args.fire or args.FireDamage
	cleanArgs.cold = args.cold or args.ColdDamage
	cleanArgs.lightning = args.lightning or args.LightningDamage
	cleanArgs.chaos = args.chaos or args.ChaosDamage
	cleanArgs.averageDamage = args.averageDamage or args.AverageDamage
	cleanArgs.critChance = args.critChance or args.CriticalStrikeChance
	cleanArgs.attacksPerSecond = args.attacksPerSecond or args.AttacksPerSecond
	cleanArgs.blockChance = args.blockChance or args.Block
	cleanArgs.armour = args.armour or args.Armour
	cleanArgs.evasion = args.evasion or args.Evasion
	cleanArgs.energyShield = args.energyShield or args.EnergyShield
	cleanArgs.mapLevel = args.mapLevel or args.MapLevel
	cleanArgs.itemQuantity = args.itemQuantity or args.itemQuantity
	cleanArgs.radius = args.radius or args.Radius
	cleanArgs.stackSize = args.stackSize or args.StackSize
	cleanArgs.effect = args.effect or args.Effect
	cleanArgs.life = args.life or args.FlaskLife
	cleanArgs.mana = args.mana or args.FlaskMana
	cleanArgs.duration = args.duration or args.FlaskDuration
	cleanArgs.chargeCap = args.chargeCap or args.FlaskCharges
	cleanArgs.chargeUse = args.chargeUse or args.ChargesUsed
	cleanArgs.implicitMods = args.implicitMods or args.ImplicitMods
	cleanArgs.randomMods = args.randomMods or args.RandomMods
	cleanArgs.cosmeticMods = args.cosmeticMods or args.CosmeticMods
	cleanArgs.helpText = args.helpText or args.HelpText
	cleanArgs.flavourText = args.flavourText or args.FlavourText
	return views[cleanArgs.view](cleanArgs)
end

---------------------------------------------------------------------
-- Views
---------------------------------------------------------------------
function views.full(args)
	args.stats = p._statsBuilder(args)
	args.class = 'itembox-full'
	args.name = '[[' .. args.pageName .. '|' .. args.name .. ']]'
	args.baseItem = args.baseItem and ('[[' .. args.baseItemPage .. '|' .. args.baseItem .. ']]') or nil
	args.belowStats = mw.html.create('div')
		:attr('class', 'itemboximage')
		:wikitext( '[[File:' .. args.image .. '|' .. p._itemsize({args.size}) .. '|]]' )
	local category
	local types = {
		['Weapon'] = {
			['Bow'] = 'Bows',
			['Claw'] = 'Claws',
			['Dagger'] = 'Daggers',
			['Wand'] = 'Wands',
			['Fishing Rod'] = 'Fishing rods',
			['Staff'] = 'Staves',
			['One Handed Axe'] = 'One-handed axes',
			['Two Handed Axe'] = 'Two-handed axes',
			['One Handed Mace'] = 'One-handed maces',
			['Two Handed Mace'] = 'Two-handed maces',
			['One Handed Sword'] = 'One-handed swords',
			['Two Handed Sword'] = 'Two-handed swords'
		},
		['Armour'] = {
			['Body Armour'] = 'Body armours',
			['Helmet'] = 'Helmets',
			['Shield'] = 'Shields',
			['Boots'] = 'Boots',
			['Gloves'] = 'Gloves'
		},
		['Accessory'] = {
			['Amulet'] = 'Amulets',
			['Belt'] = 'Belts',
			['Quiver'] = 'Quivers',
			['Ring'] = 'Rings'
		},
		['Flask'] = {
			['Life'] = 'Life flasks',
			['Mana'] = 'Mana flasks',
			['Hybrid'] = 'Hybrid flasks',
			['Utility'] = 'Utility flasks'
		},
		['Map'] = {
			['Fragment'] = 'Map fragments',
			['_default'] = 'Maps'
		},
		['Jewel'] = 'Jewels',
		['Currency'] = 'Currency items',
		['Quest'] = 'Quest items',
		['Microtrans'] = 'Microtransaction features'
	}
	category = types[args.type]
	if type(category) == 'table' then
		category = types[args.type][args.subtype or '_default']
	end
	if category then
		if args.rarity == 'Unique' then
			category = 'Unique ' .. string.lower(category)
		end
	else
		category = 'Items with invalid types'
	end
	return tostring( p._itembox(args) ) .. '[[Category:' .. category .. ']]'
end

function views.standard(args)
	args.stats = p._statsBuilder(args)
	args.name = '[[' .. args.pageName .. '|' .. args.name .. ']]'
	args.baseItem = args.baseItem and ('[[' .. args.baseItemPage .. '|' .. args.baseItem .. ']]') or nil
	return tostring( p._itembox(args) )
end

function views.inline(args)
	args.stats = p._statsBuilder(args)
	args.class = 'itemboxhover itemboxhoverhide itemboxhovernojs'
	args.isHover = true
	local fArgs = args.format and mw.text.split(args.format, '║', true) or {}
	fArgs.text = fArgs[1] or args.name
	fArgs.image = fArgs[2] or args.image
	fArgs.large = fArgs[3] or false
	local container = mw.html.create('span')
		:tag('span')
			:attr('class', 'itemhover')
			:wikitext(
				fArgs.large
					and '[[' .. args.pageName .. '|' .. fArgs.text .. ']] <br> [[File:' .. fArgs.image .. '|' .. p._itemsize({args.size, '39'}) .. '|link=' .. args.pageName .. '|alt=]]'
					or '[[File:' .. fArgs.image .. '|16x16px|link=|alt=]][[' .. args.pageName .. '|' .. fArgs.text .. ']]'
			)
			:done()
		:node( p.itembox(args) )
		:tag('span')
			:attr('class', 'itemboxhovericon itemboxhoverhide itemboxhovernojs')
			:wikitext( '[[File:' .. fArgs.image .. '|' .. p._itemsize({args.size}) .. '|link=|alt=]]' )
			:done()
	return tostring(container)
end

function views.tablerow(args)
	if not mathModule then
		mathModule = require('Module:Math')
	end
	local otherPage = ( mw.title.getCurrentTitle().fullText == args.pageName )
	local fArgs = args.format and mw.text.split(args.format, ' ', true) or {}
	for i=1, #fArgs do
		fArgs[ fArgs[i] ] = true
	end
	local function newNA()
		return mw.html.create('td')
			:attr('class', 'table-na')
			:attr('style', 'text-align: center;')
			:attr('data-sort-value', '0')
			:wikitext('<small>N/A</small>')
	end
	local row = mw.html.create('tr')
	if otherPage then
		row
			:attr('id', args.name)
	end
	if fArgs.name then
		row
			:tag('td')
				:attr('data-sort-value', args.sortKey)
				:wikitext( otherPage and '[[' .. args.pageName .. '|' .. args.name .. ']]' or args.name .. ' <br> [[File:' .. args.image .. '|' .. p._itemsize({args.size, '39'}) .. '|link=' .. (otherPage and args.pageName or '') .. '|alt=]]' )
				:done()
	end
	if fArgs.base then
		row
			:tag('td')
				:wikitext( '[[' .. args.baseItem .. ']]' )
				:done()
	end
	if fArgs.level then
		if args.level then
			row
				:tag('td')
					:wikitext( '[[' .. args.level .. ']]' )
					:done()
		else
			row
				:node( newNA() )
		end
	end
	if args.type == 'Weapon' or args.type == 'Armour' then
		if fArgs.str then
			if args.strength then
				row
					:tag('td')
						:wikitext(args.strength)
						:done()
			else
				row
					:node( newNA() )
			end
		end
		if fArgs.dex then
			if args.dexterity then
				row
					:tag('td')
						:wikitext(args.dexterity)
						:done()
			else
				row
					:node( newNA() )
			end
		end
		if fArgs.int then
			if args.intelligence then
				row
					:tag('td')
						:wikitext(args.intelligence)
						:done()
			else
				row
					:node( newNA() )
			end
		end
	end
	if args.type == 'Weapon' then
		if fArgs.weapon then
			local avgDmg = tonumber(args.averageDamage) or 0
			local avgCrt = 0
			local avgAps = 0
			row
				:tag('td')
					:attr('data-sort-value', avgDmg)
					:wikitext(args.averageDamage)
					:done()
				:tag('td')
					:attr('data-sort-value', avgCrt)
					:wikitext(args.critChance)
					:done()
				:tag('td')
					:attr('data-sort-value', avgAps)
					:wikitext(args.attacksPerSecond)
					:done()
				:tag('td')
					:wikitext( tostring( mathModule._round( avgDmg * avgAps * (1 - avgCrt / 100) + avgDmg * avgAps * avgCrt / 100 * 1.5, 2 ) ) )
					:done()
		end
	elseif args.type == 'Armour' then
		if fArgs.block then
			if args.blockChance then
				row
					:tag('td')
						:wikitext(args.blockChance)
						:done()
			else
				row
					:node( newNA() )
			end
		end
		if fArgs.armour then
			if args.armour then
				row
					:tag('td')
						:wikitext(args.armour)
						:done()
			else
				row
					:node( newNA() )
			end
		end
		if fArgs.evasion then
			if args.evasion then
				row
					:tag('td')
						:wikitext(args.evasion)
						:done()
			else
				row
					:node( newNA() )
			end
		end
		if fArgs.energyshield then
			if args.energyShield then
				row
					:tag('td')
						:wikitext(args.energyShield)
						:done()
			else
				row
					:node( newNA() )
			end
		end
	elseif args.type == 'Flask' then
		if fArgs.life then
			if args.life then
				row
					:tag('td')
						:wikitext(args.life)
						:done()
			else
				row
					:node( newNA() )
			end
		end
		if fArgs.mana then
			if args.mana then
				row
					:tag('td')
						:wikitext(args.mana)
						:done()
			else
				row
					:node( newNA() )
			end
		end
		if fArgs.effect then
			if args.effect then
				row
					:tag('td')
						:attr('class', 'text-mod')
						:wikitext(args.effect)
						:done()
			else
				row
					:node( newNA() )
			end
			row
				:tag('td')
					:wikitext(args.duration)
					:done()
				:tag('td')
					:wikitext(args.chargeCap)
					:done()
				:tag('td')
					:wikitext(args.chargeUse)
					:done()
		end
	elseif args.type == 'Map' then
		row
			:tag('td')
				:wikitext(args.mapLevel)
				:done()
		if fArgs.qty then
			if args.itemQuantity then
				row
					:tag('td')
						:wikitext(args.itemQuantity)
						:done()
			else
				row
					:node( newNA() )
			end
		end
	elseif args.type == 'Jewel' then
		row
			:tag('td')
				:wikitext(args.radius)
				:done()
	elseif args.type == 'Currency' then
		row
			:tag('td')
				:wikitext(args.stackSize)
				:done()
		if fArgs.effect then
			if args.effect then
				row
					:tag('td')
						:attr('class', 'text-mod')
						:wikitext(args.effect)
						:done()
			else
				row
					:node( newNA() )
			end
		end
	end
	if fArgs.mods then
		if args.implicitMods or args.randomMods or args.cosmeticMods then
			local stats = mw.html.create('div')
				:attr('class', 'itemboxstats')
			if args.implicitMods then
				stats
					:tag('div')
						:attr('class', 'itemboxstatsgroup text-mod')
						:wikitext(args.implicitMods)
						:done()
			end
			if args.randomMods then
				stats
					:tag('div')
						:attr('class', 'itemboxstatsgroup text-mod')
						:wikitext(args.randomMods)
						:done()
			end
			if args.cosmeticMods then
				stats
					:tag('div')
						:attr('class', 'itemboxstatsgroup text-cosmetic')
						:wikitext(args.cosmeticMods)
						:done()
			end
			row
				:tag('td')
					:node(stats)
					:done()
		else
			row
				:node( newNA() )
		end
	end
	if fArgs.flavour then
		if args.flavourText then
			row
				:tag('td')
					:attr('class', 'text-flavour')
					:wikitext(args.flavourText)
					:done()
		else
			row
				:node( newNA() )
		end
	end
	if fArgs.help then
		if args.helpText then
			row
				:tag('td')
					:attr('class', 'text-help')
					:wikitext(args.helpText)
					:done()
		else
			row
				:node( newNA() )
		end
	end
	return row
end

---------------------------------------------------------------------
-- Stats builder
---------------------------------------------------------------------
function p._statsBuilder(args)
	local container = mw.html.create('span')
	local group
	local function newGroup(class)
		return mw.html.create('span')
			:attr( 'class', 'itemboxstatsgroup ' .. (class or '') )
	end
	local function newColor(label, text)
		if text == nil or text == '' then
			return nil
		end
		return mw.html.create('span')
			:attr('class', 'text-' .. label)
			:wikitext(text)
	end
	if args.type == 'Weapon' then
		group = newGroup()
			:wikitext(args.subtype)
			:tag('br'):done()
		if args.physical then
			group
				:wikitext('Physical Damage: ')
				:node( newColor('value', args.physical) )
				:tag('br'):done()
		end
		if args.fire or args.cold or args.lightning then
			local elementalDamage = {}
			if args.fire then
				table.insert( elementalDamage, tostring( newColor('fire', args.fire) ) )
			end
			if args.cold then
				table.insert( elementalDamage, tostring( newColor('cold', args.cold) ) )
			end
			if args.lightning then
				table.insert( elementalDamage, tostring( newColor('lightning', args.lightning) ) )
			end
			group
				:wikitext('Elemental Damage: ')
				:wikitext( table.concat(elementalDamage, ', ') )
				:tag('br'):done()
		end
		if args.chaos then
			group
				:wikitext('Chaos Damage: ')
				:node( newColor('chaos', args.chaos) )
				:tag('br'):done()
		end
		group
			:wikitext('Critical Strike Chance: ')
			:node( newColor('value', args.critChance) )
			:tag('br'):done()
			:wikitext('Attacks per Second: ')
			:node( newColor('value', args.attacksPerSecond) )
		container:node(group)
	elseif args.type == 'Armour' then
		if args.blockChance or args.armour or args.evasion or args.energyShield then
			group = newGroup()
			if args.blockChance then
				group
					:wikitext('Chance to Block: ')
					:node( newColor('value', args.blockChance) )
					:tag('br'):done()
			end
			if args.armour then
				group
					:wikitext('Armour: ')
					:node( newColor('value', args.armour) )
					:tag('br'):done()
			end
			if args.evasion then
				group
					:wikitext('Evasion: ')
					:node( newColor('value', args.evasion) )
					:tag('br'):done()
			end
			if args.energyShield then
				group
					:wikitext('Energy Shield: ')
					:node( newColor('value', args.energyShield) )
			end
			container:node(group)
		end
	elseif args.type == 'Map' then
		if args.mapLevel then
			group = newGroup()
				:wikitext('Map Level: ')
				:node( newColor('value', args.mapLevel) )
				:tag('br'):done()
			if args.itemQuantity then
				group
					:wikitext('Item Quantity: ')
					:node( newColor('value', args.itemQuantity) )
			end
			container:node(group)
		end
	elseif args.type == 'Jewel' then
		if args.radius then
			group = newGroup()
				:wikitext('Radius: ')
				:node( newColor('value', args.radius) )
			container:node(group)
		end
	elseif args.type == 'Currency' then
		group = newGroup()
			:wikitext('Stack Size: ')
			:node( newColor('value', args.stackSize) )
		container:node(group)
		if args.effect then
			group = newGroup('textwrap text-mod')
				:wikitext(args.effect)
			container:node(group)
		end
	elseif args.type == 'Flask' then
		group = newGroup()
		if args.life then
			group
				:wikitext('Recovers ')
				:node( newColor('value', args.life) )
				:wikitext(' Life over ')
				:node( newColor('value', args.duration) )
				:wikitext(' Seconds')
				:tag('br'):done()
		end
		if args.mana then
			group
				:wikitext('Recovers ')
				:node( newColor('value', args.mana) )
				:wikitext(' Mana over ')
				:node( newColor('value', args.duration) )
				:wikitext(' Seconds')
				:tag('br'):done()
		end
		if args.effect then
			group
				:wikitext('Lasts ')
				:node( newColor('value', args.duration) )
				:wikitext(' Seconds')
				:tag('br'):done()
		end
		group
			:wikitext('Consumes ')
			:node( newColor('value', args.chargeUse) )
			:wikitext(' of ')
			:node( newColor('value', args.chargeCap) )
			:wikitext(' Charges on use')
			:tag('br'):done()
		if args.effect then
			group
				:wikitext(args.effect)
		end
		container:node(group)
	elseif args.type == 'Microtrans' then
		group = newGroup()
		if args.subtype or args.stackSize then
			group
				:wikitext(args.subtype)
				:tag('br'):done()
			if args.stackSize then
				group
					:wikitext('Stack Size: ')
					:node( newColor('value', args.stackSize) )
			end
			container:node(group)
		end
		group = newGroup('textwrap text-mod')
			:wikitext(args.effect)
		container:node(group)
	end
	if args.level or args.strength or args.dexterity or args.intelligence then
		local requirements = {}
		local attrLabel
		if args.level then
			table.insert( requirements, 'Level ' .. tostring( newColor('value', args.level) ) )
		end
		if args.strength then
			attrLabel = ' Strength'
			if args.level or args.dexterity or args.intelligence then
				attrLabel = ' Str'
			end
			table.insert( requirements, tostring( newColor('value', args.strength) ) .. attrLabel )
		end
		if args.dexterity then
			attrLabel = ' Dexterity'
			if args.level or args.strength or args.intelligence then
				attrLabel = ' Dex'
			end
			table.insert( requirements, tostring( newColor('value', args.dexterity) ) .. attrLabel )
		end
		if args.intelligence then
			attrLabel = ' Intelligence'
			if args.level or args.strength or args.dexterity then
				attrLabel = ' Int'
			end
			table.insert( requirements, tostring( newColor('value', args.intelligence) ) .. attrLabel )
		end
		group = newGroup()
			:wikitext('Requires ')
			:wikitext( table.concat(requirements, ', ') )
		container:node(group)
	end
	if args.implicitMods then
		group = newGroup('text-mod')
			:wikitext(args.implicitMods)
		container:node(group)
	end
	if args.randomMods then
		group = newGroup('text-mod')
			:wikitext(args.randomMods)
		container:node(group)
	end
	if args.cosmeticMods then
		group = newGroup('text-cosmetic')
			:wikitext(args.cosmeticMods)
		container:node(group)
	end
	if args.flavourText then
		group = newGroup('textwrap text-flavour')
			:wikitext(args.flavourText)
		container:node(group)
	end
	if args.helpText then
		group = newGroup('textwrap text-help')
			:wikitext(args.helpText)
		container:node(group)
	end
	return container
end

---------------------------------------------------------------------
-- Implements {{itembox}}
---------------------------------------------------------------------
p.itembox = makeInvokeFunc('_itembox')
function p._itembox(args)
	local frames = {
		['Currency'] = 'currency',
		['Microtrans'] = 'currency',
		['Gem'] = 'gem',
		['Quest'] = 'quest'
	}
	local container = mw.html.create(args.isHover and 'span' or 'div')
		:attr( 'class', 'itembox-' .. ( string.lower(args.frame or frames[args.type] or args.rarity or 'normal') ) .. ' ' .. (args.class or '') )
		:tag('span')
			:attr( 'class', 'itemboxheader-' .. (args.baseItem and 'double' or 'single') )
			:tag('span')
				:attr('class', 'itemboxheaderleft')
				:done()
			:tag('span')
				:attr('class', 'itemboxheaderright')
				:done()
			:tag('span')
				:attr('class', 'itemboxheadertext')
				:wikitext( args.name .. (args.baseItem and '<br>' .. args.baseItem or '') )
				:done()
			:done()
	if type(args.aboveStats) == 'table' then
		container:node(args.aboveStats)
	elseif type(args.aboveStats) == 'string' then
		container:wikitext(args.aboveStats)
	end
	local stats = mw.html.create('span')
		:attr('class', 'itemboxstats')
	if type(args.stats) == 'table' then
		stats:node(args.stats)
	elseif type(args.stats) == 'string' then
		stats:wikitext(args.stats)
	end
	container:node(stats)
	if type(args.belowStats) == 'table' then
		container:node(args.belowStats)
	elseif type(args.belowStats) == 'string' then
		container:wikitext(args.belowStats)
	end
	return container
end

---------------------------------------------------------------------
-- Implements {{item table}}
---------------------------------------------------------------------
function p.itemTable(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	local args = getArgs(frame)
	local fArgs = args.format and mw.text.split(args.format, ' ', true) or {}
	for i=1, #fArgs do
		fArgs[ fArgs[i] ] = true
	end
	local function newAbbr(text, title)
		return mw.html.create('abbr')
			:attr('class', 'nounderline')
			:attr('title', title)
			:wikitext(text)
	end
	local tbl = mw.html.create('table')
		:attr('class', 'wikitable sortable')
		:attr('style', 'text-align:center; ' .. ( args.width and 'width:' .. args.width or '' ) )
	local hdr = mw.html.create('tr')
		:tag('th')
			:wikitext('Name')
			:done()
	if fArgs.base then
		hdr
			:tag('th')
				:wikitext('Base Item')
				:done()
	end
	if fArgs.level then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:node( newAbbr('[[File:Level_up_icon_small.png|link=|Lvl.]]', 'Required Level') )
				:done()
	end
	if fArgs.str then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:node( newAbbr('[[File:StrengthIcon_small.png|link=|Str.]]', 'Required Strength') )
				:done()
	end
	if fArgs.dex then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:node( newAbbr('[[File:DexterityIcon_small.png|link=|Dex.]]', 'Required Dexterity') )
				:done()
	end
	if fArgs.int then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:node( newAbbr('[[File:IntelligenceIcon_small.png|link=|Int.]]', 'Required Intelligence') )
				:done()
	end
	if fArgs.weapon then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Damage')
				:done()
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Critical Strike Chance')
				:done()
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Attacks per Second')
				:done()
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Damage per Second')
				:done()
	end
	if fArgs.block then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Chance to Block')
				:done()
	end
	if fArgs.armour then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Armour Rating')
				:done()
	end
	if fArgs.evasion then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Evasion Rating')
				:done()
	end
	if fArgs.energyshield then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Energy Shield')
				:done()
	end
	if fArgs.flask then
		if fArgs.life or fArgs.mana then
			if fArgs.life then
				hdr
					:tag('th')
						:attr('data-sort-type', 'number')
						:node( newAbbr('Life', 'Life Recovered over Time per Sip') )
						:done()
			end
			if fArgs.mana then
				hdr
					:tag('th')
						:attr('data-sort-type', 'number')
						:node( newAbbr('Mana', 'Mana Recovered over Time per Sip') )
						:done()
			end
			hdr
				:tag('th')
					:attr('data-sort-type', 'number')
					:node( newAbbr(
						'Time', 
						(fArgs.life and 'Life' or '') .. ( (fArgs.life and fArgs.mana) and ' and ' or '' ) .. (fArgs.mana and 'Mana' or '') .. ' Recovery Time in Seconds'
					) )
					:done()
		end
		if fArgs.effect then
			hdr
				:tag('th')
					:attr('class', 'unsortable')
					:wikitext('Effects')
					:done()
				:tag('th')
					:attr('data-sort-type', 'number')
					:wikitext('Duration')
					:done()
		end
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:node( newAbbr('Capacity', 'Total Amount of Charges the Flask Can Hold') )
				:done()
			:tag('th')
				:attr('data-sort-type', 'number')
				:node( newAbbr('Usage', 'Amount of Charges Used per Sip') )
				:done()
	end
	if fArgs.map then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Map Level')
				:done()
		if fArgs.qty then
			hdr
				:tag('th')
					:attr('data-sort-type', 'number')
					:wikitext('Item Quantity')
					:done()
		end
	end
	if fArgs.jewel then
		hdr
			:tag('th')
				:wikitext('Radius')
				:done()
	end
	if fArgs.currency then
		hdr
			:tag('th')
				:attr('data-sort-type', 'number')
				:wikitext('Stack Size')
				:done()
		if fArgs.effect then
			hdr
				:tag('th')
					:attr('class', 'unsortable')
					:wikitext('Effects')
					:done()
		end
	end
	if fArgs.mods then
		hdr
			:tag('th')
				:attr('class', 'unsortable')
				:wikitext('Modifiers')
				:done()
	end
	if fArgs.flavour then
		hdr
			:tag('th')
				:attr('class', 'unsortable')
				:wikitext('Flavour Text')
				:done()
	end
	if fArgs.help then
		hdr
			:tag('th')
				:attr('class', 'unsortable')
				:wikitext('Help Text')
				:done()
	end
	tbl:node(hdr)
	local i = 1
	while args[i] do
		tbl
			:node(
				frame:expandTemplate{
					title = ':' .. args[i],
					args = {
						['View'] = 'tablerow',
						['Format'] = 'name ' .. (args.format or '')
					}
				}
			)
		i = i + 1
	end
	return tostring(tbl)
end

---------------------------------------------------------------------
-- Implements {{item range average}}
---------------------------------------------------------------------
p.itemRangeAverage = makeInvokeFunc('_itemRangeAverage')
function p._itemRangeAverage(args)
	local s = {}
	s.mod = string.match(args[1], '>([^><]+)</') or args[1]
	s.sign = string.find(s.mod, '&minus;', 0, true) and -1 or 1
	s.min = string.match(s.mod, '%((%S+)%s*to') or s.mod
	s.max = string.match(s.mod, 'to%s*(%S+)%)') or s.min
	s.minLow = tonumber( string.match(s.min, '(%d+)') )
	s.minHigh = tonumber( string.match(s.min, '&ndash;(%d+)') or s.minLow )
	s.maxLow = tonumber( string.match(s.max, '(%d+)') )
	s.maxHigh = tonumber( string.match(s.max, '&ndash;(%d+)') or s.maxLow )
	if #{s.minLow, s.minHigh, s.maxLow, s.maxHigh} > 0 then
		return nil
	end
	return ( ( (s.minLow + s.minHigh) / 2 ) + ( (s.maxLow + s.maxHigh) / 2 ) ) / 2 * s.sign
end

---------------------------------------------------------------------
-- Implements {{itemsize}}
---------------------------------------------------------------------
p.itemsize = makeInvokeFunc('_itemsize')
function p._itemsize(args)
	local size = args[1] or '1x_'
	local grid = args[2] or 78
	local dim = mw.text.split(size, 'x', true)
	if dim[1] == '_' then
		if dim[2] == '_' then
			dim[1] = grid
		else
			dim[1] = ''
		end
	else
		dim[1] = dim[1] * grid
	end
	if dim[2] == '_' then
		dim[2] = ''
	else
		dim[2] = 'x' .. dim[2] * grid
	end
	return dim[1] .. dim[2] .. 'px'
end

return p