RuneScape Wiki
Register
Advertisement

Documentation for this module may be created at Module:Disassemble/doc

-- <pre>
--------------------------
-- Module for [[Template:Disassembly]]
-- Please test changes to this module at [[Module:Disassembly]] first
--------------------------
local p = {}
local infobox = require('Module:Infobox')
local onmain = require('Module:Mainonly').on_main
local disdata = mw.loadData('Module:Disassemble/data')
local materials = mw.loadData('Module:Disassemble/mats')
local matchances = mw.loadData('Module:Disassembly material calculator/data')
local tooltips = require('Module:Tooltip')
local yesno = require('Module:Yesno')

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
}

function p.main(frame)
	local args = frame:getParent().args

	local ret = infobox.new(args)

	ret:defineParams{
		{ name = 'category', func = getCategory, dupes = true },
		{ name = 'catnames', func = { name = getCategoryNames, params = { 'category' } }, dupes = true },
		{ name = 'often_mats', func = { name = getMats, params = { 'category', 'often', 'often' }, flag = { 'd', 'd', 'r' } } },
		{ name = 'sometimes_mats', func = { name = getMats, params = { 'category', 'sometimes', 'sometimes' }, flag = { 'd', 'd', 'r' } } },
		{ name = 'rarely_mats', func = { name = getMats, params = { 'category', 'rarely', 'rarely' }, flag = { 'd', 'd', 'r' } } },
		{ name = 'mat_chances', func = { name = getMatChances, params = { 'category', 'often_mats', 'sometimes_mats', 'rarely_mats' } } },
		{ name = 'level', func = 'numbers', dupes = true },
		{ name = 'x10', func = { name = getX10, params = { 'category', 'x10' } }, dupes = true },
		{ name = 'xp', func = { name = getXP, params = { 'level', 'x10' } } },
		{ name = 'junkraw', func = { name = getRawJunk, params = { 'level' } } },
		{ name = 'junk', func = { name = getJunk, params = { 'junkraw' } } },
		{ name = 'compqty', func = { name = getCompQty, params = { 'category', 'compqty' } } },
		{ name = 'itemqty', func = { name = getItemQty, params = { 'category', 'itemqty' } } },
		{ name = 'special_mats', func = { name = getSpecialMats, params = { 'special' } } },
		{ name = 'specialchance', func = { name = getSpecialChance, params = { 'specialchance' }, flag = { 'd' } }, dupes = true },
		{ name = 'calcvalue', func = 'hascontent' },
		{ name = 'allspecmats', func = allspecsarg },
		{ name = 'returnsitems', func = getReturnedItems }
	}

	ret:setMaxButtons('8')

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

	-- Unique anchor for linking from Infobox Item
	ret:attr({ id = 'DisassemblyT' })
	ret:float('none')
	ret:css({ width = '300px',
			['margin-top'] = '10px !important',
			['margin-left'] = '10px' })

	ret:useSMW({
		junkraw = 'Junk chance',
	})
	ret:defineName('Disassembly')

	ret	:addRow{
			{ tag = 'th', content = '[[Disassemble|Disassembly XP]]', css = { ['text-align'] = 'left', width = '70%' }, title = 'Experience received for disassembling' },
			{ tag = 'argd', content = 'xp', css = { ['text-align'] = 'right' } }
		}

		:addRow{
			{ tag = 'th', content = 'Item quantity required', css = { ['text-align'] = 'left' }, title = 'Amount disassembled per action' },
			{ tag = 'argd', content = 'itemqty', css = { ['text-align'] = 'right' } }
		}

		:addRow{
			{ tag = 'th', content = 'Material count', css = { ['text-align'] = 'left' }, title = 'The number of materials received normally (not including specials); shown in chat window' },
			{ tag = 'argd', content = 'compqty', css = { ['text-align'] = 'right' } }
		}

		:addRow{
			{ tag = 'th', content = 'Base [[junk]] chance', css = { ['text-align'] = 'left' }, title = 'Base chance of receiving junk' },
			{ tag = 'argd', content = 'junk', css = { ['text-align'] = 'right' } }
		}

	-- plink function for materials
	local function matRow(builder, matname, chance)
		local td = builder:tag('td')
		
		td:wikitext(string.format('[[File:%s.png|25px|link=%s]] [[%s]]',matname,matname,matname))
		
		if chance then
			builder:tag('td')
						:wikitext(chance .. '%')
						:css('text-align', 'right')
						:attr('title', 'These are the chances of getting this material from one of the rolls for this item, after junk. See FAQ for more information.')
					:done()
		else
			td:attr('colspan', '2')
		end
		
	end


	local returneditems = ret:param('returnsitems', 'd')
	if  returneditems[1] and returneditems[1]:find('%S') then
		ret:addRow{
			{ tag = 'th', content = 'Returned items', colspan = '2', css = { background = '#E5E5E5' } },
		}
		for _,v in ipairs(returneditems) do
			ret:tag('tr')
				:tag('td')
					:attr('colspan', '2')
					:wikitext(string.format('[[File:%s.png|link=%s]] [[%s]]',v,v,v))
				:done()
			:done()
		end
	end
	
	ret:addRow{
		{ tag = 'th', content = 'Possible materials', colspan = '2', class = 'header-top' },
	}

	-- get materials in table
	local spec = ret:param('special_mats', 'd')
	local schance = ret:param('specialchance','d')
	local oftn = ret:param('often_mats', 'd')
	local smts = ret:param('sometimes_mats', 'd')
	local rrly = ret:param('rarely_mats', 'd')
	local chances = ret:param('mat_chances', 'd')

	-- only add row if specials are there
	if spec[1] then
		local allspec = ret:param('allspecmats','d')
		ret:addRow{
				{ tag = 'th', content = 'Special', colspan = '2', title = 'The number of special materials received (if any are received); note that the number of special materials received is independent of the total materials and junk chance listed above. See FAQ for more information.' }
			}
		local speccount = table.maxn(spec)
		local _tr, _td
		for i, v in ipairs(spec) do
			_tr = ret:tag('tr')
			_td = _tr:tag('td')
			_td:wikitext(mw.ustring.format('%s × [[File:%s.png|25px|link=%s]] [[%s]]', v.q,v.n,v.n,v.n))
			local _chance = v.c
			if speccount == 1 and schance == true then
				_chance = 100
			end
			
			local spcell, sptitle
			
			if _chance then
				spcell = _chance .. '%'
				sptitle = 'The chance of getting this material by disassembling this item - as a special material, this ignores junk chance. See FAQ for more information.'
			elseif schance == false then
				spcell = 'Not 100%'
				sptitle = 'This special material is not guaranteed, and the actual chance of getting it is not known. See FAQ for more information.'
			else
				spcell = 'Unknown'
				sptitle = 'The chance of receiving this special material is not known, including whether it is guaranteed or not. See FAQ for more information.'
			end
			
			_tr:tag('td')
						:wikitext(spcell)
						:css({['text-align'] = 'right', ['vertical-align'] = 'middle'})
						:attr('title', sptitle)
					:done()
			
			
			
			if i < speccount and allspec ~= 'yes' then
				ret	:tag('tr')
						:tag('td')
							:attr('colspan','2')
							:css({ ['text-align'] = 'center' })
							:wikitext("''OR''")
						:done()
					:done()
			end
		end
	end

	-- only add row if often mats are there
	if oftn[1] then
		ret:addRow{
				{ tag = 'th', content = 'Often', colspan = '2' }
			}
		for _, v in ipairs(oftn) do
			matRow(ret:tag('tr'), v, chances[v])
		end
	end

	-- only add row if sometimes mats are there
	if smts[1] then
		ret:addRow{
				{ tag = 'th', content = 'Sometimes', colspan = '2' }
			}
		for _, v in ipairs(smts) do
			matRow(ret:tag('tr'), v, chances[v])
		end
	end

	-- only add row if rarely mats are there
	if rrly[1] then
		ret:addRow{
				{ tag = 'th', content = 'Rarely', colspan = '2' }
			}
		for _, v in ipairs(rrly) do
			matRow(ret:tag('tr'), v, chances[v])
		end
	end

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

	ret:finish()
	return ret:tostring()
