Module:Items: Difference between revisions

From Melvor Idle
(another attempt to fix formatting)
(Improvements to the getItemSources code to account for more things. Probably not everything quite yet, but getting there)
Line 201: Line 201:


function p._getItemSources(item)
function p._getItemSources(item)
   local result = ''
   local result = nil
  local lineArray = {}
 
   --Alright, time to go through all the ways you can get an item...
   --Alright, time to go through all the ways you can get an item...
   --First up: Can we kill somebody and take theirs?
   --First up: Can we kill somebody and take theirs?
   local killFound = false
   local killStr = ''
   for i, monster in pairs(MonsterData.Monsters) do
   for i, monster in pairs(MonsterData.Monsters) do
     if monster.lootTable ~= nil then
     if monster.lootTable ~= nil then
       for j, loot in pairs(monster.lootTable) do
       for j, loot in pairs(monster.lootTable) do
         if loot[1] == item.id then
         if loot[1] == item.id then
           if killFound then
           if string.len(killStr) > 0 then
             result = result..','..Icons.Icon({monster.name, type="monster", notext="true"})
             killStr = killStr..','..Icons.Icon({monster.name, type="monster", notext="true"})
           else
           else
             result = result..'Killing: '..Icons.Icon({monster.name, type="monster", notext="true"})
             killStr = killStr..'Killing: '..Icons.Icon({monster.name, type="monster", notext="true"})
            killFound = true
           end
           end
         end
         end
