Anonymous

Module:Shop: Difference between revisions

From Melvor Idle
6,706 bytes added ,  18 April 2022
m
Fix typo
(Implement getPurchase, getPurchaseStat, getCostString, _getPurchaseType, _getPurchaseContents, getPurchaseIcon; facilitates implementing a 'PurchaseBox' template)
m (Fix typo)
(19 intermediate revisions by 2 users not shown)
Line 2: Line 2:


local ShopData = mw.loadData('Module:Shop/data')
local ShopData = mw.loadData('Module:Shop/data')
local ConstantData = mw.loadData('Module:Constants/data')
-- Data instead of Module:CombatAreas to avoid loop when that module attempts to require Module:Shop
local AreaData = require('Module:CombatAreas/data')


local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
Line 7: Line 10:
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
local Areas = require('Module:CombatAreas')


-- Overrides for various items, mostly relating to icon overrides
-- Overrides for various items, mostly relating to icon overrides
local purchOverrides = {
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>*' },
["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
-- Golbin Raid items
  ["Reduce Wave Skip Cost"] = { icon = {'Melvor Logo', nil}, link = nil },
["Reduce Wave Skip Cost"] = { icon = {'Melvor Logo', nil}, link = nil },
  ["Food Bonus"] = { icon = {'Melvor Logo', nil}, link = nil },
["Food Bonus"] = { icon = {'Melvor Logo', nil}, link = nil },
  ["Ammo Gatherer"] = { icon = {'Melvor Logo', nil}, link = nil },
["Ammo Gatherer"] = { icon = {'Melvor Logo', nil}, link = nil },
  ["Rune Pouch"] = { icon = {'Melvor Logo', nil}, link = nil },
["Rune Pouch"] = { icon = {'Melvor Logo', nil}, link = nil },
  ["Increase Starting Prayer Points"] = { 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 },
["Unlock Combat Passive Slot"] = { icon = {'Melvor Logo', nil}, link = nil },
  ["Prayer"] = { icon = {'Prayer', 'skill'}, link = nil },
["Prayer"] = { icon = {'Prayer', 'skill'}, link = nil },
  ["Increase Prayer Level"] = { 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 }
["Increase Prayer Points gained per Wave Completion"] = { icon = {'Prayer', 'skill'}, link = nil },
["Faster Golbin Spawns"] = { icon = {'Timer', nil}, link = nil, incCost = true},
["Golbin Crate"] = { icon = {'Golbin Crate', 'upgrade'}, link = nil, incCost = true}
}
}


function p.getPurchase(purchaseName)
function p.getPurchase(purchaseName)
  for categoryName, categoryData in pairs(ShopData.Shop) do
for categoryName, categoryData in pairs(ShopData.Shop) do
    for i, purchase in ipairs(categoryData) do
for i, purchase in ipairs(categoryData) do
      if purchase.name == purchaseName then
if purchase.name == purchaseName then
        return p.processPurchase(categoryName, i - 1)
return p.processPurchase(categoryName, i - 1)
      end
end
    end
end
  end
end
end
end


function p.processPurchase(category, purchaseID)
function p.processPurchase(category, purchaseID)
  local purchase = Shared.clone(ShopData.Shop[category][purchaseID + 1])
local purchase = Shared.clone(ShopData.Shop[category][purchaseID + 1])
  purchase.id = purchaseID
purchase.id = purchaseID
  purchase.category = category
purchase.category = category
  return purchase
return purchase
end
end


function p._getPurchaseStat(purchase, stat, inline)
function p._getPurchaseStat(purchase, stat, inline)
  local displayInline = (inline ~= nil and inline or false)
local displayInline = (inline ~= nil and inline or false)
  if stat == 'cost' then
if stat == 'cost' then
    return p.getCostString(purchase.cost, displayInline)
return p.getCostString(purchase.cost, displayInline)
  elseif stat == 'requirements' then
elseif stat == 'requirements' then
    return p.getRequirementString(purchase.unlockRequirements)
return p.getRequirementString(purchase.unlockRequirements)
  elseif stat == 'contents' then
elseif stat == 'contents' then
    return p._getPurchaseContents(purchase)
return p._getPurchaseContents(purchase, true)
  elseif stat == 'type' then
elseif stat == 'type' then
    return p._getPurchaseType(purchase)
return p._getPurchaseType(purchase)
  else
elseif stat == 'buyLimit' then
    return purchase[stat]
return p._getPurchaseBuyLimit(purchase, not displayInline)
  end
else
return purchase[stat]
end
end
end


function p.getPurchaseStat(frame)
function p.getPurchaseStat(frame)
  local args = frame.args ~= nil and frame.args or frame
local args = frame.args ~= nil and frame.args or frame
  local purchaseName = args[1]
local purchaseName = args[1]
  local statName = args[2]
local statName = args[2]
  local displayInline = (args['inline'] ~= nil and string.lower(args['inline']) == 'true' or false)
local displayInline = (args['inline'] ~= nil and string.lower(args['inline']) == 'true' or false)
  local purchase = p.getPurchase(purchaseName)
-- 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 purchase == nil then
if Shared.tableCount(purchaseList) == 0 then
    return "ERROR: Couldn't find purchase with name '" .. purchaseName .. "'[[Category:Pages with script errors]]"
return "ERROR: Couldn't find purchase with name '" .. purchaseName .. "'[[Category:Pages with script errors]]"
  else
else
    return p._getPurchaseStat(purchase, statName, displayInline)