end

-- param parsing

-- gets the category table
function getCategory(arg)
	local _arg = string.lower(arg or '')

	if _arg == 'no' or _arg == 'custom' then
		return 'custom'
	elseif disdata[_arg] then
		_arg = _arg
	else
		_arg = nil
	end

	return _arg
end

-- category name, for categorising article
function getCategoryNames(arg)
	local _arg = string.lower(arg or '')

	if _arg == 'custom' then
		return 'custom'
	elseif disdata[_arg] then
		local cat = disdata[_arg] or {}
		_arg = cat.cat or 'custom'
	else
		_arg = nil
	end

	return _arg
end

-- table of mats
-- only accepts materials that exist in the /mats page
-- arg is value passed to template, unused unless custom
function getMats(_cat,arg,mattype)
	local mat_list

	if _cat == 'custom' then
		mat_list = string.lower(arg or '')
	else
		local cat = disdata[_cat] or {}
		mat_list = cat[mattype]
	end

	if not mat_list then
		return {}
	end

	local ret = {}

	for _, v in ipairs(mw.text.split(mat_list,',')) do
		local _v = string.lower(v)
				:gsub('components?','')
				:gsub('parts?','')

		_v = mw.text.trim(_v)

		local _name = materials[_v]
		if _name then
			table.insert(ret,_name)
		end
	end

	return ret
