Module:Item

local Item = {}

-- Libraries of functions --

-- Loads high frequency functions local HF = require('Module:HF')

-- Parses invocation and template parameters, trims whitespace, and removes blanks. local getArgs = require('Dev:Arguments').getArgs

-- Language functions for the default language local lang = mw.language.getContentLanguage

-- Smarter boolean logic local yesno = require( 'Dev:Yesno' )

-- Wikitext lists local L = require( 'Dev:List' )

-- Grand Exchange data local EX = require('Module:Exchange') local EXD = require('Module:ExchangeData')

--- -- Libraries of data -- ---

-- Local functions (used only in this Module) --

local pagetitle, namespace, content = mw.title.getCurrentTitle.fullText, mw.title.getCurrentTitle.namespace, mw.title.getCurrentTitle.isContentPage local testcase = (mw.title.getCurrentTitle:inNamespace( 10 )    and mw.title.getCurrentTitle.text:lower:match('testcases$')) and true local documentation = (mw.title.getCurrentTitle:inNamespace( 10 )    and mw.title.getCurrentTitle.text:lower:match('doc$')) and true

local backrefcheck = require('Module:HF')._backrefargs local function rawnumber(value) if value then -- in case it's a number in comma-grouped form, -- or (more likely) a string -- make it a pure number value = lang:parseFormattedNumber( value ) value = tonumber( value ) and tonumber( value ) or value return value else return nil end end local function groupednumber(value) if value then -- in case it's a number in comma-grouped form, -- or (more likely) a string -- make it a pure number value = rawnumber(value) -- if it's a pure number, -- put it in comma-grouped form value = type(value) == 'number' and lang:formatNum( value ) or value return value else return nil end end local function ge(version, args) local exch = {} local name = backrefcheck('name', version, args) local exchange = backrefcheck('exchange', version, args) local override_name = backrefcheck('gemwname', version, args) if exchange and exchange:lower == 'gemw' then exch.exchange = true end if yesno(backrefcheck('tradeable', version, args)) == true and exch.exchange then exch.gemw = true end if override_name and override_name:find('%S') then exch.name = override_name:gsub('','') elseif name and name:find('%S') then exch.name = name:gsub('','') else exch.name = mw.title.getCurrentTitle.fullText end if exch.gemw == true and EX._exists(exch.name) then exch.price = tonumber(EX._price(exch.name),10) or -1 if exch.price > 0 then local wrapper = mw.html.create('span') :addClass('infobox-quantity') :attr('data-val-each', exch.price) :wikitext(	           (' %s %s %s')	                :format( groupednumber(exch.price), lang:plural(exch.price, ' coin', ' coins'), (' (%s)'):format(HF.Link('Exchange:'..exch.name, 'info')) )           )            :allDone exch.exchange = tostring(wrapper) exch.graph = EXD._chart{exch.name, ['size'] = 'small'} exch.buylimit = EX._limit(exch.name) and groupednumber(EX._limit(exch.name)) or nil exch.display = 'infobox-cell-shown' end elseif exch.gemw == true then exch.price = -1 exch.exchange = mw.smw.info('The parameter «exchange» was set to «gemw» but no page was found for «'..exch.name..'».','warning') exch.graph = 'No data to display' exch.buylimit = nil exch.display = 'infobox-cell-shown' else exch.price = 0 exch.exchange = ' Not sold ' exch.graph = 'No data to display' exch.buylimit = nil exch.display = '' end return exch end local function kept(version, args) local k = { _kept = backrefcheck('kept', version, args), ikod = backrefcheck('ikod', version, args), _reclaim = backrefcheck('reclaim', version, args), _sacrifice = backrefcheck('sacrifice', version, args), _value = backrefcheck('value', version, args) and rawnumber(backrefcheck('value', version, args)) or nil }   local display = { ['never'] = 'Always lost', ['always'] = 'Always kept outside ' .. HF.Link('Wilderness','Wild'), ['alwaysinclwild'] = 'Always kept', ['dropped'] = 'Dropped on death', ['safe'] = 'Always a safe death', ['gemwdegrade'] = nil, ['reclaimable'] = 'Reclaimable' }   local cats = { ['never'] = HF.Category('Items that are never kept on death'), ['always'] = HF.Category('Items that are always kept outside the Wilderness on death'), ['reclaimable'] = HF.Category('Items that are reclaimable on death'), ['alwaysinclwild'] = HF.Category('Items that are always kept on death') }   k.kept = type(k._kept) == 'string' and display[k._kept:lower] k.category = type(k._kept) == 'string' and cats[k._kept:lower] -- Stop there if it's not reclaimable if k.kept ~= 'Reclaimable' then return k end local i = (k.ikod and rawnumber(k.ikod)) or (((tonumber(g,10) or 0) > 0) and ge(version, args).price) or (k._value and rawnumber(k._value)) or nil k.value = i and groupednumber(i) k.reclaim = k._reclaim and rawnumber(k._reclaim) or nil k.sacrifice = k._sacrifice and rawnumber(k._sacrifice) or nil if i and not k.reclaim then local r		-- 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 k.reclaim = r and math.floor(math.floor(r*1000+0.0000099)/1000) end k.sacrifice = k.sacrifice or (k.reclaim and k.reclaim * 4) or nil return k end

