|
|
(13 intermediate revisions by 2 users not shown) |
Line 1: |
Line 1: |
| --Some skills have their own modules:
| |
| --Module:Magic for Magic
| |
| --Module:Prayer for Prayer
| |
| --Module:Skills/Agility for Agility
| |
| --Module:Skills/Summoning for Summoning
| |
| --Module:Skills/Gathering for Mining, Fishing, Woodcutting
| |
| --Module:Skills/Artisan for Smithing, Cooking, Herblore, etc.
| |
|
| |
|
| --Also be aware of:
| |
| --Module:Navboxes for navigation boxes appearing near the bottom of pages
| |
|
| |
| local p = {}
| |
|
| |
| local ItemData = mw.loadData('Module:Sandbox/Items/data')
| |
| local SkillData = mw.loadData('Module:Sandbox/Skills/data')
| |
|
| |
| local Shared = require('Module:Shared')
| |
| local Constants = require('Module:Constants')
| |
| local Items = require('Module:Sandbox/Items')
| |
| local ItemSourceTables = require('Module:Items/SourceTables')
| |
| local Icons = require('Module:Icons')
| |
|
| |
| local MasteryCheckpoints = {.1, .25, .5, .95}
| |
|
| |
| function p.getMasteryUnlockTable(frame)
| |
| local skillName = frame.args ~= nil and frame.args[1] or frame
| |
| local skillID = Constants.getSkillID(skillName)
| |
| if skillID == nil then
| |
| return "ERROR: Failed to find a skill ID for "..skillName
| |
| end
| |
|
| |
| local unlockTable = SkillData.MasteryUnlocks[skillID]
| |
| if unlockTable == nil then
| |
| return 'ERROR: Failed to find Mastery Unlock data for '..skillName
| |
| end
| |
|
| |
| local result = '{|class="wikitable"\r\n!Level!!Unlock'
| |
| for i, unlock in Shared.skpairs(unlockTable) do
| |
| result = result..'\r\n|-'
| |
| result = result..'\r\n|'..unlock.level..'||'..unlock.unlock
| |
| end
| |
| result = result..'\r\n|}'
| |
| return result
| |
| end
| |
|
| |
| function p.getMasteryCheckpointTable(frame)
| |
| local skillName = frame.args ~= nil and frame.args[1] or frame
| |
| local skillID = Constants.getSkillID(skillName)
| |
| if skillID == nil then
| |
| return "ERROR: Failed to find a skill ID for "..skillName
| |
| end
| |
|
| |
| if SkillData.MasteryCheckpoints[skillID] == nil then
| |
| return 'ERROR: Failed to find Mastery Unlock data for '..skillName
| |
| end
| |
|
| |
| local bonuses = SkillData.MasteryCheckpoints[skillID].bonuses
| |
| local totalPoolXP = SkillData.MasteryPoolXP[skillID + 1]
| |
|
| |
| local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus'
| |
| for i, bonus in Shared.skpairs(bonuses) do
| |
| result = result..'\r\n|-'
| |
| result = result..'\r\n|'..(MasteryCheckpoints[i] * 100)..'%||'
| |
| result = result..Shared.formatnum(totalPoolXP * MasteryCheckpoints[i])..' xp||'..bonus
| |
| end
| |
| result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP'
| |
| result = result..'\r\n|'..Shared.formatnum(totalPoolXP)
| |
| result = result..'\r\n|}'
| |
| return result
| |
| end
| |
|
| |
| function p._getFarmingTable(category)
| |
| local seedList = {}
| |
| if category == 'Allotment' or category == 'Herb' or category == 'Tree' then
| |
| seedList = Items.getItems(function(item) return item.tier == category end)
| |
| else
| |
| return 'ERROR: Invalid farming category. Please choose Allotment, Herb, or Tree'
| |
| end
| |
|
| |
| local result = '{|class="wikitable sortable stickyHeader"'
| |
| result = result..'\r\n|- class="headerRow-0"'
| |
| result = result..'\r\n!colspan=2|Seeds!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level'
| |
| result = result..'!!XP!!Growth Time!!Seed Value'
| |
| if category == 'Allotment' then
| |
| result = result..'!!colspan="2"|Crop!!Crop Healing!!Crop Value'
| |
| elseif category == 'Herb' then
| |
| result = result..'!!colspan="2"|Herb!!Herb Value'
| |
| elseif category == 'Tree' then
| |
| result = result..'!!colspan="2"|Logs!!Log Value'
| |
| end
| |
| result = result..'!!Seed Sources'
| |
|
| |
| table.sort(seedList, function(a, b) return a.farmingLevel < b.farmingLevel end)
| |
|
| |
| for i, seed in pairs(seedList) do
| |
| result = result..'\r\n|-'
| |
| result = result..'\r\n|'..Icons.Icon({seed.name, type='item', size='50', notext=true})..'||[['..seed.name..']]'
| |
| result = result..'||'..seed.farmingLevel..'||'..Shared.formatnum(seed.farmingXP)
| |
| result = result..'||data-sort-value="'..seed.timeToGrow..'"|'..Shared.timeString(seed.timeToGrow, true)
| |
| result = result..'||data-sort-value="'..seed.sellsFor..'"|'..Icons.GP(seed.sellsFor)
| |
|
| |
| local crop = Items.getItemByID(seed.grownItemID)
| |
| result = result..'||'..Icons.Icon({crop.name, type='item', size='50', notext=true})..'||[['..crop.name..']]'
| |
| if category == 'Allotment' then
| |
| result = result..'||'..Icons.Icon({'Hitpoints', type='skill', notext=true})..' '..(crop.healsFor * 10)
| |
| end
| |
| result = result..'||data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor)
| |
| result = result..'||'..ItemSourceTables._getItemSources(seed)
| |
| end
| |
|
| |
| result = result..'\r\n|}'
| |
| return result
| |
| end
| |
|
| |
| function p.getFarmingTable(frame)
| |
| local category = frame.args ~= nil and frame.args[1] or frame
| |
|
| |
| return p._getFarmingTable(category)
| |
| end
| |
|
| |
| function p.getFarmingFoodTable(frame)
| |
| local result = '{| class="wikitable sortable stickyHeader"'
| |
| result = result..'\r\n|- class="headerRow-0"'
| |
| result = result..'\r\n!colspan="2"|Crop!!'..Icons.Icon({"Farming", type="skill", notext=true})..' Level'
| |
| result = result..'!!Healing!!Value'
| |
|
| |
| local itemArray = Items.getItems(function(item) return item.grownItemID ~= nil end)
| |
|
| |
| table.sort(itemArray, function(a, b) return a.farmingLevel < b.farmingLevel end)
| |
|
| |
| for i, item in Shared.skpairs(itemArray) do
| |
| local crop = Items.getItemByID(item.grownItemID)
| |
| if crop.healsFor ~= nil and crop.healsFor > 0 then
| |
| result = result..'\r\n|-'
| |
| result = result..'\r\n|'..Icons.Icon({crop.name, type='item', notext='true', size='50'})..'||[['..crop.name..']]'
| |
| result = result..'||style="text-align:right;"|'..item.farmingLevel
| |
| result = result..'||style="text-align:right" data-sort-value="'..crop.healsFor..'"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..(crop.healsFor * 10)
| |
| result = result..'||style="text-align:right" data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor)
| |
| end
| |
| end
| |
|
| |
| result = result..'\r\n|}'
| |
|
| |
| return result
| |
| end
| |
|
| |
| function p.getFarmingPlotTable(frame)
| |
| local areaName = frame.args ~= nil and frame.args[1] or frame
| |
| local patches = nil
| |
| for i, area in Shared.skpairs(SkillData.Farming.Patches) do
| |
| if area.areaName == areaName then
| |
| patches = area.patches
| |
| break
| |
| end
| |
| end
| |
| if patches == nil then
| |
| return "ERROR: Invalid area name.[[Category:Pages with script errors]]"
| |
| end
| |
|
| |
| local result = '{|class="wikitable"'
| |
| result = result..'\r\n!Plot!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level!!Cost'
| |
|
| |
| for i, patch in Shared.skpairs(patches) do
| |
| result = result..'\r\n|-\r\n|'..i
| |
| result = result..'||style="text-align:right;" data-sort-value="' .. 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
| |
|
| |
| -- Accepts 1 parameter, being either:
| |
| -- 'Smelting', for which a table of all bars is generated, or
| |
| -- A bar or tier name, which if valid generates a table of all smithing recipes using that bar/tier
| |
| function p.getSmithingTable(frame)
| |
| local tableType = frame.args ~= nil and frame.args[1] or frame
| |
| tableType = Shared.splitString(tableType, ' ')[1]
| |
| -- Translates Smithing category names to Smithing recipe data categories
| |
| local categoryMap = {
| |
| ['Smelting'] = 0,
| |
| ['Bronze'] = 1,
| |
| ['Iron'] = 2,
| |
| ['Steel'] = 3,
| |
| ['Mithril'] = 4,
| |
| ['Adamant'] = 5,
| |
| ['Adamantite'] = 5,
| |
| ['Rune'] = 6,
| |
| ['Runite'] = 6,
| |
| ['Dragon'] = 7,
| |
| ['Dragonite'] = 7
| |
| }
| |
| local categoryID = categoryMap[tableType]
| |
| if categoryID == nil then
| |
| return 'ERROR: Invalid Smithing category: "' .. tableType .. '"[[Category:Pages with script errors]]'
| |
| end
| |
|
| |
| -- Build a list of recipes to be included, and a list of bars while we're at it
| |
| -- The bar list will be used later for value/bar calculations
| |
| local recipeList, barIDList = {}, {}
| |
| for i, recipe in ipairs(SkillData.Smithing.Recipes) do
| |
| if recipe.category == categoryID then
| |
| local recipeItem = Items.getItemByID(recipe.itemID)
| |
| if recipeItem ~= nil then
| |
| table.insert(recipeList, { id = i, level = recipe.level, itemName = recipeItem.name, itemValue = recipeItem.sellsFor })
| |
| end
| |
| elseif recipe.category == 0 then
| |
| barIDList[recipe.itemID] = true
| |
| end
| |
| end
| |
|
| |
| -- Generate output table
| |
| local resultPart = {}
| |
| table.insert(resultPart, '{|class="wikitable sortable stickyHeader"')
| |
| table.insert(resultPart, '\r\n|-class="headerRow-0"')
| |
| table.insert(resultPart, '\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients')
| |
| --Adding value/bar for things other than smelting
| |
| if categoryID > 0 then
| |
| table.insert(resultPart, '!!Value/Bar')
| |
| end
| |
|
| |
| table.sort(recipeList, function(a, b)
| |
| if a.level ~= b.level then
| |
| return a.level < b.level
| |
| else
| |
| return a.itemName < b.itemName
| |
| end
| |
| end)
| |
|
| |
| for i, recipeDef in ipairs(recipeList) do
| |
| local recipe = SkillData.Smithing.Recipes[recipeDef.id]
| |
| local totalValue = recipe.baseQuantity * recipeDef.itemValue
| |
| -- Determine the bar quantity & build the recipe cost string
| |
| local barQty, costString = 0, {}
| |
| for j, itemCost in ipairs(recipe.itemCosts) do
| |
| local costItem = Items.getItemByID(itemCost.id)
| |
| if costItem ~= nil then
| |
| table.insert(costString, Icons.Icon({costItem.name, type='item', qty=itemCost.qty, notext=true}))
| |
| end
| |
| if barIDList[itemCost.id] then
| |
| barQty = barQty + itemCost.qty
| |
| end
| |
| end
| |
|
| |
| table.insert(resultPart, '\r\n|-')
| |
| table.insert(resultPart, '\r\n| ' .. Icons.Icon({recipeDef.itemName, type='item', size=50, notext=true}))
| |
| table.insert(resultPart, '\r\n| ')
| |
| if recipe.baseQuantity > 1 then
| |
| table.insert(resultPart, recipe.baseQuantity .. 'x ')
| |
| end
| |
| table.insert(resultPart, Icons.Icon({recipeDef.itemName, type='item', noicon=true}))
| |
| table.insert(resultPart, '\r\n|data-sort-value="' .. recipe.level .. '"| ' .. Icons._SkillReq('Smithing', recipe.level))
| |
| table.insert(resultPart, '\r\n|data-sort-value="' .. recipe.baseXP .. '"| ' .. Shared.formatnum(recipe.baseXP))
| |
| table.insert(resultPart, '\r\n|data-sort-value="' .. totalValue .. '"| ' .. Icons.GP(recipeDef.itemValue))
| |
| if recipe.baseQuantity > 1 then
| |
| table.insert(resultPart, ' (x' .. recipe.baseQuantity .. ')')
| |
| end
| |
| table.insert(resultPart, '\r\n| ' .. table.concat(costString, ', '))
| |
| if categoryID > 0 then
| |
| local barVal, barValTxt = 0, 'N/A'
| |
| if barQty > 0 then
| |
| barVal = totalValue / barQty
| |
| barTxt = Icons.GP(Shared.round(barVal, 1, 1))
| |
| end
| |
| table.insert(resultPart, '\r\n|data-sort-value="' .. barVal .. '"| ' .. barTxt)
| |
| end
| |
| end
| |
| table.insert(resultPart, '\r\n|}')
| |
|
| |
| return table.concat(resultPart)
| |
| end
| |
|
| |
| function p.getFiremakingTable(frame)
| |
| local resultPart = {}
| |
| table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
| |
| table.insert(resultPart, '\r\n|-class="headerRow-0"')
| |
| table.insert(resultPart, '\r\n!colspan="2" rowspan="2"|Logs!!rowspan="2"|'..Icons.Icon({'Firemaking', type='skill', notext=true})..' Level')
| |
| table.insert(resultPart, '!!rowspan="2"|Burn Time!!colspan="2"|Without Bonfire!!colspan="2"|With Bonfire!!rowspan="2"|Bonfire Bonus!!rowspan="2"|Bonfire Time')
| |
| table.insert(resultPart, '\r\n|-class="headerRow-1"')
| |
| table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s')
| |
|
| |
| for i, logData in Shared.skpairs(SkillData.Firemaking) do
| |
| local logs = Items.getItemByID(logData.logID)
| |
| local name = logs.name
| |
| local burnTime = logData.baseInterval / 1000
| |
| local bonfireTime = logData.baseBonfireInterval / 1000
| |
| local XPS = logData.baseXP / burnTime
| |
| local XP_BF = logData.baseXP * (1 + logData.bonfireXPBonus / 100)
| |
| local XPS_BF = XP_BF / burnTime
| |
|
| |
| table.insert(resultPart, '\r\n|-')
| |
| table.insert(resultPart, '\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='item', size='50', notext=true}))
| |
| table.insert(resultPart, '||[['..name..']]')
| |
| table.insert(resultPart, '||style ="text-align: right;"|'..logData.level)
| |
| table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..burnTime..'"|'..Shared.timeString(burnTime, true))
| |
| table.insert(resultPart, '||style ="text-align: right;"|'..logData.baseXP)
| |
| table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS..'"|'..Shared.round(XPS, 2, 2))
| |
| table.insert(resultPart, '||style ="text-align: right;"|'..Shared.round(XP_BF, 2, 0))
| |
| table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..XPS_BF..'"|'..Shared.round(XPS_BF, 2, 2))
| |
| table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..logData.bonfireXPBonus..'"|'..logData.bonfireXPBonus..'%')
| |
| table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..bonfireTime..'"|'..Shared.timeString(bonfireTime, true))
| |
| end
| |
|
| |
| table.insert(resultPart, '\r\n|}')
| |
| return table.concat(resultPart)
| |
| end
| |
|
| |
| function p.getMasteryTokenTable()
| |
| local baseTokenChance = 18500
| |
| local masterySkills = {}
| |
|
| |
| -- Find all mastery tokens
| |
| local masteryTokens = Items.getItems(function(item) return item.isToken ~= nil and item.skill ~= nil and item.isToken end)
| |
| for i, item in pairs(masteryTokens) do
| |
| local milestones = SkillData.Milestones[item.skill + 1]
| |
| if milestones ~= nil then
| |
| table.insert(masterySkills, {tokenRef = i, skillID = item.skill, milestoneCount = milestones})
| |
| end
| |
| end
| |
| table.sort(masterySkills, function(a, b)
| |
| if a['milestoneCount'] == b['milestoneCount'] then
| |
| return a['skillID'] < b['skillID']
| |
| else
| |
| return a['milestoneCount'] > b['milestoneCount']
| |
| end
| |
| end)
| |
|
| |
| -- Generate output table
| |
| local resultPart = {}
| |
| local CCI = Items.getItem('Clue Chasers Insignia')
| |
| local CCIIcon = Icons.Icon({'Clue Chasers Insignia', type='item', notext=true})
| |
| if CCI == nil then return '' end
| |
|
| |
| table.insert(resultPart, '{| class="wikitable sortable"')
| |
| table.insert(resultPart, '\r\n!rowspan="2"|Token!!rowspan="2"|Skill!!colspan="2"|Approximate Mastery Token Chance')
| |
| table.insert(resultPart, '\r\n|-\r\n!Without ' .. CCIIcon .. '!!With ' .. CCIIcon)
| |
|
| |
| for i, m in ipairs(masterySkills) do
| |
| local token = masteryTokens[m.tokenRef]
| |
| local denom = math.floor(baseTokenChance / m['milestoneCount'])
| |
| local denomCCI = Shared.round(baseTokenChance / (m['milestoneCount'] * (1 + CCI.increasedItemChance / 100)), 0, 0)
| |
|
| |
| table.insert(resultPart, '\r\n|-')
| |
| table.insert(resultPart, '\r\n|style="text-align:center"|' .. Icons.Icon({token.name, type='item', size=50, notext=true}))
| |
| table.insert(resultPart, '\r\n|' .. Icons.Icon({Constants.getSkillName(m['skillID']), type='skill'}))
| |
| table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denom .. '"|1/' .. Shared.formatnum(denom))
| |
| table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denomCCI .. '"|1/' .. Shared.formatnum(denomCCI))
| |
| end
| |
| table.insert(resultPart, '\r\n|}')
| |
|
| |
| return table.concat(resultPart)
| |
| end
| |
|
| |
| function p.getSkillUnlockCostTable()
| |
| local returnPart = {}
| |
| table.insert(returnPart, '{| class="wikitable stickyHeader"\r\n|- class="headerRow-0"\r\n!Unlock!!Cost!!Cumulative Cost')
| |
|
| |
| local accCost = 0
| |
| for i, cost in ipairs(SkillData.SkillUnlockCosts) do
| |
| accCost = accCost + cost
| |
| table.insert(returnPart, '|-')
| |
| table.insert(returnPart, '|' .. i .. '||' .. Icons.GP(cost) .. '||' .. Icons.GP(accCost))
| |
| end
| |
| table.insert(returnPart, '|}')
| |
|
| |
| return table.concat(returnPart, '\r\n')
| |
| end
| |
|
| |
| return p
| |