end

-- material chances
function getMatChances(_cat, often_mats, sometimes_mats, rarely_mats)
	local ret = {}
	if _cat ~= 'custom' and disdata[_cat] then
		local cat = disdata[_cat].cat
		local chances = matchances[cat]
		if chances then
			for i,v in pairs(chances) do
				ret[materials[i]] = v*100
			end
		end
	end
	return ret
end


-- special materials
-- handled differently from normal mats
function getSpecialMats(arg)
	local mat_list = string.lower(arg or '')

	if not mat_list then
		return {}
	end

	local ret = {}

	for _, v in ipairs(mw.text.split(mat_list,',')) do
		local _v = string.lower(v)
				:gsub('components?','')
				:gsub('parts?','')

		_v = mw.text.trim(_v)
		local _m,_q,_c = _v:match('(%w+)%s*%[?(%d*)%]?%s*%{?(%d*)%}?')
		local _name = materials[_m]
		local _chance = nil
		if _c and _c ~= '' then
			_chance = _c
		end
		
		if _name then
			table.insert(ret,{ n = _name, q = tonumber(_q) or '?', c = _chance })
		end
	end

	return ret
end

function getSpecialChance(arg)
	if arg == '' or arg == nil then
		return nil --unknown
	else
		return yesno(arg)
	end
end


-- raw value of junk for parsing and properties
function getRawJunk(_l)
	local l = tonumber(_l)

	if not l then
		return nil
	end

	if l >= 90 then
		return 0
	end

	if l >= 75 then
		return junkpast75[l]
	end

	local junk = 100 - 1.1 * l

	junk = math.floor((junk) * 1000 + 0.009)/1000

	return junk
end

