Module:Skills: Difference between revisions

Adjusted the appearance of the Lesser Relics table
(Move Farming functions to Module:Skills/Gathering)
(Adjusted the appearance of the Lesser Relics table)
 
(29 intermediate revisions by 3 users not shown)
Line 15: Line 15:


local p = {}
local p = {}
local ItemData = mw.loadData('Module:Items/data')
local SkillData = mw.loadData('Module:Skills/data')


local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Items = require('Module:Items')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')


local MasteryCheckpoints = {.1, .25, .5, .95}
-- 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
return SkillData.Agility.obstacleUnlockLevels[recipe.category+1]
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
function p.getThievingNPCByID(npcID)
return GameData.getEntityByID(SkillData.Thieving.npcs, npcID)
end
function p.getThievingNPC(npcName)
function p.getThievingNPC(npcName)
local result = nil
return GameData.getEntityByName(SkillData.Thieving.npcs, npcName)
for i, npc in Shared.skpairs(SkillData.Thieving.NPCs) do
if npc.name == npcName then
result = Shared.clone(npc)
break
end
end
return result
end
end


function p.getThievingNPCArea(npc)
function p.getThievingNPCArea(npc)
if type(npc) == 'string' then
for i, area in ipairs(SkillData.Thieving.areas) do
npc = p.getThievingNPC(npc)
for j, npcID in ipairs(area.npcIDs) do
end
 
local result = nil
for i, area in Shared.skpairs(SkillData.Thieving.Areas) do
for j, npcID in pairs(area.npcs) do
if npcID == npc.id then
if npcID == npc.id then
result = area
return area
break
end
end
end
end
end
end
return result
end
end


Line 81: Line 122:
local npc = p.getThievingNPC(npcName)
local npc = p.getThievingNPC(npcName)
if npc == nil then
if npc == nil then
return "ERROR: Invalid Thieving NPC "..npcName.."[[Category:Pages with script errors]]"
return Shared.printError('Invalid Thieving NPC ' .. npcName)
end
end


Line 89: Line 130:
function p.getThievingSourcesForItem(itemID)
function p.getThievingSourcesForItem(itemID)
local resultArray = {}
local resultArray = {}
local areaNPCs = {}
local areaNPCs = {}


--First check area unique drops
--First check area unique drops
--If an area drops the item, add all the NPC ids to the list so we can add them later
--If an area drops the item, add all the NPC ids to the list so we can add them later
if not result then
for i, area in pairs(SkillData.Thieving.areas) do
for i, area in pairs(SkillData.Thieving.Areas) do
for j, drop in pairs(area.uniqueDrops) do
for j, drop in pairs(area.uniqueDrops) do
if drop.id == itemID then
if drop.itemID == itemID then
for k, npcID in ipairs(area.npcIDs) do
for k, npcID in pairs(area.npcs) do
areaNPCs[npcID] = { qty = drop.quantity, area = area }
areaNPCs[npcID] = drop.qty
end
break
end
end
break
end
end
end
end
Line 108: Line 146:


--Now go through and get drop chances on each NPC if needed
--Now go through and get drop chances on each NPC if needed
for i, npc in pairs(SkillData.Thieving.NPCs) do
for i, npc in pairs(SkillData.Thieving.npcs) do
local totalWt = 0
local totalWt = 0
local dropWt = 0
local dropWt = 0
local dropQty = 0
local dropQty = { min = 0, max = 0 }
for j, drop in pairs(npc.lootTable) do
for j, drop in ipairs(npc.lootTable) do
totalWt = totalWt + drop[2]
totalWt = totalWt + drop.weight
if drop[1] == itemID then
if drop.itemID == itemID then
dropWt = drop[2]
dropWt = drop.weight
dropQty = drop[3]
dropQty = { min = drop.minQuantity, max = drop.maxQuantity }
end
end
end
end
if dropWt > 0 then
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})
table.insert(resultArray, {npc = npc.name, minQty = dropQty.min, maxQty = dropQty.max, wt = dropWt * SkillData.Thieving.itemChance, totalWt = totalWt * 100, level = npc.level, npcID = npc.id, type = 'npc'})
end
end


