Module:Disassembly material calculator/sandbox

-- -- code for Template:Disassembly material calculator/t/sandbox -- 	and Template:Disassembly material calculator/t2/sandbox -- -> Calculator:Disassembly by material local p = {}

local yesno = require('Module:Yesno') local cats = mw.loadData('Module:Disassemble/data') local materials = mw.loadData('Module:Disassemble/mats') local exg = require('Module:ExchangeLite') local coin = require('Module:Coins')._amount local info = mw.loadData('Module:Disassembly category calculator/data') -- versioning info here local chances = mw.loadData('Module:Disassembly material calculator/data') -- chance info here local commas = require('Module:Addcommas')._add local Title = mw.title.getCurrentTitle local spn = Title.subpageText

-- get the material name from a passed in string m -- returns material name,true if successful -- returns m (or the empty string), false if material not found local function get_mat(m) local str = mw.text.trim(string.gsub(string.gsub(string.lower(m), ' parts?', ), ' components?', )) if materials[str] then return materials[str], true else return (m or ''), false end end local pagemat = get_mat(spn)

-- from a given category in the disassemble template, and a material, return the chance of that material -- returns chance (as a decimal between 0 and 1) if successful -- returns -1 if not local function get_chance(c, m)	-- strip off the excess stuff local m = mw.text.trim(string.gsub(string.gsub(string.lower(m), ' parts?', ), ' components?', )) local cat if type(c) == 'table' then cat = c	else cat = cats[c] end local chs, ch	if cat then chs = chances[cat.cat] if chs then ch = chs[m] if ch then return ch			end end end return -1 end

local function gep(item) item = info.gemwnames[item] or info.names[item] or item local err, val = pcall(exg.load, {args={item, 'price'}}) local err2, limit = pcall(exg.load, {args={item, 'limit'}}) if err then if err2 then return val, limit else return val, 0 end else return 0, -1 end end

local function img(item) return info.imgnames[item] or info.names[item] or item end

local function junk(lv) local junkpast75 = { [75] = 4.2, [76] = 3.8, [77] = 3.4, [78] = 3.0, [79] = 2.7,		[80] = 2.3, [81] = 2.0, [82] = 1.7, [83] = 1.4, [84] = 1.2,		[85] = 1.0, [86] = 0.8, [87] = 0.6, [88] = 0.4, [89] = 0.3 }	lv = tonumber(lv) or 1 if lv >= 90 then return 0 elseif lv >= 75 then return junkpast75[lv] else return 100 - 1.1 * lv	end end

local function plink(page, name, img) return string.format(' %s', img, page, page, name) end

local function coins(td, am) if am == 0 then td	:wikitext("N/A") :addClass('table-na') else td	:wikitext(coin(am, false)) end td	:attr('data-sort-value', am) end

local function round(n) -- significant figure funciton -- only applies to numbers < 1 local function sigfig(n, f)		f = math.floor(f) if n > 1 or f < 1 then return n		end local prec = 0 for i = 3, 10, 1 do			if n * 10^i >= 1 then prec = i + f - 2 break end end if prec == 0 then return 0 end return string.format('%.' .. prec .. 'f', n)	end if n >= 10 then return string.format('%.1f', n)	elseif n >= 0.1 then return string.format('%.2f', n)	else return sigfig(n, 2) end end

-- row creation for special materials -- item | number per item | always? | junk | price each | buy limit | mat cost local function make_row_special(data) local tr = mw.html.create('tr') local str data.cqty = data.sqty if data.iqty > 1 then str = string.format('%s %s %s', data.iqty, '×', plink(data.page, data.name, data.img)) else str = plink(data.page, data.name, data.img) end local spcstring = '100%' local spcstringsort = 100 local chance = 1 if data.chance then chance = data.chance / 100 spcstringsort = data.chance spcstring = data.chance .. '%'	elseif not data.spchance then spcstring = '' spcstringsort = 0 end local val = data.price * data.iqty / (data.cqty * chance) if val < 100 then val = string.format("%.2f", val) else val = string.format("%.0f", val) end tr	:tag('td') :css('text-align','left') :wikitext(str) :attr('data-sort-value', data.name) :done :tag('td') :wikitext(data.cqty) :attr('data-sort-value', data.cqty) :done :tag('td') :wikitext(spcstring) :attr('data-sort-value', tostring(spcstringsort)) :done :tag('td') :wikitext(string.format('%.1f%%', data.junk)) :attr('data-sort-value', data.junk) :done coins(tr:tag('td'), data.price) if tonumber(data.limit) and data.limit > 0 then tr	:tag('td') :attr('data-sort-value', data.limit) :wikitext(commas(data.limit)) :done elseif tonumber(data.limit) and data.limit < 0 then tr	:tag('td') :attr('data-sort-value', 0) :wikitext("N/A") :addClass('table-na') :done else tr	:tag('td') :attr('data-sort-value', 0) :wikitext("Unknown") :done end coins(tr:tag('td'), val) return tostring(tr) end

