Anonymous

Module:Skills/Gathering: Difference between revisions

From Melvor Idle
Move functions to Module:Skills; Move Farming functions from Module:Skills
(added getThievingNPCTable)
(Move functions to Module:Skills; Move Farming functions from Module:Skills)
(41 intermediate revisions by 3 users not shown)
Line 9: Line 9:
local Items = require('Module:Items')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
 
local Skills = require('Module:Skills')
local thievingNormalLootChance = 75
local ItemSourceTables = require('Module:Items/SourceTables')
local thievingAreaLootChance = 0.2


function p.getAxeTable(frame)
function p.getAxeTable(frame)
Line 148: Line 147:
result = result..'||'..treeName..''
result = result..'||'..treeName..''
result = result..'||style="min-width:25px" data-sort-value="'..logName..'"|'..Icons.Icon({logName, type='item', notext=true, size=50})
result = result..'||style="min-width:25px" data-sort-value="'..logName..'"|'..Icons.Icon({logName, type='item', notext=true, size=50})
result = result..'||[['..logName..']]'
result = result..'||'..Icons.Icon({logName, type='item', noicon=true})
result = result..'||style="text-align:right"|'..tree.level
result = result..'||style="text-align:right"|'..tree.levelRequired
result = result..'||style="text-align:right"|'..tree.xp
result = result..'||style="text-align:right"|'..tree.baseExperience
result = result..'||style="text-align:right" data-sort-value="'..tree.interval..'"|'..Shared.timeString(tree.interval/1000, true)
result = result..'||style="text-align:right" data-sort-value="'..tree.baseInterval..'"|'..Shared.timeString(tree.baseInterval/1000, true)
local XPs = tree.xp / (tree.interval / 1000)
local XPs = tree.baseExperience / (tree.baseInterval / 1000)
local Log = Items.getItemByID(i - 1)
local Log = Items.getItemByID(tree.logID)
local GPs = Log.sellsFor / (tree.interval / 1000)
local GPs = Log.sellsFor / (tree.baseInterval / 1000)
result = result..'||style="text-align:right"|'..Shared.round(XPs, 2, 2)
result = result..'||style="text-align:right"|'..Shared.round(XPs, 2, 2)
result = result..'||style="text-align:right" data-sort-value="'..GPs..'"|'..Icons.GP(Shared.round(GPs, 2, 2))
result = result..'||style="text-align:right" data-sort-value="'..GPs..'"|'..Icons.GP(Shared.round(GPs, 2, 2))
Line 164: Line 163:


function p.getSpecialFishingTable(frame)
function p.getSpecialFishingTable(frame)
local lootValue = 0
local totalWt, lootValue = 0, 0
local totalWt = Items.specialFishWt
local itemArray = Shared.clone(SkillData.Fishing.SpecialItems)
for i, itemDef in ipairs(itemArray) do
totalWt = totalWt + itemDef[2]
end
-- Sort the loot table by weight in descending order
table.sort(itemArray, function(a, b) return (a[2] == b[2] and a[1] < b[1]) or a[2] > b[2] end)


local result = ''
local resultPart = {}
result = result..'\r\n{|class="wikitable sortable stickyHeader"'
table.insert(resultPart, '\r\n{|class="wikitable sortable stickyHeader"')
result = result..'\r\n|- class="headerRow-0"'
table.insert(resultPart, '\r\n|- class="headerRow-0"\r\n!colspan="2"| Item\r\n!Value\r\n!colspan="2"|Chance')
result = result..'\r\n!Item'
for i, itemDef in ipairs(itemArray) do
result = result..'!!Price!!colspan="2"|Chance'
local item = Items.getItemByID(itemDef[1])
 
if item ~= nil then
--Sort the loot table by weight in descending order
local dropChance = itemDef[2] / totalWt * 100
table.sort(Items.specialFishLoot, function(a, b) return a[2] > b[2] end)
-- If chance is less than 0.10% then show 2 significant figures, otherwise 2 decimal places
for i, row in pairs(Items.specialFishLoot) do
local fmt = (dropChance < 0.10 and '%.2g') or '%.2f'
local thisItem = Items.getItemByID(row[1])
table.insert(resultPart, '\r\n|-\r\n|style="text-align:center"| ' .. Icons.Icon({item.name, type='item', notext=true}))
result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
table.insert(resultPart, '\r\n| ' .. Icons.Icon({item.name, type='item', noicon=true}))
result = result..'||style="text-align:left" data-sort-value="'..thisItem.sellsFor..'"'
table.insert(resultPart, '\r\n|data-sort-value="' .. item.sellsFor .. '"| ' .. Icons.GP(math.floor(item.sellsFor)))
result = result..'|'..Icons.GP(thisItem.sellsFor)
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. itemDef[2] .. '"| ' .. Shared.fraction(itemDef[2], totalWt))
 