--Chance of -1 on unique drops is to indicate variable chance
--Chance of -1 on unique drops is to indicate variable chance
if npc.uniqueDrop ~= nil and npc.uniqueDrop.itemID == itemID then
if npc.uniqueDrop ~= nil and npc.uniqueDrop.id == itemID then
table.insert(resultArray, {npc = npc.name, minQty = npc.uniqueDrop.qty, maxQty = npc.uniqueDrop.qty, wt = -1, totalWt = -1, level = npc.level})
table.insert(resultArray, {npc = npc.name, minQty = npc.uniqueDrop.quantity, maxQty = npc.uniqueDrop.quantity, wt = -1, totalWt = -1, level = npc.level, npcID = npc.id, type = 'npcUnique'})
end
end


if areaNPCs[npc.id] ~= nil then
local areaNPC = areaNPCs[npc.id]
table.insert(resultArray, {npc = npc.name, minQty = areaNPCs[npc.id], maxQty = areaNPCs[npc.id], wt = SkillData.Thieving.AreaUniqueChance, totalWt = 100, level = npc.level})
if areaNPC ~= nil then
table.insert(resultArray, {npc = npc.name, minQty = areaNPC.qty, maxQty = areaNPC.qty, wt = SkillData.Thieving.baseAreaUniqueChance, totalWt = 100, level = npc.level, npcID = npc.id, area = areaNPC.area, type = 'areaUnique'})
end
end
end
end


for i, drop in pairs(SkillData.Thieving.RareItems) do
for i, drop in ipairs(SkillData.Thieving.generalRareItems) do
if drop.itemID == itemID then
if drop.itemID == itemID then
table.insert(resultArray, {npc = 'all', minQty = 1, maxQty = 1, wt = 1, totalWt = Shared.round2(1/(drop.chance/100), 0), level = 1})
if drop.npcs == nil then
table.insert(resultArray, {npc = 'all', minQty = 1, maxQty = 1, wt = 1, totalWt = Shared.round2(1/(drop.chance/100), 0), level = 1, npcID = itemID, type = 'generalRare'})
else
for j, npcID in ipairs(drop.npcs) do
local npc = p.getThievingNPCByID(npcID)
if npc ~= nil then
table.insert(resultArray, {npc = npc.name, minQty = 1, maxQty = 1, wt = 1, totalWt = Shared.round2(1/(drop.chance/100), 0), level = npc.level, npcID = npc.id, type = 'generalRare'})
end
end
end
end
end
end
end
Line 144: Line 192:
-- Astrology
-- Astrology
function p.getConstellationByID(constID)
function p.getConstellationByID(constID)
return SkillData.Astrology.Constellations[constID]
return GameData.getEntityByID(SkillData.Astrology.recipes, constID)
end
end


function p.getConstellation(constName)
function p.getConstellation(constName)
for i, const in ipairs(SkillData.Astrology.Constellations) do
return GameData.getEntityByName(SkillData.Astrology.recipes, constName)
if const.name == constName then
return const
end
end
return nil
end
end


function p.getConstellations(checkFunc)
function p.getConstellations(checkFunc)
local result = {}
return GameData.getEntities(SkillData.Astrology.recipes, checkFunc)
for i, const in ipairs(SkillData.Astrology.Constellations) do
if checkFunc(const) then
table.insert(result, const)
end
end
return result
end
end


Line 203: Line 240:
table.insert(modTypes, 'uniqueModifiers')
table.insert(modTypes, 'uniqueModifiers')
end
end
local masteryReq = {
['standardModifiers'] = { 1, 40, 80 },
['uniqueModifiers'] = { 20, 60, 99 }
}


