Difference between revisions of "Module:Skills"
From Melvor Idle
Falterfire (talk | contribs) (Removed redundant references to getSkillID since that's now a Constants function) |
Falterfire (talk | contribs) (Fixed indenting) |
||
Line 24: | Line 24: | ||
function p.getMasteryUnlockTable(frame) | function p.getMasteryUnlockTable(frame) | ||
− | + | local skillName = frame.args ~= nil and frame.args[1] or frame | |
− | + | local skillID = Constants.getSkillID(skillName) | |
− | + | if skillID == nil then | |
− | + | return "ERROR: Failed to find a skill ID for "..skillName | |
− | + | end | |
− | + | local unlockTable = SkillData.MasteryUnlocks[skillID] | |
− | + | if unlockTable == nil then | |
− | + | return 'ERROR: Failed to find Mastery Unlock data for '..skillName | |
− | + | end | |
− | + | local result = '{|class="wikitable"\r\n!Level!!Unlock' | |
− | + | for i, unlock in Shared.skpairs(unlockTable) do | |
− | + | result = result..'\r\n|-' | |
− | + | result = result..'\r\n|'..unlock.level..'||'..unlock.unlock | |
− | + | end | |
− | + | result = result..'\r\n|}' | |
− | + | return result | |
end | end | ||
function p.getMasteryCheckpointTable(frame) | function p.getMasteryCheckpointTable(frame) | ||
− | + | local skillName = frame.args ~= nil and frame.args[1] or frame | |
− | + | local skillID = Constants.getSkillID(skillName) | |
− | + | if skillID == nil then | |
− | + | return "ERROR: Failed to find a skill ID for "..skillName | |
− | + | end | |
− | + | if SkillData.MasteryCheckpoints[skillID] == nil then | |
− | + | return 'ERROR: Failed to find Mastery Unlock data for '..skillName | |
− | + | end | |
− | + | local bonuses = SkillData.MasteryCheckpoints[skillID].bonuses | |
− | + | local totalPoolXP = SkillData.MasteryPoolXP[skillID + 1] | |
− | + | local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus' | |
− | + | for i, bonus in Shared.skpairs(bonuses) do | |
− | + | result = result..'\r\n|-' | |
− | + | result = result..'\r\n|'..(MasteryCheckpoints[i] * 100)..'%||' | |
− | + | result = result..Shared.formatnum(totalPoolXP * MasteryCheckpoints[i])..' xp||'..bonus | |
− | + | end | |
− | + | result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP' | |
− | + | result = result..'\r\n|'..Shared.formatnum(totalPoolXP) | |
− | + | result = result..'\r\n|}' | |
− | + | return result | |
end | end | ||
function p._getFarmingTable(category) | function p._getFarmingTable(category) | ||
− | + | local seedList = {} | |
− | + | if category == 'Allotment' or category == 'Herb' or category == 'Tree' then | |
− | + | seedList = Items.getItems(function(item) return item.tier == category end) | |
− | + | else | |
− | + | return 'ERROR: Invalid farming category. Please choose Allotment, Herb, or Tree' | |
− | + | end | |
− | + | local result = '{|class="wikitable sortable stickyHeader"' | |
− | + | result = result..'\r\n|- class="headerRow-0"' | |
− | + | result = result..'\r\n!colspan=2|Seeds!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level' | |
− | + | result = result..'!!XP!!Growth Time!!Seed Value' | |
− | + | if category == 'Allotment' then | |
− | + | result = result..'!!colspan="2"|Crop!!Crop Healing!!Crop Value' | |
− | + | elseif category == 'Herb' then | |
− | + | result = result..'!!colspan="2"|Herb!!Herb Value' | |
− | + | elseif category == 'Tree' then | |
− | + | result = result..'!!colspan="2"|Logs!!Log Value' | |
− | + | end | |
− | + | result = result..'!!Seed Sources' | |
− | + | ||
− | + | table.sort(seedList, function(a, b) return a.farmingLevel < b.farmingLevel end) | |
− | + | for i, seed in pairs(seedList) do | |
− | + | result = result..'\r\n|-' | |
− | + | result = result..'\r\n|'..Icons.Icon({seed.name, type='item', size='50', notext=true})..'||[['..seed.name..']]' | |
− | + | result = result..'||'..seed.farmingLevel..'||'..Shared.formatnum(seed.farmingXP) | |
− | + | result = result..'||data-sort-value="'..seed.timeToGrow..'"|'..Shared.timeString(seed.timeToGrow, true) | |
− | + | result = result..'||data-sort-value="'..seed.sellsFor..'"|'..Icons.GP(seed.sellsFor) | |
− | + | local crop = Items.getItemByID(seed.grownItemID) | |
− | + | result = result..'||'..Icons.Icon({crop.name, type='item', size='50', notext=true})..'||[['..crop.name..']]' | |
− | + | if category == 'Allotment' then | |
− | + | result = result..'||'..Icons.Icon({'Hitpoints', type='skill', notext=true})..' '..(crop.healsFor * 10) | |
− | + | end | |
− | + | result = result..'||data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor) | |
− | + | result = result..'||'..ItemSourceTables._getItemSources(seed) | |
− | + | end | |
− | + | result = result..'\r\n|}' | |
− | + | return result | |
end | end | ||
function p.getFarmingTable(frame) | function p.getFarmingTable(frame) | ||
− | + | local category = frame.args ~= nil and frame.args[1] or frame | |
− | + | return p._getFarmingTable(category) | |
end | end | ||
function p.getFarmingFoodTable(frame) | function p.getFarmingFoodTable(frame) | ||
− | + | local result = '{| class="wikitable sortable stickyHeader"' | |
− | + | result = result..'\r\n|- class="headerRow-0"' | |
− | + | result = result..'\r\n!colspan="2"|Crop!!'..Icons.Icon({"Farming", type="skill", notext=true})..' Level' | |
− | + | result = result..'!!Healing!!Value' | |
− | + | ||
− | + | local itemArray = Items.getItems(function(item) return item.grownItemID ~= nil end) | |
− | + | table.sort(itemArray, function(a, b) return a.farmingLevel < b.farmingLevel end) | |
− | + | for i, item in Shared.skpairs(itemArray) do | |
− | + | local crop = Items.getItemByID(item.grownItemID) | |
− | + | if crop.healsFor ~= nil and crop.healsFor > 0 then | |
− | + | result = result..'\r\n|-' | |
− | + | result = result..'\r\n|'..Icons.Icon({crop.name, type='item', notext='true', size='50'})..'||[['..crop.name..']]' | |
− | + | result = result..'||style="text-align:right;"|'..item.farmingLevel | |
− | + | result = result..'||style="text-align:right" data-sort-value="'..crop.healsFor..'"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..(crop.healsFor * 10) | |
− | + | result = result..'||style="text-align:right" data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor) | |
− | + | end | |
− | + | end | |
− | + | result = result..'\r\n|}' | |
− | + | return result | |
end | end | ||
function p.getFarmingPlotTable(frame) | function p.getFarmingPlotTable(frame) | ||
− | + | local areaName = frame.args ~= nil and frame.args[1] or frame | |
− | + | local patches = nil | |
− | + | for i, area in Shared.skpairs(SkillData.Farming.Patches) do | |
− | + | if area.areaName == areaName then | |
− | + | patches = area.patches | |
− | + | break | |
− | + | end | |
− | + | end | |
− | + | if patches == nil then | |
− | + | return "ERROR: Invalid area name.[[Category:Pages with script errors" | |
− | + | end | |
− | + | local result = '{|class="wikitable"' | |
− | + | result = result..'\r\n!Plot!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level!!Cost' | |
− | + | for i, patch in Shared.skpairs(patches) do | |
− | + | result = result..'\r\n|-\r\n|'..i | |
− | + | result = result..'||style="text-align:right;" data-sort-value="0"|'..patch.level | |
− | + | if patch.cost == 0 then | |
− | + | result = result..'||Free' | |
− | + | else | |
− | + | result = result..'||style="text-align:right;" data-sort-value="'..patch.cost..'"|'..Icons.GP(patch.cost) | |
− | + | end | |
− | + | end | |
− | + | result = result..'\r\n|}' | |
− | + | return result | |
end | end | ||
function p.getSmithingTable(frame) | function p.getSmithingTable(frame) | ||
− | + | local tableType = frame.args ~= nil and frame.args[1] or frame | |
− | + | local bar = nil | |
− | + | if tableType ~= 'Smelting' then | |
− | + | bar = Items.getItem(tableType) | |
− | + | if bar == nil then | |
− | + | return 'ERROR: Could not find an item named '..tableType..' to build a smithing table with' | |
− | + | elseif bar.type ~= 'Bar' then | |
− | + | return 'ERROR: '..tableType.." is not a bar and thus can't be used for smithing" | |
− | + | end | |
− | + | end | |
− | + | local smithList = {} | |
− | + | for i, item in pairs(ItemData.Items) do | |
− | + | if item.smithingLevel ~= nil then | |
− | + | if tableType == 'Smelting' then | |
− | + | if item.type == 'Bar' then | |
− | + | table.insert(smithList, item) | |
− | + | end | |
− | + | else | |
− | + | for j, req in pairs(item.smithReq) do | |
− | + | if req.id == bar.id then | |
− | + | table.insert(smithList, item) | |
− | + | end | |
− | + | end | |
− | + | end | |
− | + | end | |
− | + | end | |
− | + | local result = '{|class="wikitable sortable stickyHeader"' | |
− | + | result = result..'\r\n|-class="headerRow-0"' | |
− | + | result = result..'\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients' | |
− | + | --Adding value/bar for things other than smelting | |
− | + | if bar ~= nil then result = result..'!!Value/Bar' end | |
− | + | table.sort(smithList, function(a, b) | |
− | + | if a.smithingLevel ~= b.smithingLevel then | |
− | + | return a.smithingLevel < b.smithingLevel | |
− | + | else | |
− | + | return a.name < b.name | |
− | + | end end) | |
− | + | for i, item in Shared.skpairs(smithList) do | |
− | + | result = result..'\r\n|-' | |
− | + | result = result..'\r\n|'..Icons.Icon({item.name, type='item', size='50', notext=true})..'||' | |
− | + | local qty = item.smithingQty ~= nil and item.smithingQty or 1 | |
− | + | if qty > 1 then | |
− | + | result = result..item.smithingQty..'x ' | |
− | + | end | |
− | + | result = result..'[['..item.name..']]' | |
− | + | result = result..'||data-sort-value="'..item.smithingLevel..'"|'..Icons._SkillReq('Smithing', item.smithingLevel) | |
− | + | result = result..'||'..item.smithingXP | |
− | + | local totalValue = item.sellsFor * qty | |
− | + | result = result..'||data-sort-value="'..totalValue..'"|'..Icons.GP(item.sellsFor) | |
− | + | if qty > 1 then | |
− | + | result = result..' (x'..qty..')' | |
− | + | end | |
− | + | result = result..'||' | |
− | + | local barQty = 0 | |
− | + | for i, mat in Shared.skpairs(item.smithReq) do | |
− | + | matItem = Items.getItemByID(mat.id) | |
− | + | if i > 1 then result = result..', ' end | |
− | + | result = result..Icons.Icon({matItem.name, type='item', qty=mat.qty, notext=true}) | |
− | + | if bar ~= nil and mat.id == bar.id then | |
− | + | barQty = mat.qty | |
− | + | end | |
− | + | end | |
− | + | --Add the data for the value per bar | |
− | + | if bar ~= nil then | |
− | + | if barQty == 0 then | |
− | + | result = result..'||data-sort-value="0"|N/A' | |
− | + | else | |
− | + | local barVal = totalValue / barQty | |
− | + | result = result..'||data-sort-value="'..barVal..'"|'..Icons.GP(Shared.round(barVal, 1, 1)) | |
− | + | end | |
− | + | end | |
− | + | end | |
− | + | result = result..'\r\n|}' | |
− | + | return result | |
end | end | ||
function p.getFiremakingTable(frame) | function p.getFiremakingTable(frame) | ||
− | + | local resultPart = {} | |
− | + | table.insert(resultPart, '{| class="wikitable sortable stickyHeader"') | |
− | + | table.insert(resultPart, '\r\n|-class="headerRow-0"') | |
− | + | table.insert(resultPart, '\r\n!colspan="2" rowspan="2"|Logs!!rowspan="2"|'..Icons.Icon({'Firemaking', type='skill', notext=true})..' Level') | |
− | + | table.insert(resultPart, '!!rowspan="2"|Burn Time!!colspan="2"|Without Bonfire!!colspan="2"|With Bonfire!!rowspan="2"|Bonfire Bonus!!rowspan="2"|Bonfire Time') | |
− | + | table.insert(resultPart, '\r\n|-class="headerRow-1"') | |
− | + | table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s') | |
− | + | for i, logData in Shared.skpairs(SkillData.Firemaking) do | |
− | + | local logs = Items.getItemByID(logData.logID) | |
− | + | local name = logs.name | |
− | + | local burnTime = logData.baseInterval / 1000 | |
− | + | local bonfireTime = logData.baseBonfireInterval / 1000 | |
− | + | local XPS = logData.baseXP / burnTime | |
− | + | local XP_BF = logData.baseXP * (1 + logData.bonfireXPBonus / 100) | |
− | + | local XPS_BF = XP_BF / burnTime | |
− | + | table.insert(resultPart, '\r\n|-') | |
− | + | table.insert(resultPart, '\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='item', size='50', notext=true})) | |
− | + | table.insert(resultPart, '||[['..name..']]') | |
− | + | table.insert(resultPart, '||style ="text-align: right;"|'..logData.levelRequired) | |
− | + | table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..burnTime..'"|'..Shared.timeString(burnTime, true)) | |
− | + | table.insert(resultPart, '||style ="text-align: right;"|'..logData.baseXP) | |
− | + | table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS..'"|'..Shared.round(XPS, 2, 2)) | |
− | + | table.insert(resultPart, '||style ="text-align: right;"|'..Shared.round(XP_BF, 2, 0)) | |
− | + | table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS_BF..'"|'..Shared.round(XPS_BF, 2, 2)) | |
− | + | table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..logData.bonfireXPBonus..'"|'..logData.bonfireXPBonus..'%') | |
− | + | table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..bonfireTime..'"|'..Shared.timeString(bonfireTime, true)) | |
− | + | end | |
− | + | table.insert(resultPart, '\r\n|}') | |
− | + | return table.concat(resultPart) | |
end | end | ||
function p.getMasteryTokenTable() | function p.getMasteryTokenTable() | ||
− | + | local baseTokenChance = 18500 | |
− | + | local masterySkills = {} | |
− | + | ||
− | + | -- Find all mastery tokens | |
− | + | local masteryTokens = Items.getItems(function(item) return item.isToken ~= nil and item.skill ~= nil and item.isToken end) | |
− | + | for i, item in pairs(masteryTokens) do | |
− | + | local milestones = SkillData.Milestones[item.skill + 1] | |
− | + | if milestones ~= nil then | |
− | + | table.insert(masterySkills, {tokenRef = i, skillID = item.skill, milestoneCount = milestones}) | |
− | + | end | |
− | + | end | |
− | + | table.sort(masterySkills, function(a, b) | |
− | + | if a['milestoneCount'] == b['milestoneCount'] then | |
− | + | return a['skillID'] < b['skillID'] | |
− | + | else | |
− | + | return a['milestoneCount'] > b['milestoneCount'] | |
− | + | end | |
− | + | end) | |
− | + | ||
− | + | -- Generate output table | |
− | + | local resultPart = {} | |
− | + | local CCI = Items.getItem('Clue Chasers Insignia') | |
− | + | local CCIIcon = Icons.Icon({'Clue Chasers Insignia', type='item', notext=true}) | |
− | + | if CCI == nil then return '' end | |
− | + | table.insert(resultPart, '{| class="wikitable sortable"') | |
− | + | table.insert(resultPart, '\r\n!rowspan="2"|Token!!rowspan="2"|Skill!!colspan="2"|Approximate Mastery Token Chance') | |
− | + | table.insert(resultPart, '\r\n|-\r\n!Without ' .. CCIIcon .. '!!With ' .. CCIIcon) | |
− | + | for i, m in ipairs(masterySkills) do | |
− | + | local token = masteryTokens[m.tokenRef] | |
− | + | local denom = math.floor(baseTokenChance / m['milestoneCount']) | |
− | + | local denomCCI = math.floor(baseTokenChance / m['milestoneCount'] * (1 - CCI.increasedItemChance / 100)) | |
− | + | table.insert(resultPart, '\r\n|-') | |
− | + | table.insert(resultPart, '\r\n|style="text-align:center"|' .. Icons.Icon({token.name, type='item', size=50, notext=true})) | |
− | + | table.insert(resultPart, '\r\n|' .. Icons.Icon({Constants.getSkillName(m['skillID']), type='skill'})) | |
− | + | table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denom .. '"|1/' .. Shared.formatnum(denom)) | |
− | + | table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denomCCI .. '"|1/' .. Shared.formatnum(denomCCI)) | |
− | + | end | |
− | + | table.insert(resultPart, '\r\n|}') | |
− | + | ||
− | + | return table.concat(resultPart) | |
end | end | ||
function p.getSkillUnlockCostTable() | function p.getSkillUnlockCostTable() | ||
− | + | local returnPart = {} | |
− | + | table.insert(returnPart, '{| class="wikitable stickyHeader"\r\n|- class="headerRow-0"\r\n!Unlock!!Cost!!Cumulative Cost') | |
− | + | local accCost = 0 | |
− | + | for i, cost in ipairs(SkillData.SkillUnlockCosts) do | |
− | + | accCost = accCost + cost | |
− | + | table.insert(returnPart, '|-') | |
− | + | table.insert(returnPart, '|' .. i .. '||' .. Icons.GP(cost) .. '||' .. Icons.GP(accCost)) | |
− | + | end | |
− | + | table.insert(returnPart, '|}') | |
− | + | return table.concat(returnPart, '\r\n') | |
end | end | ||
return p | return p |
Revision as of 19:16, 8 December 2021
Data pulled from Module:Skills/data
--Some skills have their own modules: --Module:Magic for Magic --Module:Prayer for Prayer --Module:Skills/Agility for Agility --Module:Skills/Summoning for Summoning --Module:Skills/Gathering for Mining, Fishing, Woodcutting --Module:Skills/Artisan for Smithing, Cooking, Herblore, etc. --Also be aware of: --Module:Navboxes for navigation boxes appearing near the bottom of pages local p = {} local ItemData = mw.loadData('Module:Items/data') local SkillData = mw.loadData('Module:Skills/data') local Shared = require('Module:Shared') local Constants = require('Module:Constants') local Items = require('Module:Items') local ItemSourceTables = require('Module:Items/SourceTables') local Icons = require('Module:Icons') local MasteryCheckpoints = {.1, .25, .5, .95} function p.getMasteryUnlockTable(frame) local skillName = frame.args ~= nil and frame.args[1] or frame local skillID = Constants.getSkillID(skillName) if skillID == nil then return "ERROR: Failed to find a skill ID for "..skillName end local unlockTable = SkillData.MasteryUnlocks[skillID] if unlockTable == nil then return 'ERROR: Failed to find Mastery Unlock data for '..skillName end local result = '{|class="wikitable"\r\n!Level!!Unlock' for i, unlock in Shared.skpairs(unlockTable) do result = result..'\r\n|-' result = result..'\r\n|'..unlock.level..'||'..unlock.unlock end result = result..'\r\n|}' return result end function p.getMasteryCheckpointTable(frame) local skillName = frame.args ~= nil and frame.args[1] or frame local skillID = Constants.getSkillID(skillName) if skillID == nil then return "ERROR: Failed to find a skill ID for "..skillName end if SkillData.MasteryCheckpoints[skillID] == nil then return 'ERROR: Failed to find Mastery Unlock data for '..skillName end local bonuses = SkillData.MasteryCheckpoints[skillID].bonuses local totalPoolXP = SkillData.MasteryPoolXP[skillID + 1] local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus' for i, bonus in Shared.skpairs(bonuses) do result = result..'\r\n|-' result = result..'\r\n|'..(MasteryCheckpoints[i] * 100)..'%||' result = result..Shared.formatnum(totalPoolXP * MasteryCheckpoints[i])..' xp||'..bonus end result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP' result = result..'\r\n|'..Shared.formatnum(totalPoolXP) result = result..'\r\n|}' return result end function p._getFarmingTable(category) local seedList = {} if category == 'Allotment' or category == 'Herb' or category == 'Tree' then seedList = Items.getItems(function(item) return item.tier == category end) else return 'ERROR: Invalid farming category. Please choose Allotment, Herb, or Tree' end local result = '{|class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan=2|Seeds!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level' result = result..'!!XP!!Growth Time!!Seed Value' if category == 'Allotment' then result = result..'!!colspan="2"|Crop!!Crop Healing!!Crop Value' elseif category == 'Herb' then result = result..'!!colspan="2"|Herb!!Herb Value' elseif category == 'Tree' then result = result..'!!colspan="2"|Logs!!Log Value' end result = result..'!!Seed Sources' table.sort(seedList, function(a, b) return a.farmingLevel < b.farmingLevel end) for i, seed in pairs(seedList) do result = result..'\r\n|-' result = result..'\r\n|'..Icons.Icon({seed.name, type='item', size='50', notext=true})..'||[['..seed.name..']]' result = result..'||'..seed.farmingLevel..'||'..Shared.formatnum(seed.farmingXP) result = result..'||data-sort-value="'..seed.timeToGrow..'"|'..Shared.timeString(seed.timeToGrow, true) result = result..'||data-sort-value="'..seed.sellsFor..'"|'..Icons.GP(seed.sellsFor) local crop = Items.getItemByID(seed.grownItemID) result = result..'||'..Icons.Icon({crop.name, type='item', size='50', notext=true})..'||[['..crop.name..']]' if category == 'Allotment' then result = result..'||'..Icons.Icon({'Hitpoints', type='skill', notext=true})..' '..(crop.healsFor * 10) end result = result..'||data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor) result = result..'||'..ItemSourceTables._getItemSources(seed) end result = result..'\r\n|}' return result end function p.getFarmingTable(frame) local category = frame.args ~= nil and frame.args[1] or frame return p._getFarmingTable(category) end function p.getFarmingFoodTable(frame) local result = '{| class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan="2"|Crop!!'..Icons.Icon({"Farming", type="skill", notext=true})..' Level' result = result..'!!Healing!!Value' local itemArray = Items.getItems(function(item) return item.grownItemID ~= nil end) table.sort(itemArray, function(a, b) return a.farmingLevel < b.farmingLevel end) for i, item in Shared.skpairs(itemArray) do local crop = Items.getItemByID(item.grownItemID) if crop.healsFor ~= nil and crop.healsFor > 0 then result = result..'\r\n|-' result = result..'\r\n|'..Icons.Icon({crop.name, type='item', notext='true', size='50'})..'||[['..crop.name..']]' result = result..'||style="text-align:right;"|'..item.farmingLevel result = result..'||style="text-align:right" data-sort-value="'..crop.healsFor..'"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..(crop.healsFor * 10) result = result..'||style="text-align:right" data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor) end end result = result..'\r\n|}' return result end function p.getFarmingPlotTable(frame) local areaName = frame.args ~= nil and frame.args[1] or frame local patches = nil for i, area in Shared.skpairs(SkillData.Farming.Patches) do if area.areaName == areaName then patches = area.patches break end end if patches == nil then return "ERROR: Invalid area name.[[Category:Pages with script errors" end local result = '{|class="wikitable"' result = result..'\r\n!Plot!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level!!Cost' for i, patch in Shared.skpairs(patches) do result = result..'\r\n|-\r\n|'..i result = result..'||style="text-align:right;" data-sort-value="0"|'..patch.level if patch.cost == 0 then result = result..'||Free' else result = result..'||style="text-align:right;" data-sort-value="'..patch.cost..'"|'..Icons.GP(patch.cost) end end result = result..'\r\n|}' return result end function p.getSmithingTable(frame) local tableType = frame.args ~= nil and frame.args[1] or frame local bar = nil if tableType ~= 'Smelting' then bar = Items.getItem(tableType) if bar == nil then return 'ERROR: Could not find an item named '..tableType..' to build a smithing table with' elseif bar.type ~= 'Bar' then return 'ERROR: '..tableType.." is not a bar and thus can't be used for smithing" end end local smithList = {} for i, item in pairs(ItemData.Items) do if item.smithingLevel ~= nil then if tableType == 'Smelting' then if item.type == 'Bar' then table.insert(smithList, item) end else for j, req in pairs(item.smithReq) do if req.id == bar.id then table.insert(smithList, item) end end end end end local result = '{|class="wikitable sortable stickyHeader"' result = result..'\r\n|-class="headerRow-0"' result = result..'\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients' --Adding value/bar for things other than smelting if bar ~= nil then result = result..'!!Value/Bar' end table.sort(smithList, function(a, b) if a.smithingLevel ~= b.smithingLevel then return a.smithingLevel < b.smithingLevel else return a.name < b.name end end) for i, item in Shared.skpairs(smithList) do result = result..'\r\n|-' result = result..'\r\n|'..Icons.Icon({item.name, type='item', size='50', notext=true})..'||' local qty = item.smithingQty ~= nil and item.smithingQty or 1 if qty > 1 then result = result..item.smithingQty..'x ' end result = result..'[['..item.name..']]' result = result..'||data-sort-value="'..item.smithingLevel..'"|'..Icons._SkillReq('Smithing', item.smithingLevel) result = result..'||'..item.smithingXP local totalValue = item.sellsFor * qty result = result..'||data-sort-value="'..totalValue..'"|'..Icons.GP(item.sellsFor) if qty > 1 then result = result..' (x'..qty..')' end result = result..'||' local barQty = 0 for i, mat in Shared.skpairs(item.smithReq) do matItem = Items.getItemByID(mat.id) if i > 1 then result = result..', ' end result = result..Icons.Icon({matItem.name, type='item', qty=mat.qty, notext=true}) if bar ~= nil and mat.id == bar.id then barQty = mat.qty end end --Add the data for the value per bar if bar ~= nil then if barQty == 0 then result = result..'||data-sort-value="0"|N/A' else local barVal = totalValue / barQty result = result..'||data-sort-value="'..barVal..'"|'..Icons.GP(Shared.round(barVal, 1, 1)) end end end result = result..'\r\n|}' return result end function p.getFiremakingTable(frame) local resultPart = {} table.insert(resultPart, '{| class="wikitable sortable stickyHeader"') table.insert(resultPart, '\r\n|-class="headerRow-0"') table.insert(resultPart, '\r\n!colspan="2" rowspan="2"|Logs!!rowspan="2"|'..Icons.Icon({'Firemaking', type='skill', notext=true})..' Level') table.insert(resultPart, '!!rowspan="2"|Burn Time!!colspan="2"|Without Bonfire!!colspan="2"|With Bonfire!!rowspan="2"|Bonfire Bonus!!rowspan="2"|Bonfire Time') table.insert(resultPart, '\r\n|-class="headerRow-1"') table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s') for i, logData in Shared.skpairs(SkillData.Firemaking) do local logs = Items.getItemByID(logData.logID) local name = logs.name local burnTime = logData.baseInterval / 1000 local bonfireTime = logData.baseBonfireInterval / 1000 local XPS = logData.baseXP / burnTime local XP_BF = logData.baseXP * (1 + logData.bonfireXPBonus / 100) local XPS_BF = XP_BF / burnTime table.insert(resultPart, '\r\n|-') table.insert(resultPart, '\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='item', size='50', notext=true})) table.insert(resultPart, '||[['..name..']]') table.insert(resultPart, '||style ="text-align: right;"|'..logData.levelRequired) table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..burnTime..'"|'..Shared.timeString(burnTime, true)) table.insert(resultPart, '||style ="text-align: right;"|'..logData.baseXP) table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS..'"|'..Shared.round(XPS, 2, 2)) table.insert(resultPart, '||style ="text-align: right;"|'..Shared.round(XP_BF, 2, 0)) table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS_BF..'"|'..Shared.round(XPS_BF, 2, 2)) table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..logData.bonfireXPBonus..'"|'..logData.bonfireXPBonus..'%') table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..bonfireTime..'"|'..Shared.timeString(bonfireTime, true)) end table.insert(resultPart, '\r\n|}') return table.concat(resultPart) end function p.getMasteryTokenTable() local baseTokenChance = 18500 local masterySkills = {} -- Find all mastery tokens local masteryTokens = Items.getItems(function(item) return item.isToken ~= nil and item.skill ~= nil and item.isToken end) for i, item in pairs(masteryTokens) do local milestones = SkillData.Milestones[item.skill + 1] if milestones ~= nil then table.insert(masterySkills, {tokenRef = i, skillID = item.skill, milestoneCount = milestones}) end end table.sort(masterySkills, function(a, b) if a['milestoneCount'] == b['milestoneCount'] then return a['skillID'] < b['skillID'] else return a['milestoneCount'] > b['milestoneCount'] end end) -- Generate output table local resultPart = {} local CCI = Items.getItem('Clue Chasers Insignia') local CCIIcon = Icons.Icon({'Clue Chasers Insignia', type='item', notext=true}) if CCI == nil then return '' end table.insert(resultPart, '{| class="wikitable sortable"') table.insert(resultPart, '\r\n!rowspan="2"|Token!!rowspan="2"|Skill!!colspan="2"|Approximate Mastery Token Chance') table.insert(resultPart, '\r\n|-\r\n!Without ' .. CCIIcon .. '!!With ' .. CCIIcon) for i, m in ipairs(masterySkills) do local token = masteryTokens[m.tokenRef] local denom = math.floor(baseTokenChance / m['milestoneCount']) local denomCCI = math.floor(baseTokenChance / m['milestoneCount'] * (1 - CCI.increasedItemChance / 100)) table.insert(resultPart, '\r\n|-') table.insert(resultPart, '\r\n|style="text-align:center"|' .. Icons.Icon({token.name, type='item', size=50, notext=true})) table.insert(resultPart, '\r\n|' .. Icons.Icon({Constants.getSkillName(m['skillID']), type='skill'})) table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denom .. '"|1/' .. Shared.formatnum(denom)) table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denomCCI .. '"|1/' .. Shared.formatnum(denomCCI)) end table.insert(resultPart, '\r\n|}') return table.concat(resultPart) end function p.getSkillUnlockCostTable() local returnPart = {} table.insert(returnPart, '{| class="wikitable stickyHeader"\r\n|- class="headerRow-0"\r\n!Unlock!!Cost!!Cumulative Cost') local accCost = 0 for i, cost in ipairs(SkillData.SkillUnlockCosts) do accCost = accCost + cost table.insert(returnPart, '|-') table.insert(returnPart, '|' .. i .. '||' .. Icons.GP(cost) .. '||' .. Icons.GP(accCost)) end table.insert(returnPart, '|}') return table.concat(returnPart, '\r\n') end return p