Module:SpellTiers
Jump to navigation
Jump to search
local p = {}
local framesPerSecond = 60
local function trim(str)
return str:gsub("^%s*(.-)%s*$", "%1")
end
local function is_empty(str)
return str == nil or str.len(trim(str)) == 0
end
local function append_table(tbl, data)
tbl[#tbl + 1] = data
end
function formatNumeric(number)
return ("%.5g"):format(tonumber(number))
end
function split(str, delimiter)
local chunks = {}
for c in (str..delimiter):gmatch("(.-)"..delimiter) do
table.insert(chunks, c)
end
return chunks
end
function subrange(t, first, last)
local sub = {}
for i = first, last do
sub[#sub + 1] = t[i]
end
return sub
end
-- Values as of 22-01-2024
-- TODO - It would be ideal to generate & update this automatically
local sumOfSpellSpawnWeightsByTier = {
-- same as 8th April release (will we get more beta...?)
-- ['beta'] = { 44.55, 84.05001, 137.71, 129.96, 142.89, 125.21, 82.06, 0.6, 0, 0, 59.8 },
-- current figures from 8th April release
-- ['release'] = { 44.55, 84.05001, 137.71, 129.96, 142.89, 125.21, 82.06, 0.6, 0, 0, 59.8 },
-- these are the figures for the pre 8th April release version
-- ['old'] = { 47.1, 86.65, 139.18, 130.2, 145.1, 127.35,88.3, 0.6, 0, 0, 51.7 }
['beta'] = {
[0] = 44.55, [1] = 84.05, [2] = 137.71, [3] = 129.96,
[4] = 142.89, [5] = 125.21, [6] = 82.06, [7] = 0.6,
[8] = 0, [9] = 0, [10] = 59.8 },
['release'] = {
[0] = 44.55, [1] = 84.05, [2] = 137.71, [3] = 129.96,
[4] = 142.89, [5] = 125.21, [6] = 82.06, [7] = 0.6,
[8] = 0, [9] = 0, [10] = 59.8 },
['old'] = {
[0] = 47.1, [1] = 86.65, [2] = 139.18, [3] = 130.2,
[4] = 145.1, [5] = 127.35, [6] = 88.3, [7] = 0.6,
[8] = 0, [9] = 0, [10] = 51.7 }
}
-- Converts spell tier + spawn weight into probability per tier
-- Uses 'tiers' and 'weights' from passed or parent frame context
-- tiers: tiers the spell spawns in (valid: 0-10, used: 0-7,10)
-- weights: matching list of spawn chance weightings
-- (both are strings of comma-seperated numbers) (whitespace ignored)
-- e.g. tiers: 0,1, 2, 5,6
-- weights: 1,1,0.3,0.2,1
--
-- mw.logObject(p.getSpellSpawnInfo('0,1,2,3,4,5,6,7,10', '1,1,1,1,1,1,1,1,1', 'release'))
function getSpellSpawnInfo(tiers, weights, version)
local spellTiers = split(tiers or '', ',')
local spellWeights = split(weights or '', ',')
local version = trim(version) or 'release'
local weightSums = sumOfSpellSpawnWeightsByTier[version]
local spellTierProbabilities = {}
for i = 0, 10 do
spellTierProbabilities[i + 1] = {
['tier'] = string.format('%d', i),
['weight'] = -1,
['probability'] = 0,
['relative'] = 0,
['percentage'] = '0',
['version'] = '',
}
end
local bestProbability = 0
for spellTiersIdx, tier in ipairs(spellTiers) do
local tierIdx = tonumber(tier, 10)
local weight = tonumber(spellWeights[spellTiersIdx] or 0, 10)
local weightSum = weightSums[tierIdx] or 0
if (weight > 0 and weightSum > 0) then
local probability = weight / weightSum
spellTierProbabilities[tierIdx + 1]['weight'] = weight
spellTierProbabilities[tierIdx + 1]['probability'] = probability
spellTierProbabilities[tierIdx + 1]['percentage'] = string.format('%1.2f', probability * 100)
spellTierProbabilities[tierIdx + 1]['version'] = version
bestProbability = math.max(probability, bestProbability)
end
end
for spellTiersIdx, tier in ipairs(spellTiers) do
local tierIdx = tonumber(tier, 10)
spellTierProbabilities[tierIdx + 1]['relative'] = 1 / bestProbability * spellTierProbabilities[tierIdx + 1]['probability']
end
return spellTierProbabilities
end
function binRarity(prob)
local p = prob * 100
if p <= 0 then
return 'nospawn', 'Impossible'
elseif p < 0.01 then
return 'vrare', 'Very Rare'
elseif p < 0.1 then
return 'rare', 'Rare'
elseif p < 1 then
return 'uncommon', 'Uncommon'
elseif p < 3 then
return 'common', 'Common'
end
return 'vcommon', 'Very Common'
end
function binOdds(prob)
local mc = require('Module:Common')
local res = ''
if ( prob ~= nil ) then
local frac = mc.formatNum(1/prob)
if (frac ~= nil) then
local tmp = '{{fraction|1|'..frac..'}}'
local percent = (string.sub(mc.string.parseFloat(prob * 100), 0, 5) or 'null')..'%'
res = mw.getCurrentFrame():preprocess('{{abbr|'..tmp..'|'..percent..'}}')
end
end
return res
end
-- /* FYI - strings in this function contain U+200A 'hair space' characters */
function binPercent(prob)
local p = prob * 100
if p <= 0 then
return '0'
elseif p < 0.01 then
return '0.01'
elseif p < 0.1 then
return '0.1'
elseif p < 1 then
return '1'
end
return string.format('%1.0f', p)
end
function p.formatSpellSpawnInfo(frame)
local args = frame.args
local pArgs = frame:getParent().args
local tiers = pArgs['tiers'] or args['tiers'] or ''
local weights = pArgs['weights'] or args['weights'] or ''
local version = pArgs['version'] or args['version'] or ''
local spawnInfo = getSpellSpawnInfo(tiers, weights, version)
-- Build output HTML
local root = mw.html.create('div')
:attr('class', 'spellTierInfo')
:attr('data-version', version)
for i = 0, 10 do
local info = spawnInfo[i + 1]
local rarity, rarityDisplay = binRarity(info['probability'])
local tierTag = root:tag('div'):attr('class', 'spellTierInfo-tier')
:attr('data-tier-id', info['tier'])
:attr('data-tier-percentage', info['percentage'])
:attr('data-tier-percentage-binned', binPercent(info['probability']))
:attr('data-tier-rarity', rarity)
:attr('data-tier-weight', info['weight'])
:attr('data-tier-probability', info['probability'])
:attr('data-tier-relative', info['relative'])
:attr('data-tier-version', info['version'])
tierTag:tag('span'):attr('class', 'spellTierInfo-tiernum')
:wikitext(string.format('%d', info['tier']))
tierTag:tag('span'):attr('class', 'spellTierInfo-tierbinodds')
:wikitext(binOdds(info['probability']))
tierTag:tag('span'):attr('class', 'spellTierInfo-tierbinpercent')
:wikitext(binPercent(info['probability']))
tierTag:tag('span'):attr('class', 'spellTierInfo-tierpercent')
:wikitext(info['percentage'])
end
root:allDone()
return tostring(root)
end
return p