-- parses junk to a string
-- adds '%'
-- adds '.0' to integers
function getJunk(_j)
	local junknum = tonumber(_j)

	if not junknum then
		return nil
	end

	-- function to add '.0' to integers
	-- needed for full table in tool tip as well
	local function point0(j)
		local ji,jd = math.floor(j), (j%1) * 10

		-- kill rounding errors
		jd = math.floor((jd) * 1000 + 0.009)/1000

		return string.format('%s.%s%%',ji,jd)
	end

	local junk = point0(junknum)

	local tooltip_span = ''
	local tooltip_div = nil
	
	-- add tool tip if not 0 junk
	if (tonumber(junknum) or -1) > 0 then
		local junkreduction = {
			{34, 0.99}, {49, 0.97}, {64, 0.95}, {69, 0.93}, {78, 0.91}, {83, 0.88}, {91, 0.86}, {95, 0.83}, {105, 0.8}
		}
	
		local junktstr = 'Your actual junk chance depends on your junk chance reduction researched.<br />See the table below for all values, and [[Junk]] for more information.'
		local junkttable = mw.html.create('table')
		junkttable	:addClass('wikitable')
					:css({
						['text-align'] = 'right',
						margin = '0 auto',
					})
					:tag('tr')
						:tag('th')
							:wikitext('Reduction')
						:done()
						:tag('th')
							:wikitext('[[File:Invention-icon.png|link=Invention]]')
						:done()
						:tag('th')
							:wikitext('Junk chance')
						:done()
					:done()
					:tag('tr')
						:tag('td')
							:wikitext('None')
						:done()
						:tag('td')
							:wikitext(1)
						:done()
						:tag('td')
							:wikitext(junk)
						:done()
					:done()
		
		for i,v in ipairs(junkreduction) do
			junkttable	:tag('tr')
							:tag('td')
								:wikitext(i)
							:done()
							:tag('td')
								:wikitext(v[1])
							:done()
							:tag('td')
								-- kill rounding errors
								:wikitext(point0(math.ceil(junknum * v[2] * 10)/10))
							:done()
						:done()
		end
		
	
		tooltip_span = tostring(tooltips._span({'junkchance' .. junknum})) .. '&nbsp;&nbsp;'
		tooltip_div = tooltips._div({
			name = 'junkchance' .. junknum,
			content = junktstr .. '\n' .. tostring(junkttable),
		})
	end

	-- end o' tool tip

	return tooltip_span..junk..tostring(tooltip_div or '')
end


-- experience multiplier
-- taken from category
-- uses value passed to template if custom
function getX10(_cat,x10)
	local xx10
	if _cat == 'custom' then
		xx10 = string.lower(x10 or 'no')
	else
		local cat = disdata[_cat] or {}
		xx10 = tostring(cat.x10)
	end

	return yesno(xx10,false)
end

-- get xp from level
function getXP(_l,x10)
	local l = tonumber(_l)

	if not l then
		l = 1
	end

	local mult = yesno(tostring(x10)) and 10 or 1

	local xp = math.max(math.floor(l * 0.03 * mult * 1000 + 0.009)/1000,0.1)

	xp = math.floor(xp * 10 + 0.05)/10

	if xp % 1 == 0 then
		xp = xp..'.0'
	end

	return xp
end

-- get number of materials received
function getCompQty(_cat,qty)
	local compqty
	if _cat == 'custom' then
		compqty = string.lower(qty or 'no')
	else
		local cat = disdata[_cat] or {}
		compqty = cat.compqty
	end

	return tonumber(compqty)
end

-- get number of items disassembled per action
function getItemQty(_cat,qty)
	local itemqty
	if _cat == 'custom' then
		itemqty = string.lower(qty or 'no')
	else
		local cat = disdata[_cat] or {}
		itemqty = cat.itemqty
	end

	return tonumber(itemqty) or 1
end

-- spec amounts
function allspecsarg(arg)
	arg = arg or 'no'
	return string.lower(arg)
end

-- returned items eg refined anima core
function getReturnedItems(arg)
	local ret = {}
	if arg then
		ret = mw.text.split(arg, '%s?;%s?')
	end
	return ret
end