local modArray = {}
local modArray = {}
local isSkillMod = {}
local isSkillMod = {}
--Adding a Group Number to hold together different bonuses from the same modifier [Falterfire 22/10/27]
local groupNum = 0
for _, modType in ipairs(modTypes) do
for _, modType in ipairs(modTypes) do
for i, skillMods in ipairs(cons[modType]) do
for i, modTypeData in ipairs(cons[modType]) do
local skillID = cons.skills[i]
groupNum = masteryReq[modType][i]
if skillID ~= nil then
local modVal = nil
for j, modName in ipairs(skillMods) do
if modValue ~= nil then
local modBaseName, modText, sign, isNegative, unsign, modBase = Constants.getModifierDetails(modName)
modVal = modValue
-- Check if modifier varies by skill, and amend the modifier value accordingly
else
local modVal = modValue
modVal = modTypeData.incrementValue * modTypeData.maxCount
if Shared.contains(modText, '{SV0}') then
end
isSkillMod[modName] = true
for j, modifier in ipairs(modTypeData.modifiers) do
modVal = {skillID, modValue}
local modEntry = (modifier.skill ~= nil and { skillID = modifier.skill, value = modVal }) or modVal
end
addToArray(modArray, {modifier.key, modEntry, group = groupNum})
addToArray(modArray, {modName, modVal})
end
end
end
end
end
Line 228: Line 270:
for i, modDefn in ipairs(modArray) do
for i, modDefn in ipairs(modArray) do
local modName, modVal = modDefn[1], modDefn[2]
local modName, modVal = modDefn[1], modDefn[2]
local isSkill = isSkillMod[modName]
local isSkill = type(modVal) == 'table' and modVal.skillID ~= nil
if modArrayKV[modName] == nil then
if modArrayKV[modName] == nil then
modArrayKV[modName] = (isSkill and { modVal } or modVal)
modArrayKV[modName] = (isSkill and { modVal } or modVal)
Line 248: Line 290:
local skillID = Constants.getSkillID(skillName)
local skillID = Constants.getSkillID(skillName)
if skillID == nil then
if skillID == nil then
return "ERROR: Failed to find a skill ID for "..skillName
return Shared.printError('Failed to find a skill ID for ' .. skillName)
end
end


local unlockTable = SkillData.MasteryUnlocks[skillID]
local _, localSkillID = GameData.getLocalID(skillID)
-- Clone so that we can sort by level
local unlockTable = Shared.clone(SkillData[localSkillID].masteryLevelUnlocks)
if unlockTable == nil then
if unlockTable == nil then
return 'ERROR: Failed to find Mastery Unlock data for '..skillName
return Shared.printError('Failed to find Mastery Unlock data for ' .. skillName)
end
end
table.sort(unlockTable, function(a, b) return (a.level == b.level and a.descriptionID < b.descriptionID) or a.level < b.level end)


local result = '{|class="wikitable"\r\n!Level!!Unlock'
local result = '{|class="wikitable"\r\n!Level!!Unlock'
for i, unlock in Shared.skpairs(unlockTable) do
for i, unlock in ipairs(unlockTable) do
result = result..'\r\n|-'
result = result..'\r\n|-'
result = result..'\r\n|'..unlock.level..'||'..unlock.unlock
result = result..'\r\n|'..unlock.level..'||'..unlock.description
end
end
result = result..'\r\n|}'
result = result..'\r\n|}'
Line 269: Line 314:
local skillID = Constants.getSkillID(skillName)
local skillID = Constants.getSkillID(skillName)
if skillID == nil then
if skillID == nil then
return "ERROR: Failed to find a skill ID for "..skillName
return Shared.printError('Failed to find a skill ID for ' .. skillName)
end
end


if SkillData.MasteryCheckpoints[skillID] == nil then
local _, localSkillID = GameData.getLocalID(skillID)
return 'ERROR: Failed to find Mastery Unlock data for '..skillName
local checkpoints = SkillData[localSkillID].masteryCheckpoints
if checkpoints == nil then
return Shared.printError('Failed to find Mastery Unlock data for ' .. skillName)
end
end


