Anonymous

Module:Skills: Difference between revisions

From Melvor Idle
Move Farming functions to Module:Skills/Gathering
(Amend incomplete category & indentation)
(Move Farming functions to Module:Skills/Gathering)
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
--This module should avoid including skill specific functions which generate
--output for wiki pages, especially those which require() other modules. For
--these functions, consider using the appropriate module from the below list.
--Some skills have their own modules:
--Some skills have their own modules:
--Module:Magic for Magic
--Module:Magic for Magic
Line 18: Line 22:
local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
local Items = require('Module:Items')
local Items = require('Module:Items')
local ItemSourceTables = require('Module:Items/SourceTables')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')


local MasteryCheckpoints = {.1, .25, .5, .95}
local MasteryCheckpoints = {.1, .25, .5, .95}


function p.getMasteryUnlockTable(frame)
-- Thieving
local skillName = frame.args ~= nil and frame.args[1] or frame
function p.getThievingNPC(npcName)
local skillID = Constants.getSkillID(skillName)
local result = nil
if skillID == nil then
for i, npc in Shared.skpairs(SkillData.Thieving.NPCs) do
return "ERROR: Failed to find a skill ID for "..skillName
if npc.name == npcName then
result = Shared.clone(npc)
break
end
end
end
return result
end


local unlockTable = SkillData.MasteryUnlocks[skillID]
function p.getThievingNPCArea(npc)
if unlockTable == nil then
if type(npc) == 'string' then
return 'ERROR: Failed to find Mastery Unlock data for '..skillName
npc = p.getThievingNPC(npc)
end
end


local result = '{|class="wikitable"\r\n!Level!!Unlock'
local result = nil
for i, unlock in Shared.skpairs(unlockTable) do
for i, area in Shared.skpairs(SkillData.Thieving.Areas) do
result = result..'\r\n|-'
for j, npcID in pairs(area.npcs) do
result = result..'\r\n|'..unlock.level..'||'..unlock.unlock
if npcID == npc.id then
result = area
break
end
end
end
end
result = result..'\r\n|}'
return result
return result
end
end


function p.getMasteryCheckpointTable(frame)
function p._getThievingNPCStat(npc, statName)
local skillName = frame.args ~= nil and frame.args[1] or frame
local result = nil
local skillID = Constants.getSkillID(skillName)
 
if skillID == nil then
if statName == 'level' then
return "ERROR: Failed to find a skill ID for "..skillName
result = Icons._SkillReq('Thieving', npc.level)
elseif statName == 'maxHit' then
result = npc.maxHit * 10
elseif statName == 'area' then
local area = p.getThievingNPCArea(npc)
result = area.name
else
result = npc[statName]
end
end


if SkillData.MasteryCheckpoints[skillID] == nil then
if result == nil then
return 'ERROR: Failed to find Mastery Unlock data for '..skillName
result = ''
end
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
return result
end
end


function p._getFarmingTable(category)
function p.getThievingNPCStat(frame)
local seedList = {}
local npcName = frame.args ~= nil and frame.args[1] or frame[1]
if category == 'Allotment' or category == 'Herb' or category == 'Tree' then
local statName = frame.args ~= nil and frame.args[2] or frame[2]
seedList = Items.getItems(function(item) return item.tier == category end)
local npc = p.getThievingNPC(npcName)
else
if npc == nil then
return 'ERROR: Invalid farming category. Please choose Allotment, Herb, or Tree'
return "ERROR: Invalid Thieving NPC "..npcName.."[[Category:Pages with script errors]]"
end
end


local result = '{|class="wikitable sortable stickyHeader"'
return p._getThievingNPCStat(npc, statName)
result = result..'\r\n|- class="headerRow-0"'
end
result = result..'\r\n!colspan=2|Seeds!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level'
 
