Module:DropsLine
Jump to navigation
Jump to search
Module documentation
This documentation is transcluded from Module:DropsLine/doc. [edit] [history] [purge]
Module:DropsLine is invoked by .
Module:DropsLine requires .
Module:DropsLine loads data from Module:DropsLine/itemData.json.
Module:DropsLine loads data from Module:GEHighAlchs/data.json.
Module:DropsLine loads data from Module:GEPrices/data.json.
| Function list |
|---|
| L 105 — get_rarity_class L 113 — commas L 120 — sigfigalt L 127 — qty_parse L 147 — qty_range L 158 — qty_format_html L 175 — qty_bucket L 187 — get_total L 200 — parse_dropnotes L 240 — get_currency_image L 247 — get_currency_name L 263 — get_price_cell_data L 357 — categories L 378 — add_rarity_attrs L 391 — parse_rarity L 455 — get_value_info L 528 — p.main |
This module provides functionality for the monster drop tables. See Template:DropsLine for use.
local p = {}
local params = require('Module:Paramtest')
local lang = mw.language.getContentLanguage()
local coins_image = require('Module:Coins image')
local curr_image = require('Module:Currency Image')
local exchange = require('Module:Exchange')
local yesno = require('Module:Yesno')
local round = require('Module:Round')
local on_main = require('Module:Mainonly').on_main
require("Module:Mw.html extension")
local var = mw.ext.VariablesLua
-- precalculated cached data
local droppeditem_data = mw.loadJsonData('Module:DropsLine/itemData.json')
local geprices_data = mw.loadJsonData('Module:GEPrices/data.json')
local highalch_data = mw.loadJsonData('Module:GEHighAlchs/data.json')
local ptitle = mw.title.getCurrentTitle()
local title = ptitle.fullText
local pgTitle = ptitle.text
local _noted = ' <span class="dropsline-noted">(noted)</span>'
local members_note = ' <sub title="Members only" style="cursor:help; margin-left:3px;">(m)</sub>'
local _priceStrings = {
coins = "%s %s",
standard = "%s %s each",
alch_alt = "%s %s each; this item has a distinct value, even though it cannot be alchemised.",
ge_alch = "%s %s each; this is the high alchemy value " ..
"as this item cannot be traded on the Grand Exchange.",
ge_alch_alt = "%s %s each; this item has a distinct value, " ..
"even though it cannot be traded on the Grand Exchange.",
ge_alt = "%s %s each; this item has a distinct value, even though it cannot " ..
"be traded on the Grand Exchange or be alchemised."
}
local _altval =
'<span class="dropsline-altval" style="margin-left:0.3em;">[[File:AltValue.png|link=|frameless|20px]]</span>'
local valueImages = {
alch_alt = _altval,
ge_alt = _altval,
ge_alch = '<span class="dropsline-gealch" style="margin-left:0.3em;">' ..
'[[File:High Level Alchemy icon.png|link=High Level Alchemy|frameless|20px]]</span>'
}
-- txt = bg, sort, needs_exact; acceptable non-quantity rarity names
local rarities = {
always = { 'table-bg-blue', 1, false },
common = { 'table-bg-green', 16, true },
uncommon = { 'table-bg-yellow', 64, true },
rare = { 'table-bg-orange', 256, true },
['very rare'] = { 'table-bg-red', 1024, true },
conditional = { 'table-bg-pink', 2048, false },
random = { 'table-bg-pink', 4096, true },
varies = { 'table-bg-pink', 4096, false },
once = { 'table-bg-pink', 65536, false },
_default = { 'table-bg-grey', 65536, true }
}
-- Treasure Hunter gem icons
local th_gem_icons = {
white = '[[File:THGem-common.png|link=|frameless|20px|Common]]',
yellow = '[[File:THGem-fairly-common.png|link=|frameless|20px|Fairly common]]',
orange = '[[File:THGem-uncommon.png|link=|frameless|20px|Uncommon]]',
red = '[[File:THGem-rare.png|link=|frameless|20px|Rare]]',
purple = '[[File:THGem-very-rare.png|link=|frameless|20px|Very rare]]',
shadow = '[[File:THGem-ultra-rare.png|link=|frameless|20px|Shadow]]',
['ultra-rare'] = '[[File:THGem-ultra-rare2.png|link=|frameless|20px|Ultra-Rare]]',
no = 'N/A',
}
-- Treasure Hunter gem rarities
local th_gem_rarities = {
white = 1,
yellow = 1 / 2,
orange = 1 / 3,
red = 1 / 4,
purple = 1 / 5,
shadow = 1 / 6,
['ultra-rare'] = 1 / 7,
no = 0,
}
-- Squeal of Fortune slot icons
local sof_slot_icons = {
common = '[[File:SoF_slot_common.png|link=|frameless|x31px|Common]]',
uncommon = '[[File:SoF_slot_uncommon.png|link=|frameless|x31px|Uncommon]]',
rare = '[[File:SoF_slot_rare.png|link=|frameless|x31px|Rare]]',
['super rare'] = '[[File:SoF_slot_super_rare.png|link=|frameless|x31px|Super rare]]',
no = 'N/A',
}
-- Squeal of Fortune slot rarities
local sof_slot_rarities = {
common = 1,
uncommon = 1 / 2,
rare = 1 / 3,
['super rare'] = 1 / 4,
no = 0,
}
-- colour-code (arbitrary numbers)
local function get_rarity_class(val)
return val >= 1 and 'table-bg-blue'
or val >= 1 / 16 and 'table-bg-green'
or val >= 1 / 64 and 'table-bg-yellow'
or val >= 1 / 256 and 'table-bg-orange'
or 'table-bg-red'
end
local function commas(n)
if tonumber(n) and n ~= 1 / 0 then
return lang:formatNum(tonumber(n))
end
return n
end
local function sigfigalt(n)
if n >= 100 then
return math.floor(n + 0.5)
end
return round.sigfig(n, 3)
end
local function qty_parse(quantity)
-- normalize dashes before splitting
local normalized = mw.ustring.gsub(quantity, '[-—]', '–')
local vals = mw.text.split(normalized, '[,;]')
local values = {}
for _, v in ipairs(vals) do
local noted = v:lower():find('%(noted%)') ~= nil
local clean = v:gsub('%s', ''):gsub('%([Nn]oted%)', '')
local parts = mw.text.split(clean, '–')
local a, b = tonumber(parts[1]), tonumber(parts[2])
if not a then
error('Non-numeric quantity found: "' .. tostring(quantity) .. '"')
end
if b and a > b then a, b = b, a end
table.insert(values, { min = a, max = b, noted = noted })
end
return { values = values }
end
-- Returns min and max of the dataset (nil, nil for special cases)
local function qty_range(parsed)
if parsed.special then return nil, nil end
local low, high = math.huge, 0
for _, v in ipairs(parsed.values) do
low = math.min(low, v.min)
high = math.max(high, v.max or v.min)
end
return low, high
end
-- quantity -> html quantity
local function qty_format_html(parsed)
if parsed.special then return parsed.special end
local parts = {}
for _, v in ipairs(parsed.values) do
local s = v.max and (commas(v.min) .. '–' .. commas(v.max)) or commas(v.min)
if v.noted then s = s .. _noted end
table.insert(parts, s)
end
-- Add line break if too many elements
if #parts > 11 then
local mid = math.floor(#parts / 2)
parts[mid] = '<br/>' .. parts[mid]
end
return table.concat(parts, '; ')
end
-- quantity -> bucket quantity (basically just no commas and a nice (noted) string)
local function qty_bucket(parsed)
if parsed.special then return parsed.special end
local parts = {}
for _, v in ipairs(parsed.values) do
local s = v.max and (v.min .. '–' .. v.max) or tostring(v.min)
if v.noted then s = s .. ' (noted)' end
table.insert(parts, s)
end
return table.concat(parts, ', ')
end
-- turns out value could only ever possibly be a single number
local function get_total(value, qhigh, qlow)
if not value or value < 0 then return false end
if not qhigh or not qlow then
return commas(value), value
end
local lower, higher = qlow * value, qhigh * value
if higher == lower then
return commas(higher), higher
end
return commas(lower) .. '–' .. commas(higher), higher
end
-- parse output from {{DropNote}} into
local function parse_dropnotes(notes)
local note_list = {}
local notes_new = ''
local has_ref = notes:match('UNIQ%-%-ref') ~= nil
if not string.match(notes, '<separator2>') then
return note_list, notes, has_ref
end
-- We're creating refs on the drop source 'programmatically'
local note_list_raw = mw.text.split(notes, '<separator2>')
for _, note_raw in ipairs(note_list_raw) do
if note_raw ~= '' then
local note_table = {}
local note_keyvals = mw.text.split(note_raw, '<separator1>')
for _, keyval in ipairs(note_keyvals) do
local eq_pos = mw.ustring.find(keyval, '=')
local param_name = mw.ustring.sub(keyval, 1, eq_pos - 1)
local param_val = mw.ustring.sub(keyval, eq_pos + 1)
note_table[param_name] = param_val:gsub('<(/?)mathnote>', '<%1math>')
end
if params.has_content(note_table.name) then
local varname = 'dropnote_' .. note_table.name
if var.varexists(varname) then
note_table.content = var.var(varname)
else
var.vardefine(varname, note_table.content)
end
end
table.insert(note_list, note_table)
notes_new = notes_new .. mw.getCurrentFrame():extensionTag {
name = 'ref',
content = note_table.content,
args = { group = 'd', name = note_table.name }
}
end
end
return note_list, notes_new, has_ref
end
local function get_currency_image(altcur, total)
local total_string = tostring(total)
local img = curr_image(altcur, total_string) or 'AltValue.png'
return '<span class="dropsline-altval" style="margin-left:0.3em;">' ..
'[[File:' .. img .. '|link=|frameless|20px]]</span>'
end
local function get_currency_name(altcur, price)
local lowcur = string.lower(altcur)
local subbed = tostring(price):gsub('%W', '')
local price_num = tonumber(subbed) or 0
local is_plural = lang:plural(price_num, 'f', 't') == 't'
if is_plural or lowcur == 'zemomark' or lowcur == 'tokkul' or lowcur == 'teci' then
return altcur
elseif lowcur == 'pieces of eight' then
return 'piece of eight'
else -- drop the last letter
return altcur:sub(1, -2)
end
end
-- Build GE and alch cell data based on item type and value info
local function get_price_cell_data(ctx)
local NA_DATA = { content = 'N/A', title = 'This does not exist.', is_na = true, sort = nil }
-- Nothing has no value
if ctx.is_nothing then
return NA_DATA, NA_DATA
end
-- Compute totals from value_info
local ge_info = ctx.value_info.ge
local total, vsort
if ge_info then
total, vsort = get_total(ge_info.value, ctx.qty_high, ctx.qty_low)
end
local alch_info = ctx.value_info.alch
local alchtotal, vasort
if alch_info then
alchtotal, vasort = get_total(alch_info.value, ctx.qty_high, ctx.qty_low)
end
-- Coins are 1:1
if ctx.is_coins then
local coins_title = mw.ustring.format('%s coin%s', total, lang:plural(vsort, '', 's'))
local coins_data = { content = total, title = coins_title, sort = vsort }
return coins_data, coins_data
end
-- Normal items: build from value_info
local ge_data = { content = nil, title = nil, is_na = false, sort = vsort }
local alch_data = { content = nil, title = nil, is_na = false, sort = vasort }
-- Alch price (processed first so it's available as GE fallback)
local alch_currency_name
if alch_info then
alch_currency_name = lang:plural(alch_info.value, 'coin', 'coins')
local currency_img
if alch_info.currency then
currency_img = get_currency_image(alch_info.currency, vasort)
alch_currency_name = get_currency_name(alch_info.currency, alch_info.value)
end
alch_data.title = mw.ustring.format(_priceStrings[alch_info.type], commas(alch_info.value), alch_currency_name)
alch_data.content = alchtotal .. (currency_img or valueImages[alch_info.type] or '')
end
-- GE price (with alch fallback)
if ge_info then
local currency_name = lang:plural(ge_info.value, 'coin', 'coins')
local currency_img
if ge_info.currency then
currency_img = get_currency_image(ge_info.currency, vsort)
currency_name = get_currency_name(ge_info.currency, ge_info.value)
end
ge_data.title = mw.ustring.format(_priceStrings[ge_info.type], commas(ge_info.value), currency_name)
ge_data.content = total .. (currency_img or valueImages[ge_info.type] or '')
elseif alch_info then
ge_data.title = mw.ustring.format(_priceStrings.ge_alch, commas(alch_info.value), alch_currency_name)
ge_data.content = alchtotal .. valueImages.ge_alch
ge_data.sort = vasort -- Use alch sort when falling back
end
-- no GE
if ge_data.content == nil then
ge_data = {
content = 'Not sold',
title =
'This item cannot be traded on the Grand Exchange nor alchemised and has no applicable value to display.',
is_na = true,
sort = nil
}
end
-- no alch
if alch_data.content == nil then
alch_data = {
content = 'N/A',
title = 'This item cannot be alchemised and has no applicable value to display.',
is_na = true,
sort = nil
}
end
return ge_data, alch_data
end
-- category mappings
local name_categories = {
{ 'effigy', '[[Category:Ancient effigy drop sources]]' },
{ 'clue scroll ', '[[Category:Clue scroll drop sources]]' },
{ 'rare drop table', '[[Category:Rare drop table sources]]' },
{ 'wilderness shared loot table', '[[Category:Wilderness shared loot table sources]]' },
}
-- adding categories to mainspace
local function categories(name, qty_parsed, rarity, drop_version_found)
local ret = ''
name = name:lower()
for _, entry in ipairs(name_categories) do
if name:find(entry[1]) then
ret = ret .. entry[2]
end
end
if rarity == 'Unknown' then
ret = ret .. '[[Category:Needs drop rarity added]]'
end
if qty_parsed.special == 'Unknown' then
ret = ret .. '[[Category:Needs drop quantity added]]'
end
if drop_version_found == false then
ret = ret .. '[[Category:Uses unrecognised drop version]]'
end
return ret
end
-- Add data attributes to a rarity span, return title text if numeric
local function add_rarity_attrs(span, info, prefix)
if type(info.value) ~= 'number' then return nil end
prefix = prefix or ''
span:attr({
['data-drop-fraction'] = prefix .. info.text,
['data-drop-oneover'] = prefix .. info.oneover,
['data-drop-percent'] = prefix .. info.percent,
['data-drop-permil'] = prefix .. info.permil,
['data-drop-permyriad'] = prefix .. info.permyriad,
})
return prefix .. info.title_percent
end
local function parse_rarity(rarity_arg)
-- string rarities (always, common, rare, etc.)
local rarity_lower = rarity_arg:lower()
if rarities[rarity_lower] then
local class, sort, needs_exact_tf = unpack(rarities[rarity_lower])
return {
text = params.ucflc(rarity_arg),
value = nil,
class = class,
sort = sort,
needs_exact = needs_exact_tf and rarity_lower or nil
}
end
-- Try parsing as fraction (e.g., "1/128" or "1,000/10,000")
local stripped = rarity_arg:gsub(',', '')
local rv1, rv2 = stripped:match('([%d%.]+)/([%d%.]+)')
if rv1 and rv2 then
local value = rv1 / rv2
return {
text = commas(rv1) .. '/' .. commas(rv2),
value = value,
class = get_rarity_class(value),
sort = 1 / value,
needs_exact = nil,
oneover = '1/' .. commas(sigfigalt(1 / value)),
percent = round.sigfig(100 * value, 3),
permil = round.sigfig(1000 * value, 3),
permyriad = round.sigfig(10000 * value, 3),
title_percent = string.format('%.3g%%', 100 * value),
}
end
-- Fallback: try evaluating as math expression
local ok, val = pcall(mw.ext.ParserFunctions.expr, rarity_arg)
if ok and tonumber(val) then
local value = tonumber(val)
return {
text = rarity_arg,
value = value,
class = get_rarity_class(value),
sort = 1 / value,
needs_exact = nil,
oneover = '1/' .. commas(sigfigalt(1 / value)),
percent = round.sigfig(100 * value, 3),
permil = round.sigfig(1000 * value, 3),
permyriad = round.sigfig(10000 * value, 3),
title_percent = string.format('%.3g%%', 100 * value),
}
end
-- Complete fallback - use default
local class, sort, needs_exact_tf = unpack(rarities._default)
return {
text = rarity_arg,
value = false,
class = class,
sort = sort,
needs_exact = needs_exact_tf and '_default' or nil
}
end
-- Helper: Find alch value from cache, GEMW, or bucket (in priority order)
-- Only call for normal items (not coins, not nothing)
local function get_value_info(bucket_name, gemw, alch, altvalue, altcur)
local value_info = {}
-- Normal items: look up values from caches
local cached_alch = droppeditem_data[bucket_name]
if type(cached_alch) ~= 'number' then
cached_alch = highalch_data[bucket_name]
if type(cached_alch) ~= 'number' or cached_alch < -1 then
cached_alch = nil
end
end
-- Find alch price (priority: cache → gemw → bucket)
if alch then
if cached_alch then
value_info.alch = { value = cached_alch, type = 'standard' }
elseif gemw then
local hasgealch, gealchval = pcall(exchange._highalch, bucket_name)
if hasgealch and gealchval > -1 then
value_info.alch = { value = tonumber(gealchval), type = 'standard' }
end
end
if not value_info.alch then
local bucketData = bucket("infobox_item")
.select("high_alchemy_value")
.where("page_name", bucket_name)
.limit(1)
.run()
if #bucketData > 0 and bucketData[1].high_alchemy_value ~= nil then
value_info.alch = { value = bucketData[1].high_alchemy_value, type = 'standard' }
end
end
alch = value_info.alch ~= nil
end
local geprice_frombulk = geprices_data[bucket_name]
if type(geprice_frombulk) ~= 'number' or geprice_frombulk < 0 then
geprice_frombulk = nil
end
-- Find GE price
if gemw then
if geprice_frombulk then
value_info.ge = { value = geprice_frombulk, type = 'standard' }
end
gemw = value_info.ge ~= nil
end
-- Alt value overrides
if altvalue ~= '' then
local parsed_value = tonumber((altvalue:gsub(',', '')))
if parsed_value then
value_info.ge = {
value = parsed_value,
type = value_info.alch and 'ge_alch_alt' or 'ge_alt',
currency = altcur
}
if not value_info.alch then
value_info.alch = {
value = parsed_value,
type = 'alch_alt',
currency = altcur
}
end
end
end
return value_info, gemw, alch
end
local IMAGE_STRING = '[[File:%s|link=%s|alt=%s: RS3 %s drops %s with rarity %s%s in quantity %s]]'
local NOTHING_STRING = '[[File:Nothing.png|link=Nothing|alt=This does not exist.]]'
function p.main(frame)
local args = frame:getParent().args
local frameArgs = frame.args
local dropType = params.default_to(frameArgs.dtype, 'combat')
-- Name
local hasName = params.has_content(args.name)
local name = hasName and args.name or 'Item'
local altname = params.default_to(args.alt, name)
local bucketName = params.default_to(args.bucketname, name)
local isCoins = name:lower() == 'coins'
local isNothing = name:lower() == 'nothing'
-- Image
local image
if not hasName then
image = ''
elseif isNothing then
image = NOTHING_STRING
else
local imageArg = params.default_to(args.image, name .. '.png')
local imageFile = isCoins and coins_image(args.quantity) or imageArg:gsub('#.+$', '.png')
local rarity_arg = params.default_to(args.rarity, 'Unknown')
local quantity_arg = mw.ustring.lower(params.default_to(args.quantity, 'Unknown'))
local rolls_arg = tonumber(args.rolls)
local rollstext_img = rolls_arg and rolls_arg > 1 and (rolls_arg .. ' × ') or ''
image = imageFile:lower() == 'no' and ''
or mw.ustring.format(IMAGE_STRING, imageFile, name, imageFile, title, name, rollstext_img, rarity_arg,
quantity_arg)
end
-- Name notes
local namenotes = params.default_to(args.namenotes, '')
local namenote_list, namenotes_new = parse_dropnotes(namenotes)
local namenotes_display = params.has_content(namenotes) and namenotes_new or ''
-- Quantity
local quantity = mw.ustring.lower(params.default_to(args.quantity, 'Unknown'))
local qty_parsed = isNothing and { special = 'N/A' }
or quantity == 'varies' and { special = 'Varies' }
or quantity == 'unknown' and { special = 'Unknown' }
or qty_parse(quantity)
local qty_low, qty_high = qty_range(qty_parsed)
-- Quantity notes
local quantitynotes = params.default_to(args.quantitynotes, '')
local quantitynote_list, quantitynotes_new, qty_has_ref = parse_dropnotes(quantitynotes)
local quantity_html = qty_format_html(qty_parsed)
if params.has_content(quantitynotes) then
quantity_html = quantity_html .. quantitynotes_new
end
--Rarity
local rarity = params.default_to(args.rarity, 'Unknown')
local rolls = tonumber(args.rolls)
local rollstext = rolls and rolls > 1 and (rolls .. ' × ') or ''
local approx = yesno(params.default_to(args.approx, ''), false)
local tilde = approx and '~' or ''
local rarity_info = parse_rarity(rarity)
local needs_exact_rarity = rarity_info.needs_exact
if rolls and rarity_info.value ~= false then
rarity_info.sort = rarity_info.sort / rolls
rarity_info.class = get_rarity_class(math.min(1 / rarity_info.sort, 0.99))
end
-- Alt rarities (altrarity, altrarity2, altrarity3, ...)
local alt_rarity_endash = params.default_to(args.altraritydash, '')
local alt_rarities = {}
local i = 1
while true do
local suffix = i ~= 1 and i or ''
local suffixed_alt_rarity = args['altrarity' .. suffix]
if params.is_empty(suffixed_alt_rarity) then break end
local alt_info = parse_rarity(suffixed_alt_rarity)
alt_info.dash = params.has_content(args['altrarity' .. suffix .. 'dash'])
table.insert(alt_rarities, alt_info)
i = i + 1
end
local alt_rarity = alt_rarities[1] and alt_rarities[1].text or '' -- bucket compat
-- Rarity notes
local raritynotes = params.default_to(args.raritynotes, '')
local citations = params.default_to(args.citations, '')
local raritynote_list, raritynotes_new, rarity_has_ref = parse_dropnotes(raritynotes)
raritynotes_new = raritynotes_new .. citations
-- Values (ge, alch, th/sof)
local altvalue = params.default_to(args.altvalue, '')
local altcur = params.default_to(args.altcurrency, '')
local gemw_arg = yesno(args.gemw or 'yes', false)
local alch_arg = yesno(args.alch or 'yes', false)
local value_info, gemw, alch
if isNothing then
value_info, gemw, alch = {}, false, alch_arg
elseif isCoins then
value_info = { alch = { value = 1, type = 'coins' }, ge = { value = 1, type = 'coins' } }
gemw, alch = gemw_arg, alch_arg
else
value_info, gemw, alch = get_value_info(bucketName, gemw_arg, alch_arg, altvalue, altcur)
end
-- Structure - row version and table version
local rowVersion = params.default_to(args.version, '')
local hasRowwideVersion = params.has_content(rowVersion)
local versionKey = hasRowwideVersion and rowVersion
or params.has_content(frameArgs.version) and frameArgs.version
or 'DEFAULT'
-- Auto-generate version reference
local hideautoversionnote = yesno(args.hideautoversionnote, false)
if hasRowwideVersion and not hideautoversionnote then
local cleanref = mw.ustring.gsub(
mw.ustring.gsub(mw.ustring.lower(versionKey), "%s", "-"),
"[^%w%-]", ""
)
local refname = "autod-" .. cleanref
local ref_content = mw.ustring.format('Only dropped by version "%s".', versionKey)
raritynotes_new = raritynotes_new .. mw.getCurrentFrame():extensionTag {
name = 'ref',
content = ref_content,
args = { group = 'd', name = refname }
}
end
local level = tonumber(args.level) or 0
local rdt = yesno(args.rdt, false) or false
local memsover = params.default_to(args.members, '')
local members = yesno(memsover, false)
local use_bucket_str = params.default_to(args.bucket, var.var('_bucket'))
local use_bucket = params.is_empty(use_bucket_str) or yesno(use_bucket_str, true)
-- Th/SoF specfic stuff
local thgem = mw.ustring.lower(params.default_to(args.thgem, ''))
local sofslot = mw.ustring.lower(params.default_to(args.sofslot, ''))
local convert = tonumber(params.default_to(args.convert, ''))
local defaultConvertCurrency = dropType == 'sof' and 'Coins' or 'Oddments'
local convertcurrencyKey = params.default_to(args.convertcurrency, '')
if not params.has_content(convertcurrencyKey) then
convertcurrencyKey = params.default_to(frameArgs.convertcurrency, defaultConvertCurrency)
end
-- rows
local ret = mw.html.create('tr')
:css('text-align', 'center')
-- inventory image
ret:td({
class = 'inventory-image',
attr = { ['data-sort-value'] = name },
wikitext = image
})
-- item name
ret:td({
class = 'item-col',
css = { ['text-align'] = 'left' },
wikitext = string.format('[[%s|%s]]%s%s', name, altname, namenotes_display, members and members_note or '')
})
if level > 0 then
ret:td({
attr = { ['data-sort-value'] = level },
wikitext = level
})
end
-- quantity
ret:td({
attr = { ['data-sort-value'] = qty_high },
wikitext = quantity_html
})
:addClassIf(isNothing, 'table-na')
-- rarity
local prefix = rollstext .. tilde
local rarity_span_text = prefix .. rarity_info.text
local rarity_cell = ret:td({ class = rarity_info.class, attr = { ['data-sort-value'] = rarity_info.sort } })
local rarity_span = rarity_cell:tag('span'):wikitext(rarity_span_text)
local rarity_cell_title = add_rarity_attrs(rarity_span, rarity_info, prefix)
for _, alt in ipairs(alt_rarities) do
local sep = alt.dash and '–' or '; '
rarity_cell:tag('span'):wikitext(sep)
local alt_span = rarity_cell:tag('span'):wikitext(alt.text)
local alt_title = add_rarity_attrs(alt_span, alt)
if alt_title then
rarity_cell_title = (rarity_cell_title or rarity_span_text) .. sep .. alt_title
elseif alt.needs_exact then
needs_exact_rarity = needs_exact_rarity
and (needs_exact_rarity .. ', ' .. alt.needs_exact)
or alt.needs_exact
end
end
rarity_cell
:attrIf(rarity_cell_title, 'title', rarity_cell_title)
:wikitextIf(#raritynotes_new > 3, raritynotes_new)
if dropType == 'th' then
-- Treasure Hunter gem
ret:tag('td')
:addClassIf(thgem == 'no', 'table-na')
:wikitext(th_gem_icons[thgem] or '')
:attr('data-sort-value', th_gem_rarities[thgem] or 2)
elseif dropType == 'sof' then
-- Squeal of Fortune slot
ret:tag('td')
:addClassIf(sofslot == 'no', 'table-na')
:wikitext(sof_slot_icons[sofslot] or '')
:attr('data-sort-value', sof_slot_rarities[sofslot] or 2)
end
-- Determine GE and alch cell data
local ge_data, alch_data = get_price_cell_data({
is_nothing = isNothing,
is_coins = isCoins,
value_info = value_info,
qty_high = qty_high,
qty_low = qty_low
})
-- Render GE and alch cells
local value_cell_css = { ['text-align'] = 'right', cursor = 'help' }
ret:td({
class = 'ge-column',
attr = { ['data-sort-value'] = ge_data.sort, title = ge_data.title },
css = value_cell_css,
wikitext = ge_data.content
})
:addClassIf(ge_data.is_na, 'table-na')
:cssIf(ge_data.is_na, 'text-decoration', 'underline dotted')
ret:td({
class = 'alch-column',
attr = { ['data-sort-value'] = alch_data.sort, title = alch_data.title },
css = value_cell_css,
wikitext = alch_data.content
})
:addClassIf(alch_data.is_na, 'table-na')
:cssIf(alch_data.is_na, 'text-decoration', 'underline dotted')
local convertstr = 'each'
local converttotal, vcsort
-- If there is no quantity range, assume the convert value is the total
if convert and qty_high == qty_low then
converttotal, vcsort = get_total(convert, 1, 1)
convertstr = 'total'
elseif convert then
converttotal, vcsort = get_total(convert, qty_high, qty_low)
end
-- SoF/TH convert value
if dropType == 'sof' or dropType == 'th' then
-- Determine convert cell data
local convert_data = { content = nil, title = nil, is_disabled = false }
if params.has_content(convert) then
if convert ~= 'no' then
local currency_img = get_currency_image(convertcurrencyKey, vcsort)
local currency_name = get_currency_name(convertcurrencyKey, convert)
convert_data.title = mw.ustring.format('%s %s %s', commas(convert), currency_name, convertstr)
convert_data.content = converttotal .. currency_img
else
convert_data.content = 'Cannot be converted'
convert_data.title = 'This item cannot be converted and has no applicable value to display.'
convert_data.is_disabled = true
end
end
-- Render convert cell
ret:td({
class = 'convert-column',
attr = { ['data-sort-value'] = convert or -1 },
css = { ['text-align'] = 'right', cursor = 'help' }
})
:wikitextIf(convert_data.content, convert_data.content)
:attrIf(convert_data.title, 'title', convert_data.title)
:cssIf(convert_data.is_disabled, 'color', '#999')
end
-- Bucket
local drop_version_found = true
if on_main() and use_bucket and not isNothing then
local bucketNameNote = mw.text.killMarkers(namenotes)
local bucketQuantity = qty_bucket(qty_parsed)
local bucketRolls = rolls or 1
-- if versionKey isn't DEFAULT, bucketSubName is versionKey, else empty
local bucketSubName = versionKey ~= 'DEFAULT' and versionKey or ''
-- if bucketSubName isn't empty, dropFrom is pgTitle#bucketSubName, else pgTitle
local dropFrom = pgTitle .. (bucketSubName ~= '' and '#' or '') .. bucketSubName
local droppedItemName = rdt and 'Dropped item from RDT' or 'Dropped item'
local bucket_alt_rarities = {}
for _, alt in ipairs(alt_rarities) do
table.insert(bucket_alt_rarities, { text = alt.text, value = alt.value, dash = alt.dash })
end
local bucket_json = {
[droppedItemName] = bucketName,
['Name Notes'] = bucketNameNote,
['Name NotesP'] = namenote_list,
['Drop Quantity'] = bucketQuantity,
['Quantity High'] = qty_high,
['Quantity Low'] = qty_low,
['Quantity Notes'] = quantitynote_list,
['Rarity'] = rarity_info.text,
['Alt Rarity'] = alt_rarity,
['Alt Rarity Dash'] = alt_rarity_endash,
['Alt Rarities'] = bucket_alt_rarities,
['Rarity Notes'] = raritynote_list,
['Rolls'] = bucketRolls,
['Drop Value'] = value_info.alch and value_info.alch.value or 0,
['Drop GEMW'] = gemw,
['Drop Alch'] = alch,
['Dropped from'] = dropFrom,
['Drop type'] = dropType,
['Approx'] = approx
}
if dropType == 'store' then
local dropLevelVar = string.format("DropLevel_%s_%s", dropType, versionKey)
if not var.varexists(dropLevelVar) then
drop_version_found = false
else
bucket_json['Drop level'] = var.var(dropLevelVar)
bucket_json['Drop currency'] = var.var(string.format("DropStoreCurrency_%s_%s", dropType, versionKey))
end
elseif level > 0 then
bucket_json['Drop level'] = tostring(level)
elseif dropType == 'reward' or dropType == 'search' or dropType == 'th' or dropType == 'sof' then
bucket_json['Drop level'] = 'N/A'
else
local seenLevels = {}
for dropVersion in string.gmatch(versionKey, ' *([^,]+) *') do
local dropLevelVar = string.format("DropLevel_%s_%s", dropType, dropVersion)
if not var.varexists(dropLevelVar) then
if versionKey ~= 'DEFAULT' then
-- Fallback to 'DEFAULT' version
dropLevelVar = string.format("DropLevel_%s_%s", dropType, 'DEFAULT')
end
if not var.varexists(dropLevelVar) then
drop_version_found = false
end
end
local curDropLevelValues = var.var(dropLevelVar)
for curDropLevel in string.gmatch(curDropLevelValues, ' *([^,]+) *') do
seenLevels[curDropLevel] = true
end
end
local orderedLevels = {}
for lvl, _ in pairs(seenLevels) do
local n = tonumber(lvl)
if n ~= nil then
table.insert(orderedLevels, n)
end
end
table.sort(orderedLevels)
bucket_json['Drop level'] = table.concat(orderedLevels, ',')
end
if rarity_has_ref then
bucket_json['RarityNote Ref'] = true
end
if qty_has_ref then
bucket_json['QuantityNote Ref'] = true
end
if dropType == 'archaeology' then
if var.var('dropsline_is_arch_soil') == 'true' then
bucket_json['Is soil screening'] = 'true'
else
bucket_json['Is soil screening'] = 'false'
end
end
local bucket_sub = {
item_name = bucketName,
rare_drop_table = rdt,
drop_json = mw.text.jsonEncode(bucket_json)
}
if needs_exact_rarity then
bucket_sub.needs_exact_rarity = needs_exact_rarity
end
bucket("dropsline").sub(bucketSubName).put(bucket_sub)
end
---------------------------------------------------------------------------
-- RETURN
---------------------------------------------------------------------------
local cats = on_main() and categories(name, qty_parsed, rarity, drop_version_found) or ''
return tostring(ret) .. cats
end
return p