Module:Navboxes: Difference between revisions

From Melvor Idle
(getPotionNavbox: Link to general potion pages rather than tier I potion specifically)
(Use tabs instead of spaces for indentation)
Line 13: Line 13:


function p.getFarmingNavbox(frame)
function p.getFarmingNavbox(frame)
  local resultPart = {}
local resultPart = {}
  local seedsTable = {}
local seedsTable = {}
  local produceTable = {}
local produceTable = {}


  for i, item in ipairs(ItemData.Items) do
for i, item in ipairs(ItemData.Items) do
    if item.farmingLevel ~= nil then
if item.farmingLevel ~= nil then
      local tier = item.tier
local tier = item.tier
      if seedsTable[tier] == nil then
if seedsTable[tier] == nil then
        -- Initialise tier tables
-- Initialise tier tables
        seedsTable[tier] = {}
seedsTable[tier] = {}
        produceTable[tier] = {}
produceTable[tier] = {}
      end
end


      if item.grownItemID ~= nil then
if item.grownItemID ~= nil then
        local grownItem = Items.getItemByID(item.grownItemID)
local grownItem = Items.getItemByID(item.grownItemID)
        if grownItem ~= nil then
if grownItem ~= nil then
          table.insert(produceTable[tier], { ["name"] = grownItem.name, ["level"] = item.farmingLevel })
table.insert(produceTable[tier], { ["name"] = grownItem.name, ["level"] = item.farmingLevel })
        end
end
      end
end
      table.insert(seedsTable[tier], { ["name"] = item.name, ["level"] = item.farmingLevel })
table.insert(seedsTable[tier], { ["name"] = item.name, ["level"] = item.farmingLevel })
    end
end
  end
end


  -- Generate output table
-- Generate output table
  table.insert(resultPart, '{| class="wikitable mw-collapsible" style="margin:auto; clear:both; width: 100%"')
table.insert(resultPart, '{| class="wikitable mw-collapsible" style="margin:auto; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n!colspan="2" style="padding-left:64px;"|' .. Icons.Icon({'Farming', type='skill'}))
table.insert(resultPart, '\r\n!colspan="2" style="padding-left:64px;"|' .. Icons.Icon({'Farming', type='skill'}))


  local getItemList = function(itemTable)
local getItemList = function(itemTable)
      local listPart = {}
local listPart = {}
      for i, item in ipairs(itemTable) do
for i, item in ipairs(itemTable) do
        table.insert(listPart, Icons.Icon({item.name, type='item'}))
table.insert(listPart, Icons.Icon({item.name, type='item'}))
      end
end
      return table.concat(listPart, ' • ')
return table.concat(listPart, ' • ')
    end
end
  local sortFunc = function(a, b) return (a.level == b.level and a.name < b.name) or a.level < b.level end
local sortFunc = function(a, b) return (a.level == b.level and a.name < b.name) or a.level < b.level end


  -- Determine tier list & order in which tiers will be listed in output
-- Determine tier list & order in which tiers will be listed in output
  local tierList = {}
local tierList = {}
  for tier, seeds in pairs(seedsTable) do
for tier, seeds in pairs(seedsTable) do
    table.insert(tierList, tier)
table.insert(tierList, tier)
  end
end
  table.sort(tierList, function(a, b) return a < b end)
table.sort(tierList, function(a, b) return a < b end)


  -- Generate table section for each tier
-- Generate table section for each tier
  for i, tier in pairs(tierList) do
for i, tier in pairs(tierList) do
    -- Sort tables by Farming level order
-- Sort tables by Farming level order
    table.sort(seedsTable[tier], sortFunc)
table.sort(seedsTable[tier], sortFunc)
    table.sort(produceTable[tier], sortFunc)
table.sort(produceTable[tier], sortFunc)


    table.insert(resultPart, '\r\n|-\r\n!colspan="2"| ' .. tier .. 's')
table.insert(resultPart, '\r\n|-\r\n!colspan="2"| ' .. tier .. 's')
    table.insert(resultPart, '\r\n|-\r\n!scope="row"| Seeds')
table.insert(resultPart, '\r\n|-\r\n!scope="row"| Seeds')
    table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getItemList(seedsTable[tier]))
table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getItemList(seedsTable[tier]))
    table.insert(resultPart, '\r\n|-\r\n!scope="row"| Produce')
table.insert(resultPart, '\r\n|-\r\n!scope="row"| Produce')
    table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getItemList(produceTable[tier]))
table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getItemList(produceTable[tier]))
  end
end
  table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')


  return table.concat(resultPart)
return table.concat(resultPart)
end
end


function p.getFoodNavbox(frame)
function p.getFoodNavbox(frame)
  local foundIDs, cookedFood, harvestedFood, otherFood = {}, {}, {}, {}
local foundIDs, cookedFood, harvestedFood, otherFood = {}, {}, {}, {}


  -- Hide Lemon cake
-- Hide Lemon cake
  foundIDs[1029] = true
foundIDs[1029] = true
  foundIDs[1061] = true
foundIDs[1061] = true


  -- Harvested food first
-- Harvested food first
  for i, item in ipairs(ItemData.Items) do
for i, item in ipairs(ItemData.Items) do
    if item.grownItemID ~= nil then
if item.grownItemID ~= nil then
      local grownItem = Items.getItemByID(item.grownItemID)
local grownItem = Items.getItemByID(item.grownItemID)
      if grownItem ~= nil and grownItem.canEat then
if grownItem ~= nil and grownItem.canEat then
        table.insert(harvestedFood, { ["name"] = grownItem.name, ["order"] = item.farmingLevel })
table.insert(harvestedFood, { ["name"] = grownItem.name, ["order"] = item.farmingLevel })
        foundIDs[grownItem.id] = true
foundIDs[grownItem.id] = true
      end
end
    end
end
  end
end


  -- Any cooked & other food
-- Any cooked & other food
  for i, item in ipairs(ItemData.Items) do
for i, item in ipairs(ItemData.Items) do
    -- If an item can be eaten then it must be food
-- If an item can be eaten then it must be food
    if foundIDs[i - 1] == nil and item.canEat then
if foundIDs[i - 1] == nil and item.canEat then
      if item.cookingCategory ~= nil then
if item.cookingCategory ~= nil then
        -- Item is cooked, such food items are split by category
-- Item is cooked, such food items are split by category
        if cookedFood[item.cookingCategory + 1] == nil then
if cookedFood[item.cookingCategory + 1] == nil then
          cookedFood[item.cookingCategory + 1] = {}
cookedFood[item.cookingCategory + 1] = {}
        end
end


        local perfectName = nil
