RuneScape Wiki
No edit summary
No edit summary
Line 163: Line 163:
 
:css('text-align','center')
 
:css('text-align','center')
 
:tag('td'):css('text-align','left'):wikitext(name):done()
 
:tag('td'):css('text-align','left'):wikitext(name):done()
:tag('td'):wikitext(combat):done()
+
:tag('td'):wikitext(combat or ''):done()
 
:tag('td'):attr('data-sort-value', qtysort):wikitext(quantity):done()
 
:tag('td'):attr('data-sort-value', qtysort):wikitext(quantity):done()
 
:tag('td')
 
:tag('td')

Revision as of 06:36, 6 June 2019

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

-- Rewrite of Module:DropsLine
-- Rewrite of Module:Get drop info
local Drops = {}
----------------------------
-- Libraries of functions --
----------------------------
-- Loads high frequency functions
local HF = require('Module:HF')

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

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

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

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

-- {{ItemDropsLine}} support
--local IDL = require( 'Module:ItemDropsLine' ).main
--local _IDL = require( 'Module:ItemDropsLine' )._main

-------------------------------------------
-- Local data (used only in this Module) --
-------------------------------------------
--bg, txt, sort
local rarities = {
	always = {'#8FD7FA !important', '#083F66', 1},
	common = {'#98E553 !important', '#245200', 2},
	uncommon = {'#F5EB4E !important', '#524E00', 3},
	rare = {'#F6AB58 !important', '#582E00', 4},
	['very rare'] = {'#F86C67 !important', '#520800', 5},
	random = {'#F3BFF3 !important', '#801B80', 6},
	varies = {'#F3BFF3 !important', '#801B80', 6},
	discontinued = {'#CFCFCF !important', '#464646', 7}
}

------------------------------------------------
-- Local functions (used only in this Module) --
------------------------------------------------
local commas = function (n) return lang:formatNum(tonumber(n)) end

local function categories(...)
	local name,quantity,rarity = unpack(...)
	local cats = {}
	name = name:lower()
	quantity = quantity:lower()
	if name:find('effigy') then table.insert(cats, HF.Category('Effigy dropping monsters'))
	elseif name:find('clue scroll') then table.insert(cats, HF.Category('Clue scroll dropping monsters'))
	elseif name:find('rare drop table') then table.insert(cats, HF.Category('Monsters with access to the rare drop table'))
	end
	if not rarities[rarity:lower()] then table.insert(cats, HF.Category('Needs drop rarity added')) end
	if quantity:find('unknown') then table.insert(cats, HF.Category('Needs drop quantity added')) end
	return table.concat(cats)
end

local function qty(quantity)
	-- if no quantity is given, return unknown
	if not quantity or quantity == 'unknown' then
		return 'Unknown'
	end
	-- en dashes are the proper dash for number ranges
	-- replace all hyphens and em dashes with en
	-- strip *all* whitespace
	-- change '(noted)' to '$n' for parsing
	quantity = mw.ustring.gsub(quantity,'[-—]','–')
		:gsub('%s','')
		:gsub('%(noted%)','$n')
	-- split list into table
	local vals = mw.text.split(quantity,'[,;]')
	-- recreate the quantity string to ensure consistent formatting
	local numstr = {}
	for i, v in ipairs(vals) do
		local clean = v:gsub('$n','')
		-- if list element contains an en dash (indicating range)
		-- Find the smaller/larger number (just in case)
		-- Compare them to the current min/max
		-- put them in order with desired format
		if mw.ustring.find(v,'–') then
			local splitvals = mw.text.split(clean,'–')
			-- assume a is smaller, b is larger
			local a = tonumber(splitvals[1])
			local b = tonumber(splitvals[2])
			-- Just in case
			if a > b then
				a,b = b,a
			end
			addx = commas(a)..'–'..commas(b)
			if v:find('$n') then
				addx = addx..' (noted)'
			end
			table.insert(numstr,addx)
		else
			local addx = tonumber(clean) ~= nil and commas(tonumber(clean)) or clean
			if v:find('$n') then
				addx = addx..' (noted)'
			end
			table.insert(numstr,addx)
		end
	end
	-- To prevent any possible confusion with formatted numbers
	-- elements should be separated with semicolons followed by a space
	numstr = table.concat(numstr,'; ')
	if numstr:find('%d') then
		return numstr
	else
		return 'Unknown'
	end
end

local function cmb(levels)
	-- if no level is given, return unknown
	if not levels then
		return 'Unknown'
	end

	-- split list into table
	local vals = mw.text.split(levels,'[,;]')
	-- recreate the list string to ensure consistent formatting
	local numstr = {}
	for i, v in ipairs(vals) do
		table.insert(numstr,v)
	end

	table.sort(numstr,function (a,b)
			a = tonumber(a) or 0
			b = tonumber(b) or 0
			return a < b
		end)
	-- To prevent any possible confusion with formatted numbers
	-- elements should be separated with semicolons followed by a space
	return table.concat(numstr,'; ')
end

local function getCombatLevel(source)
	local levelstring
	local results = mw.smw.ask{
		HF.Link(source),
		'?All Combat level=CLs',
		'format=list',
		'headers=hide',
		'mainlabel=-'
	}
	if type(results) == 'table' then
		levelstring = results[1]['CLs']
		if type(levelstring) == 'string' and levelstring:find(',') then
		levels = mw.text.split(levelstring, ', ')
		table.sort(levels)
		levelstring = table.concat(levels, ', ')
		end
	else
		levelstring = 'N/A'
	end
	return levelstring