table.insert(resultPart, '\r\n|style="text-align:right"| ' .. string.format(fmt, dropChance) .. '%')
local dropChance = (row[2] / totalWt) * 100
lootValue = lootValue + (dropChance / 100 * item.sellsFor)
result = result..'||style="text-align:right" data-sort-value="'..row[2]..'"'
end
result = result..'|'..Shared.fraction(row[2], totalWt)
result = result..'||style="text-align:right"|'..Shared.round(dropChance, 2, 2)..'%'
lootValue = lootValue + (dropChance * 0.01 * thisItem.sellsFor)
end
end
result = result..'\r\n|}'
table.insert(resultPart, '\r\n|}\r\nThe average value of a roll on the special fishing loot table is ' .. Icons.GP(Shared.round(lootValue, 2, 0)))
result = result..'\r\nThe average value of a roll on the special fishing loot table is '..Icons.GP(Shared.round(lootValue, 2, 0))
return table.concat(resultPart)
 
return result
end
end


function p.getFishingJunkTable(frame)
function p.getFishingJunkTable(frame)
local result = '{| class="wikitable sortable stickyHeader"'
local resultPart = {}
result = result..'\r\n|- class="headerRow-0"'
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
result = result..'\r\n!colspan="2"|Item!!Value'
table.insert(resultPart, '\r\n|- class="headerRow-0"')
table.insert(resultPart, '\r\n!colspan="2"|Item!!Value')
local itemArray = Items.getItems(function(item) return item.type == "Junk" end)


local itemArray = {}
for i, itemID in ipairs(SkillData.Fishing.JunkItems) do
local item = Items.getItemByID(itemID)
if item ~= nil then
table.insert(itemArray, item)
end
end
table.sort(itemArray, function(a, b) return a.name < b.name end)
table.sort(itemArray, function(a, b) return a.name < b.name end)


for i, item in Shared.skpairs(itemArray) do
for i, item in ipairs(itemArray) do
result = result..'\r\n|-'
table.insert(resultPart, '\r\n|-')
result = result..'\r\n|style="min-width:25px"|'..Icons.Icon({item.name, type='item', notext='true', size='50'})..'||[['..item.name..']]'
table.insert(resultPart, '\r\n|style="min-width:25px"| ' .. Icons.Icon({item.name, type='item', notext=true, size=50}))
result = result..'||style="text-align:right;" data-sort-value="'..item.sellsFor..'"|'..Icons.GP(item.sellsFor)
table.insert(resultPart, '\r\n| ' .. Icons.Icon({item.name, type='item', noicon=true}))
table.insert(resultPart, '\r\n|data-sort-value="' .. item.sellsFor .. '"| ' .. Icons.GP(math.floor(item.sellsFor)))
end
end
 
table.insert(resultPart, '\r\n|}')
result = result..'\r\n|}'
return table.concat(resultPart)
 
return result
end
end


Line 221: Line 225:
local mineData = Shared.clone(SkillData.Mining.Rocks)
local mineData = Shared.clone(SkillData.Mining.Rocks)


table.sort(mineData, function(a, b) return a.level < b.level end)
table.sort(mineData, function(a, b) return a.levelRequired < b.levelRequired end)


for i, oreData in Shared.skpairs(mineData) do
for i, oreData in Shared.skpairs(mineData) do
local ore = Items.getItemByID(oreData.ore)
local ore = Items.getItemByID(oreData.oreID)
result = result..'\r\n|-\r\n|style="min-width:25px"|'..Icons.Icon({ore.name, type='item', size='50', notext=true})..'||[['..ore.name..']]'
result = result..'\r\n|-\r\n|style="min-width:25px"|'..Icons.Icon({ore.name, type='item', size='50', notext=true})
result = result..'||style="text-align:right"|'..oreData.level..'||style="text-align:right"|'..ore.miningXP
result = result..'||'..Icons.Icon({ore.name, type='item', noicon=true})
result = result..'||style="text-align:right" data-sort-value="'..oreData.respawnInterval..'"|'
result = result..'||style="text-align:right"|'..oreData.levelRequired..'||style="text-align:right"|'..oreData.baseExperience
result = result..Shared.timeString(oreData.respawnInterval / 1000, true)
result = result..'||style="text-align:right" data-sort-value="'..oreData.baseRespawnInterval..'"|'
result = result..Shared.timeString(oreData.baseRespawnInterval / 1000, true)
result = result..'||data-sort-value="'..ore.sellsFor..'"|'..Icons.GP(ore.sellsFor)
result = result..'||data-sort-value="'..ore.sellsFor..'"|'..Icons.GP(ore.sellsFor)
end
end
Line 245: Line 250:
local gem = Items.getItemByID(gemData.id)
local gem = Items.getItemByID(gemData.id)
result = result..'\r\n|-\r\n|style="min-width:25px"|'
result = result..'\r\n|-\r\n|style="min-width:25px"|'
result = result..Icons.Icon({gem.name, type='item', size='50', notext=true})..'||[['..gem.name..']]'
result = result..Icons.Icon({gem.name, type='item', size='50', notext=true})
result = result..'||'..Icons.Icon({gem.name, type='item', noicon=true})
result = result..'||style="text-align:right"|'..string.format("%.1f%%", gemData.chance)
result = result..'||style="text-align:right"|'..string.format("%.1f%%", gemData.chance)
result = result..'||data-sort-value="'..gem.sellsFor..'"|'..Icons.GP(gem.sellsFor)
result = result..'||data-sort-value="'..gem.sellsFor..'"|'..Icons.GP(gem.sellsFor)
Line 255: Line 261:


function p.getFishTable(frame)
function p.getFishTable(frame)
local data = Items.getItems(function(item) return item.fishingID ~= nil end)
local recipeList = {}
for i, recipe in ipairs(SkillData.Fishing.Fish) do
table.insert(recipeList, recipe)
end
table.sort(recipeList, function(a, b) return (a.level == b.level and a.masteryID < b.masteryID) or a.level < b.level end)


table.sort(data, function(a, b) return a.fishingID < b.fishingID end)
-- Determine cooking levels for all fish
 
local cookReq = {}
local result = '{| class="wikitable sortable stickyHeader"'
for i, recipe in ipairs(SkillData.Cooking.Recipes) do
result = result..'\r\n|- class="headerRow-0"'
-- This assumes that each raw fish only appears in a single recipe, which is a bit rubbish
result = result..'\r\n!Fish\r\n!Name\r\n!'..Icons.Icon({'Fishing', type='skill', notext=true})..' Level\r\n!Catch Time'
-- but currently holds
result = result..'\r\n!Experience\r\n!Fish Price\r\n!'..Icons.Icon({'Cooking', type='skill', notext=true})..' Level'
for j, mat in ipairs(recipe.itemCosts) do
if cookReq[mat.id] == nil then
cookReq[mat.id] = recipe.level
end
end
end


for i, fish in Shared.skpairs(data) do
local resultPart = {}
result = result..'\r\n|-'
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
result = result..'\r\n| style="text-align: left;" | '..Icons.Icon({fish.name, type='item', size='50', notext=true})
table.insert(resultPart, '\r\n|- class="headerRow-0"')
result = result..'\r\n| style ="text-align: left;" |[['..fish.name..']]'
table.insert(resultPart, '\r\n!Fish\r\n!Name\r\n!' .. Icons.Icon({'Fishing', type='skill', notext=true}) .. ' Level\r\n!Catch Time')
result = result..'\r\n| style="text-align:right"|'..fish.fishingLevel
table.insert(resultPart, '\r\n!XP\r\n!Value\r\n!XP/s\r\n!GP/s')
 
table.insert(resultPart, '\r\n!' .. Icons.Icon({'Cooking', type='skill', notext=true}) .. ' Level')
local timeSortVal = (fish.minFishingInterval + fish.maxFishingInterval) / 2
for i, recipe in ipairs(recipeList) do
local timeStr = string.format("%.1fs-%.1fs", (fish.minFishingInterval/1000), (fish.maxFishingInterval/1000))
local fish = Items.getItemByID(recipe.itemID)
result = result..'\r\n| style="text-align:right" data-sort-value="'..timeSortVal..'"|'..timeStr
if fish ~= nil then
result = result..'\r\n| style="text-align:right"|'..fish.fishingXP
local timeSortVal = (recipe.baseMinInterval + recipe.baseMaxInterval) / 2000
result = result..'\r\n| style="text-align:right"|'..fish.sellsFor
local timeStr = string.format("%.1fs - %.1fs", recipe.baseMinInterval / 1000, recipe.baseMaxInterval / 1000)
 