-- non-special mat row -- item | cqty | junk | price each | buy limit | chance of mat per nonjunk | overall chance per item base/red5/red9 | cost base/red5/red9 local function make_row(data) if data.isspecial then return make_row_special(data) end local tr = mw.html.create('tr') local chance = {} local val = {} local str if data.iqty > 1 then str = string.format('%s %s %s', data.iqty, '×', plink(data.page, data.name, data.img)) else str = plink(data.page, data.name, data.img) end chance.before = data.chance * 100 chance.base = (1 - data.junk/100) * data.chance * data.cqty val.base = data.price * data.iqty / chance.base chance.base = round(chance.base * 100) val.matsperhour = 3000 * chance.base --round to 0dp if >100, else 2dp for i,v in pairs(val) do		if v < 100 then val[i] = string.format("%.2f", v)		else val[i] = string.format("%.0f", v)		end end tr	:attr({		['data-dis-mats'] = data.cqty,		['data-dis-junk'] = data.junk,		['data-dis-price'] = data.price,		['data-dis-raw'] = chance.before,		}) tr	:tag('td') :css('text-align','left') :wikitext(str) :attr('data-sort-value', data.name) :done :tag('td') :wikitext(data.cqty) :attr('data-sort-value', data.cqty) :done :tag('td') :wikitext(string.format('%.1f%%', data.junk)) :attr('data-sort-value', data.junk) :addClass('data-dis-junkcell') :done coins(tr:tag('td'), data.price) if tonumber(data.limit) and data.limit > 0 then tr	:tag('td') :attr('data-sort-value', data.limit) :wikitext(commas(data.limit)) :done elseif tonumber(data.limit) and data.limit < 0 then tr	:tag('td') :attr('data-sort-value', 0) :wikitext("N/A") :addClass('table-na') :done else tr	:tag('td') :attr('data-sort-value', 0) :wikitext("Unknown") :done end tr	:tag('td') :attr('data-sort-value', chance.before) :wikitext(chance.before .. '%') :done tr	:tag('td') :attr('data-sort-value', chance.base) :wikitext(chance.base .. '%') :addClass('data-dis-chancecell') :done local costtd = tr:tag('td') costtd:addClass('data-dis-cost') coins(costtd, val.base) tr	:tag('td') :attr('data-sort-value', val.matsperhour) :wikitext(val.matsperhour) :addClass('data-dis-mphcell') :done return tostring(tr) end

-- special case: potions -- cqty does not vary, it might actually idk local function potion(data) local rows = {} if data.calcvalue and data.calccomp then data.name = string.format('%s (%s)', data.page, data.calccomp) data.img = img(data.name) data.cqty = data.calccomp data.price = data.calcvalue data.limit = -1 return make_row(data) end -- setup 6-dose data.name = data.page .. ' (6)'	data.img = img(data.name) data.cqty = 6 data.price, data.limit = gep(data.name) if data.price > 0 then -- if 6-dose has a price, then this is a flask; only show 6 dose (5 and lower not GE-able) return make_row(data) else data.name = data.page .. ' (4)'		data.price, data.limit = gep(data.name) if data.price > 0 then -- if 4 dose has a price, this is a 4-dose vial for i = 4, 1, -1 do				data.name = string.format('%s (%s)',data.page,i) data.img = img(data.name) data.cqty = i				data.price, data.limit = gep(data.name) table.insert(rows, make_row(data)) end else -- if 4 dose does not have a price, this is a 2-dose mix for i = 2, 1, -1 do				data.name = string.format('%s (%s)',data.page,i) data.img = img(data.name) data.cqty = i				data.price, data.limit = gep(data.name) table.insert(rows, make_row(data)) end end return table.concat(rows, '\n') end end

-- main parsing function and module entry point p._main = function (args) local cat = cats[string.lower(args.category)] if not cat then return '' end local data = {} local rows = {} local pot = args.potion or cat.potion or false pot = string.lower(tostring(pot)) data.isspecial = args.isspecial -- if is special, get the number of special mat per item out of the template if data.isspecial then local _special = mw.text.split(args.special or '','%s*,%s*') local numsp = 1 local chsp = nil

local specmatcount = table.maxn(_special) for i, v in ipairs(_special) do			v = string.lower(v) :gsub('components?','') :gsub('parts?','') local _m,_q,_c = v:match('(%w+)%s*%[?(%d*)%]?%s*%{?(%d*)%}?') local _name, matb = get_mat(_m) local _chance = nil local _quant = tonumber(_q) or 1 if _c and _c ~= '' and tonumber(_c) then _chance = tonumber(_c) elseif yesno(args.specialchance) and specmatcount == 1 then _chance = 100 end _name = mw.text.trim(_name) if v:find('%S') then if matb and _name == pagemat then numsp = _quant chsp = _chance break end end end if string.lower(args.specialchance or '') == 'no' then data.spchance = false else if args.specmatcount == 1 then data.spchance = true elseif args.allspecmats then data.spchance = true else data.spchance = false end end data.sqty = numsp data.cqty = numsp data.chance = chsp else data.chance = get_chance(cat, pagemat) if data.chance < 0 then return '' end data.cqty = tonumber(cat.compqty) or 1 end data.iqty = tonumber(cat.itemqty) or 1 data.page = args['%PAGE%'] data.junk = junk(args.level) -- defaults data.name = data.page data.img = img(data.page) data.calcvalue = tonumber(args.calcvalue) or nil data.calccomp = tonumber(args.calccomp) or nil if yesno(pot) then return potion(data) end if info.versions[args['%PAGE%']] then for i,v in ipairs(info.versions[args['%PAGE%']]) do			data.name = v			if data.calcvalue then data.price, data.limit = data.calcvalue, -1 else data.price, data.limit = gep(v) end data.img = img(v) table.insert(rows, make_row(data)) end return table.concat(rows, '\n') else if data.calcvalue then data.price, data.limit = data.calcvalue, -1 else data.price, data.limit = gep(data.page) end return make_row(data) end end

-- special component entry point p.special = function(frame) local args = frame:getParent.args args.isspecial = true return p._main(args) end

-- normal component entry point p.main = function(frame) local args = frame:getParent.args args.isspecial = false return p._main(args) end

return p