local resultPart = {}
  end
for i, purchase in ipairs(purchaseList) do
table.insert(resultPart, p._getPurchaseStat(purchase, statName, displayInline))
end
return table.concat(resultPart, ' or ')
end
end
end


function p.getCostString(cost, inline)
function p.getCostString(cost, inline)
  local displayInline = (inline ~= nil and inline or false)
local displayInline = (inline ~= nil and inline or false)
  local costArray = {}
local costArray = {}
  if cost.gp ~= nil and cost.gp > 0 then
if cost.gp ~= nil and cost.gp > 0 then
    table.insert(costArray, Icons.GP(cost.gp))
table.insert(costArray, Icons.GP(cost.gp))
  end
end
  if cost.slayerCoins ~= nil and cost.slayerCoins > 0 then
if cost.slayerCoins ~= nil and cost.slayerCoins > 0 then
    table.insert(costArray, Icons.SC(cost.slayerCoins))
table.insert(costArray, Icons.SC(cost.slayerCoins))
  end
end
  if cost.raidCoins ~= nil and cost.raidCoins > 0 then
if cost.raidCoins ~= nil and cost.raidCoins > 0 then
    table.insert(costArray, Icons.RC(cost.raidCoins))
table.insert(costArray, Icons.RC(cost.raidCoins))
  end
end
  local itemArray = {}
local itemArray = {}
  if cost.items ~= nil then
if cost.items ~= nil then
    for i, itemCost in Shared.skpairs(cost.items) do
for i, itemCost in Shared.skpairs(cost.items) do
      local item = Items.getItemByID(itemCost[1])
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]}))
table.insert(itemArray, Icons.Icon({item.name, type="item", notext=(not displayInline and true or nil), qty=itemCost[2]}))
    end
end


    if Shared.tableCount(itemArray) > 0 then
if Shared.tableCount(itemArray) > 0 then
      table.insert(costArray, table.concat(itemArray, ", "))
table.insert(costArray, table.concat(itemArray, ", "))
    end
end
  end
end


  local sep, lastSep = '<br/>', nil
local sep, lastSep = '<br/>', '<br/>'
  if displayInline then
if displayInline then
    sep = ', '
sep = ', '
    lastSep = Shared.tableCount(costArray) > 2 and ', and ' or ' and '
lastSep = Shared.tableCount(costArray) > 2 and ', and ' or ' and '
  end
end
  return Shared.joinList(costArray, sep, lastSep)
return mw.text.listToText(costArray, sep, lastSep)
end
end


function p.getRequirementString(reqs)
function p.getRequirementString(reqs)
  if reqs == nil or Shared.tableCount(reqs) == 0 then
if reqs == nil or Shared.tableCount(reqs) == 0 then
    return "None"
return "None"
  end
end


  local reqArray = {}
local reqArray = {}
  if reqs.slayerTaskCompletion ~= nil then
if reqs.slayerTaskCompletion ~= nil then
    for i, taskReq in Shared.skpairs(reqs.slayerTaskCompletion) do
for i, taskReq in Shared.skpairs(reqs.slayerTaskCompletion) do
      local tierName = Constants.getSlayerTierName(taskReq[1])
local tierName = Constants.getSlayerTierName(taskReq[1])
      table.insert(reqArray, 'Complete '..taskReq[2]..' '..tierName..' Slayer Tasks')
table.insert(reqArray, 'Complete '..taskReq[2]..' '..tierName..' Slayer Tasks')
    end
end
  end
end


  if reqs.dungeonCompletion ~= nil then
if reqs.dungeonCompletion ~= nil then
    for i, dungReq in Shared.skpairs(reqs.dungeonCompletion) do
for i, dungReq in Shared.skpairs(reqs.dungeonCompletion) do
      local dung = Areas.getAreaByID('dungeon', dungReq[1])
local dung = AreaData['dungeons'][dungReq[1] + 1]
      local dungStr = 'Complete '..Icons.Icon({dung.name, type='dungeon'})
local dungStr = 'Complete '..Icons.Icon({dung.name, type='dungeon'})
      if dungReq[2] > 1 then
if dungReq[2] > 1 then
        dungStr = dungStr..' '..dungReq[2]..' times'
dungStr = dungStr..' '..dungReq[2]..' times'
      end
end
      table.insert(reqArray, dungStr)
table.insert(reqArray, dungStr)
    end
end
  end
end


  if reqs.skillLevel ~= nil then
if reqs.skillLevel ~= nil then
    for i, skillReq in Shared.skpairs(reqs.skillLevel) do
for i, skillReq in Shared.skpairs(reqs.skillLevel) do
      local skillName = Constants.getSkillName(skillReq[1])
local skillName = Constants.getSkillName(skillReq[1])
      table.insert(reqArray, Icons._SkillReq(skillName, skillReq[2]))
table.insert(reqArray, Icons._SkillReq(skillName, skillReq[2]))
    end
end
  end
end


  if reqs.shopItemPurchased ~= nil then
if reqs.shopItemPurchased ~= nil then
    for i, shopReq in Shared.skpairs(reqs.shopItemPurchased) do
for i, shopReq in Shared.skpairs(reqs.shopItemPurchased) do
      local purchase = ShopData.Shop[shopReq[1]][shopReq[2] + 1]
local purchase = ShopData.Shop[shopReq[1]][shopReq[2] + 1]
      local isUpgrade = purchase.contains.items == nil or Shared.tableCount(purchase.contains.items) == 0
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')
table.insert(reqArray, Icons.Icon({purchase.name, type=(isUpgrade and 'upgrade' or 'item')})..' Purchased')
    end