local XPs = recipe.baseXP / timeSortVal
local cookStr = "N/A"
local GPs = fish.sellsFor / timeSortVal
if fish.cookingLevel ~= nil then
local cookSortVal = cookReq[recipe.itemID] or 0
cookStr = fish.cookingLevel
local cookStr = cookReq[recipe.itemID] or 'N/A'
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|style="text-align:center"| ' .. Icons.Icon({fish.name, type='item', size='50', notext=true}))
table.insert(resultPart, '\r\n| ' .. Icons.Icon({fish.name, type='item', noicon=true}))
table.insert(resultPart, '\r\n|style="text-align:right"| ' .. recipe.level)
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. timeSortVal .. '"| ' .. timeStr)
table.insert(resultPart, '\r\n|style="text-align:right"| ' .. recipe.baseXP)
table.insert(resultPart, '\r\n|data-sort-value="' .. fish.sellsFor .. '"| ' .. Icons.GP(fish.sellsFor))
table.insert(resultPart, '\r\n|style="text-align:right"| ' .. Shared.round(XPs, 2, 2))
table.insert(resultPart, '\r\n|data-sort-value="' .. GPs .. '"|' .. Icons.GP(Shared.round(GPs, 2, 2)))
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. cookSortVal .. '"| ' .. cookStr)
end
end
result = result..'\r\n| style="text-align:right"|'..cookStr
end
end
 
table.insert(resultPart, '\r\n|}')
result = result..'\r\n|}'
return table.concat(resultPart)
return result
end
end


function p.getFishingAreasTable(frame)
function p.getFishingAreasTable(frame)
local result = '{| class="wikitable sortable stickyHeader"'
local result = '{| class="wikitable sortable stickyHeader"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n|- class="headerRow-0"'
Line 294: Line 316:
result = result..'\r\n!Junk Chance\r\n!Special Chance'
result = result..'\r\n!Junk Chance\r\n!Special Chance'


for i, area in Shared.skpairs(SkillData.Fishing.Areas) do
for i, area in ipairs(SkillData.Fishing.Areas) do
result = result..'\r\n|-'
result = result..'\r\n|-'
result = result..'\r\n| style ="text-align: left;" |'..area.name
result = result..'\r\n| style ="text-align: left;" |'..area.name


local fishArray = {}
local fishArray = {}
for j, fish in Shared.skpairs(area.fish) do
for j, fish in ipairs(area.fish) do
local fishTable = Items.getItems(function(item) return item.fishingID == fish end)
local fishItem = Items.getItemByID(fish.itemID)
local fishItem = fishTable[0] or fishTable[1]
if fishItem ~= nil then
table.insert(fishArray, Icons.Icon({fishItem.name, type='item'}))
table.insert(fishArray, Icons.Icon({fishItem.name, type='item'}))
end
end
end
result = result..'\r\n|'..table.concat(fishArray, '<br />')
result = result..'\r\n|'..table.concat(fishArray, '<br/>')


result = result..'\r\n| style="text-align:right"|'..area.fishChance..'%'
result = result..'\r\n| style="text-align:right"|'..area.fishChance..'%'
Line 315: Line 338:
end
end


function p.getThievingNPC(npcName)
function p.getThievingGeneralRareTable(frame)
local result = nil
local rareTxt = '{|class="wikitable sortable"'
for i, npc in Shared.skpairs(SkillData.Thieving.NPCs) do
rareTxt = rareTxt..'\r\n!Item!!Qty'
if npc.name == npcName then
rareTxt = rareTxt..'!!Price!!colspan="2"|Chance'
result = Shared.clone(npc)
for i, drop in pairs(SkillData.Thieving.RareItems) do
break
local thisItem = Items.getItemByID(drop.itemID)
end
local odds = drop.chance
end
return result
end


function p.getThievingNPCArea(npc)
rareTxt = rareTxt..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
if type(npc) == 'string' then
rareTxt = rareTxt..'||1||data-sort-value="'..thisItem.sellsFor..'"|'..Icons.GP(thisItem.sellsFor)
npc = p.getThievingNPC(npc)
rareTxt = rareTxt..'||style="text-align:right" data-sort-value="'..odds..'"|'..Shared.fraction(1, Shared.round2(1/(odds/100), 0))
rareTxt = rareTxt..'||style="text-align:right" data-sort-value="'..odds..'"|'..Shared.round(odds, 4, 4)..'%'
end
end
rareTxt = rareTxt..'\r\n|}'
local result = nil
return rareTxt
for i, area in Shared.skpairs(SkillData.Thieving.Areas) do
for j, npcID in pairs(area.npcs) do
if npcID == npc.id then
result = area
break
end
end
end
return result
end
 
function p._getThievingNPCStat(npc, statName)
local result = nil
if statName == 'level' then
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
if result == nil then
result = ''
end
return result
end
 
function p.getThievingNPCStat(frame)
local npcName = frame.args ~= nil and frame.args[1] or frame[1]
local statName = frame.args ~= nil and frame.args[2] or frame[2]
local npc = p.getThievingNPC(npcName)
if npc == nil then
return "ERROR: Invalid Thieving NPC "..npcName.."[[Category:Pages with script errors]]"
end
return p._getThievingNPCStat(npc, statName)
end
end