local bonuses = SkillData.MasteryCheckpoints[skillID].bonuses
local totalPoolXP = SkillData[localSkillID].baseMasteryPoolCap
local totalPoolXP = SkillData.MasteryPoolXP[skillID + 1]
local checkpointPct = GameData.rawData.masteryCheckpoints
 
local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus'
local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus'
for i, bonus in Shared.skpairs(bonuses) do
for i, checkpointDesc in ipairs(checkpoints) do
result = result..'\r\n|-'
result = result..'\r\n|-'
result = result..'\r\n|'..(MasteryCheckpoints[i] * 100)..'%||'
result = result..'\r\n|'..checkpointPct[i]..'%||'
result = result..Shared.formatnum(totalPoolXP * MasteryCheckpoints[i])..' xp||'..bonus
result = result..Shared.formatnum(math.floor(totalPoolXP * checkpointPct[i] / 100))..' xp||'..checkpointDesc
end
end
result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP'
result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP'
Line 292: Line 338:


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 masterySkills = {}
local masteryActionCount = {}
local CCI_ID = 'melvorD:Clue_Chasers_Insignia'
local CCI = Items.getItemByID(CCI_ID)
if CCI == nil then
return Shared.printError('Failed to find item with ID ' .. CCI_ID)
end


-- Find all mastery tokens
-- Iterate over each skill with mastery, determining the number of
local masteryTokens = Items.getItems(function(item) return item.isToken ~= nil and item.skill ~= nil and item.isToken end)
-- mastery actions for each
for i, item in pairs(masteryTokens) do
for skillLocalID, skill in pairs(SkillData) do
local milestones = SkillData.Milestones[item.skill + 1]
if skill.masteryTokenID ~= nil then
if milestones ~= nil then
local actCount = { ["skill"] = skill }
table.insert(masterySkills, {tokenRef = i, skillID = item.skill, milestoneCount = milestones})
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(masterySkills, function(a, b)
if a['milestoneCount'] == b['milestoneCount'] then
return a['skillID'] < b['skillID']
else
return a['milestoneCount'] > b['milestoneCount']
end
end)


local firstID = skillLevels[1].id
table.sort(masteryActionCount,
function(a, b)
if a[firstID] == b[firstID] then
return a.skill.name < b.skill.name
else
return a[firstID] > b[firstID]
end
end)
-- Generate output table
-- Generate output table
local resultPart = {}
local resultPart = {}
local CCI = Items.getItem('Clue Chasers Insignia')
local CCIIcon = Icons.Icon({CCI.name, type='item', notext=true})
local CCIIcon = Icons.Icon({'Clue Chasers Insignia', type='item', notext=true})
local columnPairs = Shared.tableCount(skillLevels)
if CCI == nil then return '' end


-- Generate header
table.insert(resultPart, '{| class="wikitable sortable"')
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, '\n!rowspan="3"|Token!!rowspan="3"|Skill!!colspan="' .. columnPairs * 2 .. '"|Approximate Mastery Token Chance')
table.insert(resultPart, '\r\n|-\r\n!Without ' .. CCIIcon .. '!!With ' .. CCIIcon)
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, m in ipairs(masterySkills) do
for i, rowData in ipairs(masteryActionCount) do
local token = masteryTokens[m.tokenRef]
local token = Items.getItemByID(rowData.skill.masteryTokenID)
local denom = math.floor(baseTokenChance / m['milestoneCount'])
table.insert(resultPart, '\n|-')
local denomCCI = Shared.round(baseTokenChance / (m['milestoneCount'] * (1 + CCI.increasedItemChance / 100)), 0, 0)
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'}))


table.insert(resultPart, '\r\n|-')
for j, levelDef in ipairs(skillLevels) do
table.insert(resultPart, '\r\n|style="text-align:center"|' .. Icons.Icon({token.name, type='item', size=50, notext=true}))
local actCount = rowData[levelDef.id]
table.insert(resultPart, '\r\n|' .. Icons.Icon({Constants.getSkillName(m['skillID']), type='skill'}))
local denom, denomCCI = 0, 0
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denom .. '"|1/' .. Shared.formatnum(denom))
if actCount > 0 then
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denomCCI .. '"|1/' .. Shared.formatnum(denomCCI))
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, '\r\n|}')
table.insert(resultPart, '\n|}')