local perfectName = nil
        if item.perfectItem ~= nil then
if item.perfectItem ~= nil then
          local perfectItem = Items.getItemByID(item.perfectItem)
local perfectItem = Items.getItemByID(item.perfectItem)
          if perfectItem ~= nil then
if perfectItem ~= nil then
            perfectName = perfectItem.name
perfectName = perfectItem.name
            foundIDs[item.perfectItem] = true
foundIDs[item.perfectItem] = true
          end
end
        end
end
        table.insert(cookedFood[item.cookingCategory + 1], { ["name"] = item.name, ["order"] = item.cookingLevel, ["perfectName"] = perfectName })
table.insert(cookedFood[item.cookingCategory + 1], { ["name"] = item.name, ["order"] = item.cookingLevel, ["perfectName"] = perfectName })
      else
else
        -- Item cannot be cooked or grown, but can be eaten
-- Item cannot be cooked or grown, but can be eaten
        table.insert(otherFood, { ["name"] = item.name, ["order"] = item.id })
table.insert(otherFood, { ["name"] = item.name, ["order"] = item.id })
      end
end
      foundIDs[i - 1] = true
foundIDs[i - 1] = true
    end
end
  end
end


  -- Sort food lists
-- Sort food lists
  local sortFunc = function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end
local sortFunc = function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end
  for i, items in pairs(cookedFood) do
for i, items in pairs(cookedFood) do
    table.sort(cookedFood[i], sortFunc)
table.sort(cookedFood[i], sortFunc)
  end
end
  table.sort(harvestedFood, sortFunc)
table.sort(harvestedFood, sortFunc)
  table.sort(otherFood, sortFunc)
table.sort(otherFood, sortFunc)


  -- Generate food lists for final output
-- Generate food lists for final output
  local cookingCatHeader = {
local cookingCatHeader = {
    Icons.Icon({'Normal Cooking Fire', 'Cooking Fire', type='upgrade', nolink=true}),
Icons.Icon({'Normal Cooking Fire', 'Cooking Fire', type='upgrade', nolink=true}),
    Icons.Icon({'Basic Furnace', 'Furnace', type='upgrade', nolink=true}),
Icons.Icon({'Basic Furnace', 'Furnace', type='upgrade', nolink=true}),
    Icons.Icon({'Basic Pot', 'Pot', type='upgrade', nolink=true})
Icons.Icon({'Basic Pot', 'Pot', type='upgrade', nolink=true})
  }
}
  local getFoodList = function(foodTable)
local getFoodList = function(foodTable)
      local listPart = {}
local listPart = {}
      for i, food in ipairs(foodTable) do
for i, food in ipairs(foodTable) do
        local foodText = Icons.Icon({food.name, type='item'})
local foodText = Icons.Icon({food.name, type='item'})
        if food.perfectName ~= nil then
if food.perfectName ~= nil then
          foodText = Icons.Icon({food.perfectName, type='item', notext=true}) .. ' ' .. foodText
foodText = Icons.Icon({food.perfectName, type='item', notext=true}) .. ' ' .. foodText
        end
end
        table.insert(listPart, foodText)
table.insert(listPart, foodText)
      end
end
      return table.concat(listPart, ' • ')
return table.concat(listPart, ' • ')
    end
end


  local resultPart = {}
local resultPart = {}
  table.insert(resultPart, '{| class="wikitable mw-collapsible" style="margin:0 auto 10px; clear:both; width: 100%"')
table.insert(resultPart, '{| class="wikitable mw-collapsible" style="margin:0 auto 10px; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n|-\r\n!style="background-color:#275C87;color:#FFFFFF;padding-left:64px;" colspan="2"| [[File:Crab_(item).svg|25px|link=Food]] [[Food]]')
table.insert(resultPart, '\r\n|-\r\n!style="background-color:#275C87;color:#FFFFFF;padding-left:64px;" colspan="2"| [[File:Crab_(item).svg|25px|link=Food]] [[Food]]')
  table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Cooked')
table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Cooked')
  for catID, foodTable in ipairs(cookedFood) do
for catID, foodTable in ipairs(cookedFood) do
    table.insert(resultPart, '\r\n|-\r\n!scope="row"| ' .. cookingCatHeader[catID])
table.insert(resultPart, '\r\n|-\r\n!scope="row"| ' .. cookingCatHeader[catID])
    table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getFoodList(foodTable))
table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getFoodList(foodTable))
  end
end
  table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Harvested')
table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Harvested')
  table.insert(resultPart, '\r\n|-\r\n|colspan="2" style="text-align:center;"| ' .. getFoodList(harvestedFood))
table.insert(resultPart, '\r\n|-\r\n|colspan="2" style="text-align:center;"| ' .. getFoodList(harvestedFood))
  table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Other')
table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Other')
  table.insert(resultPart, '\r\n|-\r\n|colspan="2" style="text-align:center;"| ' .. getFoodList(otherFood))
table.insert(resultPart, '\r\n|-\r\n|colspan="2" style="text-align:center;"| ' .. getFoodList(otherFood))
  table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')


  return table.concat(resultPart)
return table.concat(resultPart)
end
end


function p.getPotionNavbox(frame)
function p.getPotionNavbox(frame)
  local catList = {
local catList = {
    { ["categoryID"] = 0, ["name"] = 'Combat' },
{ ["categoryID"] = 0, ["name"] = 'Combat' },
    { ["categoryID"] = 1, ["name"] = 'Skill' }
{ ["categoryID"] = 1, ["name"] = 'Skill' }
  }
}
  table.sort(catList, function(a, b) return a.name < b.name end)
table.sort(catList, function(a, b) return a.name < b.name end)


  -- Compile list of potions to be included
-- Compile list of potions to be included
  local potList = {}
local potList = {}
  for i, potData in ipairs(SkillData.Herblore.ItemData) do
for i, potData in ipairs(SkillData.Herblore.ItemData) do
    if potList[potData.category] == nil then
if potList[potData.category] == nil then
      potList[potData.category] = {}
potList[potData.category] = {}
    end
end
    local potFirstItem = Items.getItemByID(potData.itemID[1])
local potFirstItem = Items.getItemByID(potData.itemID[1])
    local potName = string.gsub(potFirstItem.name, ' Potion [IV]+$', '')
local potName = string.gsub(potFirstItem.name, ' Potion [IV]+$', '')
    table.insert(potList[potData.category], { ["name"] = potName, ["order"] = potData.level, ["img"] = potFirstItem.name })
table.insert(potList[potData.category], { ["name"] = potName, ["order"] = potData.level, ["img"] = potFirstItem.name })
  end
end


  local resultPart = {}
