No edit summary |
m (Changed protection level for "Module:DropTable" ([Edit=Allow only autoconfirmed users] (indefinite) [Move=Allow only autoconfirmed users] (indefinite))) |
||
(45 intermediate revisions by 2 users not shown) | |||
Line 2: | Line 2: | ||
function p.main(frame) |
function p.main(frame) |
||
− | + | if frame == mw.getCurrentFrame() then |
|
args = require('Module:ProcessArgs').merge(true) |
args = require('Module:ProcessArgs').merge(true) |
||
else |
else |
||
Line 8: | Line 8: | ||
end |
end |
||
− | -- If the user defined |
+ | -- If the user defined "args.ShowRecipes" we will show Recipe Items in the table, otherwise we wont. |
showRecipes = args.ShowRecipes or nil |
showRecipes = args.ShowRecipes or nil |
||
+ | |||
+ | dlc = getDLCArgs(frame) or '' |
||
-- create the base html holder |
-- create the base html holder |
||
Line 16: | Line 18: | ||
-- display the title of the drop table |
-- display the title of the drop table |
||
html:tag('b'):wikitext(args.Title):tag('br'):done() |
html:tag('b'):wikitext(args.Title):tag('br'):done() |
||
+ | |||
+ | locArgs = args.Location or args.Locations or frame:getParent().args.Location or frame:getParent().args.Locations or '' |
||
+ | if (args.Type == 'LootContainer') then |
||
+ | local locations = '' |
||
+ | local locTbl = split(locArgs, ',') |
||
+ | for i, v in ipairs(locTbl) do |
||
+ | if (i == #locTbl and i > 1) then locations = locations .. ' and ' |
||
+ | elseif locations ~= '' then locations = locations .. ', ' end |
||
+ | locations = locations .. '[[' .. v .. ']]' |
||
⚫ | |||
+ | html:tag('ul') |
||
+ | :tag('li'):wikitext(frame:preprocess('Can be found on containers at ' .. locations)) |
||
+ | end |
||
-- calculate the average number of rolls, if applicable |
-- calculate the average number of rolls, if applicable |
||
Line 85: | Line 100: | ||
local trueMaxQty = maxqty |
local trueMaxQty = maxqty |
||
local trueChance = 100 |
local trueChance = 100 |
||
− | local |
+ | local trueChanceInt = 100 |
if (args.Random ~= nil) then |
if (args.Random ~= nil) then |
||
Line 92: | Line 107: | ||
trueMaxQty = maxqty * args.MaxRolls -- total potential max quantity |
trueMaxQty = maxqty * args.MaxRolls -- total potential max quantity |
||
trueChance = 100 - ((((100 - chance) / 100) ^ avgRolls) * 100) -- the chance of any drop at all, based on average num of rolls |
trueChance = 100 - ((((100 - chance) / 100) ^ avgRolls) * 100) -- the chance of any drop at all, based on average num of rolls |
||
− | + | trueChance = round(trueChance, 2) |
|
+ | trueChanceInt = round(trueChance, 0) -- for displayed value (round to 0 places) |
||
end |
end |
||
Line 99: | Line 115: | ||
local tr = table:tag('tr'):attr({ valign = 'middle' }) |
local tr = table:tag('tr'):attr({ valign = 'middle' }) |
||
⚫ | |||
− | -- check if the item has an image. if not, its assumed to be a recipe item (display the Recipe Scroll) |
||
+ | if (string.find(item, 'Recipe:', 1, true) ~= nil or string.find(item, 'Cooking:', 1, true) ~= nil or string.find(item, 'Alchemy:', 1, true) ~= nil or string.find(item, 'Crafting:', 1, true) ~= nil) then |
||
− | local image = frame:callParserFunction{ name = '#ifexist', args = |
||
⚫ | |||
⚫ | |||
− | + | else |
|
− | string.format('[[File:%s.png|link=%s|20px]]', item, item) |
+ | image = string.format('[[File:%s.png|link=%s|20px]]', item, item) |
+ | end |
||
⚫ | |||
+ | |||
⚫ | |||
− | local qtyText = (minqty == maxqty and minqty) or (minqty .. '-' .. maxqty) |
+ | local qtyText = (minqty == maxqty and minqty) or (minqty .. '-' .. maxqty) |
-- format and display the actual output for the first cell |
-- format and display the actual output for the first cell |
||
Line 114: | Line 130: | ||
-- if random table, display the random cell |
-- if random table, display the random cell |
||
if (args.Random ~= nil) then |
if (args.Random ~= nil) then |
||
− | local color = |
+ | local color = p.getRarity(chance) |
− | local td = tr:tag('td'): |
+ | local td = tr:tag('td'):addClass(color):attr('data-sort-value', tonumber(chance)):tag('span'):attr('title', string.format('Each roll, you have a %s%% chance of receiving %s %s', chance, qtyText, item)) |
td:wikitext(chance .. '%') |
td:wikitext(chance .. '%') |
||
if (avgRolls > 1) then |
if (avgRolls > 1) then |
||
− | td:tag('sup'):tag('small'):tag('span'):attr('title', string.format('Total %s%% chance of receiving at least %s %s, from %s%s rolls', tostring(round(trueChance, 2)), minqty, item, pretext, round(avgRolls, 1))):wikitext(' (' .. |
+ | td:tag('sup'):tag('small'):tag('span'):attr('title', string.format('Total %s%% chance of receiving at least %s %s, from %s%s rolls', tostring(round(trueChance, 2)), minqty, item, pretext, round(avgRolls, 1))):wikitext(' (' .. trueChanceInt .. '%)') |
end |
end |
||
end |
end |
||
end |
end |
||
+ | if not isTemplate(frame) then |
||
− | -- add to cargo 'ItemSources' table |
||
− | frame:callParserFunction{ name = '#cargo_store', args = |
+ | frame:callParserFunction{ name = '#cargo_store', args = |
− | + | { |
|
− | + | '_table = ItemSource', |
|
− | + | itemName = item, |
|
− | + | minQty = minqty, |
|
− | + | maxQty = trueMaxQty, -- listing with total potential max quantity |
|
+ | chance = trueChance, -- listing with average chance of any drop at all |
||
+ | type = args.Type or '', |
||
+ | location = locArgs, |
||
+ | DLC = dlc |
||
+ | } |
||
} |
} |
||
− | + | end |
|
end |
end |
||
Line 138: | Line 159: | ||
if (avgRolls > 1) then |
if (avgRolls > 1) then |
||
− | html:tag('i'):tag('small'):wikitext('* |
+ | html:tag('i'):tag('small'):wikitext('* The second number indicates the total chance of receiving the drop at least once, from ' .. pretext .. tostring(round(avgRolls, 1)) .. ' rolls.'):tag('br') |
end |
end |
||
return html |
return html |
||
+ | end |
||
+ | |||
+ | function getDLCArgs(frame) |
||
+ | if notempty(frame.args.DLC) then |
||
+ | return frame.args.DLC |
||
+ | elseif frame:getParent() ~= nil then |
||
+ | return getDLCArgs(frame:getParent()) |
||
+ | else |
||
+ | return '' |
||
+ | end |
||
+ | end |
||
+ | |||
+ | function notempty(string) |
||
+ | return string ~= nil and string ~= '' |
||
+ | end |
||
+ | |||
+ | function isTemplate(iframe) |
||
+ | local namespace = getRootParent(iframe):preprocess('{{NAMESPACE}}') |
||
+ | return namespace == 'Template' |
||
+ | end |
||
+ | |||
+ | function getRootParent(iframe) |
||
+ | if iframe:getParent() == nil then |
||
+ | return iframe |
||
+ | else |
||
+ | return getRootParent(iframe:getParent()) |
||
+ | end |
||
end |
end |
||
Line 147: | Line 195: | ||
local color = '' |
local color = '' |
||
if chance == 100 then |
if chance == 100 then |
||
− | color = ' |
+ | color = 'rarity-always' -- Guaranteed (blue) |
elseif chance > 24 then |
elseif chance > 24 then |
||
− | color = ' |
+ | color = 'rarity-common' -- Common (green) |
elseif chance > 11 then |
elseif chance > 11 then |
||
− | color = ' |
+ | color = 'rarity-uncommon' -- Uncommon (yellow) |
elseif chance > 4 then |
elseif chance > 4 then |
||
− | color = ' |
+ | color = 'rarity-rare' -- Rare (orange) |
else |
else |
||
− | color = ' |
+ | color = 'rarity-veryrare' -- Very rare (dark red) |
end |
end |
||
return color |
return color |
||
Line 163: | Line 211: | ||
local mult = 10^(numDecimalPlaces or 0) |
local mult = 10^(numDecimalPlaces or 0) |
||
return math.floor(num * mult + 0.5) / mult |
return math.floor(num * mult + 0.5) / mult |
||
+ | end |
||
+ | |||
+ | function split(inputstr, sep) |
||
+ | if sep == nil then |
||
+ | sep = "%s" |
||
+ | end |
||
+ | local t={} |
||
+ | for str in string.gmatch(inputstr, "([^"..sep.."]+)") do |
||
+ | table.insert(t, str) |
||
+ | end |
||
+ | return t |
||
end |
end |
||
Latest revision as of 20:05, 1 July 2021
The above documentation is transcluded from Module:DropTable/doc. (edit | history)
local p = {}
function p.main(frame)
if frame == mw.getCurrentFrame() then
args = require('Module:ProcessArgs').merge(true)
else
frame = mw.getCurrentFrame()
end
-- If the user defined "args.ShowRecipes" we will show Recipe Items in the table, otherwise we wont.
showRecipes = args.ShowRecipes or nil
dlc = getDLCArgs(frame) or ''
-- create the base html holder
local html = mw.html.create()
-- display the title of the drop table
html:tag('b'):wikitext(args.Title):tag('br'):done()
locArgs = args.Location or args.Locations or frame:getParent().args.Location or frame:getParent().args.Locations or ''
if (args.Type == 'LootContainer') then
local locations = ''
local locTbl = split(locArgs, ',')
for i, v in ipairs(locTbl) do
if (i == #locTbl and i > 1) then locations = locations .. ' and '
elseif locations ~= '' then locations = locations .. ', ' end
locations = locations .. '[[' .. v .. ']]'
end
html:tag('ul')
:tag('li'):wikitext(frame:preprocess('Can be found on containers at ' .. locations))
end
-- calculate the average number of rolls, if applicable
avgRolls = 1
if (args.Random ~= nil) then
local rollsText = ''
if (args.MinRolls == args.MaxRolls) then
avgRolls = tonumber(args.MinRolls) -- min rolls and max rolls are same value, so only display one number.
rollsText = args.MinRolls
else
avgRolls = (tonumber(args.MinRolls) + tonumber(args.MaxRolls)) / 2 -- calculate the average num of rolls
rollsText = string.format('%s to %s', args.MinRolls, args.MaxRolls) -- display "x to y" rolls
end
html:wikitext(frame:preprocess(string.format('This drop table will be rolled <b><u>%s</u></b> times.', rollsText)))
end
-- create the actual table
local table = html:tag('table'):addClass('wikitable sortable'):attr({
align = 'center', border = '1', cellspacing = '0', cellpadding = '2'
}):cssText('border-collapse: collapse; border: 1px solid darkgray; empty-cells: show; text-align: center')
-- header row
local headerRow = table:tag('tr')
headerRow:tag('th'):wikitext('Items')
if (args.Random ~= nil) then
table:addClass('randomDropTable')
local suffix = avgRolls > 1 and " *" or ""
headerRow:tag('th'):wikitext('Chance' .. suffix)
else
table:addClass('guaranteedDropTable')
end
-- iterate all unnamed arguments of the frame by using ipairs(args) and storing into a table
-- this allows us to define an unlimited number of drop table entries, without having to worry about how many there are.
local ip = {}
for k, v in ipairs(args) do
ip[k] = v
end
-- little helper to display "an average" on the hover-text when needed
local pretext = ''
if (args.Random ~= nil and args.MinRolls ~= args.MaxRolls) then
pretext = 'an average '
end
-- display the "empty drop" entry
if (args.NoDrop ~= nil and tonumber(args.NoDrop) > 0) then
-- display the chance per roll, and the alt-text for it
local td = table:tag('tr'):tag('td'):wikitext('Empty drop'):tag('td'):attr('data-sort-value', 101):tag('span'):attr('title', 'Empty drop chance per roll'):wikitext(args.NoDrop .. '%')
end
-- iterate over our ipairs(args) table, counting up by 4. this is because each drop table entry takes 4 unnamed arguments
-- 1: Name, 2: minQty, 3: maxQty, 4: Chance
-- note: even guaranteed tables need to have chance defined, otherwise this becomes too messy. just set any value (even nil)
for i = 1, #ip, 4 do
local item = ip[i]
local minqty = ip[i + 1]
local maxqty = ip[i + 2]
-- figure out if we should actually display this (for showrecipes)
local show = true
if (showRecipes == nil and (string.find(item, 'Cooking:', 1, true) ~= nil or string.find(item, 'Crafting:') ~= nil or string.find(item, 'Alchemy:') ~= nil) or string.find(item, 'Recipe:') ~= nil) then
show = false
end
-- calculate the cumulative chance and potential max quantity (based on drop table max rolls and average rolls)
local chance = 100
local trueMaxQty = maxqty
local trueChance = 100
local trueChanceInt = 100
if (args.Random ~= nil) then
chance = tonumber(ip[i + 3]) -- this is a random table, so get the actual chance value
trueMaxQty = maxqty * args.MaxRolls -- total potential max quantity
trueChance = 100 - ((((100 - chance) / 100) ^ avgRolls) * 100) -- the chance of any drop at all, based on average num of rolls
trueChance = round(trueChance, 2)
trueChanceInt = round(trueChance, 0) -- for displayed value (round to 0 places)
end
-- if actually displaying this entry
if (show == true) then
local tr = table:tag('tr'):attr({ valign = 'middle' })
local image = ''
if (string.find(item, 'Recipe:', 1, true) ~= nil or string.find(item, 'Cooking:', 1, true) ~= nil or string.find(item, 'Alchemy:', 1, true) ~= nil or string.find(item, 'Crafting:', 1, true) ~= nil) then
image = string.format('[[File:Recipe Scroll.png|link=%s|20px]]', item)
else
image = string.format('[[File:%s.png|link=%s|20px]]', item, item)
end
local qtyText = (minqty == maxqty and minqty) or (minqty .. '-' .. maxqty)
-- format and display the actual output for the first cell
local output = image .. ' [[' .. item .. ']] (' .. qtyText .. ')'
tr:tag('td'):cssText('padding-left: 0px; padding-top: 0px; padding-bottom: 0px; text-align: left'):wikitext(frame:preprocess(output))
-- if random table, display the random cell
if (args.Random ~= nil) then
local color = p.getRarity(chance)
local td = tr:tag('td'):addClass(color):attr('data-sort-value', tonumber(chance)):tag('span'):attr('title', string.format('Each roll, you have a %s%% chance of receiving %s %s', chance, qtyText, item))
td:wikitext(chance .. '%')
if (avgRolls > 1) then
td:tag('sup'):tag('small'):tag('span'):attr('title', string.format('Total %s%% chance of receiving at least %s %s, from %s%s rolls', tostring(round(trueChance, 2)), minqty, item, pretext, round(avgRolls, 1))):wikitext(' (' .. trueChanceInt .. '%)')
end
end
end
if not isTemplate(frame) then
frame:callParserFunction{ name = '#cargo_store', args =
{
'_table = ItemSource',
itemName = item,
minQty = minqty,
maxQty = trueMaxQty, -- listing with total potential max quantity
chance = trueChance, -- listing with average chance of any drop at all
type = args.Type or '',
location = locArgs,
DLC = dlc
}
}
end
end
table:done()
if (avgRolls > 1) then
html:tag('i'):tag('small'):wikitext('* The second number indicates the total chance of receiving the drop at least once, from ' .. pretext .. tostring(round(avgRolls, 1)) .. ' rolls.'):tag('br')
end
return html
end
function getDLCArgs(frame)
if notempty(frame.args.DLC) then
return frame.args.DLC
elseif frame:getParent() ~= nil then
return getDLCArgs(frame:getParent())
else
return ''
end
end
function notempty(string)
return string ~= nil and string ~= ''
end
function isTemplate(iframe)
local namespace = getRootParent(iframe):preprocess('{{NAMESPACE}}')
return namespace == 'Template'
end
function getRootParent(iframe)
if iframe:getParent() == nil then
return iframe
else
return getRootParent(iframe:getParent())
end
end
function p.getRarity(chance)
local color = ''
if chance == 100 then
color = 'rarity-always' -- Guaranteed (blue)
elseif chance > 24 then
color = 'rarity-common' -- Common (green)
elseif chance > 11 then
color = 'rarity-uncommon' -- Uncommon (yellow)
elseif chance > 4 then
color = 'rarity-rare' -- Rare (orange)
else
color = 'rarity-veryrare' -- Very rare (dark red)
end
return color
end
function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
function split(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
return p