Line 378: Line 358:
local result = ''
local result = ''
local sectionTxt = {}
local sectionTxt = {}
 
--Five sections here: GP, normal loot, area loot, rare loot, and unique item
--Five sections here: GP, normal loot, area loot, rare loot, and unique item
--First up, GP:
--First up, GP:
local gpTxt = 'Successfully pickpocketing the '..npc.name..' will always give '..Icons.GP(1, npc.maxGP)
local gpTxt = 'Successfully pickpocketing the '..npc.name..' will always give '..Icons.GP(1, npc.maxGP)
table.insert(sectionTxt, gpTxt)
table.insert(sectionTxt, gpTxt)
 
--Next up, normal loot:
--Next up, normal loot:
--(Skip if no loot)
--(Skip if no loot)
Line 389: Line 369:
local normalTxt = '===Possible Common Drops:===\r\nUp to one of these will be received on a successful pickpocket:'
local normalTxt = '===Possible Common Drops:===\r\nUp to one of these will be received on a successful pickpocket:'
local totalWt = 0
local totalWt = 0
local lootChance = thievingNormalLootChance
local lootChance = SkillData.Thieving.ItemChance
local lootValue = 0
local lootValue = 0
 
--First loop through to get the total weight so we have it for later
--First loop through to get the total weight so we have it for later
for i, loot in pairs(npc.lootTable) do
for i, loot in pairs(npc.lootTable) do
totalWt = totalWt + loot[2]
totalWt = totalWt + loot[2]
end
end
 
normalTxt = normalTxt..'\r\n{|class="wikitable sortable"'
normalTxt = normalTxt..'\r\n{|class="wikitable sortable"'
normalTxt = normalTxt..'\r\n!Item!!Qty'
normalTxt = normalTxt..'\r\n!Item!!Qty'
normalTxt = normalTxt..'!!Price!!colspan="2"|Chance'
normalTxt = normalTxt..'!!Price!!colspan="2"|Chance'
 
--Then sort the loot table by weight
--Then sort the loot table by weight
table.sort(npc.lootTable, function(a, b) return a[2] > b[2] end)
table.sort(npc.lootTable, function(a, b) return a[2] > b[2] end)
Line 412: Line 392:
end
end
normalTxt = normalTxt..'||style="text-align:right" data-sort-value="'..maxQty..'"|'
normalTxt = normalTxt..'||style="text-align:right" data-sort-value="'..maxQty..'"|'
 
if maxQty > 1 then
if maxQty > 1 then
normalTxt = normalTxt.. '1 - '
normalTxt = normalTxt.. '1 - '
end
end
normalTxt = normalTxt..Shared.formatnum(row[3])
normalTxt = normalTxt..Shared.formatnum(row[3])
 
--Adding price columns
--Adding price columns
local itemPrice = 0
local itemPrice = 0
Line 430: Line 410:
end
end
end
end
 
--Getting the drop chance
--Getting the drop chance
local dropChance = (row[2] / totalWt * lootChance)
local dropChance = (row[2] / totalWt * lootChance)
Line 442: Line 422:
end
end
normalTxt = normalTxt..'style="text-align:right"|'..Shared.round(dropChance, 2, 2)..'%'
normalTxt = normalTxt..'style="text-align:right"|'..Shared.round(dropChance, 2, 2)..'%'
 
--Adding to the average loot value based on price & dropchance
--Adding to the average loot value based on price & dropchance
lootValue = lootValue + (dropChance * 0.01 * itemPrice * ((1 + maxQty) / 2))
lootValue = lootValue + (dropChance * 0.01 * itemPrice * ((1 + maxQty) / 2))
end
end
if multiDrop then
if Shared.tableCount(npc.lootTable) > 1 then
normalTxt = normalTxt..'\r\n|-class="sortbottom" \r\n!colspan="3"|Total:'
normalTxt = normalTxt..'\r\n|-class="sortbottom" \r\n!colspan="3"|Total:'
if lootChance < 100 then
if lootChance < 100 then
Line 453: Line 433:
normalTxt = normalTxt..'\r\n|colspan="2" '
normalTxt = normalTxt..'\r\n|colspan="2" '
end
end
normalTxt = normalTxt..'style="text-align:right"|'..lootChance..'.00%'
normalTxt = normalTxt..'style="text-align:right"|'..Shared.round(lootChance, 2, 2)..'%'
end
end
normalTxt = normalTxt..'\r\n|}'
normalTxt = normalTxt..'\r\n|}'
table.insert(sectionTxt, normalTxt)
table.insert(sectionTxt, normalTxt)
end
end
 