end

local function IDL_HTML ( name, combat, qtysort, quantity, rarity)
	local rare_bg, rare_txt, rare_sort = unpack(rarities[rarity:lower()] or {'#FFFFFF !important', '#000000', 8})
	local row = mw.html.create('tr')
			:css('text-align','center')
			:tag('td'):css('text-align','left'):wikitext(name):done()
			:tag('td'):wikitext(combat or ''):done()
			:tag('td'):attr('data-sort-value', qtysort):wikitext(quantity):done()
			:tag('td')
				:attr('data-sort-value', rare_sort)
				:css('background', rare_bg)
				:css('color', rare_txt)
				:wikitext(rarity)
			:done()
	return tostring(row)
end

---------------------------------------------------------
-- Internal functions (used in this and other Modules) --
---------------------------------------------------------
-- {{Dropping monsters list}}
function Drops.DML (frame)
	local args = getArgs(frame, { parentOnly = true })
	local listfor = args[1] or mw.title.getCurrentTitle().fullText
	local head = frame:newTemplateParserValue{
		title = "ItemDropsTableHead",
		args = { listfor }
	}
	local foot = frame:newTemplateParserValue{ title = "ItemDropsEnd" }
	local results = mw.smw.ask{
		HF.Category('Drops'),
		HF.Link(("Item::%s"):format(listfor)),
		'?Source',
		'?Drops/Quantity (low)=Low',
		'?Drops/Quantity (high)=High',
		'?Rarity',
		'mainlabel=-',
		'limit='..(args['limit'] or 50),
		'sort='..(args['sort'] or 'Rarity,Source'),
		'order='..(args['order'] or '')
	}
	if not results then return HF.Category('Empty drop lists') end
	local output = {}
	--[==[
	<includeonly>:''This list was created dynamically. For help, see [[Template:Dropping monsters list/FAQ|the FAQ]].''
:''To force an update of this list, click {{purge|here|tag=span}}.''
{{ItemDropsTableHead|{{{1|{{PAGENAME}}}}}}}
{{#ask:[[Drops item::{{{1|{{PAGENAME}}}}}]]|?=monster|userparam={{{1|{{PAGENAME}}}}}|format=template|template=Get drop info|named args=yes|link=none|searchlabel=|limit={{{limit|50}}}|sort={{{sort|}}}|order={{{order|}}}|default=[[Category:Empty drop lists]]}}
{{ItemDropsEnd}}</includeonly><noinclude>{{/doc}}</noinclude>
	--]==]

	for _,item in ipairs(results) do
	    item.Source = item.Source:gsub('[][]','')
		-- merge quantity if same
		local quantity
		if item['Low'] and item['High'] and item['Low'] == item['High'] then
			quantity = item['Low']
		elseif type(tonumber(item['Low'])) == 'number' and type(tonumber(item['High'])) then
			quantity = item['Low'] .. '–' .. item['High']
		else
			quantity = 'unknown'
		end

		item.Rarity = item.Rarity and lang:lc(item.Rarity) or 'Unknown'
		item.Rarity = item.Rarity and lang:ucfirst(item.Rarity)
		table.insert(output, Drops._IDL{
			['Monster'] = item['Source'],
			['Combat'] = getCombatLevel(item['Source']),
			['Quantity'] = quantity,
			['Rarity'] = item['Rarity']
		})
	end
	return
	( head and head:expand() or '' ) .. table.concat(output) .. ( foot and foot:expand() or '' )
end

function Drops.IDL (frame)
	local args = getArgs(frame, { parentOnly = true })
	args.Monster = args.Monster or 'monster'
	args.Quantity = args.Quantity and args['Quantity']:lower() or 'unknown'
	args.Rarity = args.Rarity and lang:lc(args.Rarity) or 'Unknown'
	args.Rarity = args.Rarity and lang:ucfirst(args.Rarity)
	return Drops._IDL(args)
end

function Drops._IDL (args)
	args.Monster = args.Monster and HF.Link(args.Monster)
	args.Monster = (args.Namenotes and #args['Namenotes'] > 5)
		and (args.Monster ..' '.. args.Namenotes) or args.Monster
	args.Combat = (args.cbnotes and #args['cbnotes'] > 5)
		and (args.combat ..' '.. args.cbnotes) or args.Combat
	args.Quantity = (args.Quantitynotes and #args['Quantitynotes'] > 5)
		and (args.Quantity ..' '.. args.Quantitynotes) or args.Quantity
	args.Rarity = (args.Raritynotes and #args['Raritynotes'] > 5)
		and (args.Rarity ..' '.. args.Raritynotes) or args.Rarity

	-- Clean up the lists
	quantity = qty(quantity)
	local qtysort = mw.text.split(quantity, '%D')[1]
	if qtysort == '' then
		qtysort = 0
	end

	args.Combat = args.Combat
	return IDL_HTML ( args.Monster, args.Combat, qtysort, args.Quantity, args.Rarity)
end


-------------------------------------------------
-- Output (send it back to whatever called it) --
-------------------------------------------------
return Drops