Module:Infobox Item

-- -- ( ͡° ͜ʖ ͡°)

local p = {}

-- "imports" local infobox = require('Module:Infobox') local onmain = require('Module:Mainonly').on_main local paramtest = require('Module:Paramtest') local commas = require('Module:Addcommas')._add local exchange = require('Module:Exchange')

-- Main function called with invokes function p.main(frame) local args = frame:getParent.args local ret = infobox.new(args)

-- Parameter definitions ret:defineParams{ { name = 'name', func = 'name' }, { name = 'aka', func = 'has_content' }, { name = 'image', func = 'image' },

-- release and removal -- removal only shown if it exists { name = 'release', func = 'release' }, { name = 'removal', func = 'removal' }, { name = 'removaldisp', func = { name = removaldisp, params = { 'removal' } }, dupes = true },

{ name = 'members', func = 'has_content' }, { name = 'tooltip', func = tooltiparg }, { name = 'examine', func = 'has_content' }, { name = 'quest', func = 'has_content' }, { name = 'tradeable', func = tradeablearg }, { name = 'equipable', func = 'has_content' },

-- bankable; only show if "No"; default to "Yes" { name = 'bankable', func = { name = 'has_content', params = { 'bankable', 'Yes'}, flag = { 'd', 'r' } } }, { name = 'bankabledisp', func = { name = yesnodisp, params = { 'bankable', 'no' }, flag = { 'd', 'r' } }, dupes = true },

-- stacksinbank; only show if "No"; default to "Yes" { name = 'stacksinbank', func = { name = 'has_content', params = { 'stacksinbank', 'Yes'}, flag = { 'd', 'r' } } }, { name = 'stacksinbankdisp', func = { name = yesnodisp, params = { 'stacksinbank', 'no' }, flag = { 'd', 'r' } }, dupes = true },

-- lendable; only show if "Yes"; default to "No" { name = 'lendable', func = { name = 'has_content', params = { 'lendable', 'No'}, flag = { 'd', 'r' } } }, { name = 'lendabledisp', func = { name = yesnodisp, params = { 'lendable' } }, dupes = true },

{ name = 'stackable', func = 'has_content' }, { name = 'disassembly', func = disassemblyarg },

-- edible; only show if "Yes"; default to "No" { name = 'edible', func = { name = 'has_content', params = { 'edible', 'No'}, flag = { 'd', 'r' } } }, { name = 'edibledisp', func = { name = yesnodisp, params = { 'edible' } }, dupes = true },

-- noteable; only show if "Yes"; default to "No" { name = 'noteable', func = { name = 'has_content', params = { 'noteable', 'No'}, flag = { 'd', 'r' } } }, { name = 'noteabledisp', func = { name = yesnodisp, params = { 'noteable' } }, dupes = true }, { name = 'destroy', func = 'has_content' }, { name = 'store', func = storearg }, { name = 'val', func = { name = valraw, params = { 'value' }, flag = 'p' }, dupes = true }, { name = 'value', func = { name = valuearg, params = { 'val', 'convert' }, flag = { 'd', 'p' } } }, -- gemw prices -- only displayed if they exist --dupes must exist for individual prices to have them display properly { name = 'gemw', func = { name = gemwarg, params = { 'exchange', 'tradeable' }, flag = {'p', 'd'} } }, { name = 'gemwname', func = { name = gemwnamearg, params = { 'name', 'gemwname' } } }, { name = 'gemwprice', func = { name = gemwpricearg, params = { 'gemw', 'gemwname' } }, dupes = true }, { name = 'exchange', func = { name = exchangearg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, { name = 'graph', func = { name = gemwgrapharg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, { name = 'buylimit', func = { name = buylimitarg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, -- used for both exchange and graphs { name = 'gemwdisp', func = { name = gemwdisp, params = { 'gemwprice' } }, dupes = true }, { name = 'kept', func = { name = keptondeatharg, params = { 'kept', 'ikod', 'reclaim', 'sacrifice', 'val', 'gemwprice' }, flag = { 'p', 'p', 'p', 'd', 'd' } } },

-- alchemy { name = 'alchable', func = { name = alchablearg, params = { 'alchable', 'high', 'low' }, flag = 'p' }, dupes = true }, { name = 'alchmultiplier', func = multiplierarg }, { name = 'high', func = { name = alchvalues, params = { 'val', 'high', 'alchmultiplier', 1, 'alchable' }, flag = { 'd', 'p', 'd', 'r', 'd' } } }, { name = 'low', func = { name = alchvalues, params = { 'val', 'low', 'alchmultiplier', 2/3, 'alchable' }, flag = { 'd', 'p', 'd', 'r', 'd' } } },

{ name = 'weight', func = weightarg }, { name = 'weightraw', func = { name = weightargraw, params = { 'weight' }, flag = 'p' } },

-- not used; only for categories { name = 'id', func = 'numbers' }, { name = 'rscid', func = 'numbers' } }

ret:setMaxButtons(7) ret:create ret:cleanParams

-- parameter linkings for hidden rows ret:linkParams{ { 'removal', 'removaldisp' }, { 'exchange', 'gemwdisp' }, { 'graph', 'gemwdisp' }, { 'buylimit', 'gemwdisp' }, { 'bankable', 'bankabledisp' }, { 'stacksinbank', 'stacksinbankdisp' }, { 'lendable', 'lendabledisp' }, { 'noteable', 'noteabledisp' }, { 'edible', 'edibledisp' } }

ret:defineLinks({ { 'Template:%s/FAQ', 'FAQ' },			{ 'Template:%s/doc', 'doc' } })

ret:useSMW({		id = 'Item ID',		val = 'Value',		weightraw = 'Weight',	})

ret:caption ret:defineName('Infobox Item') ret:addClass('infobox-item') -- PARAMETER: image ret:addRow{ { tag = 'argd', content = 'image', class = 'infobox-image', colspan = '2' } }

-- PARAMETER: release -- (update included automatically by infobox) :addRow{ { tag = 'th', content = 'Release' }, { tag = 'argd', content = 'release' } } -- PARAMETER: removal if ret:paramDefined('removal') then ret:addRow{ { tag = 'th', content = 'Removal' }, { tag = 'argd', content = 'removal' } } end

-- PARAMETER: aka -- add only if it exists if ret:paramDefined('aka') then ret:addRow{ { tag = 'th', content = 'AKA' }, { tag = 'argd', content = 'aka' } } end

-- PARAMETER: members ret:addRow{ { tag = 'th', content = 'Members' }, { tag = 'argd', content = 'members' } }

-- PARAMETER: quest :addRow{ { tag = 'th', content = 'Quest item' }, { tag = 'argd', content = 'quest' } }

-- PARAMETER: tradeable :addRow{ { tag = 'th', content = 'Tradeable' }, { tag = 'argd', content = 'tradeable' } }

-- PARAMETER: bankable if ret:paramGrep('bankable','no') then ret:addRow{ { tag = 'th', content = 'Bankable' }, { tag = 'argd', content = 'bankable' } } end

-- PARAMETER: stacksinbank if ret:paramGrep('stacksinbank','no') then ret:addRow{ { tag = 'th', content = 'Stacks in bank' }, { tag = 'argd', content = 'stacksinbank' } } end

-- PARAMETER: lendable if ret:paramGrep('lendable','yes') then ret:addRow{ { tag = 'th', content = 'Lendable' }, { tag = 'argd', content = 'lendable' } } end

-- PARAMETER: equipable ret:addRow{ { tag = 'th', content = 'Equipable' }, { tag = 'argd', content = 'equipable' } }

-- PARAMETER: stackable :addRow{ { tag = 'th', content = 'Stackable' }, { tag = 'argd', content = 'stackable' } }

-- PARAMETER: disassembly :addRow{ { tag = 'th', content = 'Disassembly' }, { tag = 'argd', content = 'disassembly' } }

-- PARAMETER: noteable if ret:paramGrep('noteable','yes') then ret:addRow{ { tag = 'th', content = 'Noteable' }, { tag = 'argd', content = 'noteable' } } end

-- PARAMETER: edible if ret:paramGrep('edible','yes') then ret:addRow{ { tag = 'th', content = 'Edible' }, { tag = 'argd', content = 'edible' } } end

-- PARAMETER: value ret:addRow{ { tag = 'th', content = 'Value' }, { tag = 'argd', content = 'value' } }

-- PARAMETER: alchable | high | low -- find if any version is alchable local anyalchable = ret:paramGrep('alchable',true)

-- if any are alchable, add both rows if anyalchable == true then ret:addRow{ { tag = 'th', content = 'High alch' }, { tag = 'argd', content = 'high' } } :addRow{ { tag = 'th', content = 'Low alch' }, { tag = 'argd', content = 'low' } } else -- otherwise add a single "no alch" row ret:addRow{ { tag = 'th', content = 'Alchemy' }, { tag = 'td', content = 'Not alchemisable' } } end

-- PARAMETER: destroy ret:addRow{ { tag = 'th', content = 'Destroy' }, { tag = 'argd', content = 'destroy', css = { ['max-width'] = '200px' } } }

-- PARAMETER: death ret:addRow{ { tag = 'th', content = 'On death' }, { tag = 'argd', content = 'kept' } }

-- find if we have any exchange prices local anygemw = ret:paramGrep('gemwprice', function(_arg) return _arg > 0 end)

-- if we have any on the ge, add the gemw row if anygemw == true then -- PARAMETER: exchange | gemwname ret:addRow{ { tag = 'th', content = 'Exchange' }, { tag = 'argd', content = 'exchange' } } :addRow{ { tag = 'th', content = 'Buy limit' }, { tag = 'argd', content = 'buylimit' } } end

-- PARAMETER: weight ret:addRow{ { tag = 'th', content = 'Weight' }, { tag = 'argd', content = 'weight' } }

-- PARAMETER: tooltip if ret:paramDefined('tooltip') then ret:addRow{ { tag = 'th', content = 'Tooltip' }, { tag = 'argd', content = 'tooltip' } } end

-- PARAMETER: examine ret:addRow{ { tag = 'th', content = 'Examine' }, { tag = 'argd', content = 'examine', css = { ['max-width'] = '200px' } } }

-- PARAMETER: graph if anygemw == true then ret:addRow{ { tag = 'argd', content = 'graph', colspan = '2', css = { ['text-align'] = 'center', ['padding'] = '0', ['background-color'] = 'white' } }, meta = { addClass = 'hidden' } } end

if onmain then local a1 = ret:param('all') local a2 = ret:categoryData ret:wikitext(addcategories(a1,a2)) end

return ret:tostring end

-- Store price function storearg(store, currency, seller) -- remove any commas store = string.gsub(store or ,',',)

-- no for not sold if string.lower(store) == 'no' then return 'Not sold' else store = tonumber(store,10) end

if type(store) == 'number' then return store else return nil end end

-- tradeable -- tradeablearg(value) function tradeablearg(v) v = string.lower(v or '') if v == 'yes' or v == 'no' then v = mw.text.split(v,'') v[1] = string.upper(v[1]) return table.concat(v,'') elseif v == 'restricted' then return 'Restricted' else return nil end end

-- disassembly -- disassemblyarg(yes/no) function disassemblyarg(d) d = string.lower(d or '') if d == 'yes' then return 'Yes' -- Unique anchor ID created by 	elseif d == 'no' then return 'No' elseif d == 'restricted' then return 'Restricted' elseif d == 'na' or d == 'n/a' or d == 'discontinued' or d == 'irrelevant' then return 'N/A' else return nil end end

-- tooltip -- tooltiparg(v) function tooltiparg(v) d = string.lower(v or '') if d == 'no' or d == '' then return nil else f = '' for w in string.gmatch(v, '([^,]+)') do           w = w:gsub("^%s*(.-)%s*$", "%1") w2 = string.lower(w) if w2 == 'passive' then f = f .. '\n* Passive effect' elseif w2 == 'set' then f = f .. '\n* Set bonus' elseif w2 == 'time' then f = f .. '\n* Time remaining' elseif w2 == 'degrade' then f = f .. '\n* Degradation' elseif w2 == 'items' then f = f .. '\n* Items consumed' elseif w2 == 'urn' then f = f .. '\n* Percentage filled' else f = f .. '\n* ' .. w       	end end if f == '' then return nil else return f       end end end

-- value -- separate number storage for operation -- valraw(value) function valraw(v) local _ v = v or '' _v = string.gsub(v,',','')

return tonumber(v,10) end

-- value -- valuearg(value, convert) -- actual value already parsed function valuearg(v,c) -- replace commas and turn into a number if paramtest.has_content(c) then c = string.gsub(c,',','') c = tonumber(c,10) else c = nil end

v = tonumber(v,10)

-- if both are defined, show both, value first if v and c then return string.format('%s Cash out: %s',plural('coin',v),plural('coin',c)) -- if only value is defined, show just that elseif v and not c then return plural('coin',v) -- if only convert is defined, show just that -- may need to change this so that value is requested elseif c and not v then return string.format('Cash out: %s',plural('coin',c)) else return nil end end -- Alchables -- alchablearg(alchable, high, low) function alchablearg(a,h,l) -- not alchable if both are false, or if "alchable" is false if string.lower(a or '') == 'no' then return false elseif string.lower(h or ) == 'no' and string.lower(l or ) == 'no' then return false else return true end end

-- alch multiplier arg -- only accepts numbers -- defaults to .6 function multiplierarg(v) return tonumber(v) or .6 end

-- high/low alch -- alchvalues(value, override value, multiplier, alchable) -- actual value already parsed -- value, template param, alch multiplier, override multiplier, not alchable bool function alchvalues(v,_p,a,m,n) -- remove commas and turn into a number v = tonumber(v,10) if paramtest.has_content(_p) then _p = string.gsub(_p,',','') _p = tonumber(_p,10) else _p = nil end

-- return override always if type(_p) == 'number' then return plural('coin',_p) end

-- if you can't alch it, return this -- used in the case of 1 version being alchable and the other not if n == false then return 'Not alchemisable' end -- otherwise try the value and multiply it	if v then local r = math.floor(killRoundingError(v * m * a)) return plural('coin',r) end

return nil end

-- weight -- weightarg(weight) function weightarg(w) if paramtest.has_content(w) then -- replace all "kg" and spaces here w = string.gsub(w or ,'[kg ]',)

-- replace hyphen with minus sign w = string.gsub(w,'-','&minus;')

-- use non-breaking spaces and html entities for display -- still necessary to convert the "kg" to html? return string.format('%s &#107;&#103;',w) end return nil end

-- weightargraw(weight) function weightargraw(w) if paramtest.has_content(w) then -- replace all "kg" and spaces here w = string.gsub(w or ,'[kg ]',) return tonumber(w) end return nil end

-- on ge or not -- only accepts "gemw" -- gemwarg(exchange,tradeable) function gemwarg(arg,arg2) g = string.lower(arg or '') return arg2 == 'Yes' and g == 'gemw' end

-- gemw names -- gemwnamearg(name, override name) function gemwnamearg(n,a) -- return override if a and a:find('%S') then return string.gsub(a,'','') -- otherwise use the "name" parameter elseif n and n:find('%S') then return string.gsub(n,'','') -- default to page name else return mw.title.getCurrentTitle.fullText end end

-- separate thing to hold all the prices as raw numbers -- gemwpricearg(gemw, name) function gemwpricearg(g,n) if g == true then -- return price if page is found -- -1 for errors if exchange._exists(n) then return tonumber(exchange._price(n),10) or -1 else return -1 end -- 0 for no price else return 0 end end

-- exchange display -- exchangearg(gemw price, name) -- uses the already fetched ge price to operate -- values less than 1 are used for parsing instructions function exchangearg(g,n) if type(g) ~= 'number' then g = tonumber(g,10) or 0 end -- 0 for not sold if g == 0 then return ' Not sold ' -- -1 for no page found elseif g == -1 then return badarg('exchange','was set to «gemw» but no page was found for «'..n..'».') -- all other numbers elseif g > 0 then -- plural done in format because we need a span around the value return string.format(' %s coin%s (info) ',g,commas(g),g>1 and 's' or '',n) -- not a number = nil -- shouldn't be used, but it's a fallback else return 0 end end

-- ge graphs -- gemwgrapharg(gemw price, name) -- uses the already fetched ge price to operate -- values less than 1 are used for parsing instructions function gemwgrapharg(g,n) if type(g) ~= 'number' then g = tonumber(g,10) or 0 end

-- 0 for not sold an	-- -1 for error -- call to hide the graph if g == 0 or g == -1 then return 'No data to display' -- all other numbers elseif g > 0 then -- TODO: Change Module:ExchangeData and give it a proper graph function -- remove reliance on frame return mw.getCurrentFrame:preprocess(string.format('',n)) -- not a number = nil -- shouldn't be used, but it's a fallback else return nil end end

-- ge buy limits -- buylimitarg(gemw price, name) -- uses the already fetched ge price to operate -- values less than 1 are used for parsing instructions function buylimitarg(g,n) if type(g) ~= 'number' then g = tonumber(g,10) or 0 end

-- 0 for not sold an	-- -1 for error -- call to hide the graph if g == 0 or g == -1 then return '-' -- all other numbers elseif g > 0 then local ret = exchange._limit(n) if ret == nil then return '-' else return commas(ret) end -- not a number = nil -- shouldn't be used, but it's a fallback else return nil end end

-- class names based on value -- gemwdisp(price) function gemwdisp(_p) if _p == 0 then return '' else return 'infobox-cell-shown' end end

-- Shows if the param matches the alt -- alt defaults to yes -- Everything else = hide function yesnodisp(arg, alt) arg = string.lower(arg or '') alt = string.lower(alt or 'yes') if arg == alt then return 'infobox-cell-shown' else return '' end end

-- Shows if has a date function removaldisp(arg) if string.find(arg or '','%[%[') then return 'infobox-cell-shown' else return '' end end

-- death -- keptondeatharg(death, override value, override reclaim, override sacrifice, value, gemwprice) function keptondeatharg(d,_i,_r,_s,v,g) d = string.lower(d or '') v = tonumber(v,10) -- items always lost if d == 'never' then return 'Always lost' -- items always kept unless in the wilderness elseif d == 'always' then return 'Always kept outside Wild' elseif d == 'alwaysinclwild' then return 'Always kept' elseif d == 'dropped' then return 'Dropped on death' elseif d == 'safe' then return 'Always a safe death' -- returns a nil value to force it to use gemw elseif d == 'gemwdegrade' then return nil -- reclaimable items elseif d == 'reclaimable' then local i		-- all other items display reclaim and sacrifice -- if overridden ikod value, display that as well -- default is to show this local ret = { 'Reclaimable' }

-- replace commas and convert to number if paramtest.has_content(_i) then i = string.gsub(_i,',','') i = tonumber(i,10) else i = nil end

-- if i is defined, show that value if i then table.insert(ret,string.format('Value: %s',commas(i))) -- test geprice next elseif (tonumber(g,10) or 0) > 0 then i = g		-- test value next elseif v then i = v		end

-- otherwise give up		if not tonumber(i,10) then return i		end

-- reclaim cost is based on the death value of an item -- sacrifice is 4 x reclaim -- sacrifice value is a function of reclaim and not the original number -- this is evident by the fact that items with a death value of 1 have a sacrifice value of 4

-- reclaim, sacrifice local r,s

-- test for overridden reclaim if paramtest.has_content(_r) then _r = string.gsub(_r,',','') r = tonumber(_r) end

-- if no number, use formula if not r then -- less than 10,000: .15x if i < 10000 then r = math.floor(i * .15) -- all items cost at least 1 coin, so round back up if 0 if r == 0 then r = 1 end

--Death formula -- 10,000 to 49,999: 500 + 0.1x elseif i >= 10000 and i < 50000 then r = 500 + i * 0.1

-- 50,000 to 249,999: 3000 + 0.05x elseif i >= 50000 and i < 250000 then r = 3000 + i * 0.05

-- 250,000 to 999,999: 10500 + 0.02x elseif i >= 250000 and i < 1000000 then r = 10500 + i * 0.02

-- 1,000,000 to 9,999,999: 20500 + 0.01x elseif i >= 1000000 and i < 10000000 then r = 20500 + i * 0.01

-- 10,000,000 and greater: 70,500 + 0.005x elseif i >= 10000000 then r = 70500 + i * 0.005

-- this shouldn't happen, but fallback to 1 else r = 1 end end

r = math.floor(killRoundingError(r))

if paramtest.has_content(_s) then _s = string.gsub(_s,',','') _s = tonumber(_s,10) end

-- if overridden, use _s for sacrifice if tonumber(_s,10) then s = _s else -- otherwise include sacrifice as 4r s = r * 4 end

table.insert(ret,string.format('Reclaim: %s',commas(r))) table.insert(ret,string.format('Sacrifice: %s',commas(s)))

return table.concat(ret,' ') end -- otherwise unknown return nil end

-- red ERR span with title hover for explanation function badarg(argname, argmessage) return ''.. 'ERR ' end

-- plural -- returns number with the word function plural(arg,n,alt) local _n = commas(tonumber(n,10) or 1) if tonumber(n,10) == 1 then return string.format('%s %s',_n,arg) elseif alt then return string.format('%s %s',_n,alt) else return string.format('%s %ss',_n,arg) end end

-- Does exactly what's on the tin function killRoundingError(n) return math.floor(n*1000+0.0000099)/1000 end

-- Categories -- oman this is still blatant copy pasta function addcategories(args,catargs) local ret = { 'Items' } local cat_map = { -- Added if the parameter has content defined = { aka = 'Pages with AKA', tooltip = 'Items that have a tooltip' },		-- Added if the parameter has no content notdefined = { image = 'Needs image', members = 'Needs members status', release = 'Needs release date', examine = 'Needs examine added', level = 'Needs combat level', weight = 'Needs weight added', value = 'Items missing value', quest = 'Items missing quest', destroy = 'Missing destroy text', kept = 'Items missing death info', disassembly = 'Items missing disassembly info' },		-- Parameters that have text -- map a category to a value grep = { members = { yes = 'Members\' items', no = 'Free-to-play items' }, stackable = { yes = 'Stackable items' }, lendable = { yes = 'Lendable items' }, equipable = { yes = 'Equipable items' }, gemw = { ['true'] = 'Grand Exchange items' }, tradeable = { yes = 'Tradeable items', no = 'Untradeable items', restricted = 'Restricted trade items' }, disassembly = { yes = 'Items that can be disassembled', no = 'Items that cannot be disassembled', restricted = 'Location restricted disassembly', ['n/a'] = 'Items with N/A disassembly' }, kept = { ['always lost'] = 'Items that are never kept on death', ['always kept outside'] = 'Items that are always kept outside the Wilderness on death', reclaimable = 'Items that are reclaimable on death' } }	}

-- Run and add mapped categories -- defined categories for n, v in pairs(cat_map.defined) do		if catargs[n] and catargs[n].one_defined then table.insert(ret,v) end end

-- undefined categories for n, v in pairs(cat_map.notdefined) do		if catargs[n] and catargs[n].all_defined == false then table.insert(ret,v) end end

-- searches for n, v in pairs(cat_map.grep) do		for m, w in pairs(v) do			if args[n] then if string.find(string.lower(tostring(args[n].d) or ''),m) then table.insert(ret,w) end if args[n].switches then for _, x in ipairs(args[n].switches) do						if string.find(string.lower(tostring(x)),m) then table.insert(ret,w) end end end end end end

-- quest items -- just look for a link if args.quest.d:find('%[%[') then table.insert(ret,'Quest items') elseif args.quest.switches then for _, v in ipairs(args.quest.switches) do			if v:find('%[%[') then table.insert(ret,'Quest items') break end end end

-- extra func for death -- searching for 'always kept' would match more than what we want if args.kept.d == 'Always kept' then table.insert(ret,'Items that are always kept on death') elseif args.kept.switches then for _, v in ipairs(args.kept.switches) do			if v == 'Always kept' then table.insert(ret,'Items that are always kept on death') break end end end -- ids if not catargs.id.all_defined then -- rsc ids have no id		if catargs.rscid.all_defined then -- do nothing else table.insert(ret,'Needs ID') end end

-- store if string.lower(args.store.d or '') ~= 'not sold' and not string.lower(args.store.d or 'edit'):find('edit') then table.insert(ret,'Pages that use Store') elseif args.store.switches then for _, v in ipairs(args.store.switches) do			if string.lower(v or ) ~= 'not sold' and string.lower(v or ) ~= infobox.nil_param and not string.lower(v or 'edit'):find('edit') then table.insert(ret,'Pages that use Store') end end end

-- alchemy -- non alchable if args.alchable.d == false then table.insert(ret,'Items that cannot be alchemised') elseif args.alchable.switches then for _, v in ipairs(args.alchable.switches) do			if v == false then table.insert(ret,'Items that cannot be alchemised') break end end end

-- gemw -- if item is both (not untradeable) and (not GEMW) then add Non-GE items if not args.gemw.d and string.lower(args.tradeable.d) ~= 'no' then table.insert(ret, 'Non-GE items') end -- switches; if tradeable switches exist, if gemwX and tradeableX are as above, add Non-GE items --						if no switches, gemwX and tradeable (default) if args.gemw.switches then if args.tradeable.switches then for i, v in ipairs(args.gemw.switches) do				if not v and string.lower(args.tradeable.switches[i] or args.tradeable.d) ~= 'no' then table.insert(ret, 'Non-GE items') end end else for i, v in ipairs(args.gemw.switches) do				if not v and string.lower(args.tradeable.d) ~= 'no' then table.insert(ret, 'Non-GE items') end end end end

-- combine table and format category wikicode for i, v in ipairs(ret) do		ret[i] = string.format('',v) end

return table.concat(ret,'') .. '__NOINDEX__' end

return p