--After normal drops, add in rare drops
--After normal drops, add in rare drops
local rareTxt = '===Possible Rare Drops:===\r\nAny of these can be received after a successful pickpocket'
local rareTxt = '===Possible Rare Drops:===\r\nAny of these can be received after a successful pickpocket'
rareTxt = rareTxt..'\r\n{|class="wikitable sortable"'
rareTxt = rareTxt..'\r\n'..p.getThievingGeneralRareTable()
rareTxt = rareTxt..'\r\n!Item!!Qty'
rareTxt = rareTxt..'!!Price!!Chance'
for i, drop in pairs(SkillData.Thieving.RareItems) do
local thisItem = Items.getItemByID(drop.itemID)
local odds = drop.chance
rareTxt = rareTxt..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
rareTxt = rareTxt..'||1||data-sort-value="'..thisItem.sellsFor..'"|'..Icons.GP(thisItem.sellsFor)
rareTxt = rareTxt..'||style="text-align:right" data-sort-value="'..odds..'"|'..Shared.round(odds, 4, 4)..'%'
end
rareTxt = rareTxt..'\r\n|}'
table.insert(sectionTxt, rareTxt)
table.insert(sectionTxt, rareTxt)
 
local areaTxt = '===Possible Area Unique Drops==='
local areaTxt = '===Possible Area Unique Drops==='
areaTxt = areaTxt..'\r\nAny Area Unique Drop is equally likely to be obtained after a successful pickpocket. '
areaTxt = areaTxt..'\r\nAny Area Unique Drop is equally likely to be obtained after a successful pickpocket. '
areaTxt = areaTxt..'\r\nEach Area Unique Drop is rolled for separately, so it is possible to receive multiple Area Unique Drops from a single action. '
areaTxt = areaTxt..'The chance of receiving an Area Unique drop is tripled if the 95% Thieving Mastery Pool checkpoint is active.'
areaTxt = areaTxt..'The chance of receiving an Area Unique drop is tripled if the 95% Thieving Mastery Pool checkpoint is active.'
 
local area = p.getThievingNPCArea(npc)
local area = Skills.getThievingNPCArea(npc)
areaTxt = areaTxt..'\r\n{|class="wikitable sortable"'
areaTxt = areaTxt..'\r\n{|class="wikitable sortable"'
areaTxt = areaTxt..'\r\n!Item!!Qty'
areaTxt = areaTxt..'\r\n!Item!!Qty'
areaTxt = areaTxt..'!!Price!!colspan="2"|Chance'
areaTxt = areaTxt..'!!Price!!colspan="2"|Chance'
local dropCount = Shared.tableCount(area.uniqueDrops)
local dropCount = Shared.tableCount(area.uniqueDrops)
local areaDropChance = thievingAreaLootChance / dropCount
local dropLines = {}
local dropLines = {}
for i, drop in pairs(area.uniqueDrops) do
for i, drop in pairs(area.uniqueDrops) do
Line 491: Line 460:
lineTxt = lineTxt..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
lineTxt = lineTxt..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
lineTxt = lineTxt..'||'..drop.qty..'||data-sort-value="'..thisItem.sellsFor..'"|'..Icons.GP(thisItem.sellsFor)
lineTxt = lineTxt..'||'..drop.qty..'||data-sort-value="'..thisItem.sellsFor..'"|'..Icons.GP(thisItem.sellsFor)
lineTxt = lineTxt..'||style="text-align:right"|'..Shared.fraction(areaDropChance, 100)
lineTxt = lineTxt..'||style="text-align:right"|'..Shared.fraction(1, 1/(SkillData.Thieving.AreaUniqueChance/100))
lineTxt = lineTxt..'||'..Shared.round(areaDropChance, 2, 2)..'%'
lineTxt = lineTxt..'||'..Shared.round(SkillData.Thieving.AreaUniqueChance, 2, 2)..'%'
dropLines[thisItem.name] = lineTxt
dropLines[thisItem.name] = lineTxt
end
end
Line 499: Line 468:
end
end
areaTxt = areaTxt..'\r\n|-class="sortbottom" \r\n!colspan="3"|Total:'
areaTxt = areaTxt..'\r\n|-class="sortbottom" \r\n!colspan="3"|Total:'
areaTxt = areaTxt..'\r\n|style="text-align:right"|'..Shared.fraction(thievingAreaLootChance, 100)..'||'
areaTxt = areaTxt..'\r\n|style="text-align:right"|'..Shared.fraction(1, 1/(SkillData.Thieving.AreaUniqueChance/100))..'||'
areaTxt = areaTxt..'style="text-align:right"|'..Shared.round(thievingAreaLootChance, 2, 2)..'%'
areaTxt = areaTxt..'style="text-align:right"|'..Shared.round(SkillData.Thieving.AreaUniqueChance, 2, 2)..'%'
areaTxt = areaTxt..'\r\n|}'
areaTxt = areaTxt..'\r\n|}'
table.insert(sectionTxt, areaTxt)
table.insert(sectionTxt, areaTxt)
 
