Difference between revisions of "Module:Skills/Gathering"
From Melvor Idle
(getThievingNPCTable: Add GP column) |
(Implement Astrology constellation functions) |
||
Line 12: | Line 12: | ||
local thievingNormalLootChance = 75 | local thievingNormalLootChance = 75 | ||
local thievingAreaLootChance = 0.2 | local thievingAreaLootChance = 0.2 | ||
+ | |||
+ | function p.getConstellationByID(constID) | ||
+ | return SkillData.Astrology.Constellations[constID] | ||
+ | end | ||
+ | |||
+ | function p.getConstellation(constName) | ||
+ | for i, const in ipairs(SkillData.Astrology.Constellations) do | ||
+ | if const.name == constName then | ||
+ | return const | ||
+ | end | ||
+ | end | ||
+ | return nil | ||
+ | end | ||
+ | |||
+ | function p.getConstellations(checkFunc) | ||
+ | local result = {} | ||
+ | for i, const in ipairs(SkillData.Astrology.Constellations) do | ||
+ | if checkFunc(const) then | ||
+ | table.insert(result, const) | ||
+ | end | ||
+ | end | ||
+ | return result | ||
+ | end | ||
function p.getAxeTable(frame) | function p.getAxeTable(frame) |
Revision as of 23:00, 23 January 2022
Documentation for this module may be created at Module:Skills/Gathering/doc
--Splitting some functions into here to avoid bloating a single file local p = {} local SkillData = mw.loadData('Module:Skills/data') local ShopData = mw.loadData('Module:Shop/data') local Constants = require('Module:Constants') local Shared = require('Module:Shared') local Items = require('Module:Items') local Icons = require('Module:Icons') local thievingNormalLootChance = 75 local thievingAreaLootChance = 0.2 function p.getConstellationByID(constID) return SkillData.Astrology.Constellations[constID] end function p.getConstellation(constName) for i, const in ipairs(SkillData.Astrology.Constellations) do if const.name == constName then return const end end return nil end function p.getConstellations(checkFunc) local result = {} for i, const in ipairs(SkillData.Astrology.Constellations) do if checkFunc(const) then table.insert(result, const) end end return result end function p.getAxeTable(frame) local toolArray = {} for i, upgrade in Shared.skpairs(ShopData.Shop.SkillUpgrades) do if Shared.contains(upgrade.name, 'Axe') then table.insert(toolArray, upgrade) end end local result = '{| class="wikitable"' result = result..'\r\n!colspan="4"| !!colspan="2"|Cut Time Decrease' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan="2"|Name!!'..Icons.Icon({'Woodcutting', type='skill', notext=true})..' Level' result = result..'!!Cost!!This Axe!!Total' local total = 0 for i, tool in Shared.skpairs(toolArray) do result = result..'\r\n|-' result = result..'\r\n|style="min-width:25px" data-sort-value="'..tool.name..'"|'..Icons.Icon({tool.name, type='upgrade', size='50', notext=true}) result = result..'||'..tool.name local level = 1 if tool.unlockRequirements ~= nil and tool.unlockRequirements.skillLevel ~= nil then --Gonna be lazy and assume there's only the one skill level and it's the one we care about level = tool.unlockRequirements.skillLevel[1][2] end result = result..'||style="text-align:right"|'..level result = result..'||style="text-align:right" data-sort-value="'..tool.cost.gp..'"|'..Icons.GP(tool.cost.gp) local cutTime = tool.contains.modifiers.decreasedSkillIntervalPercent[1][2] total = total + cutTime result = result..'||style="text-align:right"|-'..cutTime..'%' result = result..'||style="text-align:right"|-'..total..'%' end result = result..'\r\n|}' return result end function p.getPickaxeTable(frame) local toolArray = {} for i, upgrade in Shared.skpairs(ShopData.Shop.SkillUpgrades) do if Shared.contains(upgrade.name, 'Pickaxe') then table.insert(toolArray, upgrade) end end local result = '{| class="wikitable"' result = result..'\r\n!colspan="4"| !!colspan="2"|Mine Time Decrease!!colspan="2"|2x Ore Chance' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan="2"|Name!!'..Icons.Icon({'Mining', type='skill', notext=true})..' Level' result = result..'!!Cost!!This Pick!!Total!!This Pick!!Total' local total = 0 local total2 = 0 for i, tool in Shared.skpairs(toolArray) do result = result..'\r\n|-' result = result..'\r\n|style="min-width:25px" data-sort-value="'..tool.name..'"|'..Icons.Icon({tool.name, type='upgrade', size='50', notext=true}) result = result..'||'..tool.name local level = 1 if tool.unlockRequirements ~= nil and tool.unlockRequirements.skillLevel ~= nil then --Gonna be lazy and assume there's only the one skill level and it's the one we care about level = tool.unlockRequirements.skillLevel[1][2] end result = result..'||style="text-align:right"|'..level result = result..'||style="text-align:right" data-sort-value="'..tool.cost.gp..'"|'..Icons.GP(tool.cost.gp) local cutTime = tool.contains.modifiers.decreasedSkillIntervalPercent[1][2] total = total + cutTime result = result..'||style="text-align:right"|-'..cutTime..'%' result = result..'||style="text-align:right"|-'..total..'%' local OreDouble = tool.contains.modifiers.increasedChanceToDoubleOres total2 = total2 + OreDouble result = result..'||style="text-align:right"|+'..OreDouble..'%' result = result..'||style="text-align:right"|+'..total2..'%' end result = result..'\r\n|}' return result end function p.getRodTable(frame) local toolArray = {} for i, upgrade in Shared.skpairs(ShopData.Shop.SkillUpgrades) do if Shared.contains(upgrade.name, 'Fishing Rod') then table.insert(toolArray, upgrade) end end local result = '{| class="wikitable"' result = result..'\r\n!colspan="4"| !!colspan="2"|Catch Time Decrease' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan="2"|Name!!'..Icons.Icon({'Fishing', type='skill', notext=true})..' Level' result = result..'!!Cost!!This Rod!!Total' local total = 0 for i, tool in Shared.skpairs(toolArray) do result = result..'\r\n|-' result = result..'\r\n|style="min-width:25px" data-sort-value="'..tool.name..'"|'..Icons.Icon({tool.name, type='upgrade', size='50', notext=true}) result = result..'||'..tool.name local level = 1 if tool.unlockRequirements ~= nil and tool.unlockRequirements.skillLevel ~= nil then --Gonna be lazy and assume there's only the one skill level and it's the one we care about level = tool.unlockRequirements.skillLevel[1][2] end result = result..'||style="text-align:right"|'..level result = result..'||style="text-align:right" data-sort-value="'..tool.cost.gp..'"|'..Icons.GP(tool.cost.gp) local cutTime = tool.contains.modifiers.decreasedSkillIntervalPercent[1][2] total = total + cutTime result = result..'||style="text-align:right"|-'..cutTime..'%' result = result..'||style="text-align:right"|-'..total..'%' end result = result..'\r\n|}' return result end function p.getTreesTable(frame) local result = '{| class="wikitable sortable"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan="2"|Tree!!colspan="2"|Logs!!'..Icons.Icon({'Woodcutting', type='skill', notext=true})..' Level' result = result..'!!XP!!Cut Time!!XP/s!!GP/s' for i, tree in Shared.skpairs(SkillData.Woodcutting.Trees) do result = result..'\r\n|-' local treeName = Shared.titleCase(tree.type..' tree') local logName = Shared.titleCase(tree.type..' logs') result = result..'\r\n|style="min-width:25px" data-sort-value="'..treeName..'"|'..Icons.Icon({logName, img=treeName, type='tree', notext=true, size=50}) result = result..'||'..treeName..'' result = result..'||style="min-width:25px" data-sort-value="'..logName..'"|'..Icons.Icon({logName, type='item', notext=true, size=50}) result = result..'||'..Icons.Icon({logName, type='item', noicon=true}) result = result..'||style="text-align:right"|'..tree.level result = result..'||style="text-align:right"|'..tree.xp result = result..'||style="text-align:right" data-sort-value="'..tree.interval..'"|'..Shared.timeString(tree.interval/1000, true) local XPs = tree.xp / (tree.interval / 1000) local Log = Items.getItemByID(i - 1) local GPs = Log.sellsFor / (tree.interval / 1000) 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)) end result = result..'\r\n|}' return result end function p.getSpecialFishingTable(frame) local lootValue = 0 local totalWt = Items.specialFishWt local result = '' result = result..'\r\n{|class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!Item' result = result..'!!Price!!colspan="2"|Chance' --Sort the loot table by weight in descending order table.sort(Items.specialFishLoot, function(a, b) return a[2] > b[2] end) for i, row in pairs(Items.specialFishLoot) do local thisItem = Items.getItemByID(row[1]) result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'}) result = result..'||style="text-align:left" data-sort-value="'..thisItem.sellsFor..'"' result = result..'|'..Icons.GP(thisItem.sellsFor) local dropChance = (row[2] / totalWt) * 100 result = result..'||style="text-align:right" data-sort-value="'..row[2]..'"' 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 result = result..'\r\n|}' result = result..'\r\nThe average value of a roll on the special fishing loot table is '..Icons.GP(Shared.round(lootValue, 2, 0)) return result end function p.getFishingJunkTable(frame) local result = '{| class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan="2"|Item!!Value' local itemArray = Items.getItems(function(item) return item.type == "Junk" end) table.sort(itemArray, function(a, b) return a.name < b.name end) for i, item in Shared.skpairs(itemArray) do result = result..'\r\n|-' result = result..'\r\n|style="min-width:25px"|'..Icons.Icon({item.name, type='item', notext=true, size='50'}) result = result..'||'..Icons.Icon({item.name, type='item', noicon=true}) result = result..'||style="text-align:right;" data-sort-value="'..item.sellsFor..'"|'..Icons.GP(item.sellsFor) end result = result..'\r\n|}' return result end function p.getMiningOresTable(frame) local result = '{|class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan=2|Ore!!'..Icons.Icon({'Mining', type='skill', notext=true})..' Level' result = result..'!!XP!!Respawn Time!!Ore Value' local mineData = Shared.clone(SkillData.Mining.Rocks) table.sort(mineData, function(a, b) return a.levelRequired < b.levelRequired end) for i, oreData in Shared.skpairs(mineData) do 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}) result = result..'||'..Icons.Icon({ore.name, type='item', noicon=true}) result = result..'||style="text-align:right"|'..oreData.levelRequired..'||style="text-align:right"|'..ore.miningXP 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) end result = result..'\r\n|}' return result end function p.getMiningGemsTable(frame) local result = '{|class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!colspan=2|Gem!!Gem Chance!!Gem Price' -- Sort gems by ID order for i, gemData in Shared.spairs(Items.GemTable, function(t,a,b) return t[a].id < t[b].id end) do local gem = Items.getItemByID(gemData.id) result = result..'\r\n|-\r\n|style="min-width:25px"|' 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..'||data-sort-value="'..gem.sellsFor..'"|'..Icons.GP(gem.sellsFor) end result = result..'\r\n|}' return result end function p.getFishTable(frame) local data = Items.getItems(function(item) return item.fishingID ~= nil end) table.sort(data, function(a, b) return a.fishingID < b.fishingID end) local result = '{| class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!Fish\r\n!Name\r\n!'..Icons.Icon({'Fishing', type='skill', notext=true})..' Level\r\n!Catch Time' result = result..'\r\n!Experience\r\n!Fish Price\r\n!XP/s\r\n!GP/s\r\n!' result = result..Icons.Icon({'Cooking', type='skill', notext=true})..' Level' for i, fish in Shared.skpairs(data) do result = result..'\r\n|-' result = result..'\r\n| style="text-align: left;" | '..Icons.Icon({fish.name, type='item', size='50', notext=true}) result = result..'\r\n| style="text-align: left;" | '..Icons.Icon({fish.name, type='item', noicon=true}) result = result..'\r\n| style="text-align:right"|'..fish.fishingLevel local timeSortVal = (fish.minFishingInterval + fish.maxFishingInterval) / 2 local timeStr = string.format("%.1fs-%.1fs", (fish.minFishingInterval/1000), (fish.maxFishingInterval/1000)) result = result..'\r\n| style="text-align:right" data-sort-value="'..timeSortVal..'"|'..timeStr result = result..'\r\n| style="text-align:right"|'..fish.fishingXP result = result..'\r\n| style="text-align:right"|'..fish.sellsFor local XPs = fish.fishingXP / (timeSortVal / 1000) local GPs = fish.sellsFor / (timeSortVal / 1000) result = result..'\r\n| style="text-align:right"|'..Shared.round(XPs, 2, 2) result = result..'\r\n| style="text-align:right" data-sort-value="'..GPs..'"|'..Icons.GP(Shared.round(GPs, 2, 2)) local cookStr = "N/A" if fish.cookingLevel ~= nil then cookStr = fish.cookingLevel end result = result..'\r\n| style="text-align:right"|'..cookStr end result = result..'\r\n|}' return result end function p.getFishingAreasTable(frame) local result = '{| class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' result = result..'\r\n!Name\r\n!Fish\r\n!Fish Chance' result = result..'\r\n!Junk Chance\r\n!Special Chance' for i, area in Shared.skpairs(SkillData.Fishing.Areas) do result = result..'\r\n|-' result = result..'\r\n| style ="text-align: left;" |'..area.name local fishArray = {} for j, fish in Shared.skpairs(area.fish) do local fishTable = Items.getItems(function(item) return item.fishingID == fish end) local fishItem = fishTable[0] or fishTable[1] table.insert(fishArray, Icons.Icon({fishItem.name, type='item'})) end 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.junkChance..'%' result = result..'\r\n| style="text-align:right"|'..area.specialChance..'%' end result = result..'\r\n|}' return result end function p.getThievingNPC(npcName) local result = nil 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 function p.getThievingNPCArea(npc) if type(npc) == 'string' then npc = p.getThievingNPC(npc) 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 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 function p.getThievingGeneralRareTable(frame) local rareTxt = '{|class="wikitable sortable"' rareTxt = rareTxt..'\r\n!Item!!Qty' rareTxt = rareTxt..'!!Price!!colspan="2"|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.fraction(1, Shared.round2(1/(odds/100), 0)) rareTxt = rareTxt..'||style="text-align:right" data-sort-value="'..odds..'"|'..Shared.round(odds, 4, 4)..'%' end rareTxt = rareTxt..'\r\n|}' return rareTxt end function p._getThievingNPCLootTables(npc) local result = '' local sectionTxt = {} --Five sections here: GP, normal loot, area loot, rare loot, and unique item --First up, GP: local gpTxt = 'Successfully pickpocketing the '..npc.name..' will always give '..Icons.GP(1, npc.maxGP) table.insert(sectionTxt, gpTxt) --Next up, normal loot: --(Skip if no loot) if npc.lootTable ~= nil and Shared.tableCount(npc.lootTable) > 0 then local normalTxt = '===Possible Common Drops:===\r\nUp to one of these will be received on a successful pickpocket:' local totalWt = 0 local lootChance = thievingNormalLootChance local lootValue = 0 --First loop through to get the total weight so we have it for later for i, loot in pairs(npc.lootTable) do totalWt = totalWt + loot[2] end normalTxt = normalTxt..'\r\n{|class="wikitable sortable"' normalTxt = normalTxt..'\r\n!Item!!Qty' normalTxt = normalTxt..'!!Price!!colspan="2"|Chance' --Then sort the loot table by weight table.sort(npc.lootTable, function(a, b) return a[2] > b[2] end) for i, row in Shared.skpairs(npc.lootTable) do local thisItem = Items.getItemByID(row[1]) local maxQty = row[3] if thisItem ~= nil then normalTxt = normalTxt..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'}) else normalTxt = normalTxt..'\r\n|-\r\n|Unknown Item[[Category:Pages with script errors]]' end normalTxt = normalTxt..'||style="text-align:right" data-sort-value="'..maxQty..'"|' if maxQty > 1 then normalTxt = normalTxt.. '1 - ' end normalTxt = normalTxt..Shared.formatnum(row[3]) --Adding price columns local itemPrice = 0 if thisItem == nil then normalTxt = normalTxt..'||data-sort-value="0"|???' else itemPrice = thisItem.sellsFor ~= nil and thisItem.sellsFor or 0 if itemPrice == 0 or maxQty == 1 then normalTxt = normalTxt..'||'..Icons.GP(itemPrice) else normalTxt = normalTxt..'||'..Icons.GP(itemPrice, itemPrice * maxQty) end end --Getting the drop chance local dropChance = (row[2] / totalWt * lootChance) if dropChance ~= 100 then --Show fraction as long as it isn't going to be 1/1 normalTxt = normalTxt..'||style="text-align:right" data-sort-value="'..row[2]..'"' normalTxt = normalTxt..'|'..Shared.fraction(row[2] * lootChance, totalWt * 100) normalTxt = normalTxt..'||' else normalTxt = normalTxt..'||colspan="2" data-sort-value="'..row[2]..'"' end normalTxt = normalTxt..'style="text-align:right"|'..Shared.round(dropChance, 2, 2)..'%' --Adding to the average loot value based on price & dropchance lootValue = lootValue + (dropChance * 0.01 * itemPrice * ((1 + maxQty) / 2)) end if multiDrop then normalTxt = normalTxt..'\r\n|-class="sortbottom" \r\n!colspan="3"|Total:' if lootChance < 100 then normalTxt = normalTxt..'\r\n|style="text-align:right"|'..Shared.fraction(lootChance, 100)..'||' else normalTxt = normalTxt..'\r\n|colspan="2" ' end normalTxt = normalTxt..'style="text-align:right"|'..lootChance..'.00%' end normalTxt = normalTxt..'\r\n|}' table.insert(sectionTxt, normalTxt) end --After normal drops, add in rare drops local rareTxt = '===Possible Rare Drops:===\r\nAny of these can be received after a successful pickpocket' rareTxt = rareTxt..'\r\n'..p.getThievingGeneralRareTable() table.insert(sectionTxt, rareTxt) 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\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.' local area = p.getThievingNPCArea(npc) areaTxt = areaTxt..'\r\n{|class="wikitable sortable"' areaTxt = areaTxt..'\r\n!Item!!Qty' areaTxt = areaTxt..'!!Price!!colspan="2"|Chance' local dropCount = Shared.tableCount(area.uniqueDrops) local dropLines = {} for i, drop in pairs(area.uniqueDrops) do local thisItem = Items.getItemByID(drop.itemID) local lineTxt = '' 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..'||style="text-align:right"|'..Shared.fraction(1, 1/(thievingAreaLootChance/100)) lineTxt = lineTxt..'||'..Shared.round(thievingAreaLootChance, 2, 2)..'%' dropLines[thisItem.name] = lineTxt end for i, txt in Shared.skpairs(dropLines) do areaTxt = areaTxt..txt end areaTxt = areaTxt..'\r\n|-class="sortbottom" \r\n!colspan="3"|Total:' areaTxt = areaTxt..'\r\n|style="text-align:right"|'..Shared.fraction(1, 1/(thievingAreaLootChance/100))..'||' areaTxt = areaTxt..'style="text-align:right"|'..Shared.round(thievingAreaLootChance, 2, 2)..'%' areaTxt = areaTxt..'\r\n|}' table.insert(sectionTxt, areaTxt) if npc.uniqueDrop ~= nil and npc.uniqueDrop.itemID > -1 then local uniqueTxt = '===Possible NPC Unique Drop===' uniqueTxt = uniqueTxt..'\r\nThe chance of receiving the unique drop for an NPC is based on a combination of several factors.' uniqueTxt = uniqueTxt..' The unique drop chance for an NPC is included in the tooltip for your Stealth against that NPC.' local thisItem = Items.getItemByID(npc.uniqueDrop.itemID) uniqueTxt = uniqueTxt..'\r\nThe unique drop for the '..npc.name..' is ' if npc.uniqueDrop.qty > 1 then uniqueTxt = uniqueTxt..Icons.Icon({thisItem.name, type='item', qty=npc.uniqueDrop.qty}) else uniqueTxt = uniqueTxt..Icons.Icon({thisItem.name, type='item'}) end table.insert(sectionTxt, uniqueTxt) end return table.concat(sectionTxt, '\r\n') end function p.getThievingNPCLootTables(frame) local npcName = frame.args ~= nil and frame.args[1] or frame local npc = p.getThievingNPC(npcName) if npc == nil then return "ERROR: Invalid Thieving NPC "..npcName.."[[Category:Pages with script errors]]" end return p._getThievingNPCLootTables(npc) end function p.getThievingNPCTable() local result = '{| class="wikitable sortable stickyHeader"' result = result..'\r\n|- class="headerRow-0"' 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) table.sort(npcArray, function(a, b) return a.level < b.level end) for i, npc in Shared.skpairs(npcArray) do result = result..'\r\n|-' result = result..'\r\n|'..Icons.Icon({npc.name, type='thieving', size='50', notext=true}) result = result..'||'..Icons.Icon({npc.name, type='thieving', noicon=true}) local area = p.getThievingNPCArea(npc) result = result..'||'..area.name result = result..'||'..Icons._SkillReq('Thieving', npc.level) result = result..'||style="text-align:right"|'..npc.xp result = result..'||style="text-align:right"|'..(npc.maxHit * 10) 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 local uniqueDrop = Items.getItemByID(npc.uniqueDrop.itemID) if npc.uniqueDrop.qty > 1 then result = result..'||data-sort-value="'..uniqueDrop.name..'"|'..Icons.Icon({uniqueDrop.name, type='item', qty = npc.uniqueDrop.qty}) else result = result..'||data-sort-value="'..uniqueDrop.name..'"|'..Icons.Icon({uniqueDrop.name, type='item'}) end else result = result..'|| ' end end 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.getThievingSourcesForItem(itemID) local resultArray = {} local areaNPCs = {} --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 not result then 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 --Now go through and get drop chances on each NPC if needed for i, npc in pairs(SkillData.Thieving.NPCs) do 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 * thievingNormalLootChance, totalWt = totalWt * 100, level = npc.level}) end --Chance of -1 on unique drops is to indicate variable chance 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 if areaNPCs[npc.id] ~= nil then table.insert(resultArray, {npc = npc.name, minQty = areaNPCs[npc.id], maxQty = areaNPCs[npc.id], wt = thievingAreaLootChance, totalWt = 100, level = npc.level}) end end for i, drop in pairs(SkillData.Thieving.RareItems) do 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}) end end return resultArray 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 Shared.skpairs(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 standMods = {} local skillArray = {} local skillIconArray = {} for j, skillID in pairs(cons.skills) do local skill = SkillData.Skills[skillID + 1] table.insert(skillArray, skill) table.insert(skillIconArray, Icons.Icon({skill.name, type='skill'})) --Building the list of Standard modifiers: for k, modName in pairs(cons.standardModifiers[j]) do table.insert(standMods, Constants._getModifierText(modName, {skillID, maxModifier}, false)) end end result = result..'||'..table.concat(skillIconArray, '<br/>') result = result..'|| '..table.concat(standMods, '<br/>') --Building the list of all Unique Modifiers local uMods = {} for j, modName in pairs(cons.uniqueModifiers) do --The most important thing we're getting here is the modText and modBase --modText lets us check if this is a per-skill modifier or not --modBase lets us check .isSkill, which are modifiers that we only use for skills with Mastery local modBaseName, modText, sign, isNegative, unsign, modBase = Constants.getModifierDetails(modName) if Shared.contains(modText, '{SV0}') then for k, skill in pairs(skillArray) do local skillID = cons.skills[k] local useMod = true if modBase.isSkill then useMod = skill.hasMastery end if useMod then table.insert(uMods, Constants._getModifierText(modName, {skillID, maxModifier}, false)) end end else table.insert(uMods, Constants._getModifierText(modName, maxModifier, false)) end 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 lastChance = 0 local cumulativeChance = 100 for i, chance in Shared.skpairs(SkillData.Astrology.Defaults.valueWeight) do local thisChance = (i == 5 and chance) or chance - lastChance result = result..'\r\n|-' result = result..'\r\n|style="text-align:right"| '..i result = result..'\r\n|style="text-align:right"| ' .. thisChance .. '%' result = result..'\r\n|style="text-align:right"| ' .. cumulativeChance .. '%' cumulativeChance = cumulativeChance - thisChance lastChance = chance end result = result..'\r\n|}' return result end return p