return table.concat(resultPart)
return table.concat(resultPart)
Line 339: Line 435:
-- Skill unlock costs for Adventure game mode
-- Skill unlock costs for Adventure game mode
function p.getSkillUnlockCostTable()
function p.getSkillUnlockCostTable()
local returnPart = {}
local advMode = GameData.getEntityByID('gamemodes', 'melvorF:Adventure')
table.insert(returnPart, '{| class="wikitable stickyHeader"\r\n|- class="headerRow-0"\r\n!Unlock!!Cost!!Cumulative Cost')
if advMode ~= nil then
 
local unlockCount = Shared.tableCount(GameData.skillData) - Shared.tableCount(advMode.startingSkills)
local accCost = 0
local costLength = Shared.tableCount(advMode.skillUnlockCost)
for i, cost in ipairs(SkillData.SkillUnlockCosts) do
local returnPart = {}
accCost = accCost + cost
table.insert(returnPart, '{| class="wikitable stickyHeader"\r\n|- class="headerRow-0"\r\n!Unlock!!Cost!!Cumulative 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
 
-- 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
local accCost = 0
-- The bar list will be used later for value/bar calculations
for i = 1, unlockCount, 1 do
local recipeList, barIDList = {}, {}
local cost = advMode.skillUnlockCost[math.min(i, costLength)]
for i, recipe in ipairs(SkillData.Smithing.Recipes) do
accCost = accCost + cost
if recipe.category == categoryID then
table.insert(returnPart, '|-')
local recipeItem = Items.getItemByID(recipe.itemID)
table.insert(returnPart, '|' .. i .. '||' .. Icons.GP(cost) .. '||' .. Icons.GP(accCost))
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
end
table.insert(returnPart, '|}')


-- Generate output table
return table.concat(returnPart, '\r\n')
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
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
end


Line 462: Line 464:
table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s')
table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s')


for i, logData in Shared.skpairs(SkillData.Firemaking) do
for i, logData in ipairs(SkillData.Firemaking.logs) do
local logs = Items.getItemByID(logData.logID)
local logs = Items.getItemByID(logData.logID)
local name = logs.name
local name = logs.name
local burnTime = logData.baseInterval / 1000
local burnTime = logData.baseInterval / 1000
local bonfireTime = logData.baseBonfireInterval / 1000
local bonfireTime = logData.baseBonfireInterval / 1000
local XPS = logData.baseXP / burnTime
local XPS = logData.baseExperience / burnTime
local XP_BF = logData.baseXP * (1 + logData.bonfireXPBonus / 100)
local XP_BF = logData.baseExperience * (1 + logData.bonfireXPBonus / 100)
local XPS_BF = XP_BF / burnTime
local XPS_BF = Shared.round(XP_BF / burnTime, 2, 2)
XP_BF = Shared.round(XP_BF, 2, 0)


table.insert(resultPart, '\r\n|-')
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, '\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='item', size='50', notext=true}))
table.insert(resultPart, '||[['..name..']]')
table.insert(resultPart, '||'..Icons.getExpansionIcon(logs.id)..Icons.Icon({name, type='item', noicon=true}))
table.insert(resultPart, '||style ="text-align: right;"|'..logData.level)
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;" 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="' .. logData.baseExperience .. '"| ' .. Shared.formatnum(logData.baseExperience))
table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS..'"|'..Shared.round(XPS, 2, 2))
table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS..'"|'..Shared.formatnum(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="' .. XP_BF .. '"| ' .. Shared.formatnum(XP_BF))
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="'..XPS_BF..'"|'..Shared.formatnum(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="'..logData.bonfireXPBonus..'"|'..logData.bonfireXPBonus..'%')
table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..bonfireTime..'"|'..Shared.timeString(bonfireTime, true))
table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..bonfireTime..'"|'..Shared.timeString(bonfireTime, true))
Line 486: Line 489:
table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
return table.concat(resultPart)
end
function p.getAncientRelicsTable(frame)
local skillName = frame.args ~= nil and frame.args[1] or frame
local skillID = nil
if skillName ~= nil and skillName ~= '' then
skillID = Constants.getSkillID(skillName)
if skillID == nil then
return Shared.printError('Failed to find a skill ID for ' .. skillName)
end
end
local resultPart = {}
table.insert(resultPart, '{| class="wikitable sortable stickyHeader lighttable"')
table.insert(resultPart, '\n|-class="headerRow-0"')
table.insert(resultPart, '\n|-\n!colspan="2"|Skill\n!Relic\n!Modifiers')
local relics = GameData.getEntities('ancientRelics',
function(relic)
return skillID == nil or relic.skillID == skillID
end)
table.sort(relics,
function (a, b)
local skillNameA, skillNameB = Constants.getSkillName(a.skillID), Constants.getSkillName(b.skillID)
if skillNameA == skillNameB then
-- Order by numbers at the end of relic IDs
-- Relics have a 'number' property, but this appears to contain duplicates
return string.sub(a.id, string.len(a.id)) < string.sub(b.id, string.len(b.id))
else
return skillNameA < skillNameB
end
end)
local function appendSkillRows(resultTable, rowTable, relicCount, skillID)
local skillName = Constants.getSkillName(skillID)
table.insert(resultTable, '\n|-\n|rowspan="' .. relicCount .. '"| ' .. Icons.Icon({skillName, type='skill', notext=true, size=50}))
table.insert(resultTable, '\n|rowspan="' .. relicCount .. '"| ' .. Icons.Icon({skillName, type='skill', noicon=true}))
table.insert(resultTable, table.concat(rowTable))
end
local skillRelicCount, currentSkillID, tablePart = 0, nil, {}
for i, relic in ipairs(relics) do
if currentSkillID == nil then
currentSkillID = relic.skillID
elseif relic.skillID ~= currentSkillID then
appendSkillRows(resultPart, tablePart, skillRelicCount, currentSkillID)
tablePart = {}
currentSkillID = relic.skillID
skillRelicCount = 0
end
skillRelicCount = skillRelicCount + 1
if skillRelicCount > 1 then
table.insert(tablePart, '\n|-')
end
table.insert(tablePart, '\n| ' .. skillRelicCount .. '\n| ' .. Constants.getModifiersText(relic.modifiers))
end
appendSkillRows(resultPart, tablePart, skillRelicCount, currentSkillID)
table.insert(resultPart, '\n|}')
return table.concat(resultPart)
end
function p.getLesserRelicsTable(frame)
local lesserRelics = {}
-- Iterate over each skill with a global rare drop then check
-- if the skill has a Lesser Relic drop
for skillLocalID, skill in pairs(SkillData) do
if skill.rareDrops ~= nil then
for i, drops in pairs(skill.rareDrops) do
if string.match(drops.itemID, '_Lesser_Relic') then
table.insert(lesserRelics, Items.getItemByID(drops.itemID))
end
end
end
end
table.sort(lesserRelics, function(a, b) return a.name < b.name end)
-- Create the Table
local resultTable = mw.html.create('table')
resultTable:addClass('wikitable sortable')
resultTable:tag('tr'):addClass('headerRow-0')
:tag('th'):wikitext('Icon')
:tag('th'):wikitext('Lesser Relic')
:tag('th'):wikitext('Modifiers')
for _, relic in ipairs(lesserRelics) do
local tr = mw.html.create('tr')
tr:tag('td'):wikitext(Icons.Icon({relic.name, type='item', size='50', notext=true}))
tr:tag('td'):wikitext(Icons.Icon({relic.name, type='item', noicon=true}))
tr:tag('td'):wikitext(Constants.getModifiersText(relic.modifiers))
resultTable:node(tr)
end
return resultTable
end
end


return p
return p
463

edits