end
  end
end


  if reqs.completionPercentage ~= nil then
if reqs.completionPercentage ~= nil then
    table.insert(reqArray, tostring(reqs.completionPercentage) .. '% Completion Log')
table.insert(reqArray, tostring(reqs.completionPercentage) .. '% Completion Log')
  end
end


  if reqs.text ~= nil then
if reqs.text ~= nil then
    table.insert(reqArray, reqs.text)
table.insert(reqArray, reqs.text)
  end
end


  return table.concat(reqArray, '<br/>')
return table.concat(reqArray, '<br/>')
end
end


function p._getPurchaseType(purchase)
function p._getPurchaseType(purchase)
  if purchase.contains == nil then
if purchase.contains == nil then
    return 'Unknown'
return 'Unknown'
  elseif purchase.contains.pet ~= nil then
elseif purchase.contains.pet ~= nil then
    return 'Pet'
return 'Pet'
  elseif purchase.contains.modifiers ~= nil or purchase.contains.items == nil or Shared.tableCount(purchase.contains.items) == 0 then
elseif purchase.contains.modifiers ~= nil or purchase.contains.items == nil or Shared.tableCount(purchase.contains.items) == 0 then
    return 'Upgrade'
return 'Upgrade'
  elseif purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 1 then
elseif purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 1 then
    return 'Item Bundle'
return 'Item Bundle'
  else
else
    return 'Item'
return 'Item'
  end
end
end
end


function p._getPurchaseContents(purchase)
function p._getPurchaseContents(purchase, asList)
  local containArray = {}
if asList == nil then asList = true end
  if purchase.contains.items ~= nil then
local containArray = {}
    for i, itemLine in Shared.skpairs(purchase.contains.items) do
local GPTotal = 0
      local item = Items.getItemByID(itemLine[1])
if purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 0 then
      table.insert(containArray, Icons.Icon({item.name, type='item', qty=itemLine[2]}))
if not asList then
    end
table.insert(containArray, '{| class="wikitable sortable stickyHeader"')
  end
table.insert(containArray, '|- class="headerRow-0"')
  if purchase.charges ~= nil and purchase.charges > 0 then
table.insert(containArray, '! colspan="2" | Item !! Quantity !! Price')
    table.insert(containArray, '+'..purchase.charges..' '..Icons.Icon({purchase.name, type='item'})..' Charges')
end
  end
for i, itemLine in Shared.skpairs(purchase.contains.items) do
  return table.concat(containArray, '<br/>')
local item = Items.getItemByID(itemLine[1])
if asList then
table.insert(containArray, Icons.Icon({item.name, type='item', qty=itemLine[2]}))
else
local GPVal = item.sellsFor * itemLine[2]
GPTotal = GPTotal + GPVal
table.insert(containArray, '|-\r\n| style="min-width:25px"| ' .. Icons.Icon({item.name, type='item', notext=true, size='25'}))
table.insert(containArray, '| ' .. Icons.Icon({item.name, type='item', noicon=true}) .. '\r\n| data-sort-value="' .. itemLine[2] .. '" style="text-align:right" | ' .. Shared.formatnum(itemLine[2]))
table.insert(containArray, '| data-sort-value="' .. GPVal .. '"| ' .. Icons.GP(GPVal))
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, '| ' .. Icons.Icon({purchase.name, type='item', noicon=true}) .. ' Charges\r\n| data-sort-value="' .. purchase.charges .. '" style="text-align:right" | ' .. Shared.formatnum(purchase.charges))
table.insert(containArray, '| data-sort-value="0"| ' .. Icons.GP(0))
end
end
if not asList and Shared.tableCount(containArray) > 0 then
table.insert(containArray, '|- class="sortbottom"\r\n! colspan="3"| Total\r\n| ' .. Icons.GP(GPTotal) .. '\r\n|}')
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 string.upper(args[2]) == 'TRUE')
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
 
function p._getPurchaseBuyLimit(purchase, asList)
if asList == nil then asList = true end
if type(purchase.buyLimit) == 'table' then
local limitTable = {}
local gamemodeHasIcon = { 1, 2 }
-- Populate limitTable for each game mode to be included
for id, modeName in pairs(ConstantData.gamemode) do
if tonumber(id) ~= nil and string.upper(modeName) ~= 'CHAOS' then
local buyLimit = tostring(purchase.buyLimit[id + 1])
if limitTable[buyLimit] == nil then
limitTable[buyLimit] = {}
end
local gamemodeText = '[[Game Mode#' .. modeName .. '|' .. modeName .. ']]'
if Shared.contains(gamemodeHasIcon, id) then
gamemodeText = Icons.Icon({modeName, notext=(not asList or nil)})
end
table.insert(limitTable[buyLimit], gamemodeText)
end
end
local numLimits = Shared.tableCount(limitTable)
local resultPart = {}
for buyLimit, gameModes in Shared.skpairs(limitTable, true) do
local limitText = (buyLimit == '0' and 'Unlimited' or tostring(buyLimit))
if numLimits == 1 then
-- Buy limit is the same for all game modes
return limitText
else
table.insert(resultPart, limitText .. (asList and ' for ' or ' ') .. mw.text.listToText(gameModes, ', ', (asList and ' and ' or ', ')))
end
end
return table.concat(resultPart, (asList and ' or ' or '<br/>'))
end
end
 
