17,030
edits
Tag: Undo |
(getMasteryTokenTable: Correct values for change in game logic & extend to display both base game and TotH values) |
||
Line 22: | Line 22: | ||
local Items = require('Module:Items') | local Items = require('Module:Items') | ||
local Icons = require('Module:Icons') | local Icons = require('Module:Icons') | ||
-- Given a skill ID, returns the key for that skill's recipe data. | |||
-- If the skill has no recipes (e.g. is a combat skill) then the | |||
-- return value is nil | |||
function p.getSkillRecipeKey(skillID) | |||
-- Convert skillID to local ID if not already | |||
local ns, localSkillID = GameData.getLocalID(skillID) | |||
local recipeIDs = { | |||
["Woodcutting"] = 'trees', | |||
["Fishing"] = 'fish', | |||
["Firemaking"] = 'logs', | |||
["Mining"] = 'rockData', | |||
["Thieving"] = 'npcs', | |||
["Agility"] = 'obstacles', | |||
["Cooking"] = 'recipes', | |||
["Smithing"] = 'recipes', | |||
["Farming"] = 'recipes', | |||
["Summoning"] = 'recipes', | |||
["Fletching"] = 'recipes', | |||
["Crafting"] = 'recipes', | |||
["Runecrafting"] = 'recipes', | |||
["Herblore"] = 'recipes', | |||
["Astrology"] = 'recipes' | |||
} | |||
return recipeIDs[localSkillID] | |||
end | |||
-- Given a skill ID & recipe, returns the skill level requirement for | |||
-- that recipe. If the level could not be determined, then the return | |||
-- value is nil | |||
function p.getRecipeLevel(skillID, recipe) | |||
-- Convert skillID to local ID if not already | |||
local ns, localSkillID = GameData.getLocalID(skillID) | |||
if localSkillID == 'Agility' then | |||
-- For Agility, level is derived from obstacle category | |||
if recipe.category ~= nil then | |||
-- Obstacle | |||
if recipe.category == 0 then | |||
return 1 | |||
else | |||
return SkillData.Agility.obstacleUnlockLevels[recipe.category] | |||
end | |||
else | |||
-- Pillar | |||
local nsR, localRecipeID = GameData.getLocalID(recipe.id) | |||
if localRecipeID ~= nil then | |||
if string.find(localRecipeID, '^Pillar') ~= nil then | |||
return 99 | |||
elseif string.find(localRecipeID, '^ElitePillar') ~= nil then | |||
return 120 | |||
end | |||
end | |||
end | |||
else | |||
-- For all other skills, the recipe should have a level property | |||
return recipe.level | |||
end | |||
end | |||
-- Thieving | -- Thieving | ||
Line 283: | Line 341: | ||
function p.getMasteryTokenTable() | function p.getMasteryTokenTable() | ||
-- Defines which skill levels should be included within the output | |||
local skillLevels = { | |||
{ | |||
["id"] = 'Base', | |||
["level"] = 99, | |||
["description"] = '[[Full Version|Base Game]] (Level 99)' | |||
}, { | |||
["id"] = 'TotH', | |||
["level"] = 120, | |||
["description"] = Icons.TotH() .. ' [[Throne of the Herald Expansion|Throne of the Herald]] (Level 120)' | |||
} | |||
} | |||
local baseTokenChance = 18500 | local baseTokenChance = 18500 | ||
local | local masteryActionCount = {} | ||
local CCI = Items.getItemByID( | local CCI_ID = 'melvorD:Clue_Chasers_Insignia' | ||
if CCI == nil then return '' end | local CCI = Items.getItemByID(CCI_ID) | ||
if CCI == nil then | |||
return Shared.printError('Failed to find item with ID ' .. CCI_ID) | |||
end | |||
-- | -- Iterate over each skill with mastery, determining the number of | ||
-- mastery actions for each | |||
for skillLocalID, skill in pairs(SkillData) do | for skillLocalID, skill in pairs(SkillData) do | ||
if skill.masteryTokenID ~= nil then | if skill.masteryTokenID ~= nil then | ||
table.insert( | local actCount = { ["skill"] = skill } | ||
for i, levelDef in ipairs(skillLevels) do | |||
actCount[levelDef.id] = 0 | |||
end | |||
local recipeKey = p.getSkillRecipeKey(skillLocalID) | |||
if recipeKey ~= nil then | |||
local recipeData = skill[recipeKey] | |||
for i, recipe in ipairs(recipeData) do | |||
if recipe.noMastery == nil or not recipe.noMastery then | |||
local skillLevel = p.getRecipeLevel(skillLocalID, recipe) | |||
if skillLevel ~= nil then | |||
for j, levelDef in ipairs(skillLevels) do | |||
if skillLevel <= levelDef.level then | |||
actCount[levelDef.id] = actCount[levelDef.id] + 1 | |||
end | |||
end | |||
end | |||
end | |||
end | |||
end | |||
table.insert(masteryActionCount, actCount) | |||
end | end | ||
end | end | ||
table.sort( | |||
local firstID = skillLevels[1].id | |||
table.sort(masteryActionCount, | |||
function(a, b) | function(a, b) | ||
if a | if a[firstID] == b[firstID] then | ||
return a.name < b.name | return a.skill.name < b.skill.name | ||
else | else | ||
return a | return a[firstID] > b[firstID] | ||
end | end | ||
end) | end) | ||
-- Generate output table | -- Generate output table | ||
local resultPart = {} | local resultPart = {} | ||
local CCIIcon = Icons.Icon({CCI.name, type='item', notext=true}) | local CCIIcon = Icons.Icon({CCI.name, type='item', notext=true}) | ||
local columnPairs = Shared.tableCount(skillLevels) | |||
-- Generate header | |||
table.insert(resultPart, '{| class="wikitable sortable"') | table.insert(resultPart, '{| class="wikitable sortable"') | ||
table.insert(resultPart, ' | table.insert(resultPart, '\n!rowspan="3"|Token!!rowspan="3"|Skill!!colspan="' .. columnPairs * 2 .. '"|Approximate Mastery Token Chance') | ||
table.insert(resultPart, '\ | table.insert(resultPart, '\n|-') | ||
for i, levelDef in ipairs(skillLevels) do | |||
table.insert(resultPart, '\n!colspan="2"| ' .. levelDef.description) | |||
end | |||
table.insert(resultPart, '\n|-' .. string.rep('\n!Without ' .. CCIIcon .. '\n!With ' .. CCIIcon, columnPairs)) | |||
for i, | for i, rowData in ipairs(masteryActionCount) do | ||
local token = Items.getItemByID(skill.masteryTokenID) | local token = Items.getItemByID(rowData.skill.masteryTokenID) | ||
table.insert(resultPart, '\n|-') | |||
table.insert(resultPart, '\n|style="text-align:center"|' .. Icons.Icon({token.name, type='item', size=50, notext=true})) | |||
table.insert(resultPart, '\n|' .. Icons.Icon({rowData.skill.name, type='skill'})) | |||
for j, levelDef in ipairs(skillLevels) do | |||
local actCount = rowData[levelDef.id] | |||
local denom, denomCCI = 0, 0 | |||
if actCount > 0 then | |||
denom = math.floor(baseTokenChance / actCount) | |||
denomCCI = Shared.round(baseTokenChance / (actCount * (1 + CCI.modifiers.increasedOffItemChance / 100)), 0, 0) | |||
end | |||
table.insert(resultPart, '\n|style="text-align:right" data-sort-value="' .. denom .. '"|1/' .. Shared.formatnum(denom)) | |||
table.insert(resultPart, '\n|style="text-align:right" data-sort-value="' .. denomCCI .. '"|1/' .. Shared.formatnum(denomCCI)) | |||
end | |||
end | end | ||
table.insert(resultPart, ' | table.insert(resultPart, '\n|}') | ||
return table.concat(resultPart) | return table.concat(resultPart) |