result = result..'!!XP!!Growth Time!!Seed Value'
function p.getThievingSourcesForItem(itemID)
if category == 'Allotment' then
local resultArray = {}
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
local areaNPCs = {}
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)
--First check area unique drops
result = result..'||'..Icons.Icon({crop.name, type='item', size='50', notext=true})..'||[['..crop.name..']]'
--If an area drops the item, add all the NPC ids to the list so we can add them later
if category == 'Allotment' then
if not result then
result = result..'||'..Icons.Icon({'Hitpoints', type='skill', notext=true})..' '..(crop.healsFor * 10)
for i, area in pairs(SkillData.Thieving.Areas) do
for j, drop in pairs(area.uniqueDrops) do
if drop.itemID == itemID then
for k, npcID in pairs(area.npcs) do
areaNPCs[npcID] = drop.qty
end
break
end
end
end
end
result = result..'||data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor)
result = result..'||'..ItemSourceTables._getItemSources(seed)
end
end


result = result..'\r\n|}'
--Now go through and get drop chances on each NPC if needed
return result
for i, npc in pairs(SkillData.Thieving.NPCs) do
end
local totalWt = 0
local dropWt = 0
local dropQty = 0
for j, drop in pairs(npc.lootTable) do
totalWt = totalWt + drop[2]
if drop[1] == itemID then
dropWt = drop[2]
dropQty = drop[3]
end
end
if dropWt > 0 then
table.insert(resultArray, {npc = npc.name, minQty = 1, maxQty = dropQty, wt = dropWt * SkillData.Thieving.ItemChance, totalWt = totalWt * 100, level = npc.level})
end


function p.getFarmingTable(frame)
--Chance of -1 on unique drops is to indicate variable chance
local category = frame.args ~= nil and frame.args[1] or frame
if npc.uniqueDrop ~= nil and npc.uniqueDrop.itemID == itemID then
table.insert(resultArray, {npc = npc.name, minQty = npc.uniqueDrop.qty, maxQty = npc.uniqueDrop.qty, wt = -1, totalWt = -1, level = npc.level})
end


return p._getFarmingTable(category)
if areaNPCs[npc.id] ~= nil then
end
table.insert(resultArray, {npc = npc.name, minQty = areaNPCs[npc.id], maxQty = areaNPCs[npc.id], wt = SkillData.Thieving.AreaUniqueChance, totalWt = 100, level = npc.level})
 
end
function p.getFarmingFoodTable(frame)
end
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
for i, drop in pairs(SkillData.Thieving.RareItems) do
local crop = Items.getItemByID(item.grownItemID)
if drop.itemID == itemID then
if crop.healsFor ~= nil and crop.healsFor > 0 then
table.insert(resultArray, {npc = 'all', minQty = 1, maxQty = 1, wt = 1, totalWt = Shared.round2(1/(drop.chance/100), 0), level = 1})
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
end
end


result = result..'\r\n|}'
return resultArray
end


return result
-- Astrology
function p.getConstellationByID(constID)
return SkillData.Astrology.Constellations[constID]
end
end


function p.getFarmingPlotTable(frame)
function p.getConstellation(constName)
local areaName = frame.args ~= nil and frame.args[1] or frame
for i, const in ipairs(SkillData.Astrology.Constellations) do
local patches = nil
if const.name == constName then
for i, area in Shared.skpairs(SkillData.Farming.Patches) do
return const
if area.areaName == areaName then
patches = area.patches
break
end
end
end
end
if patches == nil then
return nil
return "ERROR: Invalid area name.[[Category:Pages with script errors]]"
end
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
function p.getConstellations(checkFunc)
result = result..'\r\n|-\r\n|'..i
local result = {}
result = result..'||style="text-align:right;" data-sort-value="0"|'..patch.level
for i, const in ipairs(SkillData.Astrology.Constellations) do
if patch.cost == 0 then
if checkFunc(const) then
result = result..'||Free'
table.insert(result, const)
else
result = result..'||style="text-align:right;" data-sort-value="'..patch.cost..'"|'..Icons.GP(patch.cost)
end
end
end
end
result = result..'\r\n|}'
return result
return result
end
end