function p.getPurchaseBuyLimit(frame)
local args = frame.args ~= nil and frame.args or frame
local purchaseName = args[1]
local asList = (args[2] ~= nil and string.upper(args[2]) == 'TRUE')
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._getPurchaseBuyLimit(purchase, asList)
end
end
end


-- Accept similar arguments to Icons.Icon
-- Accept similar arguments to Icons.Icon
function p._getPurchaseIcon(iconArgs)
function p._getPurchaseIcon(iconArgs)
  local purchase = iconArgs[1]
local purchase = iconArgs[1]
  local override = purchOverrides[purchase.name]
local override = purchOverrides[purchase.name]
  local purchType = p._getPurchaseType(purchase)
local purchType = p._getPurchaseType(purchase)
  -- Amend iconArgs before passing to Icons.Icon()
-- Amend iconArgs before passing to Icons.Icon()
  iconArgs[1] = ((override ~= nil and override.icon[1]) or purchase.name)
iconArgs[1] = ((override ~= nil and override.icon[1]) or purchase.name)
  if override ~= nil then
if override ~= nil then
    iconArgs['type'] = override.icon[2]
iconArgs['type'] = override.icon[2]
    if override.link == nil then
if override.link == nil then
      iconArgs['nolink'] = true
iconArgs['nolink'] = true
    end
end
  else
else
    iconArgs['type'] = (purchType == 'Item Bundle' and 'item') or string.lower(purchType)
iconArgs['type'] = (purchType == 'Item Bundle' and 'item') or string.lower(purchType)
  end
end


  return Icons.Icon(iconArgs)
return Icons.Icon(iconArgs)
end
end


function p.getPurchaseIcon(frame)
function p.getPurchaseIcon(frame)
  local args = frame.args ~= nil and frame.args or frame
local args = frame.args ~= nil and frame.args or frame
  local purchaseName = args[1]
local purchaseName = args[1]
  local purchase = p.getPurchase(purchaseName)
local purchase = p.getPurchase(purchaseName)


  if purchase == nil then
if purchase == nil then
    return "ERROR: Couldn't find purchase with name '" .. purchaseName .. "'[[Category:Pages with script errors]]"
return "ERROR: Couldn't find purchase with name '" .. purchaseName .. "'[[Category:Pages with script errors]]"
  else
else
    args[1] = purchase
args[1] = purchase
    return p._getPurchaseIcon(args)
return p._getPurchaseIcon(args)
  end
end
end
end


function p._getPurchaseSortValue(purchase)
function p._getPurchaseSortValue(purchase)
  local costCurrencies = {'gp', 'slayerCoins', 'raidCoins'}
local costCurrencies = {'gp', 'slayerCoins', 'raidCoins'}
  for j, curr in ipairs(costCurrencies) do
for j, curr in ipairs(costCurrencies) do
    local costAmt = purchase.cost[curr]
local costAmt = purchase.cost[curr]
    if costAmt ~= nil and costAmt > 0 then
if costAmt ~= nil and costAmt > 0 then
      return costAmt
return costAmt
    end
end
  end
end
end
end


function p._getShopTable(Purchases, options)
function p._getShopTable(Purchases, options)
  local availableColumns = { 'Purchase', 'Type', 'Description', 'Cost', 'Requirements' }
local availableColumns = { 'Purchase', 'Type', 'Description', 'Cost', 'Requirements', 'Buy Limit' }
  local headerPropsDefault = {
local headerPropsDefault = {
    ["Purchase"] = 'colspan="2"',
["Purchase"] = 'colspan="2"',
    ["Cost"] = 'style="min-width:90px"'
["Cost"] = 'style="min-width:100px"'
  }
}
  local usedColumns, purchHeader, sortOrder, headerProps = {}, 'Purchase', nil, {}
local usedColumns, purchHeader, sortOrder, headerProps = {}, 'Purchase', nil, {}


  -- Process options if specified
-- Process options if specified
  if options ~= nil and type(options) == 'table' then
if options ~= nil and type(options) == 'table' then
    -- Custom columns
-- Custom columns
    if options.columns ~= nil and type(options.columns) == 'table' then
if options.columns ~= nil and type(options.columns) == 'table' then
      for i, column in ipairs(options.columns) do
for i, column in ipairs(options.columns) do
        if Shared.contains(availableColumns, column) then
if Shared.contains(availableColumns, column) then
          table.insert(usedColumns, column)
table.insert(usedColumns, column)
        end
end
      end
end
    end
end
    -- Purchase column header text
-- Purchase column header text
    if options.purchaseHeader ~= nil and type(options.purchaseHeader) == 'string' then
if options.purchaseHeader ~= nil and type(options.purchaseHeader) == 'string' then
      purchHeader = options.purchaseHeader
purchHeader = options.purchaseHeader
    end
end
    -- Custom sort order
-- Custom sort order
    if options.sortOrder ~= nil and type(options.sortOrder) == 'function' then
if options.sortOrder ~= nil and type(options.sortOrder) == 'function' then
      sortOrder = options.sortOrder
sortOrder = options.sortOrder
    end
end
    -- Header properties
-- Header properties
    if options.headerProps ~= nil and type(options.headerProps) == 'table' then
if options.headerProps ~= nil and type(options.headerProps) == 'table' then
      headerProps = options.headerProps
headerProps = options.headerProps
    end
end
  end
end
  -- Use default columns if no custom columns specified
