Module:Infobox Item
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Infobox Item/doc
-- <nowiki> -- Module for [[Template:Infobox Item]] -- Test changes using [[Module:Infobox Item/sandbox]] [[Template:Infobox Item/sandbox]] 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') local chart = require('Module:ExchangeData')._chart local yesno = require('Module:Yesno') local editbutton = require('Module:Edit button') local userError = require("Module:User error") local formatCalcvalue = require("Module:Calcvalue formatter").main local death_map = { allowed = { reclaimable = 'reclaimable', never = 'never', always = 'always', alwaysinclwild = 'alwaysinclwild', dropped = 'dropped', safe = 'safe', gemwdegrade = 'gemwdegrade' }, strings = { reclaimable = 'reclaimable', --extra processing so no nice string never = 'Always lost', always = 'Always kept outside [[Skull (status)|dangerous area]]', alwaysinclwild = 'Always kept', dropped = 'Dropped on death', safe = 'Always a safe death', gemwdegrade = nil --intentional nil } } -- location restriction local restriction_map = { surface = 'surface', dungeoneering = 'dungeoneering', dg = 'dungeoneering', daemonheim = 'dungeoneering', quest = 'quest', minigame = 'minigame', activity = 'minigame', beta = 'removed', gone = 'removed', removed = 'removed', limited = 'limited', ['time limited'] = 'limited', th = 'microtransaction', sof = 'microtransaction', ['treasure hunter'] = 'microtransaction', ['squeal of fortune'] = 'microtransaction', cache = 'cache' } -- 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' }, { name = 'vanchor', func = { name = 'has_content', params = { 'version' }, flag = 'p' } }, -- 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 = 'examine', func = 'has_content' }, { name = 'quest', func = 'has_content' }, { name = 'tradeable', func = tradeablearg }, { name = 'tradeablesmw', func = { name = yesno, params = { 'tradeable', false }, flag = { 'd', 'r' } } }, { 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 }, { name = 'bankablesmw', func = { name = yesno, params = { 'bankable', false }, 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 }, { name = 'stacksinbanksmw', func = { name = yesno, params = { 'stacksinbank', false }, 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 = 'lendablesmw', func = { name = yesno, params = { 'lendable', false }, flag = { 'd', 'r' } }, dupes = true }, { name = 'stackable', func = 'has_content' }, { name = 'stackablesmw', func = { name = yesno, params = { 'stackable', false }, flag = { 'd', 'r' } }, dupes = true }, { name = 'disassembly', func = disassemblyarg }, { name = 'disassemblysmw', func = { name = disassemblysmwarg, params = { 'disassembly' }, flag = 'p' } }, -- 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 = 'noteablesmw', func = { name = yesno, params = { 'noteable', true }, flag = { 'd', 'r' }, dupes = true } }, { name = 'destroy', func = 'has_content' }, { name = 'store', func = storearg }, -- options { name = 'options', func = { name = optionscheckargs, params = { 'options', 'actions' } } }, { name = 'optionsdisp', func = { name = optionsdisparg, params = { 'options', 'options_ground', 'options_equipped', 'options_bank', 'options_currency_pouch' }, flag = 'd' }, dupes = true }, { name = 'options_ground', func = { name = optionscheckargs, params = { 'options_ground', 'actions_ground' } } }, { name = 'options_equipped', func = { name = optionscheckargs, params = { 'options_equipped', 'actions_equipped' } } }, { name = 'options_bank', func = { name = optionscheckargs, params = { 'options_bank', 'actions_bank' } } }, { name = 'options_currency_pouch', func = { name = optionscheckargs, params = { 'options_currency_pouch', 'actions_currency_pouch' } } }, -- 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', 'gemw' }, flag={'d', 'd', 'r'} }, dupes = true }, { name = 'gemwpage', func = { name = gemwpagearg, params = { 'gemwprice', 'gemwname' } } }, { name = 'exchange', func = { name = exchangearg, params = { 'gemwprice', 'gemwname', 'gemw'}, flag={'d', 'd', 'r'} }, dupes = true }, { name = 'graph', func = { name = gemwgrapharg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, { name = 'buylimit', func = { name = buylimitarg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, { name = 'buylimitsmw', func = { name = buylimitsmwarg, params = { 'buylimit' } }, dupes = true }, { name = 'exgvalue', func = { name = exgvaluearg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, { name = 'val', func = { name = valraw, params = { 'value', 'exgvalue' }, flag = {'p', 'd'} }, dupes = true }, { name = 'value', func = { name = valuearg, params = { 'val', 'convert' }, flag = { 'd', 'p' } } }, { name = 'volume', func = { name = volumearg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, -- used for both exchange and graphs { name = 'gemwdisp', func = { name = gemwdisp, params = { 'gemwprice' } }, dupes = true }, { name = 'deathstatus', func = { name = deathstatusarg, params = { 'kept' }, flag = 'p' } }, { name = 'ikodvalue', func = { name = ikodarg, params = { 'deathstatus', 'ikod', 'val', 'gemwprice' }, flag = { 'd', 'p', 'd', 'd' } } }, { name = 'reclaimvalue', func = { name = reclaimvaluearg, params = { 'ikodvalue', 'reclaim', }, flag = { 'd', 'p' } } }, { name = 'kept', func = { name = keptondeatharg, params = { 'deathstatus', 'ikodvalue', 'reclaimvalue' }, flag = {'d', 'd', 'd'} } }, -- alchemy { name = 'gemwalchable', func = { name = gemwalchablearg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, { name = 'gemwalchmultiplier', func = { name = gemwalchmultiplierarg, params = { 'gemwprice', 'gemwname' } }, dupes = true }, { name = 'alchable', func = { name = alchablearg, params = { 'alchable', 'high', 'low', 'gemwalchable' }, flag = {'p', 'p', 'p', 'd' } }, dupes = true }, { name = 'alchmultiplier', func = 'numbers' }, { name = 'alchmultiplier_final', func = { name = multiplierarg, params = { 'alchmultiplier', 'gemwalchmultiplier' }, flag = {'p','d'} } }, { name = 'highraw', func = { name = alchvaluesraw, params = { 'val', 'high', 'alchmultiplier_final', 1, 'alchable' }, flag = { 'd', 'p', 'd', 'r', 'd' } } }, { name = 'lowraw', func = { name = alchvaluesraw, params = { 'val', 'low', 'alchmultiplier_final', 2/3, 'alchable' }, flag = { 'd', 'p', 'd', 'r', 'd' } } }, { name = 'high', func = { name = alchvalues, params = { 'val', 'high', 'alchmultiplier_final', 1, 'alchable' }, flag = { 'd', 'p', 'd', 'r', 'd' } } }, { name = 'low', func = { name = alchvalues, params = { 'val', 'low', 'alchmultiplier_final', 2/3, 'alchable' }, flag = { 'd', 'p', 'd', 'r', 'd' } } }, -- calcvalue (value for items not on the GE) { name = 'calcvalue', func = { name = calcvalParse, params = { 'calcvalue' }, flag = { 'p' } }, dupes = true }, { name = 'calcvalue_smw', func = { name = calcvalSMW, params = { 'calcvalue' }, flag = { 'p' } }, dupes = true }, { name = 'calcvalue_smw_nowiki', func = { name = calcvalSMWNowiki, params = { 'calcvalue' }, flag = { 'p' } }, dupes = true }, { name = 'calcvalue_pretty', func = { name = calcvalPretty, params = { 'calcvalue' }, flag = { 'p' } }, dupes = true }, { name = 'weight', func = weightarg }, { name = 'weightraw', func = { name = weightargraw, params = { 'weight' }, flag = 'p' } }, { name = 'restriction', func = restrictionarg }, { name = 'restrictionsurface', func = { name = restrsurfarg , params = { 'restriction', 'restriction', 'quest' }, flag = { 'd', 'p', 'd' } } }, -- not used; only for categories { name = 'id', func = { name = iddisp, params = { 'id' }, flag = 'p' } }, { name = 'id_smw', func = { name = idsmw, params = { 'id' }, flag = 'p' } }, { name = 'chisel_links', func = { name = make_chisel_links, params = { 'id_smw', 'name' }, flag = 'd' } }, { name = 'rscid', func = 'numbers' }, { name = 'SMWarg', func = { name = SMWarg, params = { 'name', 'version', 'id', 'members', 'release', 'removal', 'examine', 'quest', 'destroy', 'restriction', -- strings 'deathstatus', 'ikodvalue', 'reclaimvalue', -- death 'tradeable', 'equipable', 'bankable', 'stacksinbank', 'lendable', 'stackable', 'disassembly', 'edible', 'noteable', --generally boolean or tri-lean 'val', 'high', 'low', 'weightraw', -- numbers 'gemw', 'gemwname', 'buylimit' -- gemw }, flag = 'd' } } } ret:setMaxButtons(7) ret:create() ret:cleanParams() ret:customButtonPlacement(true) -- parameter linkings for hidden rows ret:linkParams{ { 'removal', 'removaldisp' }, { 'exchange', 'gemwdisp' }, { 'graph', 'gemwdisp' }, { 'volume', 'gemwdisp' }, { 'buylimit', 'gemwdisp' }, { 'bankable', 'bankabledisp' }, { 'stacksinbank', 'stacksinbankdisp' }, { 'lendable', 'lendabledisp' }, { 'noteable', 'noteabledisp' }, { 'edible', 'edibledisp' }, } ret:defineLinks() ret:useSMW({ id_smw = 'Item ID', members = 'Is members only', }) ret:useSMWElement({ buylimitsmw = 'Buy limit', SMWarg = 'Item JSON', }) --[[ Handled in categories currently so it only sets default value ret:useSMWOne({ calcvalue_smw = 'Calculated value', }) --]] ret:useSMWSubobject({ id_smw = 'Item ID', vanchor = 'Version anchor', name = 'Item name', examine = 'Examine', val = 'Value', highraw = 'High Alchemy value', lowraw = 'Low Alchemy value', weightraw = 'Weight', members = 'Is members only', tradeablesmw = 'Tradeable', stackablesmw = 'Stackable', bankablesmw = 'Bankable', stacksinbanksmw = 'Stacksinbank', lendablesmw = 'Lendable', disassemblysmw = 'Disassembleable', noteablesmw = 'Noteable', gemwpage = 'Exchange page', buylimitsmw = 'Buy limit', restriction = 'Location restriction', deathstatus = 'Kept on death', release = 'Release date', update = 'Release update', calcvalue_smw = 'Calculated value', --removal = 'Removal date', removalupdate = 'Removal update', }) if onmain() then local a2 = ret:categoryData() if not a2['restriction'].all_defined then ret:useSMWSubobject({ restrictionsurface = 'Location restriction', }) end end ret:addButtonsCaption() ret:defineName('Infobox Item') ret:addClass('infobox-item') ret:addRow{ { tag = 'argh', content = 'name', class='infobox-header', colspan = '60' } } :pad(60) ret:addRow{ { tag = 'argd', content = 'image', class = 'infobox-image inventory-image infobox-full-width-content', colspan = '60' } } :pad(60) :addRow{ { tag = 'th', content = 'Release', colspan = '20' }, { tag = 'argd', content = 'release', colspan = '40' } } if ret:paramDefined('removal') then ret:addRow{ { tag = 'th', content = 'Removal', colspan = '20' }, { tag = 'argd', content = 'removal', colspan = '40' } } end if ret:paramDefined('aka') then ret:addRow{ { tag = 'th', content = '[[Slang dictionary|AKA]]', colspan = '20' }, { tag = 'argd', content = 'aka', colspan = '40' } } end ret:addRow{ { tag = 'th', content = '[[Members]]', colspan = '20' }, { tag = 'argd', content = 'members', colspan = '40' } } :addRow{ { tag = 'th', content = '[[Quest items|Quest item]]', colspan = '20' }, { tag = 'argd', content = 'quest', colspan = '40' } } :pad(60) :addRow{ { tag = 'th', content = 'Properties', class = 'infobox-subheader', colspan = '60' } } :pad(60) :addRow{ { tag = 'th', content = '[[Items#Tradeability|Tradeable]]', colspan = '20' }, { tag = 'argd', content = 'tradeable', colspan = '40' } } if ret:paramGrep('bankable','no') then ret:addRow{ { tag = 'th', content = '[[Bank]]able', colspan = '20' }, { tag = 'argd', content = 'bankable', colspan = '40' } } end if ret:paramGrep('stacksinbank','no') then ret:addRow{ { tag = 'th', content = 'Stacks in bank', colspan = '20' }, { tag = 'argd', content = 'stacksinbank', colspan = '40' } } end if ret:paramGrep('lendable','yes') then ret:addRow{ { tag = 'th', content = '[[Item Lending|Lendable]]', colspan = '20' }, { tag = 'argd', content = 'lendable', colspan = '40' } } end ret:addRow{ { tag = 'th', content = '[[Equipment|Equipable]]', colspan = '20' }, { tag = 'argd', content = 'equipable', colspan = '40' } } :addRow{ { tag = 'th', content = '[[Stackable items|Stackable]]', colspan = '20' }, { tag = 'argd', content = 'stackable', colspan = '40' } } :addRow{ { tag = 'th', content = '[[Disassemble|Disassembly]]', colspan = '20' }, { tag = 'argd', content = 'disassembly', colspan = '40' } } if ret:paramGrep('noteable','yes') then ret:addRow{ { tag = 'th', content = '[[Note|Noteable]]', colspan = '20' }, { tag = 'argd', content = 'noteable', colspan = '40' } } end if ret:paramGrep('edible','yes') then ret:addRow{ { tag = 'th', content = '[[Food|Edible]]', colspan = '20' }, { tag = 'argd', content = 'edible', colspan = '40' } } end ret:addRow{ { tag = 'th', content = '[[Destroy (option)|Destroy]]', colspan = '20' }, { tag = 'argd', content = 'destroy', css = { ['max-width'] = '200px' }, colspan = '40' } } ret:addRow{ { tag = 'th', content = '[[Examine]]', colspan = '20' }, { tag = 'argd', content = 'examine', colspan = '40' } } if ret:paramGrep('optionsdisp', true) then local options_help = '<sup class="hover-text noprint" style="border: 0;" title="Options shown on the item when right-clicked or long-pressed.">[?]</sup>' ret:pad(60) :addRow{ { tag = 'th', content = 'Options '..options_help, class = 'infobox-subheader', colspan = '60' }, } :pad(60) if yesno(ret:param('options'), true) ~= false then ret:addRow{ { tag = 'th', content = '[[Backpack]]', colspan = '20' }, { tag = 'argd', content = 'options', colspan = '40' } } end if ret:paramDefined('options_ground') or ret:paramDefined('actions_ground') then ret:addRow{ { tag = 'th', content = 'On ground', colspan = '20' }, { tag = 'argd', content = 'options_ground', colspan = '40' } } end if ret:paramDefined('options_equipped') or ret:paramDefined('actions_equipped') then ret:addRow{ { tag = 'th', content = '[[Worn Equipment|Equipped]]', colspan = '20' }, { tag = 'argd', content = 'options_equipped', colspan = '40' } } end if ret:paramDefined('options_bank') or ret:paramDefined('actions_bank') then local bank_options_help = '<sup class="hover-text noprint" style="border: 0;" title="In the backpack section of the bank interface, excluding all variants of the "deposit" option and the "examine" option.">[?]</sup>' ret:addRow{ { tag = 'th', content = '[[Bank]]'..bank_options_help, colspan = '20'}, { tag = 'argd', content = 'options_bank', colspan = '40' } } end if ret:paramDefined('options_currency_pouch') or ret:paramDefined('actions_currency_pouch') then ret:addRow{ { tag = 'th', content = '[[Currency pouch]]', colspan = '20'}, { tag = 'argd', content = 'options_currency_pouch', colspan = '40' } } end end ret:pad(60) :addRow{ { tag = 'th', content = 'Values', class = 'infobox-subheader', colspan = '60' } } :pad(60) ret:addRow{ { tag = 'th', content = '[[Value]]', colspan = '20' }, { tag = 'argd', content = 'value', colspan = '40' } } -- If any are alchable, add both rows, otherwise add a single "no alch" row local anyalchable = ret:paramGrep('alchable',true) if anyalchable == true then ret:addRow{ { tag = 'th', content = '[[High Level Alchemy|High alch]]', colspan = '20' }, { tag = 'argd', content = 'high', colspan = '40' } } :addRow{ { tag = 'th', content = '[[Low Level Alchemy|Low alch]]', colspan = '20' }, { tag = 'argd', content = 'low', colspan = '40' } } else ret:addRow{ { tag = 'th', content = '[[Items#Alchemy|Alchemy]]', colspan = '20' }, { tag = 'td', content = 'Not alchemisable', colspan = '40' } } end ret:addRow{ { tag = 'th', content = '[[Items Kept on Death|On death]]', colspan = '20' }, { tag = 'argd', content = 'kept', colspan = '40' } } :addRow{ { tag = 'th', content = '[[Weight]]', colspan = '20' }, { tag = 'argd', content = 'weight', colspan = '40' } } :pad(60) -- Include GE section if we have any exchange prices local anygemw = ret:paramGrep('gemwprice', function(_arg) return _arg > 0 end) if anygemw == true then ret :addRow{ { tag = 'th', content = '[[Grand Exchange]]', class = 'infobox-subheader', colspan = '60' } } :pad(60) :addRow{ { tag = 'th', content = '[[RuneScape:Grand Exchange Market Watch|Exchange]]', colspan = '20' }, { tag = 'argd', content = 'exchange', colspan = '40' } } :addRow{ { tag = 'th', content = '[[Grand Exchange#Trade restrictions|Buy limit]]', colspan = '20' }, { tag = 'argd', content = 'buylimit', colspan = '40' } } :addRow{ { tag = 'th', content = '[[Grand Exchange#Volume|Volume]]', colspan = '20' }, { tag = 'argd', content = 'volume', colspan = '40' } } :addRow{ { tag = 'argd', content = 'graph', colspan = '60', css = { ['text-align'] = 'center', ['padding'] = '0'} } } end ret :addRow{ { tag = 'th', content = 'Advanced data', class = 'infobox-subheader', colspan = '60' }, meta = {addClass = 'advanced-data'} } :pad(60, 'advanced-data') :addRow{ { tag = 'th', content = 'Item ID', colspan = '20' }, { tag = 'argd', content = 'id', colspan = '40' }, meta = {addClass = 'advanced-data'} } :addRow{ { tag = 'th', content = 'Links', colspan = '20' }, { tag = 'argd', content = 'chisel_links', colspan = '40' }, meta = {addClass = 'advanced-data'} } ret:pad(60, 'advanced-data') if ret:paramDefined('calcvalue') then ret :addRow{ { tag = 'th', content = 'Calculated value', class = 'infobox-subheader', colspan = '60' }, meta = {addClass = 'advanced-data'} } :pad(60, 'advanced-data') ret :addRow{ { tag = 'th', content = 'Parsed', colspan = '20' }, { tag = 'argd', content = 'calcvalue', colspan = '40' }, meta = {addClass = 'advanced-data'} } :addRow{ { tag = 'th', content = 'SMW', colspan = '20' }, { tag = 'argd', content = 'calcvalue_smw_nowiki', colspan = '40' }, meta = {addClass = 'advanced-data'} } :addRow{ { tag = 'th', content = 'Formatted', colspan = '20' }, { tag = 'argd', content = 'calcvalue_pretty', colspan = '40' }, meta = {addClass = 'advanced-data'} } ret:pad(60, 'advanced-data') end if onmain() then local a1 = ret:param('all') local a2 = ret:categoryData() ret:wikitext(addcategories(ret, a1,a2)) end return ret:tostring() end function optionsdisparg(options, options_ground, options_equipped, options_bank) -- if options="no" and other options aren't defined or no options defined, hide if (yesno(options, true) == false and not (infobox.isDefined(options_ground) or infobox.isDefined(options_equipped) or infobox.isDefined(options_bank) or infobox.isDefined(options_currency_pouch)))or not (infobox.isDefined(options) or infobox.isDefined(options_ground) or infobox.isDefined(options_equipped) or infobox.isDefined(options_bank) or infobox.isDefined(options_currency_pouch)) then return nil end -- else show return true 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 trade items|Restricted]]' else return nil end end -- disassembly -- disassemblyarg(yes/no) local allowed_disassembly = { yes = 'true', no = 'false', restricted = 'restricted', na = 'N/A', ['n/a'] = 'N/A', discontinued = 'N/A', irrelevant = 'N/A' } function disassemblyarg(d) d = string.lower(d or '') d = allowed_disassembly[d] if d == 'true' then return '[[#DisassemblyT|Yes]]' -- Unique anchor ID created by {{Disassembly}} elseif d == 'false' then return 'No' elseif d == 'restricted' then return '[[:Category:Location restricted disassembly|Restricted]]' elseif d == 'N/A' then return 'N/A' else return nil end end -- disassemblysmwarg(yes/no) function disassemblysmwarg(d) d = string.lower(d or '') return allowed_disassembly[d] end -- value -- separate number storage for operation -- pulls the exchange value first, and prefers that if it exists -- valraw(value, exchange value) function valraw(v, ex) if type(ex) == 'number' then return ex else return tonumber(string.gsub(v or '', ',', ''), 10) end 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<br/><b>Cash out:</b><br/>%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('<b>Cash out:</b><br/>%s',plural('coin',c)) else return nil end end -- ge alchable boolean -- gemwalchablearg(gemw price, name) -- uses the already fetched ge price to operate -- values less than 1 are used for parsing instructions function gemwalchablearg(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._alchable(n) if ret == nil then return '-' elseif ret == false then return 'false' --not very good at handling false else return true end -- not a number = nil -- shouldn't be used, but it's a fallback else return '-' end end -- ge alch multiplier -- gemwalchmultiplierarg(gemw price, name) -- uses the already fetched ge price to operate -- values less than 1 are used for parsing instructions function gemwalchmultiplierarg(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._alchmultiplier(n) if ret == nil then return '-' else return ret end -- not a number = nil -- shouldn't be used, but it's a fallback else return '-' end end -- Alchables -- alchablearg(alchable, high, low) function alchablearg(a,h,l,ex) if ex == true then return true elseif ex == 'false' then return 'false' end -- 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, ex) if type(ex) == 'number' then return ex end return tonumber(v) or 0.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) -- if you can't alch it, return this -- used in the case of 1 version being alchable and the other not if not infobox.isDefined(n) or n == 'false' then return 'Not alchemisable' end -- 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 -- otherwise try the value and multiply it if v then local r = math.floor(killRoundingError(v * m * a)) -- both high and low alch have a lower bound of one coin r = math.max(r, 1) return plural('coin',r) end return nil end -- alchvaluesraw(value, override value, multiplier, alchable) -- actual value already parsed -- value, template param, alch multiplier, override multiplier, not alchable bool function alchvaluesraw(v,_p,a,m,n) -- if you can't alch it, return nil if not infobox.isDefined(n) or n == 'false' then return nil end -- 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 _p end -- otherwise try the value and multiply it if v then local r = math.floor(killRoundingError(v * m * a)) -- both high and low alch have a lower bound of one coin r = math.max(r, 1) return r end return nil end -- calcvalue (calculated value for items not sold on GE) function calcvalSMW(calcval) if tonumber(calcval) then return calcval end local str = string.gsub( string.gsub(calcval, '{', '{{'), '}', '}}') str = string.gsub(str, '¦', '|') return str end function calcvalSMWNowiki(calcval) return calcvalSMW(calcval) :gsub("{", "{") :gsub("|", "|") :gsub("}", "}") end function calcvalParse(calcval) if tonumber(calcval) then return plural('coin', calcval) end local val = calcvalSMW(calcval) if not infobox.isDefined(calcval) or not infobox.isDefined(val) then return nil end val = mw.getCurrentFrame():preprocess(val) if tonumber(val) then val = math.floor(val * 100 + 0.5) / 100 else val = userError('Cannot parse "' .. val .. '" as a number', "Erroneous parameter") end return plural('coin', val) end function calcvalPretty(calcval) if tonumber(calcval) then return calcval end return formatCalcvalue(calcvalSMW(calcval)) 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,'-','−') -- use non-breaking spaces and html entities for display -- still necessary to convert the "kg" to html? return string.format('%s kg',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 -- add formatted "placeholder" texts -- if the there is empty options in some version function optionscheckargs(arg, arg_old) if not paramtest.has_content(arg) and paramtest.has_content(arg_old) then arg = arg_old end if paramtest.has_content(arg) then local lowarg = string.lower(arg) if lowarg == '-' or lowarg == 'no' or lowarg == 'none' then return "<i>None</i>" elseif lowarg == 'n/a' then return "<i>N/A</i>" else return arg end else return editbutton("'''?''' (edit)") end 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,'</?span>','') -- otherwise use the "name" parameter elseif n and n:find('%S') then return string.gsub(n,'</?span>','') -- 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,t) if g == true then local modl = exchange -- return price if page is found -- -1 for errors if modl._exists(n) then return tonumber(modl._price(n, nil, nil, nil, -1),10) or -1 else return -1 end -- 0 for no price else return 0 end end -- gemwpricearg(gemw price, name) -- exchange page name for SMW -- uses the already fetched ge price to operate -- values less than 1 are used for parsing instructions function gemwpagearg(g,n) if type(g) ~= 'number' then g = tonumber(g,10) or 0 end if g < 1 then return nil else return 'Exchange:'..n 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,t) if type(g) ~= 'number' then g = tonumber(g,10) or 0 end -- 0 for not sold if g == 0 then return '<span class="infobox-quantity" data-val-each="0">Not sold</span>' -- -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 local lnk = ' ([[Exchange:'..n..'|info]])' return string.format('<span class="infobox-quantity" data-val-each="%s"><span class="infobox-quantity-replace">%s</span> coin%s%s</span>',g,commas(g),g>1 and 's' or '',lnk) -- 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 return chart{n, size = 'small'} -- 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 function buylimitsmwarg(b) if type(b) == 'string' then b = b:gsub(',', '') end if tonumber(b) then return tonumber(b) end return infobox.donotsetsmw end function volumearg(gemwprice, name) -- 0 for not sold, -1 for error if gemwprice <= 0 then return '-' end local ret = exchange._volume(name) if ret == nil then return '-' end return commas(ret) end -- ge value -- exgvaluearg(gemw price, name) -- uses the already fetched ge price to operate -- values less than 1 are used for parsing instructions function exgvaluearg(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._value(n) if ret == nil then return '-' else return ret end -- not a number = nil -- shouldn't be used, but it's a fallback else return '-' 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 -- deathstatusarg(death) function deathstatusarg(d) d = string.lower(d or '') return death_map.allowed[d] end -- ikodarg() function ikodarg(d, _i, v, g) if d == 'reclaimable' then v = tonumber(v) local i -- 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 return i -- test geprice next elseif (tonumber(g,10) or 0) > 0 then i = tonumber(g,10) -- test value next elseif v then i = v end return i end return -1 end -- reclaimvaluearg(ikodvalue, reclaim) function reclaimvaluearg(i, _r) i = tonumber(i or -1) or -1 if i > 0 then local r -- 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 if i > 0 then -- limit r to be in the range [100, 2^31 - 1] r = math.min(math.max(i * .001, 100), 2^31 - 1) -- this shouldn't happen, but fallback to 100 else r = 100 end end r = math.floor(killRoundingError(r)) return r end return -1 end -- keptondeatharg(deathstatus, ikod, reclaimvalue) function keptondeatharg(d,_i,r) if d == 'reclaimable' then local ret = { 'Reclaimable' } local i -- 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 then table.insert(ret,string.format('<b>Value:</b> %s',commas(i))) end table.insert(ret,string.format('<b>Reclaim:</b> %s',commas(r))) return table.concat(ret,'<br>') else return death_map.strings[d] end end -- red ERR span with title hover for explanation function badarg(argname, argmessage) return '<span '.. 'title="The parameter «'..argname..'» '..argmessage..'" '.. 'style="color:red; font-weight:bold; cursor:help; border-bottom:1px dotted red;">'.. 'ERR</span>' 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 function restrictionarg(arg) if paramtest.is_empty(arg) then return nil end return restriction_map[string.lower(arg)] end function restrsurfarg(cleaned, passed) if infobox.isDefined(cleaned) then return nil end return restriction_map.surface end function iddisp(id) if infobox.isDefined(id) then if id:lower() ~= 'no' then local r = string.gsub(id, ', *', ', ') return r elseif id:lower() == 'no' then return 'None' end end return nil end function idsmw(id) if infobox.isDefined(id) then local r = string.gsub(id, ', *', infobox.splitpoint) return r end return nil end function make_chisel_links(id, name) local link1 = 'https://chisel.weirdgloop.org/gazproj/mrid' local link2 = 'https://chisel.weirdgloop.org/gazproj/recipe/' if infobox.isDefined(id) then local ids = mw.text.split(id, infobox.splitpoint) id1 = tonumber(ids[1]) if id1 then if #ids == 1 then link1 = string.format('%s?%s#%s-%s', link1, id1, id1-15, id1+15) link2 = link2 .. id1 else for i,j in ipairs(ids) do if i == 1 then link1 = string.format('%s?%s#%s', link1, j, j) link2 = link2 .. j else link1 = link1 .. '@' .. j end end end else link1 = string.format('%s#%s', link1, ids[1]) link2 = link2 .. ids[1] end else local _name = name:gsub(' ', '%%20') link1 = string.format('%s#%s', link1, _name) link2 = nil end if link2 then return string.format('[%s MRID] • [%s recipe]', link1, link2) else return string.format('[%s MRID]', link1) end end -- SMW JSON function SMWarg(name, version, id, members, release, removal, examine, quest, destroy, restriction, deathstatus, ikodvalue, reclaimvalue, tradeable, equipable, bankable, stacksinbank, lendable, stackable, disassembly, edible, noteable, value, high, low, weight, gemw, gemwname, buylimit) local toJSON = { name = name, version = version, id = id, members = string.lower(tostring(members) or ''), examine = examine, death = deathstatus, destroy = destroy, tradeable = string.lower(tostring(tradeable) or ''), equipable = string.lower(tostring(equipable) or ''), bankable = string.lower(tostring(bankable) or ''), stacksinbank = string.lower(tostring(stacksinbank) or ''), lendable = string.lower(tostring(lendable) or ''), stackable = string.lower(tostring(stackable) or ''), edible = string.lower(tostring(edible) or ''), noteable = string.lower(tostring(noteable) or ''), value = val, weight = weight, } local w if high == 'Not alchemisable' then toJSON.highalch = false else w = high:gsub(',',''):gsub('coins?','') toJSON.highalch = tonumber(w) or false end if low == 'Not alchemisable' then toJSON.lowalch = false else w = low:gsub(',',''):gsub('coins?','') toJSON.highalch = tonumber(w) or false end if toJSON.tradeable == 'yes' and gemw then toJSON.gemw = { name = gemwname } if buylimit ~= '-' then w = buylimit:gsub(',','') toJSON.gemw.limit = tonumber(w) end else toJSON.gemw = false end if disassembly:find('[Yy]es') then toJSON.disassembly = 'yes' elseif disassembly:find('restricted') then toJSON.disassembly = 'restricted' else toJSON.disassembly = string.lower(tostring(disassembly) or '') end if paramtest.is_empty(restriction) and tostring(restriction):find('action=edit') then toJSON.restriction = restriction_map.surface else toJSON.restriction = restriction end local rel, upd, rem, updr rel, upd = release:match('(.-) %(%[%[Update:(.-)|Update%]%]%)') if rel == nil then rel = release:match('(.-) %(Update unknown%)') end if rel then toJSON.release_date = rel:gsub('%[',''):gsub('%]','') if upd then toJSON.release_update_post = upd end end rem, updr = removal:match('(.-) %(%[%[Update:(.-)|Update%]%]%)') if rem == nil then rem = removal:match('(.-) %(Update unknown%)') end if rem then toJSON.removal_date = rem:gsub('%[',''):gsub('%]','') if updr then toJSON.removal_update_post = updr end end for k,v in pairs(toJSON) do if v == '' or (type(v) == 'string' and string.find(v,'action=edit')) then toJSON[k] = nil end end return mw.text.killMarkers(mw.text.nowiki(mw.text.jsonEncode(toJSON))) end -- Categories -- oman this is still blatant copy pasta function addcategories(ibox, args, catargs) local ret = { 'Items' } local cat_map = { -- Added if the parameter has content defined = { aka = 'Pages with AKA', alchmultiplier = 'Has Alchemy Multiplier', calcvalue = 'Items with an alternate value' }, -- 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', options = 'Needs options added', }, -- 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' }, exchange = { ['but no page was found for'] = 'Exchange page not found' }, tradeable = { yes = 'Tradeable items', no = 'Untradeable items', restricted = 'Restricted trade items' }, bankable = { no = 'Unbankable 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,'Items without 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 ~= true then table.insert(ret,'Items that cannot be alchemised') elseif args.alchable.switches then for _, v in ipairs(args.alchable.switches) do if v ~= true 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 local limit = string.gsub(tostring(args.buylimit.d), ',', '') if tonumber(limit) then if tonumber(limit) < 1000 then table.insert(ret, 'Low buy limit') else table.insert(ret, 'High buy limit') end end if args.buylimit.switches then for i,v in ipairs(args.buylimit.switches) do limit = string.gsub(tostring(args.buylimit.switches[i] or args.buylimit.d), ',', '') if tonumber(limit) then if tonumber(limit) < 1000 then table.insert(ret, 'Low buy limit') else table.insert(ret, 'High buy limit') end end end end -- Calculated value, set default to base page if args['calcvalue_smw'].d then mw.smw.set({['Calculated value'] = args['calcvalue_smw'].d}) end -- special addition for location restriction -- if everything is the same then add to the base page as well -- only matters if is a switchfo if ibox.switchfo then if not catargs.restriction.one_defined then -- no restriction set == all of them are surface mw.smw.set({['Location restriction'] = 'surface'}) else if args.restriction.switches then local val = args.restriction.switches[1] or args.restriction.d or restriction_map.surface local all_the_same = true for i,v in ipairs(args.restriction.switches) do local curr = v or args.restriction.d or restriction_map.surface if val ~= curr then all_the_same = false break end end if all_the_same then mw.smw.set({['Location restriction'] = val}) else table.insert(ret, 'Items with mixed restrictions') end else -- not a switchable param -- set to d mw.smw.set({['Location restriction'] = args.restriction.d or restriction_map.surface}) end end end -- combine table and format category wikicode for i, v in ipairs(ret) do ret[i] = string.format('[[Category:%s]]',v) end return table.concat(ret,'') end return p --</nowiki>