Module:List

local lang = mw.getLanguage('en') local p = {}

--

-- 'element' function for listing items by an element (eg all items with Ethereal stats). -- use "element=Ethereal", etc function p.element(frame) if frame == mw.getCurrentFrame then args = require('Module:ProcessArgs').merge(true) else frame = mw.getCurrentFrame end showClass = true showDurability = false

local element = args.element local elementBonus = element .. 'Bonus'

local html = mw.html.create

p.elementQuery('Weapon', element, elementBonus, html, frame) html:newline p.elementQuery('Armor', element, elementBonus, html, frame) html:newline p.elementQuery('Equipment', element, elementBonus, html, frame) return html end

function p.elementQuery(category, element, elementBonus, html, frame) -- get all items with some value for the element local cargoWhere = element .. ' IS NOT NULL OR ' .. elementBonus .. ' IS NOT NULL'

-- do the query local result = mw.ext.cargo.query('ItemData',		p.cargoFields(category, ''),		{			where = '(category="' .. category .. '") AND (' .. cargoWhere .. ')',			orderBy = 'name',			groupBy = 'name',			limit = 5000		}	)

-- if results, append to html if (result ~= nil and #result > 0) then p.formatElementResult(html, result, category, frame) end

return end

function p.formatElementResult(html, result, category, frame) -- create the header for the results html:wikitext(frame:preprocess('===' .. category .. 's===')):newline -- use the normal table builder local formattedResult = p.formatResult(result, category, frame, '') -- append the table to our html html:node(formattedResult) end

--

-- 'manual' function for listing a known list of items. Use "itemsToList = Item1, Item2, Item3" etc. function p.manual(frame) if frame == mw.getCurrentFrame then args = require('Module:ProcessArgs').merge(true) else frame = mw.getCurrentFrame end showClass = true showDurability = true

local category = args.category or 'Item'

local items = p.split(args.itemsToList, ',')

local cargoWhere = '' for _, v in ipairs(items) do if cargoWhere ~= '' then cargoWhere = cargoWhere .. ' OR ' end cargoWhere = cargoWhere .. '_pageName="' .. v .. '"' end

local result = mw.ext.cargo.query('ItemData',		p.cargoFields(category, ''),		{			where = '(category="' .. category .. '") AND (' .. cargoWhere .. ')',			orderBy = 'name',			groupBy = 'name',			limit = 5000		}	)

if result == nil or #result < 1 then return '' else return p.formatResult(result, category, frame, '') end end

--

-- Main function function p.items(frame) if frame == mw.getCurrentFrame then args = require('Module:ProcessArgs').merge(true) else frame = mw.getCurrentFrame end --frame = mw.getCurrentFrame --args = frame.args local category = args.category or "Item" local class = args.class or "" local itype = args.type or "" local set = args.set or "" local default = args.default or "true" showClass = args.showClass or args.showclass or false showDurability = args.showDurability or args.showdurability or true --mw.log(string.format("category: %s", category)) --mw.log(string.format("class: %s", class)) --mw.log(string.format("itype: %s", itype)) local result = p.doQuery(category,class,itype,set) if not result then if default == "true" then return ' \'\'No items found.\'\' ' else return '' end end return p.formatResult(result, category, frame, class) end

function p.doQuery(category,class,itype,set) local result = mw.ext.cargo.query('ItemData',		p.cargoFields(category,class),		{			where = string.format("%s AND name != '%s'",p.cargoWhere(category,class,itype,set),"%s"),			orderBy = 'name',			groupBy = 'name',			limit = 5000		}	) if not next(result) then return nil else return result end end

function p.cargoFields(category, class) if category == "Weapon" then fields = p.weaponFields(class) elseif category == "Armor" then fields = p.armorFields elseif category == "Set" then fields = p.armorFields elseif category == "Equipment" then fields = p.equipmentFields elseif category == "Consumable" then fields = p.consumableFields elseif category == "Item" then fields = p.itemFields else return nil end return table.concat(fields,',') end

function p.itemFields fields = { '_pageName','name', 'image', 'effects', 'weight', 'buy', 'sell', 'durability', 'class', 'type', 'DLC' }	return fields end

function p.armorFields fields = p.itemFields; armorFields = { 'protection','barrier','statusResist','physical','ethereal','decay','lightning','frost','fire','impact','physicalBonus','etherealBonus','decayBonus','lightningBonus','frostBonus','fireBonus','manacost','staminacost','durability','movespeed','coldresist','heatresist','pouch','itemset','corruptresist','cooldown' }	newFields = p.mergeTables(armorFields,fields) return newFields end

function p.weaponFields(class) fields = p.itemFields; if (class ~= "Shield") then weaponFields = { 'physical', 'ethereal', 'decay', 'lightning', 'frost', 'fire', 'impact', 'protection', 'barrier', 'attackspeed', 'physicalBonus', 'etherealBonus', 'decayBonus', 'lightningBonus', 'frostBonus', 'fireBonus', 'manacost', 'staminacost', 'itemset' }	else weaponFields = { 'physical', 'ethereal', 'decay', 'lightning', 'frost', 'fire', 'impact', 'protection', 'impactResist', 'physicalBonus', 'etherealBonus', 'decayBonus', 'lightningBonus', 'frostBonus', 'fireBonus', 'manacost', 'staminacost', 'itemset' }	end newFields = p.mergeTables(weaponFields,fields) return newFields end

function p.equipmentFields fields = p.itemFields; equipmentFields = { 'impact','protection', 'barrier', 'statusResist', 'physicalBonus', 'etherealBonus', 'decayBonus', 'lightningBonus', 'frostBonus', 'fireBonus','capacity','manacost','staminacost','movespeed','preservation','inventProt', 'corruptresist' }	newFields = p.mergeTables(equipmentFields,fields) return newFields end

function p.consumableFields fields = p.itemFields; consumableFields = { 'thirst','hunger' }	newFields = p.mergeTables(consumableFields,fields) return newFields end

function p.mergeTables(fields,newFields) for k,v in pairs(newFields) do 		fields[#fields+1] = v 	end return fields end

function p.cargoWhere(category,class,itype,set) local where = string.format('category="%s"', category) if not p.isempty(class) then where = where .. string.format(' AND class="%s"', class) end if not p.isempty(itype) then where = where .. string.format(' AND type="%s"', itype) end if not p.isempty(set) then where = where .. string.format(' AND itemset="%s"', set) end return where end

function p.formatResult(result,category,frame,class) formatted = {} columns = p.defineColumns(result,category,class) --mw.log('p.formatResult; columns: ') --mw.logObject(columns) for key,row in ipairs(result) do		formatted[key] = p.hydrateRows(columns,row,frame) end --mw.log('p.formatResult; formatted: ') --mw.logObject(formatted) return p.makeTable(formatted,columns,frame,category) end

function p.defineColumns(result,category,class) --mw.log(string.format('p.defineColumns. Category: %s', category)) columns = {'image','name','damage','physical','ethereal','fire','frost','lightning','decay','protection','barrier','statusResist','impact','impactResist','attackspeed','reach','bonus','thirst','hunger','heatresist','coldresist','staminacost','manacost','corruptresist','cooldown','movespeed','pouch','capacity','durability','weight','effects','class','preservation','inventProt'} if category ~= "Armor" and category ~= "Set" then table.remove(columns, p.tablefind(columns, "physical")) table.remove(columns, p.tablefind(columns, "ethereal")) table.remove(columns, p.tablefind(columns, "fire")) table.remove(columns, p.tablefind(columns, "frost")) table.remove(columns, p.tablefind(columns, "lightning")) table.remove(columns, p.tablefind(columns, "decay")) else table.remove(columns, p.tablefind(columns, "damage")) end if class ~= 'Shield' then table.remove(columns, p.tablefind(columns, "impactResist")) end if showDurability ~= true then table.remove(columns, p.tablefind(columns, "durability")) end if not showClass then table.remove(columns, p.tablefind(columns, "class")) end columns = p.removeColumns(result,category,showClass,columns) return columns end

function p.hydrateRows(columns,row,frame) formattedRow = {} image = '' local link = row.name or row._pageName if string.find(row.name, "(weapon)") then link = row._pageName or '' end for k,column in ipairs(columns) do 		if column == 'image' then if p.isempty(row.image) then image = 'Placeholder.png' else image = row.image end formattedRow.image = string.format("", image, link) elseif column == 'class' then if (row.class == "Shield" or row.class == "Bow" or row.class == "Spear") then formattedRow.class = string.format("%s", row.class, row.class) elseif(row.type == "One-Handed") then formattedRow.class = string.format("1H %s", row.class, row.type, row.class) elseif (row.type == "Two-Handed") then formattedRow.class = string.format("2H %s", row.class, row.type, row.class) elseif (row.type == "Staff" or row.type == "Halberd") then formattedRow.class = string.format("%s", row.class, row.type) else if (row.class == "Chest") then formattedRow.class = "Body Armor" elseif (row.class == "Legs") then formattedRow.class = "Boots" elseif (row.class == "Head") then formattedRow.class = "Helmets" else if (p.isempty(row.class)) then if (row.type == "Other") then formattedRow.class = "Other" else formattedRow.class = string.format("%s", row.type, row.type) end else formattedRow.class = string.format("%s", row.class, row.class) end end end elseif column == 'name' then local itemName =  .. row.name ..  if row.DLC ~= nil and row.DLC ~= '' then itemName = frame:preprocess(itemName .. ' ') end formattedRow.name = itemName formattedRow.rawName = row.name elseif column == 'durability' then formattedRow[column] = row[column] elseif column == 'damage' then phys = '' ethe = '' fire = '' fros = '' ligh = '' deca = '' damageSum = 0 if not p.isempty(row.physical) then phys = frame:preprocess(string.format(" ", row.physical)) damageSum = damageSum + row.physical end if not p.isempty(row.ethereal) then ethe = frame:preprocess(string.format(" ", row.ethereal)) damageSum = damageSum + row.ethereal end if not p.isempty(row.fire) then fire = frame:preprocess(string.format(" ", row.fire)) damageSum = damageSum + row.fire end if not p.isempty(row.frost) then fros = frame:preprocess(string.format(" ", row.frost)) damageSum = damageSum + row.frost end if not p.isempty(row.lightning) then ligh = frame:preprocess(string.format(" ", row.lightning)) damageSum = damageSum + row.lightning end if not p.isempty(row.decay) then deca = frame:preprocess(string.format(" ", row.decay)) damageSum = damageSum + row.decay end formattedRow.damage = string.format('%s%s%s%s%s%s', phys, ethe, fire, fros, ligh, deca) formattedRow.damageSum = damageSum elseif column == 'bonus' then phys = '' ethe = '' fire = '' fros = '' ligh = '' deca = '' damageSum = 0 if not p.isempty(row.physicalBonus) then phys = frame:preprocess(string.format(" ", row.physicalBonus)) damageSum = damageSum + row.physicalBonus end if not p.isempty(row.etherealBonus) then ethe = frame:preprocess(string.format(" ", row.etherealBonus)) damageSum = damageSum + row.etherealBonus end if not p.isempty(row.fireBonus) then fire = frame:preprocess(string.format(" ", row.fireBonus)) damageSum = damageSum + row.fireBonus end if not p.isempty(row.frostBonus) then fros = frame:preprocess(string.format(" ", row.frostBonus)) damageSum = damageSum + row.frostBonus end if not p.isempty(row.lightningBonus) then ligh = frame:preprocess(string.format(" ", row.lightningBonus)) damageSum = damageSum + row.lightningBonus end if not p.isempty(row.decayBonus) then deca = frame:preprocess(string.format(" ", row.decayBonus)) damageSum = damageSum + row.decayBonus end formattedRow.bonus = string.format('%s%s%s%s%s%s', phys, ethe, fire, fros, ligh, deca) formattedRow.bonusSum = damageSum if p.isempty(formattedRow.bonus) then formattedRow.bonus = '–' end else if p.isempty(tonumber(row[column])) then formattedRow[column .. 'Sum'] = 0 else formattedRow[column .. 'Sum'] = tonumber(row[column]) end if column == 'manacost' or column == 'staminacost' or column == 'movespeed' or column == 'weight' or column == 'reach' or column == 'attackspeed' or column == 'buy' or column == 'sell' or column == 'physical' or column == 'ethereal' or column == 'fire' or column == 'frost' or column == 'lightning' or column == 'decay' or column == 'protection' or column == 'thirst' or column == 'hunger' then if p.isempty(tonumber(row[column])) then formattedRow[column] = '–' elseif column == 'manacost' or column == 'staminacost' or column == 'movespeed' then formattedRow[column] = string.format("%.0f%s", row[column], '%') elseif column == 'weight' or column == 'reach' or column == 'attackspeed' then if (column == 'attackspeed') then if (row[column] == "1") then row[column] = "1.0" end end formattedRow[column] = string.format("%.1f", row[column]) else formattedRow[column] = row[column] end elseif p.isempty(row[column]) or row[column] == 0 then formattedRow[column] = '–' else formattedRow[column] = row[column] end end end return formattedRow end

function p.removeColumns(result,category,showClass,columns) --- yes, this can be refactored into a loop, but I want to make it work first, optimize it later isDamage = false isProtection = false isImpact = false isAttackSpeed = false isReach = false isBonus = false isHeatResist = false isColdResist = false isStaminaCost = false isManaCost = false isMoveSpeed = false isDurability = false isThirst = false isHunger = false isEffects = false isWeight = false isCapacity = false isPouch = false isPreservation = false isinventProt = false isCorruptres = false isCooldown = false isBarrier = false isStatusResist = false

for key,row in ipairs(result) do		if not isDamage and category ~= "Armor" and category ~= "Set" then if not p.isempty(row.physical) then isDamage = true elseif not p.isempty(row.ethereal) then isDamage = true elseif not p.isempty(row.fire) then isDamage = true elseif not p.isempty(row.frost) then isDamage = true elseif not p.isempty(row.lightning) then isDamage = true elseif not p.isempty(row.decay) then isDamage = true end end if not isBarrier then if not p.isempty(row.barrier) then isBarrier = true end end if not isStatusResist then if not p.isempty(row.statusResist) then isStatusResist = true end end if not isProtection then if not p.isempty(row.protection) then isProtection = true end end if not isImpact then if not p.isempty(row.impact) then isImpact = true end end if not isAttackSpeed then if not p.isempty(row.attackspeed) then isAttackSpeed = true end end if not isReach then if not p.isempty(row.reach) then isReach = true end end if not isColdResist then if not p.isempty(row.coldresist) then isColdResist = true end end if not isHeatResist then if not p.isempty(row.heatresist) then isHeatResist = true end end if not isBonus then if not p.isempty(row.physicalBonus) then isBonus = true elseif not p.isempty(row.etherealBonus) then isBonus = true elseif not p.isempty(row.fireBonus) then isBonus = true elseif not p.isempty(row.frostBonus) then isBonus = true elseif not p.isempty(row.lightningBonus) then isBonus = true elseif not p.isempty(row.decayBonus) then isBonus = true end end if not isStaminaCost then if not p.isempty(row.staminacost) then isStaminaCost = true end end if not isManaCost then if not p.isempty(row.manacost) then isManaCost = true end end if not isMoveSpeed then if not p.isempty(row.movespeed) then isMoveSpeed = true end end if not isDurability then if not p.isempty(row.durability) then isDurability = true end end if not isThirst then if not p.isempty(row.thirst) then isThirst = true end end if not isHunger then if not p.isempty(row.hunger) then isHunger = true end end if not isEffects then if not p.isempty(row.effects) then isEffects = true end end if not isWeight then if not p.isempty(row.weight) then isWeight = true end end if not isPouch then if not p.isempty(row.pouch) then isPouch = true end end if not isCapacity then if not p.isempty(row.capacity) then isCapacity = true end end

if not isPreservation then if not p.isempty(row.preservation) then isPreservation = true end end

if not isinventProt then if not p.isempty(row.inventProt) then isinventProt = true end end

if not isCorruptres then if not p.isempty(row.corruptresist) then isCorruptres = true end end

if not isCooldown then if not p.isempty(row.cooldown) then isCooldown = true end end end

if not isDamage then if (p.tablefind(columns, "damage") ~= -1) then table.remove(columns, p.tablefind(columns, "damage")) end end if not isBarrier then table.remove(columns, p.tablefind(columns, "barrier")) end if not isStatusResist then table.remove(columns, p.tablefind(columns, "statusResist")) end if not isProtection then table.remove(columns, p.tablefind(columns, "protection")) end if not isImpact then table.remove(columns, p.tablefind(columns, "impact")) end if not isAttackSpeed then table.remove(columns, p.tablefind(columns, "attackspeed")) end if not isReach then table.remove(columns, p.tablefind(columns, "reach")) end if not isBonus then table.remove(columns, p.tablefind(columns, "bonus")) end if not isHeatResist then table.remove(columns, p.tablefind(columns, "heatresist")) end if not isColdResist then table.remove(columns, p.tablefind(columns, "coldresist")) end if not isStaminaCost then table.remove(columns, p.tablefind(columns, "staminacost")) end if not isManaCost then table.remove(columns, p.tablefind(columns, "manacost")) end if not isMoveSpeed then table.remove(columns, p.tablefind(columns, "movespeed")) end if not isDurability then if (p.tablefind(columns, "durability") ~= -1) then table.remove(columns, p.tablefind(columns, "durability")) end end if not isThirst then table.remove(columns, p.tablefind(columns, "thirst")) end if not isHunger then table.remove(columns, p.tablefind(columns, "hunger")) end if not isEffects then table.remove(columns, p.tablefind(columns, "effects")) end if not isWeight then table.remove(columns, p.tablefind(columns, "weight")) end if not isCapacity then table.remove(columns, p.tablefind(columns, "capacity")) end if not isPouch then table.remove(columns, p.tablefind(columns, "pouch")) end if not isinventProt then table.remove(columns, p.tablefind(columns, "inventProt")) end if not isPreservation then table.remove(columns, p.tablefind(columns, "preservation")) end if not isCorruptres then table.remove(columns, p.tablefind(columns, "corruptresist")) end

if not isCooldown then if (p.tablefind(columns, 'cooldown') ~= -1) then table.remove(columns, p.tablefind(columns, "cooldown")) end end

return columns end

function p.tablefind(tab,el) for index, row in pairs(tab) do       if row == el then return index end end return -1 end

-- make table for output

-- since we did all our processing above, literally all that's left to do is to make the table for output. -- this is done using the mw.html library. function p.makeTable(formatted, columns, frame, category)

-- these are all displayed values for the POSSIBLE columns. Not the ones iterated over below. local allColumns = { image='Icon', name='Name', damage='Damage', physical='', ethereal='', fire='', frost='', lightning='', decay='', protection='', barrier='', statusResist='', impact='', impactResist=' Resist', attackspeed='Speed', reach='Reach', bonus='Damage Bonus%', thirst='Thirst', hunger='Hunger', effects='Effects', heatresist='', coldresist='', staminacost='', corruptresist='', cooldown='', manacost='', movespeed='', preservation='Preservation', inventProt='Inventory Protection', durability='Durability', weight='Weight', capacity='Capacity', pouch='Pouch Bonus', class='Class' }	align = 'text-align'; centered = {} centered[align] = 'center' vertical = 'vertical-align' styles = { red = {color = "#df756f", align = 'center'}, green = {color = "#aedc99", align = 'center'}, none = centered, vertical = {} }	styles.vertical[vertical] = 'top' --mw.log("table") --	mw.logObject(formatted) --mw.log("rows") local tbl = mw.html.create('table'):addClass('wikitable'):addClass('sortable') th = tbl:tag('tr') for k,v in ipairs(columns) do		if v == "damage" or v == "bonus" then th:tag('th'):css('width:70px'):wikitext(frame:preprocess(allColumns[v])) else th:tag('th'):wikitext(frame:preprocess(allColumns[v])) end end if category == "Set" then th:tag('th'):addClass('nomobile'):wikitext('Set items') end for i, row in ipairs(formatted) do		--mw.logObject(row) tr = tbl:tag('tr') for k,v in ipairs(columns) do			td = tr:tag('td') if v == "name" or v == "durability" or v == "class" then td:wikitext(row[v]) else if v == "physical" or v == "ethereal" or v == "decay" or v == "lightning" or v == "frost" or v == "fire" then if (tonumber(row[v]) ~= nil) then row[v] = row[v] .. '%'						end elseif v == "hunger" or v == "thirst" then if (tonumber(row[v]) ~= nil) then td:attr('data-sort-value',row[v]) row[v] = tostring(tonumber(row[v]) / 10) .. '%'					end elseif v == "movespeed" then if string.find(row[v], '-') then color = 'red' elseif string.find(row[v], '–') then color = 'none' else color = 'green' end td:css(styles[color]) elseif v == "staminacost" or v == "manacost" then if string.find(row[v], '-') then color = 'green' elseif string.find(row[v], '–') then color = 'none' else color = 'red' end td:css(styles[color]) elseif v == 'preservation' or v == 'cooldown' or v == 'corruptresist' then if (tonumber(row[v]) ~= nil) then if string.find(row[v], '-') then color = 'red' elseif string.find(row[v], '–') then color = 'none' else color = 'green' end td:css(styles[color]) td:attr('data-sort-value', row[v]) row[v] = row[v] .. '%'					else td:attr('data-sort-value', 0) row[v] = '–' end elseif v == "image" and category == "Set" then td:css(styles.vertical) end if row[v .. 'Sum'] ~= nil then td:attr('data-sort-value',tonumber(row[v .. 'Sum'])) end td:css(centered):wikitext(row[v]) end end if category == "Set" then tr:tag('td'):addClass(string.format('mw-customtoggle-%s nomobile',i)):wikitext(' Show ') tbl:tag('tr'):addClass('expand-child mw-collapsible mw-collapsed nomobile'):attr('id', string.format('mw-customcollapsible-%s',i)):tag('td'):attr('colspan', 19):wikitext(frame:expandTemplate{title="set items", args = {set=row.rawName}}) end end return tbl end

--- HELPERS

function find(tbl, val) for k, v in pairs(tbl) do       if k == val then return v end end return nil end

function p.notempty(string) return string ~= nil and string ~= '' end

function p.hasmatch(table1, table2) for _,v in ipairs(table1) do       if contains(table2, v) then return true end end return false end

function p.contains(table, value) for _,v in ipairs(table) do       if v == value then return true end end return false end

function p.split(inputstr, sep) if sep == nil then sep = "%s" end local t={} if p.notempty(inputstr) then for str in string.gmatch(inputstr .. ',', "([^"..sep.."]+)") do           table.insert(t, str) end end return t end

function p.isempty(s) return s == nil or s == '' or s == 0 or s == false end

return p