-- Use default columns if no custom columns specified
  if Shared.tableCount(usedColumns) == 0 then
if Shared.tableCount(usedColumns) == 0 then
    usedColumns = availableColumns
usedColumns = availableColumns
  end
end
  if Shared.tableCount(headerProps) == 0 then
if Shared.tableCount(headerProps) == 0 then
    headerProps = headerPropsDefault
headerProps = headerPropsDefault
  end
end


  -- Various overrides for certain shop items
-- Begin output generation
  local purchOverrides = {
local resultPart = {}
    ["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>*' },
-- Generate header
    -- Golbin Raid items
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
    ["Reduce Wave Skip Cost"] = { icon = {'Melvor Logo', nil}, link = nil },
table.insert(resultPart, '|- class="headerRow-0"')
    ["Food Bonus"] = { icon = {'Melvor Logo', nil}, link = nil },
for i, column in ipairs(usedColumns) do
    ["Ammo Gatherer"] = { icon = {'Melvor Logo', nil}, link = nil },
local prop = headerProps[column]
    ["Rune Pouch"] = { icon = {'Melvor Logo', nil}, link = nil },
table.insert(resultPart, '!' .. (prop and prop .. '| ' or ' ') .. (column == 'Purchase' and purchHeader or column))
    ["Increase Starting Prayer Points"] = { icon = {'Melvor Logo', nil}, link = nil },
end
    ["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 }
  }
  -- 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
local purchIterator = nil
  if sortOrder == nil then
if sortOrder == nil then
    purchIterator = Shared.skpairs
purchIterator = Shared.skpairs
  else
else
    table.sort(Purchases, sortOrder)
table.sort(Purchases, sortOrder)
    purchIterator = ipairs
purchIterator = ipairs
  end
end
  for i, purchase in purchIterator(Purchases) do
for i, purchase in purchIterator(Purchases) do
    local purchOverride = nil
local purchOverride = nil
    if purchOverrides ~= nil then
if purchOverrides ~= nil then
      purchOverride = purchOverrides[purchase.name]
purchOverride = purchOverrides[purchase.name]
    end
end


    local purchType = p._getPurchaseType(purchase)
local purchType = p._getPurchaseType(purchase)
    local iconNoLink = nil
local iconNoLink = nil
    local purchLink = ''
local purchLink = ''
    local costString = p.getCostString(purchase.cost, false)
local costString = p.getCostString(purchase.cost, false)
    if purchOverride ~= nil then
if purchOverride ~= nil then
      if purchOverride.link == nil then
if purchOverride.link == nil then
        iconNoLink = true
iconNoLink = true
      else
else
        purchLink = purchOverride.link .. '|'
purchLink = purchOverride.link .. '|'
      end
end
      if purchOverride.cost ~= nil then costString = purchOverride.cost end
if purchOverride.cost ~= nil then costString = purchOverride.cost end
    end
if purchOverride.incCost then
costString = costString .. '<br/>+' .. costString .. ' for each purchase'
end
end


    local purchName = purchase.name
local purchName = purchase.name
    if iconNoLink == nil or iconNoLink ~= true then purchName = '[[' .. purchLink .. purchName .. ']]' end
if iconNoLink == nil or iconNoLink ~= true then purchName = '[[' .. purchLink .. purchName .. ']]' end


    table.insert(resultPart, '|-')
table.insert(resultPart, '|-')
    for j, column in ipairs(usedColumns) do
for j, column in ipairs(usedColumns) do
      if column == 'Purchase' then
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"|' .. 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, '|style="min-width:25px"|' .. Icons.Icon({iconName, type=iconType, notext=true, nolink=iconNoLink, size='50'}))
        table.insert(resultPart, '| ' .. purchName)
table.insert(resultPart, '| ' .. purchName)
      elseif column == 'Type' then
elseif column == 'Type' then
        table.insert(resultPart, '| ' .. purchType)
table.insert(resultPart, '| ' .. purchType)
      elseif column == 'Description' then
elseif column == 'Description' then
        table.insert(resultPart, '| ' .. purchase.description)
table.insert(resultPart, '| ' .. purchase.description)
      elseif column == 'Cost' then
elseif column == 'Cost' then
        local cellProp = '|style="text-align:right;"'
local cellProp = '|style="text-align:right;"'
        local sortValue = p._getPurchaseSortValue(purchase)
local sortValue = p._getPurchaseSortValue(purchase)
        if sortValue ~= nil then cellProp = cellProp .. ' data-sort-value="' .. sortValue .. '"' end
if sortValue ~= nil then cellProp = cellProp .. ' data-sort-value="' .. sortValue .. '"' end
        table.insert(resultPart, cellProp .. '| ' .. costString)
table.insert(resultPart, cellProp .. '| ' .. costString)
      elseif column == 'Requirements' then
elseif column == 'Requirements' then
        table.insert(resultPart, '| ' .. p.getRequirementString(purchase.unlockRequirements))
table.insert(resultPart, '| ' .. p.getRequirementString(purchase.unlockRequirements))
      else
elseif column == 'Buy Limit' then
        -- Shouldn't be reached, but will prevent the resulting table becoming horribly mis-aligned if it ever happens
local buyLimit = p._getPurchaseBuyLimit(purchase, false)
        table.insert(resultPart, '| ')
local sortValue = (tonumber(buyLimit) == nil and -1 or buyLimit)
      end
table.insert(resultPart, '| data-sort-value="' .. sortValue .. '"| ' .. buyLimit)
    end
else
  end
-- Shouldn't be reached, but will prevent the resulting table becoming horribly mis-aligned if it ever happens
  table.insert(resultPart, '|}')
table.insert(resultPart, '| ')
end
end
end
table.insert(resultPart, '|}')


  return table.concat(resultPart, '\r\n')
return table.concat(resultPart, '\r\n')
end
end


Line 351: Line 447:
--  purchaseHeader: Specifies header text for the Purchase column if not 'Purchase'
--  purchaseHeader: Specifies header text for the Purchase column if not 'Purchase'
function p.getShopTable(frame)
function p.getShopTable(frame)
  local cat = frame.args ~= nil and frame.args[1] or frame
local cat = frame.args ~= nil and frame.args[1] or frame
  local options = {}
local options = {}
  if frame.args ~= nil then
if frame.args ~= nil then
    if frame.args.columns ~= nil then options.columns = Shared.splitString(frame.args.columns, ',') end
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.purchaseHeader ~= nil then options.purchaseHeader = frame.args.purchaseHeader end
    if frame.args.sortOrder ~= nil then options.sortOrder = frame.args.sortOrder end
if frame.args.sortOrder ~= nil then options.sortOrder = frame.args.sortOrder end
    if frame.args.columnProps ~= nil then
if frame.args.columnProps ~= nil then
      local columnPropValues = Shared.splitString(frame.args.columnProps, ',')
local columnPropValues = Shared.splitString(frame.args.columnProps, ',')
      local columnProps = {}
local columnProps = {}
      for i, prop in pairs(columnPropValues) do
for i, prop in pairs(columnPropValues) do
        local propName, propValue = string.match(prop, '^([^:]+):(.*)$')
local propName, propValue = string.match(prop, '^([^:]+):(.*)$')
        if propName ~= nil then
if propName ~= nil then
          columnProps[propName] = propValue
columnProps[propName] = propValue
        end
end
      end
end
      if Shared.tableCount(columnProps) > 0 then options.headerProps = columnProps end
if Shared.tableCount(columnProps) > 0 then options.headerProps = columnProps end
    end
end
  end
end
  local shopCat = ShopData.Shop[cat]
local shopCat = ShopData.Shop[cat]
  if shopCat == nil then
if shopCat == nil then
    return 'ERROR: Invalid category '..cat..'[[Category:Pages with script errors]]'
return 'ERROR: Invalid category '..cat..'[[Category:Pages with script errors]]'
  else
else
    return p._getShopTable(shopCat, options)
return p._getShopTable(shopCat, options)
  end
end
end
end


function p.getItemCostArray(itemID)
function p.getItemCostArray(itemID)
  local purchaseArray = {}
local purchaseArray = {}


  for catName, cat in Shared.skpairs(ShopData.Shop) do
for catName, cat in Shared.skpairs(ShopData.Shop) do
    for j, purchase in Shared.skpairs(cat) do
for j, purchase in Shared.skpairs(cat) do
      if purchase.cost.items ~= nil then
if purchase.cost.items ~= nil then
        for k, costLine in Shared.skpairs(purchase.cost.items) do
for k, costLine in Shared.skpairs(purchase.cost.items) do
          if costLine[1] == itemID then
if costLine[1] == itemID then
            local temp = p.processPurchase(catName, j - 1)
local temp = p.processPurchase(catName, j - 1)
            temp.qty = costLine[2]
temp.qty = costLine[2]
            table.insert(purchaseArray, temp)
table.insert(purchaseArray, temp)
            break
break
          end
end
        end
end
      end
end
    end
end
  end
end


  return purchaseArray
return purchaseArray
end
end


function p.getItemSourceArray(itemID)
function p.getItemSourceArray(itemID)
  local purchaseArray = {}
local purchaseArray = {}


  for catName, cat in Shared.skpairs(ShopData.Shop) do
for catName, cat in Shared.skpairs(ShopData.Shop) do
    for j, purchase in Shared.skpairs(cat) do
for j, purchase in Shared.skpairs(cat) do
      if purchase.contains.items ~= nil and purchase.contains.items ~= nil then
if purchase.contains.items ~= nil and purchase.contains.items ~= nil then
        for k, containsLine in Shared.skpairs(purchase.contains.items) do
for k, containsLine in Shared.skpairs(purchase.contains.items) do
          if containsLine [1] == itemID then
if containsLine [1] == itemID then
            local temp = p.processPurchase(catName, j - 1)
local temp = p.processPurchase(catName, j - 1)
            temp.qty = containsLine[2]
temp.qty = containsLine[2]
            table.insert(purchaseArray, temp)
table.insert(purchaseArray, temp)
            break
break
          end
end
        end
end
      end
end
    end
end
  end
end


  return purchaseArray
return purchaseArray
end
end


function p.getPurchases(checkFunc)
function p.getPurchases(checkFunc)
  local purchaseList = {}
local purchaseList = {}
  for category, purchaseArray in Shared.skpairs(ShopData.Shop) do
for category, purchaseArray in Shared.skpairs(ShopData.Shop) do
    for i, purchase in Shared.skpairs(purchaseArray) do
for i, purchase in Shared.skpairs(purchaseArray) do
      if checkFunc(category, purchase) then
if checkFunc(category, purchase) then
        table.insert(purchaseList, p.processPurchase(category, i - 1))
table.insert(purchaseList, p.processPurchase(category, i - 1))
      end
end
    end
end
  end
end
  return purchaseList
return purchaseList
end
end


function p._getPurchaseTable(purchase)
function p._getPurchaseTable(purchase)
  local result = '{| class="wikitable"\r\n|-'
local result = '{| class="wikitable"\r\n|-'
  result = result..'\r\n!colspan="2"|'..Icons.Icon({'Shop'})..' Purchase'
result = result..'\r\n!colspan="2"|'..Icons.Icon({'Shop'})..' Purchase'
  if purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 1 then
if purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 1 then
    result = result..' - '..Icons.Icon({purchase.name, type='item'})
result = result..' - '..Icons.Icon({purchase.name, type='item'})
  end
end


  result = result..'\r\n|-\r\n!style="text-align:right;"|Cost'
result = result..'\r\n|-\r\n!style="text-align:right;"|Cost'
  result = result..'\r\n|'..p.getCostString(purchase.cost, false)
result = result..'\r\n|'..p.getCostString(purchase.cost, false)


  result = result..'\r\n|-\r\n!style="text-align:right;"|Requirements'
result = result..'\r\n|-\r\n!style="text-align:right;"|Requirements'
  result = result..'\r\n|'..p.getRequirementString(purchase.unlockRequirements)
result = result..'\r\n|'..p.getRequirementString(purchase.unlockRequirements)


  result = result..'\r\n|-\r\n!style="text-align:right;"|Contains'
result = result..'\r\n|-\r\n!style="text-align:right;"|Contains'
  result = result..'\r\n|style="text-align:right;"|'..p._getPurchaseContents(purchase)
result = result..'\r\n|style="text-align:right;"|'..p._getPurchaseContents(purchase, true)


  result = result..'\r\n|}'
result = result..'\r\n|}'
  return result
return result
end
end


function p._getItemShopTable(item)
function p._getItemShopTable(item)
  local tableArray = {}
local tableArray = {}
  local purchaseArray = p.getItemSourceArray(item.id)
local purchaseArray = p.getItemSourceArray(item.id)


  for i, purchase in Shared.skpairs(purchaseArray) do
for i, purchase in Shared.skpairs(purchaseArray) do
    table.insert(tableArray, p._getPurchaseTable(purchase))
table.insert(tableArray, p._getPurchaseTable(purchase))
  end
end


  return table.concat(tableArray, '\r\n\r\n')
return table.concat(tableArray, '\r\n\r\n')
end
end


function p.getItemShopTable(frame)
function p.getItemShopTable(frame)
  local itemName = frame.args ~= nil and frame.args[1] or frame
local itemName = frame.args ~= nil and frame.args[1] or frame
  local item = Items.getItem(itemName)
local item = Items.getItem(itemName)
  if item == nil then
if item == nil then
    return "ERROR: No item named "..itemName.." exists in the data module"
return "ERROR: No item named "..itemName.." exists in the data module"
  end
end


  return p._getItemShopTable(item)
return p._getItemShopTable(item)
end
end


function p.getShopMiscUpgradeTable()
function p.getShopMiscUpgradeTable()
  local purchList = p.getPurchases(function(cat, purch) return cat == 'General' and string.find(purch.name, '^Auto Eat') == nil end)
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' })
return p._getShopTable(purchList, { columns = { 'Purchase', 'Description', 'Cost', 'Requirements' }, purchaseHeader = 'Upgrade' })
end
end


function p.getShopSkillcapeTable()
function p.getShopSkillcapeTable()
  local capeList = p.getPurchases(function(cat, purch) return cat == 'Skillcapes' end)
local capeList = p.getPurchases(function(cat, purch) return cat == 'Skillcapes' end)
  local sortOrderFunc = function(a, b)
local sortOrderFunc = function(a, b)
                      if a.cost.gp == b.cost.gp then
if a.cost.gp == b.cost.gp then
                        return a.name < b.name
return a.name < b.name
                      else
else
                        return a.cost.gp < b.cost.gp
return a.cost.gp < b.cost.gp
                      end
end
                    end
end
  return p._getShopTable(capeList,
return p._getShopTable(capeList, {
    { columns = { 'Purchase', 'Description', 'Cost' },
columns = { 'Purchase', 'Description', 'Cost' },
      purchaseHeader = 'Cape',
purchaseHeader = 'Cape',
      sortOrder = sortOrderFunc,
sortOrder = sortOrderFunc,
      headerProps = {["Purchase"] = 'colspan="2" style="width:200px;"', ["Cost"] = 'style=width:120px;'}
headerProps = {["Purchase"] = 'colspan="2" style="width:200px;"', ["Cost"] = 'style=width:120px;'}
    })
})
end
end


function p.getAutoEatTable()
function p.getAutoEatTable()
  local resultPart = {}
local resultPart = {}
  local purchasesAE = p.getPurchases(function(cat, purch) return string.find(purch.name, '^Auto Eat') ~= nil end)
local purchasesAE = p.getPurchases(function(cat, purch) return string.find(purch.name, '^Auto Eat') ~= nil end)


  -- Table header
-- Table header
  table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
  table.insert(resultPart, '|- class="headerRow-0"')
table.insert(resultPart, '|- class="headerRow-0"')
  table.insert(resultPart, '!colspan="2"|Auto Eat Tier!!Minimum Threshold!!Efficiency!!Max Healing!!Cost')
table.insert(resultPart, '!colspan="2"|Auto Eat Tier!!Minimum Threshold!!Efficiency!!Max Healing!!Cost')
  -- Rows for each Auto Eat tier
-- Rows for each Auto Eat tier
  local mods = {["increasedAutoEatEfficiency"] = 0, ["increasedAutoEatHPLimit"] = 0, ["increasedAutoEatThreshold"] = 0}
local mods = {["increasedAutoEatEfficiency"] = 0, ["increasedAutoEatHPLimit"] = 0, ["increasedAutoEatThreshold"] = 0}
  for i, purchase in ipairs(purchasesAE) do
for i, purchase in ipairs(purchasesAE) do
    -- Modifiers must be accumulated as we go
-- Modifiers must be accumulated as we go
    for modName, modValue in pairs(mods) do
for modName, modValue in pairs(mods) do
      if purchase.contains.modifiers[modName] ~= nil then
if purchase.contains.modifiers[modName] ~= nil then
        mods[modName] = mods[modName] + purchase.contains.modifiers[modName]
mods[modName] = mods[modName] + purchase.contains.modifiers[modName]
      end
end
    end
end


    local costAmt = p._getPurchaseSortValue(purchase)
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, '|-\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, '| ' .. Icons.Icon({purchase.name, type='upgrade', noicon=true}))
    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.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.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="' .. mods.increasedAutoEatHPLimit .. '" | ' .. Shared.formatnum(Shared.round(mods.increasedAutoEatHPLimit, 0, 0)) .. '%')
    table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. costAmt .. '" | ' .. Icons.GP(costAmt))
table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. costAmt .. '" | ' .. Icons.GP(costAmt))
  end