- -- Internal functions (used in this and other Modules) -- - function Item.PageHandler(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local id = backrefcheck('id', version, args) local tradeable = backrefcheck('tradeable', version, args) local exch = ge(version, args) local categories = { HF.Category('Items') }   if id then mw.smw.set{ ['Item ID'] = id } elseif args['id'..1] then for i=1,100,1 do           if args['id'..i] then mw.smw.set{ ['Item ID'..i] = args['id'..i] } end end else table.insert(categories, HF.Category('Needs ID')) end if exch.gemw ~= true and yesno(tradeable) == true then table.insert(categories, HF.Category('Non-GE items')) elseif exch.gemw == true then table.insert(categories, HF.Category('Grand Exchange Items')) end ---   --- Unique SMW item handling ---    return content and table.concat(categories) end

function Item.GalleryItems(frame) local args = getArgs(frame, { parentOnly = true }) local out = {} local name = args['name'] or pagetitle table.insert(out,        (args['image/detail'] or name..' detail.png') ..        '|Detailed'    ) if args['image/detail_alternative_label'] and args['image/detail_alternative'] then table.insert(out, args['image/detail_alternative']..'|'..args['image/detail_alternative_label']) end table.insert(out,        (args['image/equipped'] or name..' equipped.png') ..        '|Equipped'    ) if args['image/equipped_alternative_label'] and args['image/equipped_alternative'] then table.insert(out, args['image/equipped_alternative']..'|'..args['image/equipped_alternative_label']) end table.insert(out,        (args['image/chathead'] or name..' chathead.png') ..        '|Chathead'    ) -- table.insert(out, HF._stripFileWrapper(args['image'..1]) .. '|' .. args['version'..1]) -- table.insert(out, HF._stripFileWrapper(args['image'..2]) .. '|' .. args['version'..2]) for i = 1, 50, 1 do       if backrefcheck('image',i,args) and args['version'..i] then table.insert(out, HF._stripFileWrapper(backrefcheck('image',i,args)) .. '|' .. args['version'..i]) end end return table.concat(out,'\n') end

Item.release = require('Module:Monster').release Item.removal = require('Module:Monster').removal Item.aka = require('Module:Monster').aka function Item.members(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local members = backrefcheck('members', version, args) local categories = {} local version_name = version and (backrefcheck('version', version, args) or 'Version'..version) or nil local default = content and ('%s%s'):format('Unknown', HF.Category('Needs members status')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('members', 1, args)) and default or nil if members and content then if yesno(members) == true then mw.smw.set{ ['Is members only' .. (version or '')] = yesno(members) }           if version then mw.smw.subobject( { ['Is members only'] = yesno(members) }, version_name ) end table.insert(categories, HF.Category("Members' items")) end if yesno(members) == false then mw.smw.set{ ['Is members only' .. (version or '')] = yesno(members) }           if version then mw.smw.subobject( { ['Is members only'] = yesno(members) }, version_name ) end table.insert(categories, HF.Category('Free-to-play items')) end members = members .. table.concat(categories) end return members or default end function Item.quest(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local quest = backrefcheck('quest', version, args) local categories = {} if quest and quest:match('%[%[') then table.insert(categories, HF.Category('Quest items')) end local default = content and ('%s%s'):format('Unknown', HF.Category('Items missing quest')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('quest', 1, args)) and default or nil quest = (quest and content) and quest..table.concat(categories) or quest return quest or default end function Item.tradeable(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local tradeable = backrefcheck('tradeable', version, args) local categories = {} if (tradeable and yesno(tradeable) == true) then tradeable = 'Yes' table.insert(categories, HF.Category('Tradeable items')) elseif (tradeable and yesno(tradeable) == false) then tradeable = 'No' table.insert(categories, HF.Category('Untradeable items')) elseif (tradeable and tradeable:lower == 'restricted') then tradeable = HF.Link('Restricted trade items','Restricted') table.insert(categories, HF.Category('Restricted trade items')) else tradeable = tradeable and tradeable .. mw.smw.info('Invalid value for "bankable"','warning') or nil end tradeable = (tradeable and content) and tradeable..table.concat(categories) or tradeable return tradeable or nil end function Item.equipable(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local equipable = backrefcheck('equipable', version, args) local categories = {} if (equipable and yesno(equipable) == true) then table.insert(categories, HF.Category('Equipable items')) end equipable = (equipable and content) and equipable..table.concat(categories) or equipable return equipable or nil end function Item.bankable(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local bankable = backrefcheck('bankable', version, args) if yesno(bankable) == true then return nil elseif yesno(bankable) == false then return (content or testcase or documentation) and 'No' else return bankable and bankable .. mw.smw.info('Invalid value for "bankable"','warning') or nil end end function Item.stacksinbank(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local stacksinbank = backrefcheck('stacksinbank', version, args) if yesno(stacksinbank) == true then return nil elseif yesno(stacksinbank) == false then return (content or testcase or documentation) and 'No' else return stacksinbank and stacksinbank .. mw.smw.info('Invalid value for "stacksinbank"','warning') or nil end end function Item.lendable(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local lendable = backrefcheck('lendable', version, args) if yesno(lendable) == false then return nil elseif yesno(lendable) == true then lendable = content and 'Yes' .. HF.Category('Lendable items') or 'Yes' return (content or testcase or documentation) and lendable else return lendable and lendable .. mw.smw.info('Invalid value for "lendable"','warning') or nil end end function Item.stackable(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local stackable = backrefcheck('stackable', version, args) local categories = {} if (stackable and yesno(stackable) == true) then table.insert(categories, HF.Category('Stackable items')) end stackable = (stackable and content) and stackable..table.concat(categories) or stackable return stackable or nil end function Item.disassembly(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local disassembly = backrefcheck('disassembly', version, args) local categories = {} local notapplicable = { ['na'] = true, ['n/a'] = true, ['discontinued'] = true, ['irrelevant'] = true }   local default = content and ('%s%s'):format('Unknown', HF.Category('Items missing disassembly info')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('disassembly', 1, args)) and default or nil if (disassembly and yesno(disassembly) == true) then disassembly = HF.Link('#DisassemblyT','Yes') table.insert(categories, HF.Category('Items that can be disassembled')) elseif (disassembly and yesno(disassembly) == false) then disassembly = 'No' table.insert(categories, HF.Category('Items that cannot be disassembled')) elseif (disassembly and disassembly:lower == 'restricted') then disassembly = HF.Link(':Category:Location restricted disassembly','Restricted') table.insert(categories, HF.Category('Location restricted disassembly')) elseif (disassembly and notapplicable[disassembly:lower]) then disassembly = 'N/A' table.insert(categories, HF.Category('Items with N/A disassembly')) else disassembly = disassembly and disassembly .. mw.smw.info('Invalid value for "disassembly"','warning') or nil end disassembly = (disassembly and content) and disassembly..table.concat(categories) or disassembly return disassembly or default end function Item.noteable(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local noteable = backrefcheck('noteable', version, args) if yesno(noteable) == false then return nil elseif yesno(noteable) == true then return (content or testcase or documentation) and noteable else return noteable and noteable .. mw.smw.info('Invalid value for "noteable"','warning') or nil end end function Item.edible(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local edible = backrefcheck('edible', version, args) if yesno(edible) == false then return nil elseif yesno(edible) == true then return (content or testcase or documentation) and edible else return edible and edible .. mw.smw.info('Invalid value for "edible"','warning') or nil end end function Item.value(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local value = backrefcheck('value', version, args) local unit = value and lang:plural( rawnumber(value), ' coin', ' coins' ) local default = content and ('%s%s'):format('Unknown', HF.Category('Items missing value')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('value', 1, args)) and default or nil if value then mw.smw.set{ ['Value'] = rawnumber(value) } end return value and value..unit or default end function Item.value_cashout(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local convert = backrefcheck('convert', version, args) local unit = lang:plural( rawnumber(convert), ' coin', ' coins' ) return convert and convert..unit or nil end function Item.alchable(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local alchable = backrefcheck('alchable', version, args) local high = backrefcheck('high', version, args) local low = backrefcheck('low', version, args) if yesno(alchable) == false or (yesno(high) == false and yesno(low) == false) then alchable = content and 'Not alchemisable' .. HF.Category('Items that cannot be alchemised') or 'Not alchemisable' end return alchable or nil end function Item.highalchemy(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local alchable = backrefcheck('alchable', version, args) local high = backrefcheck('high', version, args) and rawnumber( backrefcheck('high', version, args) ) or nil local value = backrefcheck('value', version, args) and rawnumber(backrefcheck('value', version, args)) or nil local multiplier = backrefcheck('alchmultiplier', version, args) and tonumber(backrefcheck('alchmultiplier', version, args)) or .6 if high and rawnumber(high) then return high .. lang:plural( rawnumber(high), ' coin', ' coins' ) elseif yesno(alchable) == false then return nil else local X = value and rawnumber(value) * 1 * multiplier local X = X and math.floor(math.floor(X*1000+0.0000099)/1000) return X and X .. lang:plural( X, ' coin', ' coins' ) or nil end end function Item.lowalchemy(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local alchable = backrefcheck('alchable', version, args) local low = backrefcheck('low', version, args) and rawnumber( backrefcheck('low', version, args) ) or nil local value = backrefcheck('value', version, args) and rawnumber(backrefcheck('value', version, args)) or nil local multiplier = backrefcheck('alchmultiplier', version, args) and tonumber(backrefcheck('alchmultiplier', version, args)) or .6 if low and rawnumber(low) then return low .. lang:plural( rawnumber(low), ' coin', ' coins' ) elseif yesno(alchable) == false then return nil else local X = value and rawnumber(value) * (2/3) * multiplier or nil local X = X and math.floor(math.floor(X*1000+0.0000099)/1000) return X and X .. lang:plural( X, ' coin', ' coins' ) or nil end end function Item.destroy(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local destroy = backrefcheck('destroy', version, args) local default = content and ('%s%s'):format('Unknown', HF.Category('Missing destroy text')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('destroy', 1, args)) and default or nil return destroy or default end function Item.kept_death(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local k = kept(version, args) local category = content and (k.category or ) or  local default = content and ('%s%s'):format('Unknown', HF.Category('Items missing death info')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('kept', 1, args)) and default or nil return k.kept and k.kept .. ( content and (k.category or ) or  ) or default end function Item.kept_reclaim(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local k = kept(version, args) return k.reclaim or nil end function Item.kept_sacrifice(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local k = kept(version, args) return k.sacrifice or nil end function Item.weight(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local weight = backrefcheck('weight', version, args) weight = weight and weight:gsub('[kg ]','') local unit = weight and lang:plural( rawnumber(weight), ' kg', ' kg' ) local default = content and ('%s%s'):format('Unknown', HF.Category('Needs weight added')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('value', 1, args)) and default or nil if weight then mw.smw.set{ ['Weight'] = rawnumber(weight:gsub('[kg ]','')) } end weight = weight and weight:gsub('-','&minus;') return weight and weight..unit or default end function Item.tooltip(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local tooltip = backrefcheck('tooltip', version, args) if (not tooltip) or yesno(tooltip) == 'no' then return nil end local tooltips = tooltip and mw.text.split(tooltip, ',') local t = { ['passive'] = HF.Link('Passive effect'), ['set'] = HF.Link('Set bonus'), ['time'] = 'Time remaining', ['degrade'] = HF.Link('Degradation'), ['items'] = 'Items consumed', ['urn'] = 'Percentage filled' }   local out = {} for _,v in ipairs(tooltips) do       v = mw.text.trim(v):gsub("^%s*(.-)%s*$", "%1") x = v:lower if x ~= '' and t[x] then table.insert(out, t[x]) elseif v~= '' then table.insert(out, v)       end end return out[1] and L.makeList('bulleted', out) .. (content and HF.Category('Items that have a tooltip') or '') or nil end function Item.examine(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local examine = backrefcheck('examine', version, args) local default = content and ('%s%s'):format('Unknown', HF.Category('Needs examine added')) or 'Unknown' default = (content or testcase or documentation) and default or nil default = (version == nil and not backrefcheck('examine', 1, args)) and default or nil return examine or default end

function Item.ExchangePrice(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local exch = ge(version, args) return content and exch.exchange or nil end function Item.BuyLimit(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local exch = ge(version, args) return content and exch.buylimit or nil end function Item.graph(frame) local version = getArgs(frame, { frameOnly = true })[1] or nil local args = getArgs(frame, { parentOnly = true }) local exch = ge(version, args) return content and exch.graph or nil end - -- Output (send it back to whatever called it) -- - return Item