function p.getSmithingTable(frame)
-- For a given constellation cons and modifier value modValue, generates and returns
local tableType = frame.args ~= nil and frame.args[1] or frame
-- a table of modifiers, much like any other item/object elsewhere in the game.
local bar = nil
-- includeStandard: true|false, determines whether standard modifiers are included
if tableType ~= 'Smelting' then
-- includeUnique: true|false, determines whether unique modifiers are included
bar = Items.getItem(tableType)
-- isDistinct: true|false, if true, the returned list of modifiers is de-duplicated
if bar == nil then
-- asKeyValue: true|false, if true, returns key/value pairs like usual modifier objects
return 'ERROR: Could not find an item named '..tableType..' to build a smithing table with'
function p._buildAstrologyModifierArray(cons, modValue, includeStandard, includeUnique, isDistinct, asKeyValue)
elseif bar.type ~= 'Bar' then
-- Temporary function to determine if the table already contains a given modifier
return 'ERROR: '..tableType.." is not a bar and thus can't be used for smithing"
local containsMod = function(modList, modNew)
for i, modItem in ipairs(modList) do
-- Check mod names & value data types both equal
if modItem[1] == modNew[1] and type(modItem[2]) == type(modNew[2]) then
if type(modItem[2]) == 'table' then
if Shared.tablesEqual(modItem[2], modNew[2]) then
return true
end
elseif modItem[2] == modNew[2] then
return true
end
end
end
return false
end
 
local addToArray = function(modArray, modNew)
if not isDistinct or (isDistinct and not containsMod(modArray, modNew)) then
table.insert(modArray, modNew)
end
end
end
local modTypes = {}
if includeStandard then
table.insert(modTypes, 'standardModifiers')
end
if includeUnique then
table.insert(modTypes, 'uniqueModifiers')
end
end


local smithList = {}
local modArray = {}
for i, item in pairs(ItemData.Items) do
local isSkillMod = {}
if item.smithingLevel ~= nil then
for _, modType in ipairs(modTypes) do
if tableType == 'Smelting' then
for i, skillMods in ipairs(cons[modType]) do
if item.type == 'Bar' then
local skillID = cons.skills[i]
table.insert(smithList, item)
if skillID ~= nil then
end
for j, modName in ipairs(skillMods) do
else
local modBaseName, modText, sign, isNegative, unsign, modBase = Constants.getModifierDetails(modName)
for j, req in pairs(item.smithReq) do
-- Check if modifier varies by skill, and amend the modifier value accordingly
if req.id == bar.id then
local modVal = modValue
table.insert(smithList, item)
if Shared.contains(modText, '{SV0}') then
isSkillMod[modName] = true
modVal = {skillID, modValue}
end
end
addToArray(modArray, {modName, modVal})
end
end
end
end
Line 204: Line 224:
end
end


local result = '{|class="wikitable sortable stickyHeader"'
if asKeyValue then
result = result..'\r\n|-class="headerRow-0"'
local modArrayKV = {}
result = result..'\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients'
for i, modDefn in ipairs(modArray) do
--Adding value/bar for things other than smelting
local modName, modVal = modDefn[1], modDefn[2]
if bar ~= nil then result = result..'!!Value/Bar' end
local isSkill = isSkillMod[modName]
 
if modArrayKV[modName] == nil then
table.sort(smithList, function(a, b)
modArrayKV[modName] = (isSkill and { modVal } or modVal)
if a.smithingLevel ~= b.smithingLevel then
elseif isSkill then
return a.smithingLevel < b.smithingLevel
table.insert(modArrayKV[modName], modVal)
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
else
local barVal = totalValue / barQty
modArrayKV[modName] = modArrayKV[modName] + modVal
result = result..'||data-sort-value="'..barVal..'"|'..Icons.GP(Shared.round(barVal, 1, 1))
end
end
end
end
return modArrayKV
else
return modArray
end
end
-- Mastery
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
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|}'
result = result..'\r\n|}'
return result
return result
end
end