if npc.uniqueDrop ~= nil and npc.uniqueDrop.itemID > -1 then
if npc.uniqueDrop ~= nil and npc.uniqueDrop.itemID > -1 then
local uniqueTxt = '===Possible NPC Unique Drop==='
local uniqueTxt = '===Possible NPC Unique Drop==='
Line 515: Line 484:
uniqueTxt = uniqueTxt..Icons.Icon({thisItem.name, type='item'})
uniqueTxt = uniqueTxt..Icons.Icon({thisItem.name, type='item'})
end
end
 
table.insert(sectionTxt, uniqueTxt)
table.insert(sectionTxt, uniqueTxt)
end
end
 
return table.concat(sectionTxt, '\r\n')
return table.concat(sectionTxt, '\r\n')
end
end
Line 524: Line 493:
function p.getThievingNPCLootTables(frame)
function p.getThievingNPCLootTables(frame)
local npcName = frame.args ~= nil and frame.args[1] or frame
local npcName = frame.args ~= nil and frame.args[1] or frame
local npc = p.getThievingNPC(npcName)
local npc = Skills.getThievingNPC(npcName)
if npc == nil then
if npc == nil then
return "ERROR: Invalid Thieving NPC "..npcName.."[[Category:Pages with script errors]]"
return "ERROR: Invalid Thieving NPC "..npcName.."[[Category:Pages with script errors]]"
end
end
 
return p._getThievingNPCLootTables(npc)
return p._getThievingNPCLootTables(npc)
end
end
Line 535: Line 504:
local result = '{| class="wikitable sortable stickyHeader"'
local result = '{| class="wikitable sortable stickyHeader"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'!colspan="2"Name!!Area!!'..Icons.Icon({'Thieving', type='skill', notext=true})..' Level!!Experience!!Max Hit!!Perception!!Unique Drop'
result = result..'\r\n!colspan="2"|Name!!Area!!'..Icons.Icon({'Thieving', type='skill', notext=true})..' Level!!Experience!!Max Hit!!Perception!!GP!!Unique Drop'
local npcArray = Shared.clone(SkillData.Thieving.NPCs)
local npcArray = Shared.clone(SkillData.Thieving.NPCs)
table.sort(npcArray, function(a, b) return a.level < b.level end)
table.sort(npcArray, function(a, b) return a.level < b.level end)
Line 541: Line 510:
result = result..'\r\n|-'
result = result..'\r\n|-'
result = result..'\r\n|'..Icons.Icon({npc.name, type='thieving', size='50', notext=true})
result = result..'\r\n|'..Icons.Icon({npc.name, type='thieving', size='50', notext=true})
if npc.name == 'Golbin' or npc.name == 'Wizard' or npc.name == 'Cyclops' then
result = result..'||'..Icons.Icon({npc.name, type='thieving', noicon=true})
result = result..'||[['..npc.name..' (thieving)|'..npc.name..']]'
 
else
local area = Skills.getThievingNPCArea(npc)
result = result..'||[['..npc.name..']]'
end
local area = p.getThievingNPCArea(npc)
result = result..'||'..area.name
result = result..'||'..area.name
result = result..'||'..Icons._SkillReq('Thieving', npc.level)
result = result..'||'..Icons._SkillReq('Thieving', npc.level)
Line 552: Line 518:
result = result..'||style="text-align:right"|'..(npc.maxHit * 10)
result = result..'||style="text-align:right"|'..(npc.maxHit * 10)
result = result..'||style="text-align:right"|'..npc.perception
result = result..'||style="text-align:right"|'..npc.perception
result = result..'||data-sort-value="' .. npc.maxGP .. '"|'..Icons.GP(1, npc.maxGP)
if npc.uniqueDrop ~= nil and npc.uniqueDrop.itemID > -1 then
if npc.uniqueDrop ~= nil and npc.uniqueDrop.itemID > -1 then
local uniqueDrop = Items.getItemByID(npc.uniqueDrop.itemID)
local uniqueDrop = Items.getItemByID(npc.uniqueDrop.itemID)
Line 564: Line 531:
end
end
result = result..'\r\n|}'
result = result..'\r\n|}'
 
return result
end
 