end
  table.insert(resultPart, '|}')
table.insert(resultPart, '|}')


  return table.concat(resultPart, '\r\n')
return table.concat(resultPart, '\r\n')
end
end


function p.getGodUpgradeTable()
function p.getGodUpgradeTable()
  local resultPart = {}
local resultPart = {}
  -- Obtain list of God upgrades: look for skill upgrades which have a dungeon completion
-- Obtain list of God upgrades: look for skill upgrades which have a dungeon completion
  --  requirement for an area whose name ends with 'God Dungeon'
--  requirement for an area whose name ends with 'God Dungeon'
  local getGodDungeon =
local getGodDungeon =
    function(reqs)
function(reqs)
      if reqs.dungeonCompletion ~= nil then
if reqs.dungeonCompletion ~= nil then
        for i, areaReq in ipairs(reqs.dungeonCompletion) do
for i, areaReq in ipairs(reqs.dungeonCompletion) do
          local dung = Areas.getAreaByID('dungeon', areaReq[1])
local dung = AreaData['dungeons'][areaReq[1] + 1]
          if string.find(dung.name, 'God Dungeon$') ~= nil then return dung end
if string.find(dung.name, 'God Dungeon$') ~= nil then return dung end
        end
end
      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, '| ' .. Icons.Icon({upgrade.name, type='upgrade', noicon=true}))
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))


  local upgradeList = p.getPurchases(
-- Row for each upgrade
    function(cat, purch)
for i, utility in ipairs(utilityList) do
      if cat == 'SkillUpgrades' and purch.unlockRequirements ~= nil then
-- First determine bonus XP/doubling chance and perfect chance
        return getGodDungeon(purch.unlockRequirements) ~= nil
local bonusVal, perfectChance = 0, 0
      end
if type(utility.contains) == 'table' then
      return false
if type(utility.contains.modifiers) == 'table' then
    end)