-- categories
function addCategories(args,cdata)
	local ret = {}

	-- new table for special materials' names only
	local spec_mats = {}
	local has_spec = false
	for _, v in ipairs(args.special_mats.d) do
		table.insert(spec_mats,v.n)
		has_spec = true
	end

	-- iterate over all materials and add categories
	for _, v in ipairs({
				args.often_mats.d,
				args.sometimes_mats.d,
				args.rarely_mats.d,
				spec_mats
			}) do
		for _, w in ipairs(v) do
			table.insert(ret,string.format('Items that disassemble into %s',w))
		end
	end

	-- add category based on disassembly category
	-- custom = nothing
	-- not defined = tracking category
	if args.catnames.d == 'custom' then
		-- nothing
	elseif infobox.isDefined(args.catnames.d) then
		table.insert(ret,string.format('Disassemble category/%s',args.catnames.d))
	else
		table.insert(ret,'Missing disassembly category')
	end

	-- same deal, but with the other categories
	-- commenting out for now since only the default category affects materials
	-- switched categories can only affect comp/mat qty
	--[=[
	local catswitches = args.catnames.switches
	if catswitches then
		for _, v in ipairs(catswitches) do
			if infobox.isDefined(v) then
				if v == 'custom' then
					-- nothing
				else
					table.insert(ret,string.format('Disassemble category/%s',v))
				end
			else
				table.insert(ret,'Missing disassembly category')
			end
		end
	end
	--]=]

	-- special mats
	if has_spec then
		if not cdata.specialchance.all_defined then
			table.insert(ret,'Missing special chance')
		end

		-- check that all materials have a quantity
		for _, v in ipairs(args.special_mats.d) do
			if type(v.q) ~= 'number' then
				table.insert(ret,'Missing special material quantity')
			end
		end
	end

	if args.junkraw.d == 0 then
		table.insert(ret,'Items that cannot disassemble into Junk')
	elseif args.junkraw.switches then
		for _, v in ipairs(args.junkraw.switches) do
			if v == 0 then
				table.insert(ret,'Items that cannot disassemble into Junk')
				break
			end
		end
	end

	-- if default level isn't defined
	-- see if switches exist
	-- if any switch isn't defined and default isn't, add maintenance cat
	-- if switches don't exist, and default isn't defined, add maintenance cat
	if not infobox.isDefined(args.level.d) then
		if args.level.switches then
			for _, v in ipairs(args.level.switches) do
				if not infobox.isDefined(v) then
					table.insert(ret,'Missing Invention disassembly level')
				end
			end
		else
			table.insert(ret,'Missing Invention disassembly level')
		end
	end

	if infobox.isDefined(args.calcvalue.d) then
		table.insert(ret,'Disassembly calculator override')
	end
	
	-- add to the disassembly calculator for junk if the base junk is more than 20000 per hour
	local dis_per_hour = 3000
	local calc_cat_limit = 19999
	if type(args.junkraw.d) == 'number' then
		if args.junkraw.switches then
			for _,v in ipairs(args.junkraw.switches) do
				if type(args.compqty.d) == 'number' then
					if not args.compqty.switches and v/100 * args.compqty.d * dis_per_hour > calc_cat_limit then
						table.insert(ret,'Disassembly junk calculator')
					end
				end
			end
		else
			if type(args.compqty.d) == 'number' then
				if args.compqty.switches then
					for _,v in ipairs(args.compqty.switches) do
							-- ignore if both have switches
						v = tonumber(v)
						if v then
							if not args.junkraw.switches and v * args.junkraw.d/100 * dis_per_hour > calc_cat_limit then
								table.insert(ret,'Disassembly junk calculator')
							end
						end
					
					end
				else
					if args.junkraw.d/100 * args.compqty.d * dis_per_hour > calc_cat_limit then
						table.insert(ret,'Disassembly junk calculator')
					end
				end
			end
		end
	end

	-- clean return string
	local cats = {}

	for _, v in ipairs(ret) do
		table.insert(cats,string.format('[[Category:%s]]',v))
	end

	return table.concat(cats,'\n')
end

return p
Advertisement