Line 219: Line 220:
     end
     end
   end
   end
  if string.len(killStr) > 0 then table.insert(lineArray, killStr) end


   --Next: Can we find it in a box?
   --Next: Can we find it in a box?
   local boxFound = false
  --While we're here, check for upgrades, cooking, and growing
   for i, chest in pairs(ItemData) do
  local lootStr = ''
     if chest.dropTable ~= nil then
  local upgradeStr = ''
       for j, loot in pairs(chest.dropTable) do
  local cookStr = ''
  local burnStr = ''
   local growStr = ''
   for i, item2 in pairs(ItemData) do
     if item2.dropTable ~= nil then
       for j, loot in pairs(item2.dropTable) do
         if loot[1] == item.id then
         if loot[1] == item.id then
           if boxFound then
           if string.len(lootStr) > 0 then
             result = result..','..Icons.Icon({chest.name, type="item", notext="true"})
             lootStr = lootStr..','..Icons.Icon({item2.name, type="item", notext="true"})
           else
           else
             if string.len(result) > 0 then result = result..'<br/>' end
             lootStr = lootStr..'Opening: '..Icons.Icon({item2.name, type="item", notext="true"})
            result = result..'Opening: '..Icons.Icon({chest.name, type="item", notext="true"})
            boxFound = true
           end
           end
         end
         end
       end
       end
    end
    if item2.trimmedItemID == item.id then
        if string.len(upgradeStr) > 0 then
          upgradeStr = upgradeStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          upgradeStr = upgradeStr..'Upgrading: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
    end
    if item2.cookedItemID == item.id then
        if string.len(cookStr) > 0 then
          cookStr = cookStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          cookStr = cookStr..'Cooking: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
    end
    if item2.burntItemID == item.id then
        if string.len(burnStr) > 0 then
          burnStr = burnStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          burnStr = burnStr..'Burning: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
    end
    if item2.grownItemID == item.id then
        if string.len(growStr) > 0 then
          growStr = growStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          growStr = growStr..'Growing: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
     end
     end
   end
   end
  if string.len(lootStr) > 0 then table.insert(lineArray, lootStr) end
  if string.len(upgradeStr) > 0 then table.insert(lineArray, upgradeStr) end
  if string.len(cookStr) > 0 then table.insert(lineArray, cookStr) end
  if string.len(burnStr) > 0 then table.insert(lineArray, burnStr) end
  if string.len(growStr) > 0 then table.insert(lineArray, growStr) end


   --Next: Can we take it from somebody else -without- killing them?
   --Next: Can we take it from somebody else -without- killing them?
  local thiefStr = ''
   for i, npc in pairs(SkillData.Thieving) do
   for i, npc in pairs(SkillData.Thieving) do
     if npc.lootTable ~= nil then
     if npc.lootTable ~= nil then
       for j, loot in pairs(npc.lootTable) do
       for j, loot in pairs(npc.lootTable) do
         if loot[1] == item.id then
         if loot[1] == item.id then
           if string.len(result) > 0 then result = result..'<br/>' end
           if string.len(thiefStr) > 0 then
           result = result..'Pickpocketing: '..Icons.Icon({npc.name, type="thieving", notext="true"})
            thiefStr = thiefStr..','..Icons.Icon({npc.name, type="item", notext="true"})
           boxFound = true
           else
            thiefStr = thiefStr..'Pickpocketing: '..Icons.Icon({npc.name, type="item", notext="true"})
           end
         end
         end
       end
       end
     end
     end
   end
   end
 
   if string.len(thiefStr) > 0 then table.insert(lineArray, thiefStr) end
   --Next: Can we get to it via upgrading?
  local upgradeFound = false
  if item.itemsRequired ~= nil then
    if string.len(result) > 0 then result = result..'<br/>' end
    result = result..'Upgrading: '
    for i, req in pairs(item.itemsRequired) do
      local reqItem = p.getItemByID(req[1])
      if reqItem.canUpgrade then
        if upgradeFound then result = result..', ' else upgradeFound = true end
        result = result..Icons.Icon({reqItem.name, type='item', notext='true'})
      end
    end
  end


   --If all else fails, I guess we should check if we can make it ourselves
   --If all else fails, I guess we should check if we can make it ourselves
   --SmithCheck:
   --SmithCheck:
   if item.smithingLevel ~= nil then
   if item.smithingLevel ~= nil then
     if string.len(result) > 0 then result = result..'<br/>' end
     table.insert(lineArray, Icons._SkillReq("Smithing", item.smithingLevel))
    result = result..Icons._SkillReq("Smithing", item.smithingLevel)
   end
   end


   --CraftCheck:
   --CraftCheck:
   if item.craftingLevel ~= nil then
   if item.craftingLevel ~= nil then
     if string.len(result) > 0 then result = result..'<br/>' end
     table.insert(lineArray, Icons._SkillReq("Crafting", item.craftingLevel))
    result = result..Icons._SkillReq("Crafting", item.craftingLevel)
   end
   end


   --FletchCheck:
   --FletchCheck:
   if item.fletchingLevel ~= nil then
   if item.fletchingLevel ~= nil then
     if string.len(result) > 0 then result = result..'<br/>' end
     table.insert(lineArray, Icons._SkillReq("Fletching", item.fletchingLevel))
    result = result..Icons._SkillReq("Fletching", item.fletchingLevel)
   end
   end


   --RunecraftCheck:
   --RunecraftCheck:
   if item.runecraftingLevel ~= nil then
   if item.runecraftingLevel ~= nil then
     if string.len(result) > 0 then result = result..'<br/>' end
     table.insert(lineArray, Icons._SkillReq("Runecrafting", item.runecraftingLevel))
     result = result..Icons._SkillReq("Runecrafting", item.runecraftingLevel)
  end
 
  --MineCheck:
  if item.miningLevel ~= nil then
     table.insert(lineArray, Icons._SkillReq("Mining", item.miningLevel))
   end
   end


   --FishCheck:
   --FishCheck:
   if (item.category == "Fishing" and (item.type == "Junk" or item.type == "Special")) or item.category == "Gem" then
   if (item.category == "Fishing" and (item.type == "Junk" or item.type == "Special")) then
     if string.len(result) > 0 then result = result..'<br/>' end
     table.insert(lineArray, Icons._SkillReq("Fishing", 1))
    result = result..Icons._SkillReq("Fishing", 1)
   elseif item.fishingLevel ~= nil then
   elseif item.category == 'Fishing' then
     table.insert(lineArray, Icons._SkillReq("Fishing", item.fishingLevel))
     if string.len(result) > 0 then result = result..'<br/>' end
  end
     result = result..Icons._SkillReq("Fishing", item.fishingLevel)
 
  --HerbCheck:
  if item.herbloreMasteryID ~= nil then
    local potionData = SkillData.Herblore.ItemData[item.herbloreMasteryID + 1].herbloreLevel
     table.insert(lineArray, Icons._SkillReq("Herblore", potionData))
   end
   end


   --Finally there are some weird exceptions:
   --Finally there are some weird exceptions:
   --Shop items
   --Coal can be acquired via firemaking
   if item.slayerCost ~= nil or item.buysFor ~= nil then
   if item.name == "Coal Ore" then
     if string.len(result) > 0 then result = result..'<br/>' end
    table.insert(lineArray, Icons._SkillReq("Firemaking", 1))
     result = result..'[[Shop]]'
  end
 
  --Gems can be acquired from both mining & fishing
  if item.type == 'Gem' then
     table.insert(lineArray, Icons._SkillReq("Fishing", 1))
    table.insert(lineArray, Icons._SkillReq("Mining", 1))
  end
 
  --Tokens are from the appropriate skill
  if item.isToken then
     for skill, id in pairs(Constants.skill) do
      if id == item.skill then
        table.insert(lineArray, Icons._SkillReq(skill, 1))
      end
    end
   end
   end


   --Special Shop Items (ie gloves, which don't technically exist in the shop)
   --Shop items (including special items like gloves that aren't otherwise listed)
   if Shared.contains(OtherShopItems, item.name) then
   if item.slayerCost ~= nil or item.buysFor ~= nil or Shared.contains(OtherShopItems, item.name) then
     if string.len(result) > 0 then result = result..'<br/>' end
     table.insert(lineArray, '[[Shop]]')
    result = result..'[[Shop]]'
   end
   end


   --Easter Eggs (manual list 'cause don't have a better way to do that)
   --Easter Eggs (manual list 'cause don't have a better way to do that)
   if Shared.contains(EasterEggs, item.name) then
   if Shared.contains(EasterEggs, item.name) then
     if string.len(result) > 0 then result = result..'<br/>' end
     table.insert(lineArray, '[[Easter Eggs]]')
    result = result..'[[Easter Eggs]]'
   end
   end


   return result
   return table.concat(lineArray, "<br/>")
end
end



Revision as of 21:15, 23 September 2020

Lua module containing all sorts of functions for getting data on items. Pulls data from Module:GameData/data.

Some functions were split to submodules:


local p = {}

local MonsterData = mw.loadData('Module:Monsters/data')
local ItemData = mw.loadData('Module:Items/data')
local SkillData = mw.loadData('Module:Skills/data')
local Constants = mw.loadData('Module:Constants/data')

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

local EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon'}
local OtherShopItems = {'Cooking Gloves', 'Mining Gloves', 'Gem Gloves', 'Smithing Gloves', 'Thieving Gloves'}

function p.getItemByID(ID)
  local result = Shared.clone(ItemData[ID + 1])
  if result ~= nil then
    result.id = ID
  end
  return result
end

function p.getItem(name)
  local result = nil
  for i, item in pairs(ItemData) do
    if(item.name == name) then
      result = Shared.clone(item)
      --Make sure every item has an id, and account for Lua being 1-index
      result.id = i -1
    end
  end
  return result
end

function p._getItemStat(item, StatName, ZeroIfNil)
  local result = item[StatName]
  --Special Overrides:
  if StatName == 'stabAttackBonus' then
    if item.attacBonus == nil then 
      result = nil
    else
      result = item.attackBonus[1]
    end
  elseif StatName == 'slashAttackBonus' then
    if item.attackBonus == nil then 
      result = nil
    else
      result = item.attackBonus[2]
    end
  elseif StatName == 'blockAttackBonus' then
    if item.attackBonus == nil then 
      result = nil
    else
      result = item.attackBonus[3]
    end
  elseif StatName == 'attackType' then
    result = p._getWeaponAttackType(item)
  end
  if result == nil and ZeroIfNil then result = 0 end
  return result
end

function p.getItemStat(frame)
  local args = frame.args ~= nil and frame.args or frame
  local ItemName = args[1]
  local StatName = args[2]
  local ZeroIfNil = args.ForceZero ~= nil and args.ForceZero ~= '' and args.ForceZero ~= 'false'
  local item = p.getItem(ItemName)
  if item == nil then
    return "ERROR: No item named "..ItemName.." exists in the data module"
  end
  return p._getItemStat(item, StatName, ZeroIfNil)
end

function p._getWeaponAttackType(item)
  if item.type == 'Weapon' then
    return Icons.Icon({'Melee', nolink='true'})
  elseif item.type == 'Ranged Weapon' then
    return Icons.Icon({'Ranged', type='skill', nolink='true'})
  elseif item.type == 'Magic Staff' or item.type == 'Magic Wand' then
    return Icons.Icon({'Magic', type='skill', nolink='true'})
  else
    return "Invalid"
  end
end


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

function p.getPotionTable(frame)
  local potionName = frame.args ~= nil and frame.args[1] or frame
  local tiers = {'I', 'II', 'III', 'IV'}

  local result = '{| class="wikitable"'
  result = result..'\r\n!Potion!!Tier!!Charges!!Effect'

  local tier1potion = p.getItem(potionName..' I')
  for i, tier in pairs(tiers) do
    local tierName = potionName..' '..tier
    local potion = p.getItemByID(tier1potion.id + i - 1)
    if potion == nil then
       mw.log("Failed to get tier "..tier)
    else
      result = result..'\r\n|-'
      result = result..'\r\n|'..Icons.Icon({tierName, type='item', notext='true', size='60'})
      result = result..'||'..'[['..tierName..'|'..tier..']]'
      result = result..'||'..potion.potionCharges..'||'..potion.description
    end
  end

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

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

  local skill = ''
  local time = 0
  local lvl = 0
  local xp = 0
  local qty = nil
  local req = {}
  --First figure out what skill is used to make this...
  if item.smithingLevel ~= nil then
    skill = 'Smithing'
    lvl = item.smithingLevel
    xp = item.smithingXP
    req = item.smithReq
    qty = item.smithingQty
    time = 2
  elseif item.craftingLevel ~= nil then
    skill = 'Crafting'
    lvl = item.craftingLevel
    xp = item.craftingXP
    req = item.craftReq
    qty = item.craftQty
    time = 3
  elseif item.runecraftingLevel ~= nil then
    skill = 'Runecrafting'
    lvl = item.runecraftingLevel
    xp = item.runecraftingXP
    req = item.runecraftReq
    qty = item.runecraftQty
    time = 2
  elseif item.fletchingLevel ~= nil then
    skill = 'Fletching'
    lvl = item.fletchingLevel
    xp = item.fletchingXP
    req = item.fletchReq
    qty = item.fletchQty
    time = 2
  elseif item.herbloreReq ~= nil then
    skill = 'Herblore'
    req = item.herbloreReq
    --Currently using 'herbloreMasteryID' as shorthand to find details, could be a better method
    local potionID = item.herbloreMasteryID
    local potionData = SkillData.Herblore.ItemData[potionID + 1]
    lvl = potionData.herbloreLevel
    xp = potionData.herbloreXP
    time = 2
  else
    return "Failed to find creation requirements for this (Possibly the module isn't properly updated for this skill)"
  end
  if qty == nil then qty = 1 end

  local result = '{|class="wikitable"'
  result = result..'\r\n!colspan="2"|Item Creation\r\n|-'
  result = result..'\r\n|-\r\n!style="text-align: right;"|Requirements'
  result = result..'\r\n|'..Icons.Icon({skill, type="skill", notext="true"}).." '''"..lvl.."'''"
  result = result..'\r\n|-\r\n!style="text-align: right;"|Materials\r\n|'
  for i, mat in pairs(req) do
    if i > 1 then result = result..'<br/>' end
    local matItem = p.getItemByID(mat.id)
    if matItem == nil then
      result = result..mat.qty..'x ?????'
    else
      result = result..Icons.Icon({matItem.name, type='item', qty=mat.qty})
    end
  end
  result = result..'\r\n|-\r\n!style="text-align:right;"|Base Quantity'
  result = result..'\r\n|'..qty
  result = result..'\r\n|-\r\n!style="text-align:right;"|Base Experience'
  result = result..'\r\n|'..xp..' XP'
  result = result..'\r\n|-\r\n!style="text-align:right;"|Base Creation Time'
  result = result..'\r\n|'..time..'.0 s'
  result = result..'\r\n|}'

  return result
end

function p._getItemSources(item)
  local result = nil
  local lineArray = {}

  --Alright, time to go through all the ways you can get an item...
  --First up: Can we kill somebody and take theirs?
  local killStr = ''
  for i, monster in pairs(MonsterData.Monsters) do
    if monster.lootTable ~= nil then
      for j, loot in pairs(monster.lootTable) do
        if loot[1] == item.id then
          if string.len(killStr) > 0 then
            killStr = killStr..','..Icons.Icon({monster.name, type="monster", notext="true"})
          else
            killStr = killStr..'Killing: '..Icons.Icon({monster.name, type="monster", notext="true"})
          end
        end
      end
    end
  end
  if string.len(killStr) > 0 then table.insert(lineArray, killStr) end

  --Next: Can we find it in a box?
  --While we're here, check for upgrades, cooking, and growing
  local lootStr = ''
  local upgradeStr = ''
  local cookStr = ''
  local burnStr = ''
  local growStr = ''
  for i, item2 in pairs(ItemData) do
    if item2.dropTable ~= nil then
      for j, loot in pairs(item2.dropTable) do
        if loot[1] == item.id then
          if string.len(lootStr) > 0 then
            lootStr = lootStr..','..Icons.Icon({item2.name, type="item", notext="true"})
          else
            lootStr = lootStr..'Opening: '..Icons.Icon({item2.name, type="item", notext="true"})
          end
        end
      end
    end
    if item2.trimmedItemID == item.id then
        if string.len(upgradeStr) > 0 then
          upgradeStr = upgradeStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          upgradeStr = upgradeStr..'Upgrading: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
    end
    if item2.cookedItemID == item.id then
        if string.len(cookStr) > 0 then
          cookStr = cookStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          cookStr = cookStr..'Cooking: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
    end
    if item2.burntItemID == item.id then
        if string.len(burnStr) > 0 then
          burnStr = burnStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          burnStr = burnStr..'Burning: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
    end
    if item2.grownItemID == item.id then
        if string.len(growStr) > 0 then
          growStr = growStr..','..Icons.Icon({item2.name, type="item", notext="true"})
        else
          growStr = growStr..'Growing: '..Icons.Icon({item2.name, type="item", notext="true"})
        end
    end
  end
  if string.len(lootStr) > 0 then table.insert(lineArray, lootStr) end
  if string.len(upgradeStr) > 0 then table.insert(lineArray, upgradeStr) end
  if string.len(cookStr) > 0 then table.insert(lineArray, cookStr) end
  if string.len(burnStr) > 0 then table.insert(lineArray, burnStr) end
  if string.len(growStr) > 0 then table.insert(lineArray, growStr) end

  --Next: Can we take it from somebody else -without- killing them?
  local thiefStr = ''
  for i, npc in pairs(SkillData.Thieving) do
    if npc.lootTable ~= nil then
      for j, loot in pairs(npc.lootTable) do
        if loot[1] == item.id then
          if string.len(thiefStr) > 0 then
            thiefStr = thiefStr..','..Icons.Icon({npc.name, type="item", notext="true"})
          else
            thiefStr = thiefStr..'Pickpocketing: '..Icons.Icon({npc.name, type="item", notext="true"})
          end
        end
      end
    end
  end
  if string.len(thiefStr) > 0 then table.insert(lineArray, thiefStr) end

  --If all else fails, I guess we should check if we can make it ourselves
  --SmithCheck:
  if item.smithingLevel ~= nil then
    table.insert(lineArray, Icons._SkillReq("Smithing", item.smithingLevel))
  end

  --CraftCheck:
  if item.craftingLevel ~= nil then
    table.insert(lineArray, Icons._SkillReq("Crafting", item.craftingLevel))
  end

  --FletchCheck:
  if item.fletchingLevel ~= nil then
    table.insert(lineArray, Icons._SkillReq("Fletching", item.fletchingLevel))
  end

  --RunecraftCheck:
  if item.runecraftingLevel ~= nil then
    table.insert(lineArray, Icons._SkillReq("Runecrafting", item.runecraftingLevel))
  end

  --MineCheck:
  if item.miningLevel ~= nil then
    table.insert(lineArray, Icons._SkillReq("Mining", item.miningLevel))
  end

  --FishCheck:
  if (item.category == "Fishing" and (item.type == "Junk" or item.type == "Special")) then
    table.insert(lineArray, Icons._SkillReq("Fishing", 1))
  elseif item.fishingLevel ~= nil then
    table.insert(lineArray, Icons._SkillReq("Fishing", item.fishingLevel))
  end

  --HerbCheck:
  if item.herbloreMasteryID ~= nil then
    local potionData = SkillData.Herblore.ItemData[item.herbloreMasteryID + 1].herbloreLevel
    table.insert(lineArray, Icons._SkillReq("Herblore", potionData))
  end

  --Finally there are some weird exceptions:
  --Coal can be acquired via firemaking
  if item.name == "Coal Ore" then
    table.insert(lineArray, Icons._SkillReq("Firemaking", 1))
  end

  --Gems can be acquired from both mining & fishing
  if item.type == 'Gem' then
    table.insert(lineArray, Icons._SkillReq("Fishing", 1))
    table.insert(lineArray, Icons._SkillReq("Mining", 1))
  end

  --Tokens are from the appropriate skill
  if item.isToken then
    for skill, id in pairs(Constants.skill) do
      if id == item.skill then
        table.insert(lineArray, Icons._SkillReq(skill, 1))
      end
    end
  end

  --Shop items (including special items like gloves that aren't otherwise listed)
  if item.slayerCost ~= nil or item.buysFor ~= nil or Shared.contains(OtherShopItems, item.name) then
    table.insert(lineArray, '[[Shop]]')
  end

  --Easter Eggs (manual list 'cause don't have a better way to do that)
  if Shared.contains(EasterEggs, item.name) then
    table.insert(lineArray, '[[Easter Eggs]]')
  end

  return table.concat(lineArray, "<br/>")
end


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

  return p._getItemSources(item)
end

function p.getEquipmentTable(frame)
  local args = frame.args ~= nil and frame.args or frame
  local type = args.type
  local tier = args.tier
  local slotStr = args.slot
  local ammoTypeStr = args.ammoType
  local category = args.category ~= nil and args.category or 'Combat'
  local i = 0
  local j = 0

   --Find out what Ammo Type we're working with
  local ammoType = nil
  if ammoTypeStr ~= nil then
    if ammoTypeStr == "Arrows" then
      ammoType = 0
    elseif ammoTypeStr == 'Bolts' then
      ammoType = 1
    elseif ammoTypeStr == 'Javelins' then
      ammoType = 2
    elseif ammoTypeStr == 'Throwing Knives' then
      ammoType = 3
    end
  end

  --Find out what slot we're working with
  local slot = nil
  if slotStr ~= nil then
    slot = Constants.equipmentSlot[slotStr]
  end
  mw.log("Type = "..(type ~= nil and type or '')..", Slot = "..(slot ~= nil and slot or '')..", AmmoType = "..(ammoType ~= nil and ammoType or ''))
  

  --Getting some lists set up here that will be used later
  --First, the list of columns used by both weapons & armor
  local statColumns = {'slashAttackBonus', 'stabAttackBonus','blockAttackBonus','rangedAttackBonus', 'magicAttackBonus', 'strengthBonus', 'rangedStrengthBonus', 'magicDamageBonus', 'defenceBonus', 'rangedDefenceBonus', 'magicDefenceBonus'}
  --Then the lists for just weapons/just armor
  local weaponStatColumns = {'attackLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'} 
  local armorStatColumns = {'damageReduction', 'defenceLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}
  --Then the list of weapon types
  local weaponTypes = {'Magic Staff', 'Magic Wand', 'Ranged Weapon', 'Weapon'}

  local isWeaponType = Shared.contains(weaponTypes, type)
  
  --Alright, let's start the table by building the shared header
  local result = '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"'
  if isWeaponType then
    --Weapons have an extra column here for Attack Speed
    result = result..'\r\n!colspan="3"|'
  else
    result = result..'\r\n!colspan="2"|'
  end
  result = result..'\r\n!colspan="5"style="padding:0 0.5em 0 0.5em;"|Attack Bonus'
  result = result..'\r\n!colspan="2"style="padding:0 0.5em 0 0.5em;"|Strength Bonus'
  result = result..'\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|% Damage Bonus'
  result = result..'\r\n!colspan="3"style="padding:0 0.5em 0 0.5em;"|Defence Bonus'
  if isWeaponType then
    --Weapons have an extra columns here for "Two Handed?"
    result = result..'\r\n!colspan="1"|'
  else
    --Only armor pieces have DR right now, so ignore that column for weapons
    result = result..'\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|Damage Reduction'
  end
  result = result..'\r\n!colspan="3"style="padding:0 0.5em 0 0.5em;"|Levels Required'
  result = result..'\r\n!colspan="1"|'
  --One header row down, one to go
  result = result..'\r\n|-class="headerRow-1"'
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Item'
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Name'
  --Weapons have Attack Speed here
  if isWeaponType then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Attack Speed'
  end
  --Attack bonuses
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --Strength bonuses
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --Defence bonuses
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --Damage Reduction/Defence Req for armor, 2-handed/Attack Req for weapons
  if isWeaponType then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Two Handed?'
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'})
  else
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  end
  --Then Ranged/Magic requirements
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --And finally Sources
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Sources'

  --And with all the header out of the way, finally time to actually build the table itself.
  for i, itemBase in pairs(ItemData) do
    local item = Shared.clone(itemBase)
    item.id = i - 1
    local listItem = false
    if isWeaponType then
      listItem = item.type == type and item.category == category
      if ammoType ~= nil then listItem = listItem and item.ammoTypeRequired == ammoType end
      if listItem then
        result = result..'\r\n|-'
        result = result..'\r\n|style ="text-align: left;padding: 0 0 0 0;"|'..Icons.Icon({item.name, type='item', size=50, notext=true})
        result = result..'\r\n|style ="text-align: left;padding: 0 0.5em 0 0.5em;"|[['..item.name..']]'
        result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;" |'..Shared.formatnum(item.attackSpeed)
        for j, statName in pairs(statColumns) do
          local statValue = p._getItemStat(item, statName, true)
          result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
          if statValue > 0 then
            result = result..'background-color:lightgreen;'
          elseif statValue < 0 then
            result = result..'background-color:lightpink;'
          end
          result = result..'"|'..Shared.formatnum(statValue)
          if statName == 'magicDamageBonus' or statName == 'damageReduction' then result = result..'%' end
        end
        --That's the first list out of the way, now for 2-Handed
        result = result..'\r\n| style ="text-align: right;"|'
        if item.isTwoHanded then result = result..'Yes' else result = result..'No' end
        --Now the weapon exclusive columns
        for j, statName in pairs(weaponStatColumns) do
          local statValue = p._getItemStat(item, statName, true)
          result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
          result = result..'"|'..Shared.formatnum(statValue)
          if statName == 'magicDamageBonus' or statName == 'damageReduction' then result = result..'%' end
        end
        --Finally, the Sources
        result = result..'\r\n| style ="text-align: right;white-space: nowrap;padding: 0 0.5em 0 0.5em;" |'
        result = result..p._getItemSources(item)
      end
    else
      --Now for handling armor
      listItem = item.type == type and item.category == category
      if ammoType ~= nil then listItem = listItem and item.ammoType == ammoType end
      if slot ~= nil then listItem = listItem and item.equipmentSlot == slot end

      if listItem then
        result = result..'\r\n|-'
        result = result..'\r\n|style ="text-align: left;padding: 0 0 0 0;"|'..Icons.Icon({item.name, type='item', size=50, notext=true})
        result = result..'\r\n|style ="text-align: left;padding: 0 0.5em 0 0.5em;"|[['..item.name..']]'
        for j, statName in pairs(statColumns) do
          local statValue = p._getItemStat(item, statName, true)
          result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
          if statValue > 0 then
            result = result..'background-color:lightgreen;'
          elseif statValue < 0 then
            result = result..'background-color:lightpink;'
          end
          result = result..'"|'..Shared.formatnum(statValue)
          if statName == 'magicDamageBonus' or statName == 'damageReduction' then result = result..'%' end
        end
        --That's the first list out of the way, now for armor specific things
        for j, statName in pairs(armorStatColumns) do
          local statValue = p._getItemStat(item, statName, true)
          result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
          if j == 1 then
            if statValue > 0 then
              result = result..'background-color:lightgreen;'
            elseif statValue < 0 then
              result = result..'background-color:lightpink;'
            end
          end
          result = result..'"|'..Shared.formatnum(statValue)
          if statName == 'magicDamageBonus' or statName == 'damageReduction' then result = result..'%' end
        end
        --Finally, the Sources
        result = result..'\r\n| style ="text-align: right;white-space: nowrap;padding: 0 0.5em 0 0.5em;" |'
        result = result..p._getItemSources(item)
      end
    end
  end

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

return p