Module:Infobox Item/sandbox: Difference between revisions
Jump to navigation
Jump to search
m (Fix rounding) |
m (1 revision imported) |
(No difference)
|
Latest revision as of 21:22, 4 November 2021
Documentation for this module may be created at Module:Infobox Item/sandbox/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 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 [[Wilderness|Wild]]',
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 },
-- actions
{ name = 'actions', func = 'has_content' },
{ name = 'actionsdisp', func = { name = actionsdisparg, params = { 'actions', 'actions_ground', 'actions_equipped', 'actions_bank' }, flag = 'd' }, dupes = true },
{ name = 'actions_ground', func = 'has_content' },
{ name = 'actions_equipped', func = 'has_content' },
{ name = 'actions_bank', func = 'has_content' },
-- 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 = 'gemwpage', func = { name = gemwpagearg, params = { 'gemwprice', 'gemwname' } } },
{ 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 },
{ 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' } } },
-- 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 = 'sacrificevalue', func = { name = sacrificevaluearg, params = { 'reclaimvalue', 'sacrifice' }, flag = { 'd', 'p' } } },
{ name = 'kept', func = { name = keptondeatharg, params = { 'deathstatus', 'ikod', 'reclaimvalue', 'sacrificevalue' }, flag = {'d', 'p', '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 = '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', 'sacrificevalue', -- 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' },
{ 'buylimit', 'gemwdisp' },
{ 'bankable', 'bankabledisp' },
{ 'stacksinbank', 'stacksinbankdisp' },
{ 'lendable', 'lendabledisp' },
{ 'noteable', 'noteabledisp' },
{ 'edible', 'edibledisp' },
}
ret:defineLinks({ links = {{ 'Template:%s/FAQ', 'FAQ' },
{ 'Template:%s/doc', 'doc' }}, colspan = 2 })
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 = 'argd', content = 'image', class = 'infobox-image inventory-image bordered-image', colspan = '2' }
}
:addRow{
{ tag = 'argh', content = 'name', class='infobox-header', colspan = '2' }
}
:addRow{
{ tag = 'th', content = 'Release' },
{ tag = 'argd', content = 'release' }
}
if ret:paramDefined('removal') then
ret:addRow{
{ tag = 'th', content = 'Removal' },
{ tag = 'argd', content = 'removal' }
}
end
if ret:paramDefined('aka') then
ret:addRow{
{ tag = 'th', content = '[[Slang dictionary|AKA]]' },
{ tag = 'argd', content = 'aka' }
}
end
ret:addRow{
{ tag = 'th', content = '[[Members]]' },
{ tag = 'argd', content = 'members' }
}
:addRow{
{ tag = 'th', content = '[[Quest items|Quest item]]' },
{ tag = 'argd', content = 'quest' }
}
:addRow{
{ tag = 'th', content = 'Properties', class = 'infobox-subheader', colspan = '2' }
}
:addRow{
{ tag = 'th', content = '[[Items#Tradeability|Tradeable]]' },
{ tag = 'argd', content = 'tradeable' }
}
if ret:paramGrep('bankable','no') then
ret:addRow{
{ tag = 'th', content = '[[Bank]]able' },
{ tag = 'argd', content = 'bankable' }
}
end
if ret:paramGrep('stacksinbank','no') then
ret:addRow{
{ tag = 'th', content = 'Stacks in bank' },
{ tag = 'argd', content = 'stacksinbank' }
}
end
if ret:paramGrep('lendable','yes') then
ret:addRow{
{ tag = 'th', content = '[[Item Lending|Lendable]]' },
{ tag = 'argd', content = 'lendable' }
}
end
ret:addRow{
{ tag = 'th', content = '[[Equipment|Equipable]]' },
{ tag = 'argd', content = 'equipable' }
}
:addRow{
{ tag = 'th', content = '[[Stackable items|Stackable]]' },
{ tag = 'argd', content = 'stackable' }
}
:addRow{
{ tag = 'th', content = '[[Disassemble|Disassembly]]' },
{ tag = 'argd', content = 'disassembly' }
}
if ret:paramGrep('noteable','yes') then
ret:addRow{
{ tag = 'th', content = '[[Note|Noteable]]' },
{ tag = 'argd', content = 'noteable' }
}
end
if ret:paramGrep('edible','yes') then
ret:addRow{
{ tag = 'th', content = '[[Food|Edible]]' },
{ tag = 'argd', content = 'edible' }
}
end
ret:addRow{
{ tag = 'th', content = '[[Destroy (action)|Destroy]]' },
{ tag = 'argd', content = 'destroy', css = { ['max-width'] = '200px' } }
}
if ret:paramGrep('actionsdisp', true) then
local actions_help = '<sup class="hover-text noprint" title="Excludes actions \'Examine\', \'Take\', and \'Use\'">[?]</sup>'
ret:addRow{
{ tag = 'th', content = 'Actions '..actions_help, class = 'infobox-subheader', colspan = '2' },
}
if yesno(ret:param('actions'), true) ~= false then
ret:addRow{
{ tag = 'th', content = '[[Inventory|Backpack]]'},
{ tag = 'argd', content = 'actions' }
}
end
if ret:paramDefined('actions_ground') then
ret:addRow{
{ tag = 'th', content = 'On ground'},
{ tag = 'argd', content = 'actions_ground' }
}
end
if ret:paramDefined('actions_equipped') then
ret:addRow{
{ tag = 'th', content = '[[Worn Equipment|Equipped]]'},
{ tag = 'argd', content = 'actions_equipped' }
}
end
if ret:paramDefined('actions_bank') then
ret:addRow{
{ tag = 'th', content = '[[Bank|In bank]]'},
{ tag = 'argd', content = 'actions_bank' }
}
end
end
ret:addRow{
{ tag = 'th', content = 'Values', class = 'infobox-subheader', colspan = '2' }
}
ret:addRow{
{ tag = 'th', content = '[[Value]]' },
{ tag = 'argd', content = 'value' }
}
-- 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]]' },
{ tag = 'argd', content = 'high' }
}
:addRow{
{ tag = 'th', content = '[[Low Level Alchemy|Low alch]]' },
{ tag = 'argd', content = 'low' }
}
else
ret:addRow{
{ tag = 'th', content = '[[Alchemy]]' },
{ tag = 'td', content = 'Not alchemisable' }
}
end
ret:addRow{
{ tag = 'th', content = '[[Items Kept on Death|On death]]' },
{ tag = 'argd', content = 'kept' }
}
:addRow{
{ tag = 'th', content = '[[Weight]]' },
{ tag = 'argd', content = 'weight' }
}
:addRow{
{ tag = 'th', content = '[[Examine]]', class = 'infobox-subheader', colspan = '2' }
}
:addRow{
{ tag = 'argd', content = 'examine', colspan = '2', css = { ['max-width'] = '300px', ['text-align'] = 'center' } }
}
-- 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 = '2' }
}
:addRow{
{ tag = 'th', content = '[[RuneScape:Grand Exchange Market Watch|Exchange]]' },
{ tag = 'argd', content = 'exchange' }
}
:addRow{
{ tag = 'th', content = '[[Grand Exchange#Trade restrictions|Buy limit]]' },
{ tag = 'argd', content = 'buylimit' }
}
:addRow{
{ tag = 'argd', content = 'graph', colspan = '2', css = { ['text-align'] = 'center', ['padding'] = '0'} }
}
end
ret:addRow{
{ tag = 'th', content = 'Advanced data', class = 'infobox-subheader', colspan = '2' },
meta = {addClass = 'advanced-data'}
}
:addRow{
{ tag = 'th', content = 'Item ID' },
{ tag = 'argd', content = 'id' },
meta = {addClass = 'advanced-data'}
}
:addRow{
{ tag = 'th', content = 'Links' },
{ tag = 'argd', content = 'chisel_links' },
meta = {addClass = 'advanced-data'}
}
if ret:paramDefined('calcvalue') then
ret :addRow{
{ tag = 'th', content = 'Calcval parsed' },
{ tag = 'argd', content = 'calcvalue' },
meta = {addClass = 'advanced-data'}
}
:addRow{
{ tag = 'th', content = 'Calcval smw' },
{ tag = 'argd', content = 'calcvalue_smw' },
meta = {addClass = '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 actionsdisparg(actions, actions_ground, actions_equipped, actions_bank)
-- if actions="no" and other actions aren't defined or no actions defined, hide
if (yesno(actions, true) == false and not (infobox.isDefined(actions_ground) or infobox.isDefined(actions_equipped) or infobox.isDefined(actions_bank))) or not (infobox.isDefined(actions) or infobox.isDefined(actions_ground) or infobox.isDefined(actions_equipped) or infobox.isDefined(actions_bank)) 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 calcvalParse(calcval)
if tonumber(val) then
return val
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
end
return val
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
-- 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)
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
-- 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)
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
return string.format('<span class="infobox-quantity" data-val-each="%s"><span class="infobox-quantity-replace">%s</span> coin%s ([[Exchange:%s|info]])</span>',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
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
-- 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
-- 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))
return r
end
return -1
end
-- sacrificevaluearg(reclaimvalue, sacrifice)
function sacrificevaluearg(r, _s)
if r > 0 then
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
return s
end
return -1
end
-- keptondeatharg(deathstatus, ikod, reclaimvalue, sacrificevalue)
function keptondeatharg(d,_i,r,s)
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)))
table.insert(ret,string.format('<b>Sacrifice:</b> %s',commas(s)))
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('%sid?%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('%sid?%s#%s', link1, j, j)
link2 = link2 .. j
else
link1 = link1 .. '@' .. j
end
end
end
else
link1 = string.format('%sid#%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, sacrificevalue, 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',
actions = 'Needs actions 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,'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 ~= 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')
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')
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>