Module:Navboxes

Revision as of 23:20, 7 October 2021 by Auron956 (talk | contribs) (getFoodNavbox: Revise implementation to include all current and hopefully all future food)

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')

function p.getFarmingNavbox(frame)
  local allotmentSeedsTable = {}
  local allotmentProduceTable = {}
  local herbSeedsTable = {}
  local herbProduceTable = {}
  local treeSeedsTable = {}
  local treeProduceTable = {}

  for i, item in Shared.skpairs(ItemData.Items) do
    if item.tier == 'Allotment' then
      table.insert(allotmentSeedsTable, Icons.Icon({item.name, type='item'}))
    elseif item.type == 'Harvest' then
      table.insert(allotmentProduceTable, Icons.Icon({item.name, type='item'}))
    elseif item.tier == 'Herb' then
      table.insert(herbSeedsTable, Icons.Icon({item.name, type='item'}))  
    elseif item.type == 'Herb' then
      table.insert(herbProduceTable, Icons.Icon({item.name, type='item'}))
    elseif item.tier == 'Tree' then
      table.insert(treeSeedsTable, Icons.Icon({item.name, type='item'}))
    elseif i == 2 or i == 3 or i == 5 or i == 7 or i == 8 then
      table.insert(treeProduceTable, Icons.Icon({item.name, type='item'}))  
    end
  end
    
  local result = '{| class="wikitable mw-collapsible" style="margin:auto; clear:both; width: 100%"'
  result = result..'\r\n!colspan="2" style="padding-left:64px;"|'..Icons.Icon({'Farming', type='skill'})
  result = result..'\r\n|-\r\n!colspan="2"|Allotments'
  result = result..'\r\n|-\r\n!scope="row"|Seeds'
  result = result..'\r\n|style="text-align:center;|'..table.concat(allotmentSeedsTable, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|Produce'
  result = result..'\r\n|style="text-align:center;|'..table.concat(allotmentProduceTable, ' • ')
  result = result..'\r\n|-\r\n!colspan="2"|Herbs'
  result = result..'\r\n|-\r\n!scope="row"|Seeds'
  result = result..'\r\n|style="text-align:center;|'..table.concat(herbSeedsTable, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|Produce'
  result = result..'\r\n|style="text-align:center;|'..table.concat(herbProduceTable, ' • ')
  result = result..'\r\n|-\r\n!colspan="2"|Trees'
  result = result..'\r\n|-\r\n!scope="row"|Seeds'
  result = result..'\r\n|style="text-align:center;|'..table.concat(treeSeedsTable, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|Produce'
  result = result..'\r\n|style="text-align:center;|'..table.concat(treeProduceTable, ' • ')
  result = result..'\r\n|}'

  return result
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;" 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.getPrayerNavbox(frame)
  local prayers = {}
  for i, prayer in Shared.skpairs(SkillData.Prayer) do
    table.insert(prayers, Icons.Icon({prayer.name, type="prayer"}))
  end
  local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
  result = result..'\r\n!'..Icons.Icon({'Prayer', 'Prayers', type='skill'})
  result = result..'\r\n|-\r\n|style="text-align:center;"|'..table.concat(prayers, ' • ')
  result = result..'\r\n|}'
  return result
end

function p.getRuneNavbox(frame)
  local standardRunes = {}
  local combinationRunes = {}
  for i, item in pairs(ItemData.Items) do
    if (i >= 390 and i < 400) or (i >= 821 and i < 825) then
    table.insert(standardRunes, Icons.Icon({item.name, type='item'}))
    elseif i >= 825 and i < 831 then
    table.insert(combinationRunes, Icons.Icon({item.name, type='item'}))
    end
  end
  local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
  result = result..'\r\n!colspan="2"|[[File:Air_Rune_(item).svg|25px|link=Runes]] [[Runes]]'
  result = result..'\r\n|-\r\n!scope="row"|Standard Runes'
  result = result..'\r\n|style="text-align:center;"|'..table.concat(standardRunes, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|Combination Runes'
  result = result..'\r\n|style="text-align:center;"|'..table.concat(combinationRunes, ' • ')
  result = result..'\r\n|}'
  return result
end

function p.getSkillcapeNavbox(frame)
  local capeList = {}
  for i, item in pairs(ItemData.Items) do
    if Shared.contains(item.name, 'Skillcape') or item.name == 'Cape of Completion' then
    table.insert(capeList, Icons.Icon({item.name, type='item'}))
    end
  end
  table.sort(capeList, function(a,b)
    return a < b
  end)
  local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
  result = result..'\r\n![[File:Cape_of_Completion_(item).svg|25px|link=Skillcapes]] [[Skillcapes]]'
  result = result..'\r\n|-\r\n|style="text-align:center;"|'..table.concat(capeList, ' • ')
  result = result..'\r\n|}'
  return result
end

function p.getSpellNavbox(frame)
  local spells = {}
  local curses = {}
  local auroras = {}
  local ancients = {}
  local altmagic = {}

  for i, spell in Shared.skpairs(MagicData.Spells) do
    table.insert(spells, Icons.Icon({spell.name, type='spell'}))
  end
  for i, spell in Shared.skpairs(MagicData.Curses) do
    table.insert(curses, Icons.Icon({spell.name, type='curse'}))
  end
  for i, spell in Shared.skpairs(MagicData.Auroras) do
    table.insert(auroras, Icons.Icon({spell.name, type='aurora'}))
  end
  for i, spell in Shared.skpairs(MagicData.Ancient) do
    table.insert(ancients, Icons.Icon({spell.name, type='spell'}))
  end
  for i, spell in Shared.skpairs(MagicData.AltMagic) do
    table.insert(altmagic, Icons.Icon({spell.name, type='spell'}))
  end

  local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
  result = result..'\r\n!colspan=2|[[File:Magic_(skill).svg|25px|link=Spells]] [[Spells]]'
  result = result..'\r\n|-\r\n!scope="row"|[[Magic#Standard_Magic|Standard Spells]]'
  result = result..'\r\n|style="text-align:center;|'..table.concat(spells, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|[[Magic#Curses|Curses]]'
  result = result..'\r\n|style="text-align:center;|'..table.concat(curses, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|[[Magic#Auroras|Auroras]]'
  result = result..'\r\n|style="text-align:center;|'..table.concat(auroras, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|[[Magic#Ancient_Magicks|Ancient Magicks]]'
  result = result..'\r\n|style="text-align:center;|'..table.concat(ancients, ' • ')
  result = result..'\r\n|-\r\n!scope="row"|[[Alternative_Magic|Alt Magic]]'
  result = result..'\r\n|style="text-align:center;|'..table.concat(altmagic, ' • ')
  result = result..'\r\n|}'

  return result
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

return p