Module:Shop
Documentation for this module may be created at Module:Shop/doc
local p = {}
local ShopData = mw.loadData('Module:Shop/data')
local Shared = require('Module:Shared')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Constants = require('Module:Constants')
local Areas = require('Module:CombatAreas')
-- Overrides for various items, mostly relating to icon overrides
local purchOverrides = {
["Extra Bank Slot"] = { icon = {'Bank Slot', 'upgrade'}, link = 'Bank Slot', cost = Icons.Icon({'Coins', size = 25, notext = true}) .. ' <span style="font-size:127%; font-family: MathJax_Math; font-style: italic;">C<sub>b</sub></span>*' },
-- Golbin Raid items
["Reduce Wave Skip Cost"] = { icon = {'Melvor Logo', nil}, link = nil },
["Food Bonus"] = { icon = {'Melvor Logo', nil}, link = nil },
["Ammo Gatherer"] = { icon = {'Melvor Logo', nil}, link = nil },
["Rune Pouch"] = { icon = {'Melvor Logo', nil}, link = nil },
["Increase Starting Prayer Points"] = { icon = {'Melvor Logo', nil}, link = nil },
["Unlock Combat Passive Slot"] = { icon = {'Melvor Logo', nil}, link = nil },
["Prayer"] = { icon = {'Prayer', 'skill'}, link = nil },
["Increase Prayer Level"] = { icon = {'Prayer', 'skill'}, link = nil },
["Increase Prayer Points gained per Wave Completion"] = { icon = {'Prayer', 'skill'}, link = nil }
}
function p.getPurchase(purchaseName)
for categoryName, categoryData in pairs(ShopData.Shop) do
for i, purchase in ipairs(categoryData) do
if purchase.name == purchaseName then
return p.processPurchase(categoryName, i - 1)
end
end
end
end
function p.processPurchase(category, purchaseID)
local purchase = Shared.clone(ShopData.Shop[category][purchaseID + 1])
purchase.id = purchaseID
purchase.category = category
return purchase
end
function p._getPurchaseStat(purchase, stat, inline)
local displayInline = (inline ~= nil and inline or false)
if stat == 'cost' then
return p.getCostString(purchase.cost, displayInline)
elseif stat == 'requirements' then
return p.getRequirementString(purchase.unlockRequirements)
elseif stat == 'contents' then
return p._getPurchaseContents(purchase, true)
elseif stat == 'type' then
return p._getPurchaseType(purchase)
else
return purchase[stat]
end
end
function p.getPurchaseStat(frame)
local args = frame.args ~= nil and frame.args or frame
local purchaseName = args[1]
local statName = args[2]
local displayInline = (args['inline'] ~= nil and string.lower(args['inline']) == 'true' or false)
-- Hack for some purchases existing twice with varying costs (e.g. 'Extra Equipment Set')
local purchaseList = {}
if statName == 'cost' then
purchaseList = p.getPurchases(function(cat, purch) return purch.name == purchaseName end)
else
purchaseList = {p.getPurchase(purchaseName)}
end
if Shared.tableCount(purchaseList) == 0 then
return "ERROR: Couldn't find purchase with name '" .. purchaseName .. "'[[Category:Pages with script errors]]"
else
local resultPart = {}
for i, purchase in ipairs(purchaseList) do
table.insert(resultPart, p._getPurchaseStat(purchase, statName, displayInline))
end
return table.concat(resultPart, ' or ')
end
end
function p.getCostString(cost, inline)
local displayInline = (inline ~= nil and inline or false)
local costArray = {}
if cost.gp ~= nil and cost.gp > 0 then
table.insert(costArray, Icons.GP(cost.gp))
end
if cost.slayerCoins ~= nil and cost.slayerCoins > 0 then
table.insert(costArray, Icons.SC(cost.slayerCoins))
end
if cost.raidCoins ~= nil and cost.raidCoins > 0 then
table.insert(costArray, Icons.RC(cost.raidCoins))
end
local itemArray = {}
if cost.items ~= nil then
for i, itemCost in Shared.skpairs(cost.items) do
local item = Items.getItemByID(itemCost[1])
table.insert(itemArray, Icons.Icon({item.name, type="item", notext=(not displayInline and true or nil), qty=itemCost[2]}))
end
if Shared.tableCount(itemArray) > 0 then
table.insert(costArray, table.concat(itemArray, ", "))
end
end
local sep, lastSep = '<br/>', nil
if displayInline then
sep = ', '
lastSep = Shared.tableCount(costArray) > 2 and ', and ' or ' and '
end
return Shared.joinList(costArray, sep, lastSep)
end
function p.getRequirementString(reqs)
if reqs == nil or Shared.tableCount(reqs) == 0 then
return "None"
end
local reqArray = {}
if reqs.slayerTaskCompletion ~= nil then
for i, taskReq in Shared.skpairs(reqs.slayerTaskCompletion) do
local tierName = Constants.getSlayerTierName(taskReq[1])
table.insert(reqArray, 'Complete '..taskReq[2]..' '..tierName..' Slayer Tasks')
end
end
if reqs.dungeonCompletion ~= nil then
for i, dungReq in Shared.skpairs(reqs.dungeonCompletion) do
local dung = Areas.getAreaByID('dungeon', dungReq[1])
local dungStr = 'Complete '..Icons.Icon({dung.name, type='dungeon'})
if dungReq[2] > 1 then
dungStr = dungStr..' '..dungReq[2]..' times'
end
table.insert(reqArray, dungStr)
end
end
if reqs.skillLevel ~= nil then
for i, skillReq in Shared.skpairs(reqs.skillLevel) do
local skillName = Constants.getSkillName(skillReq[1])
table.insert(reqArray, Icons._SkillReq(skillName, skillReq[2]))
end
end
if reqs.shopItemPurchased ~= nil then
for i, shopReq in Shared.skpairs(reqs.shopItemPurchased) do
local purchase = ShopData.Shop[shopReq[1]][shopReq[2] + 1]
local isUpgrade = purchase.contains.items == nil or Shared.tableCount(purchase.contains.items) == 0
table.insert(reqArray, Icons.Icon({purchase.name, type=(isUpgrade and 'upgrade' or 'item')})..' Purchased')
end
end
if reqs.completionPercentage ~= nil then
table.insert(reqArray, tostring(reqs.completionPercentage) .. '% Completion Log')
end
if reqs.text ~= nil then
table.insert(reqArray, reqs.text)
end
return table.concat(reqArray, '<br/>')
end
function p._getPurchaseType(purchase)
if purchase.contains == nil then
return 'Unknown'
elseif purchase.contains.pet ~= nil then
return 'Pet'
elseif purchase.contains.modifiers ~= nil or purchase.contains.items == nil or Shared.tableCount(purchase.contains.items) == 0 then
return 'Upgrade'
elseif purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 1 then
return 'Item Bundle'
else
return 'Item'
end
end
function p._getPurchaseContents(purchase, asList)
if asList == nil then asList = true end
local containArray = {}
if purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 0 then
if not asList then
table.insert(containArray, '{| class="wikitable sortable stickyHeader"')
table.insert(containArray, '|- class="headerRow-0"')
table.insert(containArray, '! colspan="2" | Item !! Quantity')
end
for i, itemLine in Shared.skpairs(purchase.contains.items) do
local item = Items.getItemByID(itemLine[1])
if asList then
table.insert(containArray, Icons.Icon({item.name, type='item', qty=itemLine[2]}))
else
table.insert(containArray, '|-\r\n| style="min-width:25px"| ' .. Icons.Icon({item.name, type='item', notext=true, size='25'}))
table.insert(containArray, '| [[' .. item.name .. ']]\r\n| data-sort-value="' .. itemLine[2] .. '" style="text-align:right" | ' .. Shared.formatnum(itemLine[2]))
end
end
end
if purchase.charges ~= nil and purchase.charges > 0 then
if asList then
table.insert(containArray, '+'..purchase.charges..' '..Icons.Icon({purchase.name, type='item'})..' Charges')
else
table.insert(containArray, '|-\r\n| style="min-width:25px"| ' .. Icons.Icon({purchase.name, type='item', notext=true, size='25'}))
table.insert(containArray, '| [[' .. item.name .. ']] Charges\r\n| data-sort-value="' .. purchase.charges .. '" style="text-align:right" | ' .. Shared.formatnum(purchase.charges))
end
end
if not asList and Shared.tableCount(containArray) > 0 then table.insert(containArray, '|}') end
local delim = (asList and '<br/>' or '\r\n')
return table.concat(containArray, delim)
end
function p.getPurchaseContents(frame)
local args = frame.args ~= nil and frame.args or frame
local purchaseName = args[1]
local asList = ((args[2] ~= nil and args[2] == 'true') or false)
local purchase = p.getPurchase(purchaseName)
if purchase == nil then
return "ERROR: Couldn't find purchase with name '" .. purchaseName .. "'[[Category:Pages with script errors]]"
else
return p._getPurchaseContents(purchase, asList)
end
end
-- Accept similar arguments to Icons.Icon
function p._getPurchaseIcon(iconArgs)
local purchase = iconArgs[1]
local override = purchOverrides[purchase.name]
local purchType = p._getPurchaseType(purchase)
-- Amend iconArgs before passing to Icons.Icon()
iconArgs[1] = ((override ~= nil and override.icon[1]) or purchase.name)
if override ~= nil then
iconArgs['type'] = override.icon[2]
if override.link == nil then
iconArgs['nolink'] = true
end
else
iconArgs['type'] = (purchType == 'Item Bundle' and 'item') or string.lower(purchType)
end
return Icons.Icon(iconArgs)
end
function p.getPurchaseIcon(frame)
local args = frame.args ~= nil and frame.args or frame
local purchaseName = args[1]
local purchase = p.getPurchase(purchaseName)
if purchase == nil then
return "ERROR: Couldn't find purchase with name '" .. purchaseName .. "'[[Category:Pages with script errors]]"
else
args[1] = purchase
return p._getPurchaseIcon(args)
end
end
function p._getPurchaseSortValue(purchase)
local costCurrencies = {'gp', 'slayerCoins', 'raidCoins'}
for j, curr in ipairs(costCurrencies) do
local costAmt = purchase.cost[curr]
if costAmt ~= nil and costAmt > 0 then
return costAmt
end
end
end
function p._getShopTable(Purchases, options)
local availableColumns = { 'Purchase', 'Type', 'Description', 'Cost', 'Requirements' }
local headerPropsDefault = {
["Purchase"] = 'colspan="2"',
["Cost"] = 'style="min-width:90px"'
}
local usedColumns, purchHeader, sortOrder, headerProps = {}, 'Purchase', nil, {}
-- Process options if specified
if options ~= nil and type(options) == 'table' then
-- Custom columns
if options.columns ~= nil and type(options.columns) == 'table' then
for i, column in ipairs(options.columns) do
if Shared.contains(availableColumns, column) then
table.insert(usedColumns, column)
end
end
end
-- Purchase column header text
if options.purchaseHeader ~= nil and type(options.purchaseHeader) == 'string' then
purchHeader = options.purchaseHeader
end
-- Custom sort order
if options.sortOrder ~= nil and type(options.sortOrder) == 'function' then
sortOrder = options.sortOrder
end
-- Header properties
if options.headerProps ~= nil and type(options.headerProps) == 'table' then
headerProps = options.headerProps
end
end
-- Use default columns if no custom columns specified
if Shared.tableCount(usedColumns) == 0 then
usedColumns = availableColumns
end
if Shared.tableCount(headerProps) == 0 then
headerProps = headerPropsDefault
end
-- Begin output generation
local resultPart = {}
-- Generate header
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '|- class="headerRow-0"')
for i, column in ipairs(usedColumns) do
local prop = headerProps[column]
table.insert(resultPart, '!' .. (prop and prop .. '| ' or ' ') .. (column == 'Purchase' and purchHeader or column))
end
local purchIterator = nil
if sortOrder == nil then
purchIterator = Shared.skpairs
else
table.sort(Purchases, sortOrder)
purchIterator = ipairs
end
for i, purchase in purchIterator(Purchases) do
local purchOverride = nil
if purchOverrides ~= nil then
purchOverride = purchOverrides[purchase.name]
end
local purchType = p._getPurchaseType(purchase)
local iconNoLink = nil
local purchLink = ''
local costString = p.getCostString(purchase.cost, false)
if purchOverride ~= nil then
if purchOverride.link == nil then
iconNoLink = true
else
purchLink = purchOverride.link .. '|'
end
if purchOverride.cost ~= nil then costString = purchOverride.cost end
end
local purchName = purchase.name
if iconNoLink == nil or iconNoLink ~= true then purchName = '[[' .. purchLink .. purchName .. ']]' end
table.insert(resultPart, '|-')
for j, column in ipairs(usedColumns) do
if column == 'Purchase' then
table.insert(resultPart, '|style="min-width:25px"|' .. p._getPurchaseIcon({purchase, notext=true, size='50'}))
--table.insert(resultPart, '|style="min-width:25px"|' .. Icons.Icon({iconName, type=iconType, notext=true, nolink=iconNoLink, size='50'}))
table.insert(resultPart, '| ' .. purchName)
elseif column == 'Type' then
table.insert(resultPart, '| ' .. purchType)
elseif column == 'Description' then
table.insert(resultPart, '| ' .. purchase.description)
elseif column == 'Cost' then
local cellProp = '|style="text-align:right;"'
local sortValue = p._getPurchaseSortValue(purchase)
if sortValue ~= nil then cellProp = cellProp .. ' data-sort-value="' .. sortValue .. '"' end
table.insert(resultPart, cellProp .. '| ' .. costString)
elseif column == 'Requirements' then
table.insert(resultPart, '| ' .. p.getRequirementString(purchase.unlockRequirements))
else
-- Shouldn't be reached, but will prevent the resulting table becoming horribly mis-aligned if it ever happens
table.insert(resultPart, '| ')
end
end
end
table.insert(resultPart, '|}')
return table.concat(resultPart, '\r\n')
end
-- getShopTable parameter definition:
-- columns: Comma separated values indicating which columns are to be included & the order
-- in which they are displayed.
-- Values can be any of: Purchase, Type, Description, Cost, Requirements
-- columnProps: Comma separated values indicating formatting to be applied to each column. Each
-- value must be in the format column:property, e.g. Purchase:colspan="2"
-- sortOrder: A function determining the order in which table items appear
-- purchaseHeader: Specifies header text for the Purchase column if not 'Purchase'
function p.getShopTable(frame)
local cat = frame.args ~= nil and frame.args[1] or frame
local options = {}
if frame.args ~= nil then
if frame.args.columns ~= nil then options.columns = Shared.splitString(frame.args.columns, ',') end
if frame.args.purchaseHeader ~= nil then options.purchaseHeader = frame.args.purchaseHeader end
if frame.args.sortOrder ~= nil then options.sortOrder = frame.args.sortOrder end
if frame.args.columnProps ~= nil then
local columnPropValues = Shared.splitString(frame.args.columnProps, ',')
local columnProps = {}
for i, prop in pairs(columnPropValues) do
local propName, propValue = string.match(prop, '^([^:]+):(.*)$')
if propName ~= nil then
columnProps[propName] = propValue
end
end
if Shared.tableCount(columnProps) > 0 then options.headerProps = columnProps end
end
end
local shopCat = ShopData.Shop[cat]
if shopCat == nil then
return 'ERROR: Invalid category '..cat..'[[Category:Pages with script errors]]'
else
return p._getShopTable(shopCat, options)
end
end
function p.getItemCostArray(itemID)
local purchaseArray = {}
for catName, cat in Shared.skpairs(ShopData.Shop) do
for j, purchase in Shared.skpairs(cat) do
if purchase.cost.items ~= nil then
for k, costLine in Shared.skpairs(purchase.cost.items) do
if costLine[1] == itemID then
local temp = p.processPurchase(catName, j - 1)
temp.qty = costLine[2]
table.insert(purchaseArray, temp)
break
end
end
end
end
end
return purchaseArray
end
function p.getItemSourceArray(itemID)
local purchaseArray = {}
for catName, cat in Shared.skpairs(ShopData.Shop) do
for j, purchase in Shared.skpairs(cat) do
if purchase.contains.items ~= nil and purchase.contains.items ~= nil then
for k, containsLine in Shared.skpairs(purchase.contains.items) do
if containsLine [1] == itemID then
local temp = p.processPurchase(catName, j - 1)
temp.qty = containsLine[2]
table.insert(purchaseArray, temp)
break
end
end
end
end
end
return purchaseArray
end
function p.getPurchases(checkFunc)
local purchaseList = {}
for category, purchaseArray in Shared.skpairs(ShopData.Shop) do
for i, purchase in Shared.skpairs(purchaseArray) do
if checkFunc(category, purchase) then
table.insert(purchaseList, p.processPurchase(category, i - 1))
end
end
end
return purchaseList
end
function p._getPurchaseTable(purchase)
local result = '{| class="wikitable"\r\n|-'
result = result..'\r\n!colspan="2"|'..Icons.Icon({'Shop'})..' Purchase'
if purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 1 then
result = result..' - '..Icons.Icon({purchase.name, type='item'})
end
result = result..'\r\n|-\r\n!style="text-align:right;"|Cost'
result = result..'\r\n|'..p.getCostString(purchase.cost, false)
result = result..'\r\n|-\r\n!style="text-align:right;"|Requirements'
result = result..'\r\n|'..p.getRequirementString(purchase.unlockRequirements)
result = result..'\r\n|-\r\n!style="text-align:right;"|Contains'
result = result..'\r\n|style="text-align:right;"|'..p._getPurchaseContents(purchase, true)
result = result..'\r\n|}'
return result
end
function p._getItemShopTable(item)
local tableArray = {}
local purchaseArray = p.getItemSourceArray(item.id)
for i, purchase in Shared.skpairs(purchaseArray) do
table.insert(tableArray, p._getPurchaseTable(purchase))
end
return table.concat(tableArray, '\r\n\r\n')
end
function p.getItemShopTable(frame)
local itemName = frame.args ~= nil and frame.args[1] or frame
local item = Items.getItem(itemName)
if item == nil then
return "ERROR: No item named "..itemName.." exists in the data module"
end
return p._getItemShopTable(item)
end
function p.getShopMiscUpgradeTable()
local purchList = p.getPurchases(function(cat, purch) return cat == 'General' and string.find(purch.name, '^Auto Eat') == nil end)
return p._getShopTable(purchList, { columns = { 'Purchase', 'Description', 'Cost' }, purchaseHeader = 'Upgrade' })
end
function p.getShopSkillcapeTable()
local capeList = p.getPurchases(function(cat, purch) return cat == 'Skillcapes' end)
local sortOrderFunc = function(a, b)
if a.cost.gp == b.cost.gp then
return a.name < b.name
else
return a.cost.gp < b.cost.gp
end
end
return p._getShopTable(capeList,
{ columns = { 'Purchase', 'Description', 'Cost' },
purchaseHeader = 'Cape',
sortOrder = sortOrderFunc,
headerProps = {["Purchase"] = 'colspan="2" style="width:200px;"', ["Cost"] = 'style=width:120px;'}
})
end
function p.getAutoEatTable()
local resultPart = {}
local purchasesAE = p.getPurchases(function(cat, purch) return string.find(purch.name, '^Auto Eat') ~= nil end)
-- Table header
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '|- class="headerRow-0"')
table.insert(resultPart, '!colspan="2"|Auto Eat Tier!!Minimum Threshold!!Efficiency!!Max Healing!!Cost')
-- Rows for each Auto Eat tier
local mods = {["increasedAutoEatEfficiency"] = 0, ["increasedAutoEatHPLimit"] = 0, ["increasedAutoEatThreshold"] = 0}
for i, purchase in ipairs(purchasesAE) do
-- Modifiers must be accumulated as we go
for modName, modValue in pairs(mods) do
if purchase.contains.modifiers[modName] ~= nil then
mods[modName] = mods[modName] + purchase.contains.modifiers[modName]
end
end
local costAmt = p._getPurchaseSortValue(purchase)
table.insert(resultPart, '|-\r\n|style="min-width:25px; text-align:center;" data-sort-value="' .. purchase.name .. '"| ' .. Icons.Icon({purchase.name, type='upgrade', size=50, notext=true}))
table.insert(resultPart, '| [[' .. purchase.name .. ']]')
table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. mods.increasedAutoEatThreshold .. '" | ' .. Shared.formatnum(Shared.round(mods.increasedAutoEatThreshold, 0, 0)) .. '%')
table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. mods.increasedAutoEatEfficiency .. '" | ' .. Shared.formatnum(Shared.round(mods.increasedAutoEatEfficiency, 0, 0)) .. '%')
table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. mods.increasedAutoEatHPLimit .. '" | ' .. Shared.formatnum(Shared.round(mods.increasedAutoEatHPLimit, 0, 0)) .. '%')
table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. costAmt .. '" | ' .. Icons.GP(costAmt))
end
table.insert(resultPart, '|}')
return table.concat(resultPart, '\r\n')
end
function p.getGodUpgradeTable()
local resultPart = {}
-- Obtain list of God upgrades: look for skill upgrades which have a dungeon completion
-- requirement for an area whose name ends with 'God Dungeon'
local getGodDungeon =
function(reqs)
if reqs.dungeonCompletion ~= nil then
for i, areaReq in ipairs(reqs.dungeonCompletion) do
local dung = Areas.getAreaByID('dungeon', areaReq[1])
if string.find(dung.name, 'God Dungeon$') ~= nil then return dung end
end
end
end
local upgradeList = p.getPurchases(
function(cat, purch)
if cat == 'SkillUpgrades' and purch.unlockRequirements ~= nil then
return getGodDungeon(purch.unlockRequirements) ~= nil
end
return false
end)
if Shared.tableCount(upgradeList) == 0 then return '' end
-- Table header
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '|- class="headerRow-0"')
table.insert(resultPart, '!colspan="2"|God Upgrade!!Effect!!Dungeon!!Cost')
-- Rows for each God upgrade
for i, upgrade in ipairs(upgradeList) do
local dung = getGodDungeon(upgrade.unlockRequirements)
local costSortValue = p._getPurchaseSortValue(upgrade)
table.insert(resultPart, '|-\r\n|style="min-width:25px; text-align:center;" data-sort-value="' .. upgrade.name .. '"| ' .. Icons.Icon({upgrade.name, type='upgrade', size=50, notext=true}))
table.insert(resultPart, '| [[' .. upgrade.name .. ']]')
table.insert(resultPart, '| ' .. upgrade.description)
table.insert(resultPart, '| data-sort-value="' .. dung.name .. '"| ' .. Icons.Icon({dung.name, type='dungeon'}))
table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. costSortValue .. '"| ' .. p.getCostString(upgrade.cost, false))
end
table.insert(resultPart, '|}')
return table.concat(resultPart, '\r\n')
end
function p.getCookingUtilityTable(frame)
local category = nil
if frame ~= nil then category = frame.args ~= nil and frame.args[1] or frame end
local validCategories = {'Cooking Fire', 'Furnace', 'Pot'}
if category == nil or not Shared.contains({'Cooking Fire', 'Furnace', 'Pot'}, category) then
return 'ERROR: Invalid category specified. Must be one of the following: ' .. mw.text.listToText(validCategories, ', ', ' or ')
end
local categoryShort = string.match(category, '[^%s]+$')
local bonusSkillID = Constants.getSkillID('Cooking')
local bonusColMod, bonusColName = nil, nil
if category == 'Cooking Fire' then
bonusColMod = 'increasedSkillXP'
bonusColName = 'Bonus ' .. Icons.Icon({'Cooking', type='skill', notext=true}) .. ' XP'
else
bonusColMod = 'increasedChanceToDoubleItemsSkill'
bonusColName = 'Double Items Chance'
end
local modsPerfectChance = {'increasedChancePerfectCookFire', 'increasedChancePerfectCookFurnace',
'increasedChancePerfectCookPot', 'increasedChancePerfectCookGlobal'}
local totalBonusVal, totalPerfectChance = 0, 0
local utilityList = p.getPurchases(function(cat, purch) return cat == 'SkillUpgrades' and string.find(purch.name, category .. '$') ~= nil end)
local resultPart = {}
-- Table header
table.insert(resultPart, '{| class="wikitable stickyHeader"')
table.insert(resultPart, '|- class="headerRow-0"')
table.insert(resultPart, '!colspan="4"| !!colspan="2"|' .. bonusColName .. '!!colspan="2"|Bonus Perfect Chance')
table.insert(resultPart, '|- class="headerRow-1"')
table.insert(resultPart, '!colspan="2"|Name!!Level!!Cost' .. string.rep('!!This ' .. categoryShort .. '!!Total', 2))
-- Row for each upgrade
for i, utility in ipairs(utilityList) do
-- First determine bonus XP/doubling chance and perfect chance
local bonusVal, perfectChance = 0, 0
if type(utility.contains) == 'table' then
if type(utility.contains.modifiers) == 'table' then
for modName, modVal in pairs(utility.contains.modifiers) do
if modName == bonusColMod and type(modVal) == 'table' then
-- Bonus XP/doubling
for skID, skVal in pairs(modVal) do
if skVal[1] == bonusSkillID then bonusVal = bonusVal + skVal[2] end
end
elseif Shared.contains(modsPerfectChance, modName) then
-- Perfect chance
perfectChance = perfectChance + modVal
end
end
end
end
totalBonusVal = totalBonusVal + bonusVal
totalPerfectChance = totalPerfectChance + perfectChance
-- Mangle unlockRequirements so that it only includes skillLevels
local unlockReqs = {}
if type(utility.unlockRequirements) == 'table' then
unlockReqs['skillLevel'] = utility.unlockRequirements.skillLevel
end
table.insert(resultPart, '|-')
table.insert(resultPart, '|style="min-width:25px"|' .. Icons.Icon({utility.name, type='upgrade', size='50', notext=true}))
table.insert(resultPart, '|' .. utility.name)
table.insert(resultPart, '|style="text-align:right"|' .. p.getRequirementString(unlockReqs))
table.insert(resultPart, '|style="text-align:right"|' .. p.getCostString(utility.cost, false))
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. bonusVal .. '%')
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. totalBonusVal .. '%')
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. perfectChance .. '%')
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. totalPerfectChance .. '%')
end
table.insert(resultPart, '|}')
return table.concat(resultPart, '\r\n')
end
return p