function p.getThievingAreaTable(frame)
local resultPart = {}
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\r\n|- class="headerRow-0"')
table.insert(resultPart, '\r\n!Area!!'..Icons.Icon({'Thieving', type='skill', notext=true})..' Level!!NPCs!!Unique Drops')
 
local areaArray = Shared.clone(SkillData.Thieving.Areas)
table.sort(areaArray, function(a, b) return a.id < b.id end)
for i, area in ipairs(areaArray) do
local minLevel, npcList, areaItemList = nil, {}, {}
-- Build NPC list & determine level for area, this is the minimum
-- Thieving level required for all NPCs within that area
if area.npcs ~= nil and Shared.tableCount(area.npcs) > 0 then
for j, npcID in ipairs(area.npcs) do
-- Don't bother cloning the NPC below since we aren't modifying any part of it
local npc = SkillData.Thieving.NPCs[npcID + 1]
if minLevel == nil or npc.level < minLevel then
minLevel = npc.level
end
table.insert(npcList, Icons.Icon({npc.name, type='thieving'}))
end
else
table.insert(npcList, '')
end
 
-- Build area unique item list
if area.uniqueDrops ~= nil and Shared.tableCount(area.uniqueDrops) > 0 then
for k, drop in ipairs(area.uniqueDrops) do
local areaItem = Items.getItemByID(drop.itemID)
if areaItem == nil then
table.insert(areaItemList, 'Unknown[[Category:Pages with script errors]]')
else
local iconDef = {areaItem.name, type='item'}
if drop.qty > 1 then
iconDef.qty = drop.qty
end
table.insert(areaItemList, Icons.Icon(iconDef))
end
end
else
table.insert(areaItemList, '')
end
 
-- Generate table row
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|' .. area.name)
table.insert(resultPart, '\r\n|' .. Icons._SkillReq('Thieving', minLevel))
table.insert(resultPart, '\r\n|' .. table.concat(npcList, '<br/>'))
table.insert(resultPart, '\r\n|' .. table.concat(areaItemList, '<br/>'))
end
table.insert(resultPart, '\r\n|}')
 
return table.concat(resultPart)
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="' .. patch.level .. '"|'..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._buildAstrologyConstellationTable()
local maxModifier = 5
local result = '{|class="wikitable sortable stickyHeader"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n!colspan="2"|Constellation!!'..Icons.Icon({"Astrology", type='skill', notext='true'})..' Level'
result = result..'!!XP!!Skills!!Standard Modifiers!!Unique Modifiers'
 
for i, cons in ipairs(SkillData.Astrology.Constellations) do
local name = cons.name
result = result..'\r\n|-'
result = result..'\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='constellation', size='50', notext=true})..'||'..name
result = result..'||'..cons.level..'||'..cons.provides.xp
 
local skillIconArray = {}
for j, skillID in ipairs(cons.skills) do
table.insert(skillIconArray, Icons.Icon({Constants.getSkillName(skillID), type='skill'}))
end
result = result..'||'..table.concat(skillIconArray, '<br/>')
 
local standModsRaw = Skills._buildAstrologyModifierArray(cons, maxModifier, true, false, false, false)
local standMods = {}
--Building the list of Standard modifiers:
for j, modifier in ipairs(standModsRaw) do
table.insert(standMods, Constants._getModifierText(modifier[1], modifier[2], false))
end
result = result..'|| '..table.concat(standMods, '<br/>')
 
--Building the list of all Unique Modifiers
local uModsRaw = Skills._buildAstrologyModifierArray(cons, maxModifier, false, true, false, false)
local uMods = {}
for j, modifier in ipairs(uModsRaw) do
table.insert(uMods, Constants._getModifierText(modifier[1], modifier[2], false))
end
result = result..'||'..table.concat(uMods, '<br/>')
end
result = result..'\r\n|}'
 
return result
end
 
function p.buildAstrologyConstellationTable(frame)
return p._buildAstrologyConstellationTable()
end
 
function p.buildAstrologyValueTable()
local result = '{|class="wikitable sortable"'
result = result..'\r\n!rowspan="2"| Value!!colspan="2"| Chance'
result = result..'\r\n|-\r\n! This Value!! This Value or Greater'
local cumulativeChance = 100
for i, chance in ipairs(SkillData.Astrology.ModifierMagnitudeChances) do
result = result..'\r\n|-'
result = result..'\r\n|style="text-align:right"| ' .. i
result = result..'\r\n|style="text-align:right"| ' .. chance .. '%'
result = result..'\r\n|style="text-align:right"| ' .. cumulativeChance .. '%'
cumulativeChance = cumulativeChance - chance
end
result = result..'\r\n|}'
return result
return result
end
end


return p
return p