local resultPart = {}
  -- Generate table header
-- Generate table header
  table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n!colspan=2|' .. Icons.Icon({ 'Herblore', 'Potions', type='skill' }))
table.insert(resultPart, '\r\n!colspan=2|' .. Icons.Icon({ 'Herblore', 'Potions', type='skill' }))
  -- Generate section for each category of potions
-- Generate section for each category of potions
  for i, catData in ipairs(catList) do
for i, catData in ipairs(catList) do
    -- Compile list of potions
-- Compile list of potions
    local potListText = {}
local potListText = {}
    table.sort(potList[catData.categoryID], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
table.sort(potList[catData.categoryID], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
    for j, potData in ipairs(potList[catData.categoryID]) do
for j, potData in ipairs(potList[catData.categoryID]) do
      table.insert(potListText, Icons.Icon({ potData.name .. ' Potion', potData.name, img=potData.img, type='item' }))
table.insert(potListText, Icons.Icon({ potData.name .. ' Potion', potData.name, img=potData.img, type='item' }))
    end
end
    table.insert(resultPart, '\r\n|-\r\n! ' .. catData.name .. ' Potions')
table.insert(resultPart, '\r\n|-\r\n! ' .. catData.name .. ' Potions')
    table.insert(resultPart, '\r\n|class="center" style="vertical-align:middle;"| ' .. table.concat(potListText, ' • '))
table.insert(resultPart, '\r\n|class="center" style="vertical-align:middle;"| ' .. table.concat(potListText, ' • '))
  end
end
  table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')


  return table.concat(resultPart)
return table.concat(resultPart)
end
end


function p.getPrayerNavbox(frame)
function p.getPrayerNavbox(frame)
  local prayerList = {}
local prayerList = {}
  for i, prayer in Shared.skpairs(SkillData.Prayer) do
for i, prayer in Shared.skpairs(SkillData.Prayer) do
  table.insert(prayerList, { ["name"] = prayer.name, ["order"] = prayer.prayerLevel })
table.insert(prayerList, { ["name"] = prayer.name, ["order"] = prayer.prayerLevel })
  end
end
  table.sort(prayerList, function(a, b)
table.sort(prayerList, function(a, b)
                        if a.order == b.order then
if a.order == b.order then
                        return a.name < b.name
return a.name < b.name
                        else
else
                        return a.order < b.order
return a.order < b.order
                        end
end
                      end)
end)


  local prayerListText = {}
local prayerListText = {}
  for i, prayer in ipairs(prayerList) do
for i, prayer in ipairs(prayerList) do
  table.insert(prayerListText, Icons.Icon({ prayer.name, type='prayer' }))
table.insert(prayerListText, Icons.Icon({ prayer.name, type='prayer' }))
  end
end
 
 
  local resultPart = {}
local resultPart = {}
  table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n!'..Icons.Icon({'Prayer', 'Prayers', type='skill'}))
table.insert(resultPart, '\r\n!'..Icons.Icon({'Prayer', 'Prayers', type='skill'}))
  table.insert(resultPart, '\r\n|-\r\n|style="text-align:center;"| ' .. table.concat(prayerListText, ' • '))
table.insert(resultPart, '\r\n|-\r\n|style="text-align:center;"| ' .. table.concat(prayerListText, ' • '))
  table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')
  return table.concat(resultPart)
return table.concat(resultPart)
end
end


function p.getRuneNavbox(frame)
function p.getRuneNavbox(frame)
  -- Assumes all runes are from Runecrafting, which may need revising in future updates
-- Assumes all runes are from Runecrafting, which may need revising in future updates
  local runeList = { ["Standard"] = {}, ["Combination"] = {} }
local runeList = { ["Standard"] = {}, ["Combination"] = {} }
  for i, item in ipairs(ItemData.Items) do
for i, item in ipairs(ItemData.Items) do
    if item.category == 'Runecrafting' and item.type ~= nil and item.type == 'Rune' and item.runecraftingLevel ~= nil then
if item.category == 'Runecrafting' and item.type ~= nil and item.type == 'Rune' and item.runecraftingLevel ~= nil then
      local runeType = (type(item.providesRune) == 'table' and Shared.tableCount(item.providesRune) > 1 and 'Combination') or 'Standard'
local runeType = (type(item.providesRune) == 'table' and Shared.tableCount(item.providesRune) > 1 and 'Combination') or 'Standard'
      table.insert(runeList[runeType], { ["name"] = item.name, ["order"] = item.runecraftingLevel })
table.insert(runeList[runeType], { ["name"] = item.name, ["order"] = item.runecraftingLevel })
    end
end
  end
end


  local resultPart = {}
local resultPart = {}
  table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n!colspan="2"|[[File:Air_Rune_(item).svg|25px|link=Runes]] [[Runes]]')
table.insert(resultPart, '\r\n!colspan="2"|[[File:Air_Rune_(item).svg|25px|link=Runes]] [[Runes]]')
  for i, cat in ipairs({'Standard', 'Combination'}) do
for i, cat in ipairs({'Standard', 'Combination'}) do
    table.sort(runeList[cat], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
table.sort(runeList[cat], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
    table.insert(resultPart, '\r\n|-\r\n!scope="row"|' .. cat .. ' Runes')
table.insert(resultPart, '\r\n|-\r\n!scope="row"|' .. cat .. ' Runes')


    local listPart = {}
local listPart = {}
    for j, rune in ipairs(runeList[cat]) do
for j, rune in ipairs(runeList[cat]) do
      table.insert(listPart, Icons.Icon({rune.name, type='item'}))
table.insert(listPart, Icons.Icon({rune.name, type='item'}))
    end
end
    table.insert(resultPart, '\r\n|style="text-align:center;"|'..table.concat(listPart, ' • '))
table.insert(resultPart, '\r\n|style="text-align:center;"|'..table.concat(listPart, ' • '))
  end
end
  table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')


  return table.concat(resultPart)
return table.concat(resultPart)
end
end


function p.getSkillcapeNavbox(frame)
function p.getSkillcapeNavbox(frame)
  local capeList = Shop.getPurchases(function(cat, purch) return cat == 'Skillcapes' end)
local capeList = Shop.getPurchases(function(cat, purch) return cat == 'Skillcapes' end)
  table.sort(capeList, function(a, b)
table.sort(capeList, 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)


  local capeText = {}
local capeText = {}
  for i, purch in ipairs(capeList) do
for i, purch in ipairs(capeList) do
    if purch.contains ~= nil and purch.contains.items ~= nil then
if purch.contains ~= nil and purch.contains.items ~= nil then
      local item = Items.getItemByID(purch.contains.items[1][1])
local item = Items.getItemByID(purch.contains.items[1][1])
      if item ~= nil then
if item ~= nil then
        table.insert(capeText, Icons.Icon({item.name, type='item'}))
table.insert(capeText, Icons.Icon({item.name, type='item'}))
      end
end
    end
end
  end
end


  local resultPart = {}
local resultPart = {}
  table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n![[File:Cape_of_Completion_(item).svg|25px|link=Skillcapes]] [[Skillcapes]]')
table.insert(resultPart, '\r\n![[File:Cape_of_Completion_(item).svg|25px|link=Skillcapes]] [[Skillcapes]]')
  table.insert(resultPart, '\r\n|-\r\n|style="text-align:center;"|'..table.concat(capeText, ' • '))
table.insert(resultPart, '\r\n|-\r\n|style="text-align:center;"|'..table.concat(capeText, ' • '))
  table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')


  return table.concat(resultPart)
return table.concat(resultPart)
end
end


function p.getSpellNavbox(frame)
function p.getSpellNavbox(frame)
  local spellTable = { ["standard"] = {}, ["curse"] = {}, ["aurora"] = {}, ["ancient"] = {}, ["alt"] = {} }
local spellTable = { ["standard"] = {}, ["curse"] = {}, ["aurora"] = {}, ["ancient"] = {}, ["alt"] = {} }
  local catData = {
local catData = {
  { ["name"] = 'standard', ["header"] = '[[Magic#Standard_Magic|Standard Spells]]', ["imgType"] = 'spell' },
{ ["name"] = 'standard', ["header"] = '[[Magic#Standard_Magic|Standard Spells]]', ["imgType"] = 'spell' },
  { ["name"] = 'curse', ["header"] = '[[Magic#Curses|Curses]]', ["imgType"] = 'curse' },
{ ["name"] = 'curse', ["header"] = '[[Magic#Curses|Curses]]', ["imgType"] = 'curse' },
  { ["name"] = 'aurora', ["header"] = '[[Magic#Auroras|Auroras]]', ["imgType"] = 'aurora' },
{ ["name"] = 'aurora', ["header"] = '[[Magic#Auroras|Auroras]]', ["imgType"] = 'aurora' },
  { ["name"] = 'ancient', ["header"] = '[[Magic#Ancient_Magicks|Ancient Magicks]]', ["imgType"] = 'spell' },
{ ["name"] = 'ancient', ["header"] = '[[Magic#Ancient_Magicks|Ancient Magicks]]', ["imgType"] = 'spell' },
  { ["name"] = 'alt', ["header"] = '[[Alternative_Magic|Alt Magic]]', ["imgType"] = 'spell' },
{ ["name"] = 'alt', ["header"] = '[[Alternative_Magic|Alt Magic]]', ["imgType"] = 'spell' },
  }
}
 
for i, spell in ipairs(MagicData.Spells) do
table.insert(spellTable['standard'], { ["name"] = spell.name, ["order"] = spell.level })
end
for i, spell in ipairs(MagicData.Curses) do
table.insert(spellTable['curse'], { ["name"] = spell.name, ["order"] = spell.level })
end
for i, spell in ipairs(MagicData.Auroras) do
table.insert(spellTable['aurora'], { ["name"] = spell.name, ["order"] = spell.level })
end
for i, spell in ipairs(MagicData.Ancient) do
table.insert(spellTable['ancient'], { ["name"] = spell.name, ["order"] = spell.level })
end
for i, spell in ipairs(MagicData.AltMagic) do
table.insert(spellTable['alt'], { ["name"] = spell.name, ["order"] = spell.level })
end
 
local getSpellList = function(spellTable, imgType)
local listPart = {}
for i, obj in ipairs(spellTable) do
table.insert(listPart, Icons.Icon({obj.name, type=imgType}))
end
return table.concat(listPart, ' • ')
end


  for i, spell in ipairs(MagicData.Spells) do
local resultPart = {}
  table.insert(spellTable['standard'], { ["name"] = spell.name, ["order"] = spell.level })
table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
  end
table.insert(resultPart, '\r\n!colspan=2|[[File:Magic_(skill).svg|25px|link=Spells]] [[Spells]]')
  for i, spell in ipairs(MagicData.Curses) do
for i, catDefn in ipairs(catData) do
  table.insert(spellTable['curse'], { ["name"] = spell.name, ["order"] = spell.level })
table.sort(spellTable[catDefn.name], function(a, b)
  end
if a.order == b.order then
  for i, spell in ipairs(MagicData.Auroras) do
return a.name < b.name
  table.insert(spellTable['aurora'], { ["name"] = spell.name, ["order"] = spell.level })
else
  end
return a.order < b.order
  for i, spell in ipairs(MagicData.Ancient) do
end
  table.insert(spellTable['ancient'], { ["name"] = spell.name, ["order"] = spell.level })
end)
  end
table.insert(resultPart, '\r\n|-\r\n!scope="row"| ' .. catDefn.header)
  for i, spell in ipairs(MagicData.AltMagic) do
table.insert(resultPart, '\r\n|style="text-align:center;| ' .. getSpellList(spellTable[catDefn.name], catDefn.imgType))
  table.insert(spellTable['alt'], { ["name"] = spell.name, ["order"] = spell.level })
end
  end
table.insert(resultPart, '\r\n|}')
 
  local getSpellList = function(spellTable, imgType)
      local listPart = {}
      for i, obj in ipairs(spellTable) do
        table.insert(listPart, Icons.Icon({obj.name, type=imgType}))
      end
      return table.concat(listPart, ' • ')
    end
 
  local resultPart = {}
  table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n!colspan=2|[[File:Magic_(skill).svg|25px|link=Spells]] [[Spells]]')
  for i, catDefn in ipairs(catData) do
  table.sort(spellTable[catDefn.name], function(a, b)
                                if a.order == b.order then
                                return a.name < b.name
                                else
                                return a.order < b.order
                                end
                              end)
  table.insert(resultPart, '\r\n|-\r\n!scope="row"| ' .. catDefn.header)
  table.insert(resultPart, '\r\n|style="text-align:center;| ' .. getSpellList(spellTable[catDefn.name], catDefn.imgType))
  end
  table.insert(resultPart, '\r\n|}')


  return table.concat(resultPart)
return table.concat(resultPart)
end
end


function p.getFamiliarNavbox(frame)
function p.getFamiliarNavbox(frame)
  local familiars = Items.getItems(function(item) return item.type == 'Familiar' end)
local familiars = Items.getItems(function(item) return item.type == 'Familiar' end)
  table.sort(familiars, function(a, b) return a.summoningLevel < b.summoningLevel end)
table.sort(familiars, function(a, b) return a.summoningLevel < b.summoningLevel end)


  local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
  result = result..'\r\n!colspan=2|[[File:Summoning_(skill).svg|25px|link=Summoning]] [[Summoning|Summoning Familiars]]'
result = result..'\r\n!colspan=2|[[File:Summoning_(skill).svg|25px|link=Summoning]] [[Summoning|Summoning Familiars]]'
  local iconArray = {}
local iconArray = {}
  for i, fam in Shared.skpairs(familiars) do
for i, fam in Shared.skpairs(familiars) do
    table.insert(iconArray, Icons.Icon({fam.name, type='item'}))
table.insert(iconArray, Icons.Icon({fam.name, type='item'}))
  end
end
  result = result..'\r\n|-\r\n|style="text-align:center;"|'..table.concat(iconArray, ' • ')
result = result..'\r\n|-\r\n|style="text-align:center;"|'..table.concat(iconArray, ' • ')
  result = result..'\r\n|}'
result = result..'\r\n|}'
  return result
return result
end
end


function p.getThievingNavbox()
function p.getThievingNavbox()
  local returnPart = {}
local returnPart = {}


  -- Create table header
-- Create table header
  table.insert(returnPart, '{| class="wikitable" style="text-align:center; clear:both; margin:auto; margin-bottom:1em;"')
table.insert(returnPart, '{| class="wikitable" style="text-align:center; clear:both; margin:auto; margin-bottom:1em;"')
  table.insert(returnPart, '|-\r\n!' .. Icons.Icon({'Thieving', type='skill', notext=true}) .. '[[Thieving|Thieving Targets]]')
table.insert(returnPart, '|-\r\n!' .. Icons.Icon({'Thieving', type='skill', notext=true}) .. '[[Thieving|Thieving Targets]]')
  table.insert(returnPart, '|-\r\n|')
table.insert(returnPart, '|-\r\n|')


  local npcData = {}
local npcData = {}
  for i, npc in ipairs(SkillData.Thieving.NPCs) do
for i, npc in ipairs(SkillData.Thieving.NPCs) do
    table.insert(npcData, {["level"] = npc.level, ["name"] = npc.name})
table.insert(npcData, {["level"] = npc.level, ["name"] = npc.name})
  end
end
  table.sort(npcData, function(a, b) return a.level < b.level end)
table.sort(npcData, function(a, b) return a.level < b.level end)


  local npcList = {}
local npcList = {}
  -- Create row for each NPC
-- Create row for each NPC
  for i, npc in ipairs(npcData) do
for i, npc in ipairs(npcData) do
    table.insert(npcList, Icons.Icon({npc.name, type='thieving'}))
table.insert(npcList, Icons.Icon({npc.name, type='thieving'}))
  end
end
  table.insert(returnPart, table.concat(npcList, ' • '))
table.insert(returnPart, table.concat(npcList, ' • '))
  table.insert(returnPart, '|}')
table.insert(returnPart, '|}')


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


function p.getFishingNavbox()
function p.getFishingNavbox()
  local categoryHeader = {}
local categoryHeader = {}
  local categoryItems = {}
local categoryItems = {}
  local addCatData = function(cat, catLink, itemName, itemOrder)
local addCatData = function(cat, catLink, itemName, itemOrder)
                      if categoryItems[cat] == nil then
if categoryItems[cat] == nil then
                        -- Initialise category
-- Initialise category
                        table.insert(categoryHeader, { ["name"] = cat, ["link"] = catLink })
table.insert(categoryHeader, { ["name"] = cat, ["link"] = catLink })
                        categoryItems[cat] = {}
categoryItems[cat] = {}
                      end
end
                      table.insert(categoryItems[cat], { ["name"] = itemName, ["order"] = itemOrder })
table.insert(categoryItems[cat], { ["name"] = itemName, ["order"] = itemOrder })
                    end
end


  -- Identify fishing catchable items
-- Identify fishing catchable items
  local fishingToItemID = {}
local fishingToItemID = {}
  local junkItems = {}
local junkItems = {}
  local specialItems = {}
local specialItems = {}
  for i, item in ipairs(ItemData.Items) do
for i, item in ipairs(ItemData.Items) do
    if item.fishingID ~= nil then
if item.fishingID ~= nil then
      -- Create FishingID to item map
-- Create FishingID to item map
      fishingToItemID[item.fishingID] = item
fishingToItemID[item.fishingID] = item
    elseif item.category == 'Fishing' and item.type == 'Junk' then
elseif item.category == 'Fishing' and item.type == 'Junk' then
      table.insert(junkItems, item)
table.insert(junkItems, item)
    elseif item.fishingCatchWeight ~= nil then
elseif item.fishingCatchWeight ~= nil then
      table.insert(specialItems, item)
table.insert(specialItems, item)
    end
end
  end
end
  -- Fishing areas
-- Fishing areas
  -- Iterate through all fishing areas, identifying fish within each
-- Iterate through all fishing areas, identifying fish within each
  for i, area in ipairs(SkillData.Fishing.Areas) do
for i, area in ipairs(SkillData.Fishing.Areas) do
    for j, fishID in ipairs(area.fish) do
for j, fishID in ipairs(area.fish) do
      local fishItem = fishingToItemID[fishID]
local fishItem = fishingToItemID[fishID]
      if fishItem ~= nil then
if fishItem ~= nil then
        addCatData(area.name, 'Fishing#Fishing Areas', fishItem.name, fishItem.fishingLevel)
addCatData(area.name, 'Fishing#Fishing Areas', fishItem.name, fishItem.fishingLevel)
      end
end
    end
end
  end
end
  -- Junk items
-- Junk items
  for i, item in ipairs(junkItems) do
for i, item in ipairs(junkItems) do
    addCatData('Junk', 'Fishing#Junk', item.name, 1)
addCatData('Junk', 'Fishing#Junk', item.name, 1)
  end
end
  -- Special items
-- Special items
  for i, item in ipairs(specialItems) do
for i, item in ipairs(specialItems) do
    addCatData('Special Items', 'Fishing#Special', item.name, 1 / (item.fishingCatchWeight or 1))
addCatData('Special Items', 'Fishing#Special', item.name, 1 / (item.fishingCatchWeight or 1))
  end
end


  local resultPart = {}
local resultPart = {}
  -- Generate navbox header
-- Generate navbox header
  table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
  table.insert(resultPart, '\r\n|-\r\n!colspan="2" | ' .. Icons.Icon({'Fishing', type='skill'}))
table.insert(resultPart, '\r\n|-\r\n!colspan="2" | ' .. Icons.Icon({'Fishing', type='skill'}))
  -- Generate section for each fishing area, junk, and special
-- Generate section for each fishing area, junk, and special
  for i, cat in ipairs(categoryHeader) do
for i, cat in ipairs(categoryHeader) do
    local itemList = {}
local itemList = {}
    if categoryItems[cat.name] ~= nil then
if categoryItems[cat.name] ~= nil then
      table.sort(categoryItems[cat.name], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
table.sort(categoryItems[cat.name], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
      for j, item in ipairs(categoryItems[cat.name]) do
for j, item in ipairs(categoryItems[cat.name]) do
        table.insert(itemList, Icons.Icon({item.name, type='item'}))
table.insert(itemList, Icons.Icon({item.name, type='item'}))
      end
end
    end
end


    table.insert(resultPart, '\r\n|-\r\n!class="center" style="min-width:140px" | [[' .. (cat.link or cat.name) .. '|' .. cat.name .. ']]')
table.insert(resultPart, '\r\n|-\r\n!class="center" style="min-width:140px" | [[' .. (cat.link or cat.name) .. '|' .. cat.name .. ']]')
    table.insert(resultPart, '\r\n| class="center" style="vertical-align:middle;" | ' .. table.concat(itemList, ' • '))
table.insert(resultPart, '\r\n| class="center" style="vertical-align:middle;" | ' .. table.concat(itemList, ' • '))
  end
end
  table.insert(resultPart, '\r\n|}')
table.insert(resultPart, '\r\n|}')


  return table.concat(resultPart)
return table.concat(resultPart)
end
end


return p
return p

Revision as of 22:21, 6 January 2022

Documentation for this module may be created at Module:Navboxes/doc

-- New module to stop navbox generators cluttering other modules

local p = {}

local SkillData = mw.loadData('Module:Skills/data')
local MagicData = mw.loadData('Module:Magic/data')
local ItemData = mw.loadData('Module:Items/data')

local Shared = require('Module:Shared')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Shop = require('Module:Shop')

function p.getFarmingNavbox(frame)
	local resultPart = {}
	local seedsTable = {}
	local produceTable = {}

	for i, item in ipairs(ItemData.Items) do
		if item.farmingLevel ~= nil then
			local tier = item.tier
			if seedsTable[tier] == nil then
				-- Initialise tier tables
				seedsTable[tier] = {}
				produceTable[tier] = {}
			end

			if item.grownItemID ~= nil then
				local grownItem = Items.getItemByID(item.grownItemID)
				if grownItem ~= nil then
					table.insert(produceTable[tier], { ["name"] = grownItem.name, ["level"] = item.farmingLevel })
				end
			end
			table.insert(seedsTable[tier], { ["name"] = item.name, ["level"] = item.farmingLevel })
		end
	end

	-- Generate output table
	table.insert(resultPart, '{| class="wikitable mw-collapsible" style="margin:auto; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n!colspan="2" style="padding-left:64px;"|' .. Icons.Icon({'Farming', type='skill'}))

	local getItemList = function(itemTable)
		local listPart = {}
		for i, item in ipairs(itemTable) do
			table.insert(listPart, Icons.Icon({item.name, type='item'}))
		end
		return table.concat(listPart, ' • ')
	end
	local sortFunc = function(a, b) return (a.level == b.level and a.name < b.name) or a.level < b.level end

	-- Determine tier list & order in which tiers will be listed in output
	local tierList = {}
	for tier, seeds in pairs(seedsTable) do
		table.insert(tierList, tier)
	end
	table.sort(tierList, function(a, b) return a < b end)

	-- Generate table section for each tier
	for i, tier in pairs(tierList) do
		-- Sort tables by Farming level order
		table.sort(seedsTable[tier], sortFunc)
		table.sort(produceTable[tier], sortFunc)

		table.insert(resultPart, '\r\n|-\r\n!colspan="2"| ' .. tier .. 's')
		table.insert(resultPart, '\r\n|-\r\n!scope="row"| Seeds')
		table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getItemList(seedsTable[tier]))
		table.insert(resultPart, '\r\n|-\r\n!scope="row"| Produce')
		table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getItemList(produceTable[tier]))
	end
	table.insert(resultPart, '\r\n|}')

	return table.concat(resultPart)
end

function p.getFoodNavbox(frame)
	local foundIDs, cookedFood, harvestedFood, otherFood = {}, {}, {}, {}

	-- Hide Lemon cake
	foundIDs[1029] = true
	foundIDs[1061] = true

	-- Harvested food first
	for i, item in ipairs(ItemData.Items) do
		if item.grownItemID ~= nil then
			local grownItem = Items.getItemByID(item.grownItemID)
			if grownItem ~= nil and grownItem.canEat then
				table.insert(harvestedFood, { ["name"] = grownItem.name, ["order"] = item.farmingLevel })
				foundIDs[grownItem.id] = true
			end
		end
	end

	-- Any cooked & other food
	for i, item in ipairs(ItemData.Items) do
		-- If an item can be eaten then it must be food
		if foundIDs[i - 1] == nil and item.canEat then
			if item.cookingCategory ~= nil then
				-- Item is cooked, such food items are split by category
				if cookedFood[item.cookingCategory + 1] == nil then
					cookedFood[item.cookingCategory + 1] = {}
				end

				local perfectName = nil
				if item.perfectItem ~= nil then
					local perfectItem = Items.getItemByID(item.perfectItem)
					if perfectItem ~= nil then
						perfectName = perfectItem.name
						foundIDs[item.perfectItem] = true
					end
				end
				table.insert(cookedFood[item.cookingCategory + 1], { ["name"] = item.name, ["order"] = item.cookingLevel, ["perfectName"] = perfectName })
			else
				-- Item cannot be cooked or grown, but can be eaten
				table.insert(otherFood, { ["name"] = item.name, ["order"] = item.id })
			end
			foundIDs[i - 1] = true
		end
	end

	-- Sort food lists
	local sortFunc = function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end
	for i, items in pairs(cookedFood) do
		table.sort(cookedFood[i], sortFunc)
	end
	table.sort(harvestedFood, sortFunc)
	table.sort(otherFood, sortFunc)

	-- Generate food lists for final output
	local cookingCatHeader = {
		Icons.Icon({'Normal Cooking Fire', 'Cooking Fire', type='upgrade', nolink=true}),
		Icons.Icon({'Basic Furnace', 'Furnace', type='upgrade', nolink=true}),
		Icons.Icon({'Basic Pot', 'Pot', type='upgrade', nolink=true})
	}
	local getFoodList = function(foodTable)
		local listPart = {}
		for i, food in ipairs(foodTable) do
			local foodText = Icons.Icon({food.name, type='item'})
			if food.perfectName ~= nil then
				foodText = Icons.Icon({food.perfectName, type='item', notext=true}) .. ' ' .. foodText
			end
			table.insert(listPart, foodText)
		end
		return table.concat(listPart, ' • ')
	end

	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable mw-collapsible" style="margin:0 auto 10px; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n|-\r\n!style="background-color:#275C87;color:#FFFFFF;padding-left:64px;" colspan="2"| [[File:Crab_(item).svg|25px|link=Food]] [[Food]]')
	table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Cooked')
	for catID, foodTable in ipairs(cookedFood) do
		table.insert(resultPart, '\r\n|-\r\n!scope="row"| ' .. cookingCatHeader[catID])
		table.insert(resultPart, '\r\n|style="text-align:center;"| ' .. getFoodList(foodTable))
	end
	table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Harvested')
	table.insert(resultPart, '\r\n|-\r\n|colspan="2" style="text-align:center;"| ' .. getFoodList(harvestedFood))
	table.insert(resultPart, '\r\n|-\r\n!colspan="2"| Other')
	table.insert(resultPart, '\r\n|-\r\n|colspan="2" style="text-align:center;"| ' .. getFoodList(otherFood))
	table.insert(resultPart, '\r\n|}')

	return table.concat(resultPart)
end

function p.getPotionNavbox(frame)
	local catList = {
		{ ["categoryID"] = 0, ["name"] = 'Combat' },
		{ ["categoryID"] = 1, ["name"] = 'Skill' }
	}
	table.sort(catList, function(a, b) return a.name < b.name end)

	-- Compile list of potions to be included
	local potList = {}
	for i, potData in ipairs(SkillData.Herblore.ItemData) do
		if potList[potData.category] == nil then
			potList[potData.category] = {}
		end
		local potFirstItem = Items.getItemByID(potData.itemID[1])
		local potName = string.gsub(potFirstItem.name, ' Potion [IV]+$', '')
		table.insert(potList[potData.category], { ["name"] = potName, ["order"] = potData.level, ["img"] = potFirstItem.name })
	end

	local resultPart = {}
	-- Generate table header
	table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n!colspan=2|' .. Icons.Icon({ 'Herblore', 'Potions', type='skill' }))
	-- Generate section for each category of potions
	for i, catData in ipairs(catList) do
		-- Compile list of potions
		local potListText = {}
		table.sort(potList[catData.categoryID], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
		for j, potData in ipairs(potList[catData.categoryID]) do
			table.insert(potListText, Icons.Icon({ potData.name .. ' Potion', potData.name, img=potData.img, type='item' }))
		end
		table.insert(resultPart, '\r\n|-\r\n! ' .. catData.name .. ' Potions')
		table.insert(resultPart, '\r\n|class="center" style="vertical-align:middle;"| ' .. table.concat(potListText, ' • '))
	end
	table.insert(resultPart, '\r\n|}')

	return table.concat(resultPart)
end

function p.getPrayerNavbox(frame)
	local prayerList = {}
	for i, prayer in Shared.skpairs(SkillData.Prayer) do
		table.insert(prayerList, { ["name"] = prayer.name, ["order"] = prayer.prayerLevel })
	end
	table.sort(prayerList, function(a, b)
		if a.order == b.order then
			return a.name < b.name
		else
			return a.order < b.order
		end
	end)

	local prayerListText = {}
	for i, prayer in ipairs(prayerList) do
		table.insert(prayerListText, Icons.Icon({ prayer.name, type='prayer' }))
	end

	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n!'..Icons.Icon({'Prayer', 'Prayers', type='skill'}))
	table.insert(resultPart, '\r\n|-\r\n|style="text-align:center;"| ' .. table.concat(prayerListText, ' • '))
	table.insert(resultPart, '\r\n|}')
	return table.concat(resultPart)
end

function p.getRuneNavbox(frame)
	-- Assumes all runes are from Runecrafting, which may need revising in future updates
	local runeList = { ["Standard"] = {}, ["Combination"] = {} }
	for i, item in ipairs(ItemData.Items) do
		if item.category == 'Runecrafting' and item.type ~= nil and item.type == 'Rune' and item.runecraftingLevel ~= nil then
			local runeType = (type(item.providesRune) == 'table' and Shared.tableCount(item.providesRune) > 1 and 'Combination') or 'Standard'
			table.insert(runeList[runeType], { ["name"] = item.name, ["order"] = item.runecraftingLevel })
		end
	end

	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n!colspan="2"|[[File:Air_Rune_(item).svg|25px|link=Runes]] [[Runes]]')
	for i, cat in ipairs({'Standard', 'Combination'}) do
		table.sort(runeList[cat], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
		table.insert(resultPart, '\r\n|-\r\n!scope="row"|' .. cat .. ' Runes')

		local listPart = {}
		for j, rune in ipairs(runeList[cat]) do
			table.insert(listPart, Icons.Icon({rune.name, type='item'}))
		end
		table.insert(resultPart, '\r\n|style="text-align:center;"|'..table.concat(listPart, ' • '))
	end
	table.insert(resultPart, '\r\n|}')

	return table.concat(resultPart)
end

function p.getSkillcapeNavbox(frame)
	local capeList = Shop.getPurchases(function(cat, purch) return cat == 'Skillcapes' end)
	table.sort(capeList, 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)

	local capeText = {}
	for i, purch in ipairs(capeList) do
		if purch.contains ~= nil and purch.contains.items ~= nil then
			local item = Items.getItemByID(purch.contains.items[1][1])
			if item ~= nil then
				table.insert(capeText, Icons.Icon({item.name, type='item'}))
			end
		end
	end

	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n![[File:Cape_of_Completion_(item).svg|25px|link=Skillcapes]] [[Skillcapes]]')
	table.insert(resultPart, '\r\n|-\r\n|style="text-align:center;"|'..table.concat(capeText, ' • '))
	table.insert(resultPart, '\r\n|}')

	return table.concat(resultPart)
end

function p.getSpellNavbox(frame)
	local spellTable = { ["standard"] = {}, ["curse"] = {}, ["aurora"] = {}, ["ancient"] = {}, ["alt"] = {} }
	local catData = {
		{ ["name"] = 'standard', ["header"] = '[[Magic#Standard_Magic|Standard Spells]]', ["imgType"] = 'spell' },
		{ ["name"] = 'curse', ["header"] = '[[Magic#Curses|Curses]]', ["imgType"] = 'curse' },
		{ ["name"] = 'aurora', ["header"] = '[[Magic#Auroras|Auroras]]', ["imgType"] = 'aurora' },
		{ ["name"] = 'ancient', ["header"] = '[[Magic#Ancient_Magicks|Ancient Magicks]]', ["imgType"] = 'spell' },
		{ ["name"] = 'alt', ["header"] = '[[Alternative_Magic|Alt Magic]]', ["imgType"] = 'spell' },
	}

	for i, spell in ipairs(MagicData.Spells) do
		table.insert(spellTable['standard'], { ["name"] = spell.name, ["order"] = spell.level })
	end
	for i, spell in ipairs(MagicData.Curses) do
		table.insert(spellTable['curse'], { ["name"] = spell.name, ["order"] = spell.level })
	end
	for i, spell in ipairs(MagicData.Auroras) do
		table.insert(spellTable['aurora'], { ["name"] = spell.name, ["order"] = spell.level })
	end
	for i, spell in ipairs(MagicData.Ancient) do
		table.insert(spellTable['ancient'], { ["name"] = spell.name, ["order"] = spell.level })
	end
	for i, spell in ipairs(MagicData.AltMagic) do
		table.insert(spellTable['alt'], { ["name"] = spell.name, ["order"] = spell.level })
	end

	local getSpellList = function(spellTable, imgType)
		local listPart = {}
		for i, obj in ipairs(spellTable) do
			table.insert(listPart, Icons.Icon({obj.name, type=imgType}))
		end
		return table.concat(listPart, ' • ')
	end

	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n!colspan=2|[[File:Magic_(skill).svg|25px|link=Spells]] [[Spells]]')
	for i, catDefn in ipairs(catData) do
		table.sort(spellTable[catDefn.name], function(a, b)
			if a.order == b.order then
				return a.name < b.name
			else
				return a.order < b.order
			end
		end)
		table.insert(resultPart, '\r\n|-\r\n!scope="row"| ' .. catDefn.header)
		table.insert(resultPart, '\r\n|style="text-align:center;| ' .. getSpellList(spellTable[catDefn.name], catDefn.imgType))
	end
	table.insert(resultPart, '\r\n|}')

	return table.concat(resultPart)
end

function p.getFamiliarNavbox(frame)
	local familiars = Items.getItems(function(item) return item.type == 'Familiar' end)
	table.sort(familiars, function(a, b) return a.summoningLevel < b.summoningLevel end)

	local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
	result = result..'\r\n!colspan=2|[[File:Summoning_(skill).svg|25px|link=Summoning]] [[Summoning|Summoning Familiars]]'
	local iconArray = {}
	for i, fam in Shared.skpairs(familiars) do
		table.insert(iconArray, Icons.Icon({fam.name, type='item'}))
	end
	result = result..'\r\n|-\r\n|style="text-align:center;"|'..table.concat(iconArray, ' • ')
	result = result..'\r\n|}'
	return result
end

function p.getThievingNavbox()
	local returnPart = {}

	-- Create table header
	table.insert(returnPart, '{| class="wikitable" style="text-align:center; clear:both; margin:auto; margin-bottom:1em;"')
	table.insert(returnPart, '|-\r\n!' .. Icons.Icon({'Thieving', type='skill', notext=true}) .. '[[Thieving|Thieving Targets]]')
	table.insert(returnPart, '|-\r\n|')

	local npcData = {}
	for i, npc in ipairs(SkillData.Thieving.NPCs) do
		table.insert(npcData, {["level"] = npc.level, ["name"] = npc.name})
	end
	table.sort(npcData, function(a, b) return a.level < b.level end)

	local npcList = {}
	-- Create row for each NPC
	for i, npc in ipairs(npcData) do
		table.insert(npcList, Icons.Icon({npc.name, type='thieving'}))
	end
	table.insert(returnPart, table.concat(npcList, ' • '))
	table.insert(returnPart, '|}')

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

function p.getFishingNavbox()
	local categoryHeader = {}
	local categoryItems = {}
	local addCatData = function(cat, catLink, itemName, itemOrder)
		if categoryItems[cat] == nil then
			-- Initialise category
			table.insert(categoryHeader, { ["name"] = cat, ["link"] = catLink })
			categoryItems[cat] = {}
		end
		table.insert(categoryItems[cat], { ["name"] = itemName, ["order"] = itemOrder })
	end

	-- Identify fishing catchable items
	local fishingToItemID = {}
	local junkItems = {}
	local specialItems = {}
	for i, item in ipairs(ItemData.Items) do
		if item.fishingID ~= nil then
			-- Create FishingID to item map
			fishingToItemID[item.fishingID] = item
		elseif item.category == 'Fishing' and item.type == 'Junk' then
			table.insert(junkItems, item)
		elseif item.fishingCatchWeight ~= nil then
			table.insert(specialItems, item)
		end
	end
	-- Fishing areas
	-- Iterate through all fishing areas, identifying fish within each
	for i, area in ipairs(SkillData.Fishing.Areas) do
		for j, fishID in ipairs(area.fish) do
			local fishItem = fishingToItemID[fishID]
			if fishItem ~= nil then
				addCatData(area.name, 'Fishing#Fishing Areas', fishItem.name, fishItem.fishingLevel)
			end
		end
	end
	-- Junk items
	for i, item in ipairs(junkItems) do
		addCatData('Junk', 'Fishing#Junk', item.name, 1)
	end
	-- Special items
	for i, item in ipairs(specialItems) do
		addCatData('Special Items', 'Fishing#Special', item.name, 1 / (item.fishingCatchWeight or 1))
	end

	local resultPart = {}
	-- Generate navbox header
	table.insert(resultPart, '{| class="wikitable" style="margin:auto; clear:both; width: 100%"')
	table.insert(resultPart, '\r\n|-\r\n!colspan="2" | ' .. Icons.Icon({'Fishing', type='skill'}))
	-- Generate section for each fishing area, junk, and special
	for i, cat in ipairs(categoryHeader) do
		local itemList = {}
		if categoryItems[cat.name] ~= nil then
			table.sort(categoryItems[cat.name], function(a, b) return (a.order == b.order and a.name < b.name) or a.order < b.order end)
			for j, item in ipairs(categoryItems[cat.name]) do
				table.insert(itemList, Icons.Icon({item.name, type='item'}))
			end
		end

		table.insert(resultPart, '\r\n|-\r\n!class="center" style="min-width:140px" | [[' .. (cat.link or cat.name) .. '|' .. cat.name .. ']]')
		table.insert(resultPart, '\r\n| class="center" style="vertical-align:middle;" | ' .. table.concat(itemList, ' • '))
	end
	table.insert(resultPart, '\r\n|}')

	return table.concat(resultPart)
end

return p