for modName, modVal in pairs(utility.contains.modifiers) do
  if Shared.tableCount(upgradeList) == 0 then return '' end
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


  -- Table header
-- Mangle unlockRequirements so that it only includes skillLevels
  table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
local unlockReqs = {}
  table.insert(resultPart, '|- class="headerRow-0"')
if type(utility.unlockRequirements) == 'table' then
  table.insert(resultPart, '!colspan="2"|God Upgrade!!Effect!!Dungeon!!Cost')
unlockReqs['skillLevel'] = utility.unlockRequirements.skillLevel
end


  -- Rows for each God upgrade
table.insert(resultPart, '|-')
  for i, upgrade in ipairs(upgradeList) do
table.insert(resultPart, '|style="min-width:25px"|' .. Icons.Icon({utility.name, type='upgrade', size='50', notext=true}))
    local dung = getGodDungeon(upgrade.unlockRequirements)
table.insert(resultPart, '|' .. utility.name)
    local costSortValue = p._getPurchaseSortValue(upgrade)
table.insert(resultPart, '|style="text-align:right"|' .. p.getRequirementString(unlockReqs))
    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, '|style="text-align:right"|' .. p.getCostString(utility.cost, false))
    table.insert(resultPart, '| [[' .. upgrade.name .. ']]')
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. bonusVal .. '%')
    table.insert(resultPart, '| ' .. upgrade.description)
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. totalBonusVal .. '%')
    table.insert(resultPart, '| data-sort-value="' .. dung.name .. '"| ' .. Icons.Icon({dung.name, type='dungeon'}))
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. perfectChance .. '%')
    table.insert(resultPart, '| style="text-align:right;" data-sort-value="' .. costSortValue .. '"| ' .. p.getCostString(upgrade.cost, false))
table.insert(resultPart, '|style="text-align:right"|' .. '+' .. totalPerfectChance .. '%')
  end
end
  table.insert(resultPart, '|}')
table.insert(resultPart, '|}')


  return table.concat(resultPart, '\r\n')
return table.concat(resultPart, '\r\n')
end
end


return p
return p