function p.getFiremakingTable(frame)
function p.getMasteryCheckpointTable(frame)
local resultPart = {}
local skillName = frame.args ~= nil and frame.args[1] or frame
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
local skillID = Constants.getSkillID(skillName)
table.insert(resultPart, '\r\n|-class="headerRow-0"')
if skillID == nil then
table.insert(resultPart, '\r\n!colspan="2" rowspan="2"|Logs!!rowspan="2"|'..Icons.Icon({'Firemaking', type='skill', notext=true})..' Level')
return "ERROR: Failed to find a skill ID for "..skillName
table.insert(resultPart, '!!rowspan="2"|Burn Time!!colspan="2"|Without Bonfire!!colspan="2"|With Bonfire!!rowspan="2"|Bonfire Bonus!!rowspan="2"|Bonfire Time')
end
table.insert(resultPart, '\r\n|-class="headerRow-1"')
 
table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s')
if SkillData.MasteryCheckpoints[skillID] == nil then
return 'ERROR: Failed to find Mastery Unlock data for '..skillName
end


for i, logData in Shared.skpairs(SkillData.Firemaking) do
local bonuses = SkillData.MasteryCheckpoints[skillID].bonuses
local logs = Items.getItemByID(logData.logID)
local totalPoolXP = SkillData.MasteryPoolXP[skillID + 1]
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|-')
local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus'
table.insert(resultPart, '\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='item', size='50', notext=true}))
for i, bonus in Shared.skpairs(bonuses) do
table.insert(resultPart, '||[['..name..']]')
result = result..'\r\n|-'
table.insert(resultPart, '||style ="text-align: right;"|'..logData.levelRequired)
result = result..'\r\n|'..(MasteryCheckpoints[i] * 100)..'%||'
table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..burnTime..'"|'..Shared.timeString(burnTime, true))
result = result..Shared.formatnum(totalPoolXP * MasteryCheckpoints[i])..' xp||'..bonus
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
end
 
result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP'
table.insert(resultPart, '\r\n|}')
result = result..'\r\n|'..Shared.formatnum(totalPoolXP)
return table.concat(resultPart)
result = result..'\r\n|}'
return result
end
end


Line 294: Line 294:
local baseTokenChance = 18500
local baseTokenChance = 18500
local masterySkills = {}
local masterySkills = {}
 
-- Find all mastery tokens
-- Find all mastery tokens
local masteryTokens = Items.getItems(function(item) return item.isToken ~= nil and item.skill ~= nil and item.isToken end)
local masteryTokens = Items.getItems(function(item) return item.isToken ~= nil and item.skill ~= nil and item.isToken end)
Line 310: Line 310:
end
end
end)
end)
 
-- Generate output table
-- Generate output table
local resultPart = {}
local resultPart = {}
Line 324: Line 324:
local token = masteryTokens[m.tokenRef]
local token = masteryTokens[m.tokenRef]
local denom = math.floor(baseTokenChance / m['milestoneCount'])
local denom = math.floor(baseTokenChance / m['milestoneCount'])
local denomCCI = math.floor(baseTokenChance / m['milestoneCount'] * (1 - CCI.increasedItemChance / 100))
local denomCCI = Shared.round(baseTokenChance / (m['milestoneCount'] * (1 + CCI.increasedItemChance / 100)), 0, 0)


table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|-')
Line 333: Line 333:
end
end
table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')
 
return table.concat(resultPart)
return table.concat(resultPart)
end
end


-- Skill unlock costs for Adventure game mode
function p.getSkillUnlockCostTable()
function p.getSkillUnlockCostTable()
local returnPart = {}
local returnPart = {}
Line 350: Line 351:


return table.concat(returnPart, '\r\n')
return table.concat(returnPart, '\r\n')
end
-- Accepts 1 parameter, being either:
--  'Smelting', for which a table of all bars is generated, or
--  A bar or tier name, which if valid generates a table of all smithing recipes using that bar/tier
function p.getSmithingTable(frame)
local tableType = frame.args ~= nil and frame.args[1] or frame
tableType = Shared.splitString(tableType, ' ')[1]
-- Translates Smithing category names to Smithing recipe data categories
local categoryMap = {
['Smelting'] = 0,
['Bronze'] = 1,
['Iron'] = 2,
['Steel'] = 3,
['Mithril'] = 4,
['Adamant'] = 5,
['Adamantite'] = 5,
['Rune'] = 6,
['Runite'] = 6,
['Dragon'] = 7,
['Dragonite'] = 7
}
local categoryID = categoryMap[tableType]
if categoryID == nil then
return 'ERROR: Invalid Smithing category: "' .. tableType .. '"[[Category:Pages with script errors]]'
end
-- Build a list of recipes to be included, and a list of bars while we're at it
-- The bar list will be used later for value/bar calculations
local recipeList, barIDList = {}, {}
for i, recipe in ipairs(SkillData.Smithing.Recipes) do
if recipe.category == categoryID then
local recipeItem = Items.getItemByID(recipe.itemID)
if recipeItem ~= nil then
table.insert(recipeList, { id = i, level = recipe.level, itemName = recipeItem.name, itemValue = recipeItem.sellsFor })
end
elseif recipe.category == 0 then
barIDList[recipe.itemID] = true
end
end
-- Generate output table
local resultPart = {}
table.insert(resultPart, '{|class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\r\n|-class="headerRow-0"')
table.insert(resultPart, '\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients')
--Adding value/bar for things other than smelting
if categoryID > 0 then
table.insert(resultPart, '!!Value/Bar')
end
table.sort(recipeList, function(a, b)
if a.level ~= b.level then
return a.level < b.level
else
return a.itemName < b.itemName
end
end)
for i, recipeDef in ipairs(recipeList) do
local recipe = SkillData.Smithing.Recipes[recipeDef.id]
local totalValue = recipe.baseQuantity * recipeDef.itemValue
-- Determine the bar quantity & build the recipe cost string
local barQty, costString = 0, {}
for j, itemCost in ipairs(recipe.itemCosts) do
local costItem = Items.getItemByID(itemCost.id)
if costItem ~= nil then
table.insert(costString, Icons.Icon({costItem.name, type='item', qty=itemCost.qty, notext=true}))
end
if barIDList[itemCost.id] then
barQty = barQty + itemCost.qty
end
end
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n| ' .. Icons.Icon({recipeDef.itemName, type='item', size=50, notext=true}))
table.insert(resultPart, '\r\n| ')
if recipe.baseQuantity > 1 then
table.insert(resultPart, recipe.baseQuantity .. 'x ')
end
table.insert(resultPart, Icons.Icon({recipeDef.itemName, type='item', noicon=true}))
table.insert(resultPart, '\r\n|data-sort-value="' .. recipe.level .. '"| ' .. Icons._SkillReq('Smithing', recipe.level))
table.insert(resultPart, '\r\n|data-sort-value="' .. recipe.baseXP .. '"| ' .. Shared.formatnum(recipe.baseXP))
table.insert(resultPart, '\r\n|data-sort-value="' .. totalValue .. '"| ' .. Icons.GP(recipeDef.itemValue))
if recipe.baseQuantity > 1 then
table.insert(resultPart, ' (x' .. recipe.baseQuantity .. ')')
end
table.insert(resultPart, '\r\n| ' .. table.concat(costString, ', '))
if categoryID > 0 then
local barVal, barValTxt = 0, 'N/A'
if barQty > 0 then
barVal = totalValue / barQty
barTxt = Icons.GP(Shared.round(barVal, 1, 1))
end
table.insert(resultPart, '\r\n|data-sort-value="' .. barVal .. '"| ' .. barTxt)
end
end
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
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.level)
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


return p
return p