Module:Items/ComparisonTables: Difference between revisions

m
no edit summary
(_getEquipmentTable: Amend display of attack interval to have a resolution of seconds)
mNo edit summary
 
(46 intermediate revisions by 3 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local ItemData = mw.loadData('Module:Items/data')


local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local GameData = require('Module:GameData')
local Common = require('Module:Common')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Items = require('Module:Items')
Line 11: Line 11:


local styleOverrides = {
local styleOverrides = {
  Melee = {'Slayer Helmet (Basic)', 'Slayer Platebody (Basic)', 'Paladin Gloves', 'Desert Wrappings', 'Almighty Lute', 'Candy Cane', 'Bob's Rake'},
Melee = {'Slayer Helmet (Basic)', 'Slayer Platebody (Basic)', 'Paladin Gloves', 'Desert Wrappings', 'Almighty Lute', 'Candy Cane', "Bob's Rake", "Knight's Defender", "Ward of Flame Platebody"},
  Ranged = {'Slayer Cowl (Basic)', 'Slayer Leather Body (Basic)', 'Ice Arrows'},
Ranged = {'Slayer Cowl (Basic)', 'Slayer Leather Body (Basic)', 'Ice Arrows'},
  Magic = {'Slayer Wizard Hat (Basic)', 'Slayer Wizard Robes (Basic)', 'Enchanted Shield', 'Elementalist Gloves'},
Magic = {'Slayer Wizard Hat (Basic)', 'Slayer Wizard Robes (Basic)', 'Enchanted Shield', 'Elementalist Gloves', 'Frostspark Boots', 'Freezing Touch Body', 'Lightning Boots'},
  None = {},
None = {},
NotMelee = {'Frostspark Boots', 'Freezing Touch Body', 'Lightning Boots'},
NotRanged = {},
NotMagic = {'Torrential Blast Crossbow', 'Spectral Ice Sword', 'Lightning Strike 1H Sword', 'FrostSpark 1H Sword'}
}
}


function p._getEquipmentTable(itemList, includeModifiers, includeDescription)
function p._getEquipmentTable(itemList, includeModifiers, includeDescription, sortByName)
  if includeModifiers == nil then includeModifiers = false end
if includeModifiers == nil then includeModifiers = false end
 
if sortByName == nil then sortByName = false end
  --Getting some lists set up here that will be used later
  --First, the list of columns used by both weapons & armour
  local statColumns = {'stabAttackBonus', 'slashAttackBonus','blockAttackBonus','rangedAttackBonus', 'magicAttackBonus', 'meleeStrengthBonus', 'rangedStrengthBonus', 'magicDamageBonus', 'meleeDefenceBonus', 'rangedDefenceBonus', 'magicDefenceBonus', 'damageReduction', 'attackLevelRequired', 'defenceLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}
 
  if(Shared.tableCount(itemList) == 0) then
    return 'ERROR: you must select at least one item to get stats for[[Category:Pages with script errors]]'
  end
 
  local isWeaponType = itemList[1].validSlots ~= nil and Shared.contains(itemList[1].validSlots, 'Weapon') and Shared.contains(weaponTypes, itemList[1].type)
 
  --Now that we have a preliminary list, let's figure out which columns are irrelevant (IE are zero for all items in the selection)
  local ignoreColumns = Shared.clone(statColumns)
  for i, item in pairs(itemList) do
    local ndx = 1
    while Shared.tableCount(ignoreColumns) >= ndx do
      if Items._getItemStat(item, ignoreColumns[ndx], true) ~= 0 then
        table.remove(ignoreColumns, ndx)
      else
        ndx = ndx + 1
      end
    end
  end
 
  --Now to remove the ignored columns (and also we need to track groups like defence bonuses to see how many remain)
  local attBonusCols = 5
  local strBonusCols = 2
  local defBonusCols = 3
  local lvlReqCols = 4
  local ndx = 1
  while Shared.tableCount(statColumns) >= ndx do
    local colName = statColumns[ndx]
    if Shared.contains(ignoreColumns, colName) then
      if Shared.contains(colName, 'AttackBonus') then attBonusCols = attBonusCols - 1 end
      if Shared.contains(colName, 'trengthBonus') then strBonusCols = strBonusCols - 1 end
      if Shared.contains(colName, 'efenceBonus') then defBonusCols = defBonusCols - 1 end
      if Shared.contains(colName, 'LevelRequired') then lvlReqCols = lvlReqCols - 1 end
      table.remove(statColumns, ndx)
    else
      ndx = ndx + 1
    end
  end


  --Alright, let's start the table by building the shared header
--Getting some lists set up here that will be used later
  local resultPart = {}
--First, the list of columns used by both weapons & armour
  table.insert(resultPart, '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"')
local statColumns = {
  if isWeaponType then
'stabAttackBonus', 'slashAttackBonus', 'blockAttackBonus',  
    --Weapons have extra columns here for Attack Speed and "Two Handed?"
'rangedAttackBonus', 'magicAttackBonus', 'meleeStrengthBonus',
    table.insert(resultPart, '\r\n!colspan="4"|')
'rangedStrengthBonus', 'magicDamageBonus', 'meleeDefenceBonus',
  else
'rangedDefenceBonus', 'magicDefenceBonus', 'damageReduction',
    table.insert(resultPart, '\r\n!colspan="2"|')
'attackLevelRequired', 'strengthLevelRequired', 'defenceLevelRequired',
  end
'rangedLevelRequired', 'magicLevelRequired'
  if attBonusCols > 0 then
}
    table.insert(resultPart, '\r\n!colspan="'..attBonusCols..'"style="padding:0 0.5em 0 0.5em;"|Attack Bonus')
  end
  if strBonusCols > 0 then
    table.insert(resultPart, '\r\n!colspan="'..strBonusCols..'"style="padding:0 0.5em 0 0.5em;"|Str. Bonus')
  end
  if Shared.contains(statColumns, 'magicDamageBonus') then
    table.insert(resultPart, '\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|% Dmg Bonus')
  end
  if defBonusCols > 0 then
    table.insert(resultPart, '\r\n!colspan="'..defBonusCols..'"style="padding:0 0.5em 0 0.5em;"|Defence Bonus')
  end
  if Shared.contains(statColumns, 'damageReduction') then
    table.insert(resultPart, '\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|DR')
  end
  if lvlReqCols > 0 then
    table.insert(resultPart, '\r\n!colspan="'..lvlReqCols..'"style="padding:0 0.5em 0 0.5em;"|Lvl Req')
  end
  if includeModifiers and includeDescription then
    table.insert(resultPart, '\r\n!colspan="2"|')
  elseif includeModifiers or includeDescription then
    table.insert(resultPart, '\r\n!colspan="1"|')
  end
  --One header row down, one to go
  table.insert(resultPart, '\r\n|-class="headerRow-1"')
  table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|Item')
  table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|Name')
  --Weapons have Attack Speed here
  if isWeaponType then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|Attack Speed')
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|Two Handed?')
  end
  --Attack bonuses
  if Shared.contains(statColumns, 'slashAttackBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'stabAttackBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'blockAttackBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'rangedAttackBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'magicAttackBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'}))
  end
  --Strength bonuses
  if Shared.contains(statColumns, 'meleeStrengthBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'rangedStrengthBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'magicDamageBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'}))
  end
  --Defence bonuses
  if Shared.contains(statColumns, 'meleeDefenceBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'rangedDefenceBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'magicDefenceBonus') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'damageReduction') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'}))
  end
  --Level requirements
  if Shared.contains(statColumns, 'attackLevelRequired') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'defenceLevelRequired') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'rangedLevelRequired') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'}))
  end
  if Shared.contains(statColumns, 'magicLevelRequired') then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'}))
  end
  --If includeModifiers is set to 'true', add the Modifiers column
  if includeModifiers then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|Modifiers')
  end
  --If includeDescription is set to 'true', add the Description column
  if includeDescription then
    table.insert(resultPart, '\r\n!style="padding:0 1em 0 0.5em;"|Description')
  end


  table.sort(itemList, function(a, b) return a.id < b.id end)
if Shared.tableIsEmpty(itemList) then
  for i, item in pairs(itemList) do
return Shared.printError('You must select at least one item to get stats for')
    if isWeaponType then
end
      --Building rows for weapons
      table.insert(resultPart, '\r\n|-')
      table.insert(resultPart, '\r\n|style ="text-align: left;padding: 0 0 0 0;"|'..Icons.Icon({item.name, type='item', size=50, notext=true}))
      table.insert(resultPart, '\r\n|style ="text-align: left;padding: 0 0.5em 0 0.5em;"|'..Icons.Icon({item.name, type='item', noicon=true}))
      table.insert(resultPart, '\r\n| style ="text-align: right;padding: 0 0.5em 0 0;" |'..Shared.round(Items._getItemStat(item, 'attackSpeed', true) / 1000, 3, 1) .. 's')
      --That's the first list out of the way, now for 2-Handed
      table.insert(resultPart, '\r\n| style ="text-align: right;"|')
      table.insert(resultPart, Items._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No')
      for j, statName in pairs(statColumns) do
        local statValue = Items._getItemStat(item, statName, true)
        table.insert(resultPart, '\r\n| style ="text-align: right;padding: 0 0.5em 0 0;')
        if string.find(statName, '^(.+)LevelRequired$') == nil then
          if statValue > 0 then
            table.insert(resultPart, 'background-color:lightgreen;')
          elseif statValue < 0 then
            table.insert(resultPart, 'background-color:lightpink;')
          end
        end
        table.insert(resultPart, '"|'..Shared.formatnum(statValue))
        if statName == 'magicDamageBonus' or statName == 'damageReduction' then table.insert(resultPart, '%') end
      end
      --If requested, add the item Modifiers
      if includeModifiers then
        table.insert(resultPart, '\r\n|style="text-align:left;white-space:nowrap;padding:0 0.5em 0 0.5em;"|')
        table.insert(resultPart, Constants.getModifiersText(item.modifiers, true))
      end
      --If requested, add description
      if includeDescription then
        table.insert(resultPart, '\r\n|style="text-align:left;padding:0 0.5em 0 0.5em;"|')
        table.insert(resultPart, item.description ~= nil and item.description or '')
      end
    else
      --Building rows for armour
      table.insert(resultPart, '\r\n|-')
      table.insert(resultPart, '\r\n|style ="text-align: left;padding: 0 0 0 0;"|'..Icons.Icon({item.name, type='item', size=50, notext=true}))
      table.insert(resultPart, '\r\n|style ="text-align: left;padding: 0 0.5em 0 0.5em;"|'..Icons.Icon({item.name, type='item', noicon=true}))
      for j, statName in pairs(statColumns) do
        local statValue = Items._getItemStat(item, statName, true)
        table.insert(resultPart, '\r\n| style ="text-align: right;padding: 0 0.5em 0 0;')
        if statValue > 0 then
          table.insert(resultPart, 'background-color:lightgreen;')
        elseif statValue < 0 then
          table.insert(resultPart, 'background-color:lightpink;')
        end
        table.insert(resultPart, '"|'..Shared.formatnum(statValue))
        if statName == 'magicDamageBonus' or statName == 'damageReduction' then table.insert(resultPart, '%') end
      end
      --If requested, add the item Modifiers
      if includeModifiers then
        table.insert(resultPart, '\r\n|style="text-align:left;white-space:nowrap;padding:0 0.5em 0 0.5em;"|')
        table.insert(resultPart, Constants.getModifiersText(item.modifiers, true))
      end
      --If requested, add description
      if includeDescription then
        table.insert(resultPart, '\r\n|style="text-align:left;padding:0 0.5em 0 0.5em;"|')
        table.insert(resultPart, item.description ~= nil and item.description or '')
      end
    end
  end


  table.insert(resultPart, '\r\n|}')
local isWeaponType = ((itemList[1].validSlots ~= nil and Shared.contains(itemList[1].validSlots, 'Weapon'))
or (itemList[1].occupiesSlots ~= nil and Shared.contains(itemList[1].occupiesSlots, 'Weapon'))) and Shared.contains(weaponTypes, itemList[1].type)


  return table.concat(resultPart)
--Now that we have a preliminary list, let's figure out which columns are irrelevant (IE are zero for all items in the selection)
end
local ignoreColumns = Shared.clone(statColumns)
for i, item in pairs(itemList) do
local ndx = 1
while Shared.tableCount(ignoreColumns) >= ndx do
if Items._getItemStat(item, ignoreColumns[ndx], true) ~= 0 then
table.remove(ignoreColumns, ndx)
else
ndx = ndx + 1
end
end
end


function p.getEquipmentTable(frame)
--Now to remove the ignored columns (and also we need to track groups like defence bonuses to see how many remain)
  local args = frame.args ~= nil and frame.args or frame
local attBonusCols = 5
  local type = args.type
local strBonusCols = 2
  local tier = args.tier
local defBonusCols = 3
  local slot = args.slot
local lvlReqCols = 5
  local ammoTypeStr = args.ammoType
local ndx = 1
  local category = args.category ~= nil and args.category or 'Combat'
while Shared.tableCount(statColumns) >= ndx do
local colName = statColumns[ndx]
if Shared.contains(ignoreColumns, colName) then
if Shared.contains(colName, 'AttackBonus') then attBonusCols = attBonusCols - 1 end
if Shared.contains(colName, 'trengthBonus') then strBonusCols = strBonusCols - 1 end
if Shared.contains(colName, 'efenceBonus') then defBonusCols = defBonusCols - 1 end
if Shared.contains(colName, 'LevelRequired') then lvlReqCols = lvlReqCols - 1 end
table.remove(statColumns, ndx)
else
ndx = ndx + 1
end
end


  --Find out what Ammo Type we're working with
--Alright, let's start the table by building the shared header
  local ammoType = nil
local resultPart = {}
  if ammoTypeStr ~= nil then
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"')
    if ammoTypeStr == "Arrows" then
if isWeaponType then
      ammoType = 0
--Weapons have extra columns here for Attack Speed and "Two Handed?"
    elseif ammoTypeStr == 'Bolts' then
table.insert(resultPart, '\r\n!colspan="4"|')
      ammoType = 1
else
    elseif ammoTypeStr == 'Javelins' then
table.insert(resultPart, '\r\n!colspan="2"|')
      ammoType = 2
end
    elseif ammoTypeStr == 'Throwing Knives' then
if attBonusCols > 0 then
      ammoType = 3
table.insert(resultPart, '\r\n!colspan="'..attBonusCols..'"|Attack Bonus')
    end
end
  end
if strBonusCols > 0 then
table.insert(resultPart, '\r\n!colspan="'..strBonusCols..'"|Str. Bonus')
end
if Shared.contains(statColumns, 'magicDamageBonus') then
table.insert(resultPart, '\r\n!colspan="1"|% Dmg Bonus')
end
if defBonusCols > 0 then
table.insert(resultPart, '\r\n!colspan="'..defBonusCols..'"|Defence Bonus')
end
if Shared.contains(statColumns, 'damageReduction') then
table.insert(resultPart, '\r\n!colspan="1"|DR')
end
if lvlReqCols > 0 then
table.insert(resultPart, '\r\n!colspan="'..lvlReqCols..'"|Lvl Req')
end
if includeModifiers and includeDescription then
table.insert(resultPart, '\r\n!colspan="2"|')
elseif includeModifiers or includeDescription then
table.insert(resultPart, '\r\n!colspan="1"|')
end
--One header row down, one to go
table.insert(resultPart, '\r\n|-class="headerRow-1"')
table.insert(resultPart, '\r\n!Item')
table.insert(resultPart, '\r\n!Name')
--Weapons have Attack Speed here
if isWeaponType then
table.insert(resultPart, '\r\n!Attack Speed')
table.insert(resultPart, '\r\n!Two Handed?')
end
--Attack bonuses
if Shared.contains(statColumns, 'slashAttackBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Attack', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'stabAttackBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Strength', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'blockAttackBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'rangedAttackBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'magicAttackBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', notext='true'}))
end
--Strength bonuses
if Shared.contains(statColumns, 'meleeStrengthBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Strength', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'rangedStrengthBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'magicDamageBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', notext='true'}))
end
--Defence bonuses
if Shared.contains(statColumns, 'meleeDefenceBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'rangedDefenceBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'magicDefenceBonus') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'damageReduction') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', notext='true'}))
end
--Level requirements
if Shared.contains(statColumns, 'attackLevelRequired') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Attack', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'strengthLevelRequired') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Strength', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'defenceLevelRequired') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'rangedLevelRequired') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', notext='true'}))
end
if Shared.contains(statColumns, 'magicLevelRequired') then
table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', notext='true'}))
end
--If includeModifiers is set to 'true', add the Modifiers column
if includeModifiers then
table.insert(resultPart, '\r\n!Modifiers')
end
--If includeDescription is set to 'true', add the Description column
if includeDescription then
table.insert(resultPart, '\r\n!Description')
end


  local isWeaponType = Shared.contains(weaponTypes, type)
if sortByName then
table.sort(itemList, function(a, b) return a.name < b.name end)
end
for i, item in ipairs(itemList) do
if isWeaponType then
--Building rows for weapons
local atkSpeed = Items._getItemStat(item, 'attackSpeed', true)
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|style="text-align: centre;"|'..Icons.Icon({item.name, type='item', size=50, notext=true}))
table.insert(resultPart, '\r\n|' .. Icons.getExpansionIcon(item.id) .. Icons.Icon({item.name, type='item', noicon=true}))
table.insert(resultPart, '\r\n| data-sort-value="' .. atkSpeed .. '" style="text-align:right;" |'..Shared.round(atkSpeed / 1000, 3, 1) .. 's')
--That's the first list out of the way, now for 2-Handed
table.insert(resultPart, '\r\n| style="text-align: right;"|')
table.insert(resultPart, Items._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No')
for j, statName in pairs(statColumns) do
local statValue = Items._getItemStat(item, statName, true)
table.insert(resultPart, '\r\n| style="text-align:right;" class="')
if string.find(statName, '^(.+)LevelRequired$') == nil then
if statValue > 0 then
table.insert(resultPart, 'table-positive')
elseif statValue < 0 then
table.insert(resultPart, 'table-negative')
end
end
table.insert(resultPart, '"|'..Shared.formatnum(statValue))
if statName == 'magicDamageBonus' or statName == 'damageReduction' then table.insert(resultPart, '%') end
end
--If requested, add the item Modifiers
if includeModifiers then
table.insert(resultPart, '\r\n|')
local txtLines = {}
local modTxt = Constants.getModifiersText(item.modifiers, true)
if modTxt ~= '' then
table.insert(txtLines, modTxt)
end
--For items with a special attack, show the details
if item.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) then
table.insert(txtLines, "'''Special Attack:'''")
for i, spAttID in ipairs(item.specialAttacks) do
local spAtt = GameData.getEntityByID('attacks', spAttID)
local attChance = spAtt.defaultChance
if item.overrideSpecialChances ~= nil then
attChance = item.overrideSpecialChances[i]
end
table.insert(txtLines, attChance .. '% chance for ' .. spAtt.name .. ':')
table.insert(txtLines, spAtt.description)
end
end
table.insert(resultPart, table.concat(txtLines, '<br/>'))
end
--If requested, add description
if includeDescription then
table.insert(resultPart, '\r\n| ')
table.insert(resultPart, Constants.getDescription(item.customDescription, item.modifiers) or '')
end
else
--Building rows for armour
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|'..Icons.Icon({item.name, type='item', size=50, notext=true}))
table.insert(resultPart, '\r\n|' .. Icons.getExpansionIcon(item.id) .. Icons.Icon({item.name, type='item', noicon=true}))
for j, statName in pairs(statColumns) do
local statValue = Items._getItemStat(item, statName, true)
table.insert(resultPart, '\r\n|style="text-align:right;" class="')
if statValue > 0 then
table.insert(resultPart, 'table-positive')
elseif statValue < 0 then
table.insert(resultPart, 'table-negative')
end
table.insert(resultPart, '"|'..Shared.formatnum(statValue))
if statName == 'magicDamageBonus' or statName == 'damageReduction' then table.insert(resultPart, '%') end
end
--If requested, add the item Modifiers
if includeModifiers then
table.insert(resultPart, '\r\n| ')
local txtLines = {}
local modTxt = Constants.getModifiersText(item.modifiers, true)
if modTxt ~= '' then
table.insert(txtLines, modTxt)
end
--For items with a special attack, show the details
if item.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) then
table.insert(txtLines, "'''Special Attack:'''")
for i, spAttID in ipairs(item.specialAttacks) do
local spAtt = GameData.getEntityByID('attacks', spAttID)
local attChance = spAtt.defaultChance
if item.overrideSpecialChances ~= nil then
attChance = item.overrideSpecialChances[i]
end
table.insert(txtLines, attChance .. '% chance for ' .. spAtt.name .. ':')
table.insert(txtLines, spAtt.description)
end
end
table.insert(resultPart, table.concat(txtLines, '<br/>'))
end
--If requested, add description
if includeDescription then
table.insert(resultPart, '\r\n| ')
table.insert(resultPart, Constants.getDescription(item.customDescription, item.modifiers) or '')
end
end
end


  --Now we need to figure out which items are in this list
table.insert(resultPart, '\r\n|}')
  local itemList = {}
  for i, itemBase in pairs(ItemData.Items) 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
    else
      --Now for handling armour
      if type == "Armour" or type == "Melee" then
        listItem = Items._getItemStat(item, 'defenceLevelRequired') ~= nil or (item.category == 'Combat' and item.type == 'Armour')
      elseif type == "Ranged Armour" or type == "Ranged" then
        listItem = Items._getItemStat(item, 'rangedLevelRequired') ~= nil or (item.category == 'Combat' and item.type == 'Ranged Armour')
      elseif type == "Magic Armour" or type == "Magic" then
        listItem = Items._getItemStat(item, 'magicLevelRequired') or (item.category == 'Combat' and item.type == 'Magic Armour')
      else
        listItem = item.type == type and item.category ~= 'Combat'
      end
      if ammoType ~= nil then listItem = listItem and item.ammoType == ammoType end
      if slot ~= nil then listItem = listItem and Shared.contains(item.validSlots, slot) end
    end
    if listItem then
      table.insert(itemList, item)
    end
  end


  local result = p._getEquipmentTable(itemList).."[[Category:getEquipmentTable]]"
return table.concat(resultPart)
 
  return result
end
end


function p._getCategoryTable(style, slot, other, includeModifiers, includeDescription)
function p._getCategoryTable(style, slot, other, includeModifiers, includeDescription, sortByName)
  if type(slot) == 'number' then
-- If slot is a slot name, convert it to the slot ID instead
    slot = Constants.getEquipmentSlotName(slot)
slot = Constants.getEquipmentSlotID(slot) or (Constants.getEquipmentSlotName(slot) ~= nil and slot)
  end


  local itemList = Items.getItems(function(item)
local itemList = Items.getItems(function(item)
      local isMatch = true
-- Exclude Golbin raid exclusives for now, such that they don't
      if style == 'Melee' then
-- pollute various equipment tables
        if (Items._getItemStat(item, 'defenceLevelRequired') == nil and Items._getItemStat(item, 'attackLevelRequired') == nil) and not Shared.contains(styleOverrides.Melee, item.name) then isMatch = false end
if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then
      elseif style == 'Ranged' then
return false
        if Items._getItemStat(item, 'rangedLevelRequired') == nil and not Shared.contains(styleOverrides.Ranged, item.name) then isMatch = false end
end
      elseif style == 'Magic' then
local isMatch = true
        if Items._getItemStat(item, 'magicLevelRequired') == nil and not Shared.contains(styleOverrides.Magic, item.name) then isMatch = false end
if style == 'Melee' then
      elseif style == 'None' then
if ((Items._getItemStat(item, 'defenceLevelRequired') == nil and Items._getItemStat(item, 'attackLevelRequired') == nil) and not Shared.contains(styleOverrides.Melee, item.name)) or Shared.contains(styleOverrides.NotMelee, item.name) then isMatch = false end
        if (Items._getItemStat(item, 'defenceLevelRequired') ~= nil or Items._getItemStat(item, 'rangedLevelRequired') ~= nil or Items._getItemStat(item, 'magicLevelRequired') ~= nil or
elseif style == 'Ranged' then
          Shared.contains(styleOverrides.Melee, item.name) or Shared.contains(styleOverrides.Ranged, item.name) or Shared.contains(styleOverrides.Magic, item.name)) and
if (Items._getItemStat(item, 'rangedLevelRequired') == nil and not Shared.contains(styleOverrides.Ranged, item.name)) or Shared.contains(styleOverrides.NotRanged, item.name)  then isMatch = false end
          not Shared.contains(styleOverrides.None, item.name) then
elseif style == 'Magic' then
          isMatch = false
if (Items._getItemStat(item, 'magicLevelRequired') == nil and not Shared.contains(styleOverrides.Magic, item.name)) or Shared.contains(styleOverrides.NotMagic, item.name) then isMatch = false end
        end
elseif style == 'None' then
      end
if (Items._getItemStat(item, 'defenceLevelRequired') ~= nil or Items._getItemStat(item, 'rangedLevelRequired') ~= nil or Items._getItemStat(item, 'magicLevelRequired') ~= nil or
      if slot == nil or not Shared.contains(item.validSlots, slot) then isMatch = false end
Shared.contains(styleOverrides.Melee, item.name) or Shared.contains(styleOverrides.Ranged, item.name) or Shared.contains(styleOverrides.Magic, item.name)) and
not Shared.contains(styleOverrides.None, item.name) then
isMatch = false
end
end
if slot == nil or not Shared.contains(item.validSlots, slot) then isMatch = false end


      if isMatch and other ~= nil then
if isMatch and other ~= nil then
        if slot == 'Weapon' then --For quiver slot or weapon slot, 'other' is the ammo type
if slot == 'Cape' then
          if other == 'Arrows' then
-- TODO Would be more reliable if based on items appearing within the relevant shop categories instead
            if item.ammoTypeRequired ~= 0 then isMatch = false end
local isSkillcape = Shared.contains(item.name, 'Skillcape') or Shared.contains(item.name, 'Cape of Completion')
          elseif other == 'Bolts' then
if other == 'Skillcapes' then
            if item.ammoTypeRequired ~= 1 then isMatch = false end
isMatch = isSkillcape
          end
elseif other == 'No Skillcapes' then
        elseif slot == 'Quiver' then
isMatch = not isSkillcape
          if other == 'Arrows' then
end
            if item.ammoType ~= 0 then isMatch = false end
end
          elseif other == 'Bolts' then
if slot == 'Weapon' then --For quiver slot or weapon slot, 'other' is the ammo type
            if item.ammoType ~= 1 then isMatch = false end
isMatch = other == item.ammoTypeRequired
          elseif other == 'Javelins' then
elseif slot == 'Quiver' then
            if item.ammoType ~= 2 then isMatch = false end
if other == 'Thrown' and Shared.contains({'Javelins', 'ThrowingKnives'}, item.ammoType) then
          elseif other == 'Throwing Knives' then
isMatch = true
            if item.ammoType ~= 3 then isMatch = false end
else
          elseif other == 'Thrown' then
isMatch = other == item.ammoType
            if item.ammoType ~= 2 and item.ammoType ~= 3 then isMatch = false end
end
          end
end
        end
end
      end


      return isMatch
return isMatch
    end)
end)
 
  local result = p._getEquipmentTable(itemList, includeModifiers, includeDescription)
return p._getEquipmentTable(itemList, includeModifiers, includeDescription, sortByName)
 
  return result
end
end


function p.getCategoryTable(frame)
function p.getCategoryTable(frame)
  local style = frame.args ~= nil and frame.args[1] or frame[1]
local style = frame.args ~= nil and frame.args[1] or frame[1]
  local slot = frame.args ~= nil and frame.args[2] or frame[2]
local slot = frame.args ~= nil and frame.args[2] or frame[2]
  local other = frame.args ~= nil and frame.args[3] or frame[3]
local other = frame.args ~= nil and frame.args[3] or frame[3]
  local includeModifiers = frame.args ~= nil and frame.args.includeModifiers or frame.includeModifiers
local includeModifiers = frame.args ~= nil and frame.args.includeModifiers or frame.includeModifiers
  local includeDescription = frame.args ~= nil and frame.args.includeDescription or frame.includeDescription
local includeDescription = frame.args ~= nil and frame.args.includeDescription or frame.includeDescription
local sortByName = frame.args ~= nil and frame.args.sortByName or frame.sortByName


  includeModifiers = includeModifiers ~= nil and string.upper(includeModifiers) == 'TRUE' or false
includeModifiers = includeModifiers ~= nil and string.upper(includeModifiers) == 'TRUE' or false
  includeDescription = includeDescription ~= nil and string.upper(includeDescription) == 'TRUE' or false
includeDescription = includeDescription ~= nil and string.upper(includeDescription) == 'TRUE' or false
sortByName = sortByName ~= nil and string.upper(sortByName) == 'TRUE' or false


  return p._getCategoryTable(style, slot, other, includeModifiers, includeDescription)
return p._getCategoryTable(style, slot, other, includeModifiers, includeDescription, sortByName)
end
end


function p.getTableForList(frame)
function p.getTableForList(frame)
  local stuffString = frame.args ~= nil and frame.args[1] or frame[1]
local stuffString = frame.args ~= nil and frame.args[1] or frame[1]
  local itemNames = Shared.splitString(stuffString, ',')
local itemNames = Shared.splitString(stuffString, ',')


  local includeModifiers = frame.args ~= nil and frame.args[2] or frame[2]
local includeModifiers = frame.args ~= nil and frame.args[2] or frame[2]
  includeModifiers = includeModifiers ~= nil and string.upper(includeModifiers) == 'TRUE' or false
includeModifiers = includeModifiers ~= nil and string.upper(includeModifiers) == 'TRUE' or false


  local itemList = {}
local itemList = {}
  local errMsg = 'ERROR: Some items not found in database: [[Category:Pages with script errors]]'
local errMsg = 'Some items not found in database: '
  local hasErr = false
local hasErr = false
  for i, name in Shared.skpairs(itemNames) do
for i, name in Shared.skpairs(itemNames) do
    local nextItem = Items.getItem(Shared.trim(name))
local nextItem = Items.getItem(Shared.trim(name))
    if nextItem == nil then
if nextItem == nil then
      errMsg = errMsg.." '"..name.."'"
errMsg = errMsg.." '"..name.."'"
      hasErr = true
hasErr = true
    else
else
      table.insert(itemList, nextItem)
table.insert(itemList, nextItem)
    end
end
  end
end


  if hasErr then
if hasErr then
    return errMsg
return Shared.printError(errMsg)
  else
else
    return p._getEquipmentTable(itemList, includeModifiers)
return p._getEquipmentTable(itemList, includeModifiers)
  end
end
end
end


function p.getDoubleLootTable(frame)
function p.getDoubleLootTable(frame)
  local modsDL = {
local modsDL = {
    'increasedChanceToDoubleLootCombat',
'increasedChanceToDoubleLootCombat',
    'decreasedChanceToDoubleLootCombat',
'decreasedChanceToDoubleLootCombat',
    'increasedChanceToDoubleLootThieving',
'increasedChanceToDoubleLootThieving',
    'decreasedChanceToDoubleLootThieving',
'decreasedChanceToDoubleLootThieving',
    'increasedChanceToDoubleItemsGlobal',
'increasedChanceToDoubleItemsGlobal',
    'decreasedChanceToDoubleItemsGlobal'
'decreasedChanceToDoubleItemsGlobal'
  }
}
  local modDetail = {}
local modDetail = {}
  for i, modName in pairs(modsDL) do
for i, modName in pairs(modsDL) do
    local mName, mText, mSign, mIsNeg, mValUnsigned = Constants.getModifierDetails(modName)
local mName, mText, mIsNeg, mModifyValue = Constants.getModifierDetails(modName)
    modDetail[modName] = { mult = (mSign == "+" and 1 or -1) }
modDetail[modName] = { mult = (mIsNeg == false and 1 or -1) }
  end
end


  local itemList = Items.getItems(function(item)
local itemList = Items.getItems(function(item)
      if item.modifiers ~= nil then
if item.modifiers ~= nil then
        for modName, val in pairs(item.modifiers) do
for modName, val in pairs(item.modifiers) do
          if Shared.contains(modsDL, modName) then return true end
if Shared.contains(modsDL, modName) then return true end
        end
end
        return false
return false
      end
end
    end)
end)
  table.sort(itemList, function(a, b) return a.id < b.id end)


  local resultPart = {}
local resultPart = {}
  table.insert(resultPart, '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"')
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"')
  table.insert(resultPart, '\r\n!colspan="2"|Name!!Bonus!!Description')
table.insert(resultPart, '\r\n!colspan="2"|Name!!Bonus!!Description')
  for i, item in Shared.skpairs(itemList) do
for i, item in Shared.skpairs(itemList) do
    local lootValue = 0
local lootValue = 0
    for modName, modDet in pairs(modDetail) do
for modName, modDet in pairs(modDetail) do
      lootValue = lootValue + (item.modifiers[modName] or 0) * modDet.mult
lootValue = lootValue + (item.modifiers[modName] or 0) * modDet.mult
    end
end
    table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|-')
    table.insert(resultPart, '\r\n|data-sort-value="'..item.name..'"|'..Icons.Icon({item.name, type='item', size=50, notext=true}))
table.insert(resultPart, '\r\n|data-sort-value="'..item.name..'"|'..Icons.Icon({item.name, type='item', size=50, notext=true}))
    table.insert(resultPart, '||'..Icons.Icon({item.name, type='item', noicon=true}))
table.insert(resultPart, '||' .. Icons.getExpansionIcon(item.id) .. Icons.Icon({item.name, type='item', noicon=true}))
    table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..lootValue..'"|'..lootValue..'%')
table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..lootValue..'"|'..lootValue..'%')
    table.insert(resultPart, '||'..item.description)
table.insert(resultPart, '||'..(Constants.getDescription(item.customDescription, item.modifiers) or ''))
  end
end


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


function p.getStatChangeString(item1, item2)
function p.getItemUpgradeTable(frame)
  --Used by getItemUpgradeTable to get the stat change between two items
local category = frame.args ~= nil and frame.args[1] or frame
  local changeArray = {}
local upgradeArray = {}
local isEquipment = false


  local getSpecificStatString = function(val1, val2, subStr)
if string.upper(category) == 'POTION' then
      if val1 == nil then val1 = 0 end
upgradeArray = GameData.getEntities('itemUpgrades',
      if val2 == nil then val2 = 0 end
function(upgrade) return Shared.contains(upgrade.upgradedItemID, 'Potion') end
)
elseif string.upper(category) == 'OTHER' then
upgradeArray = GameData.getEntities('itemUpgrades',
function(upgrade)
if not Shared.contains(upgrade.upgradedItemID, 'Potion') then
local item = Items.getItemByID(upgrade.upgradedItemID)
if item ~= nil then
return item.validSlots == nil or Shared.tableIsEmpty(item.validSlots)
end
end
return false
end
)
else
-- If category is a slot name, convert it to the slot ID instead
category = Constants.getEquipmentSlotID(category) or (Constants.getEquipmentSlotName(category) ~= nil and category)
if category == nil then
return Shared.printError('Invalid option. Choose either an equipment slot, Potion, or Other')
end
isEquipment = true
upgradeArray = GameData.getEntities('itemUpgrades',
function(upgrade)
local item = Items.getItemByID(upgrade.upgradedItemID)
if item ~= nil then
return item.validSlots ~= nil and Shared.contains(item.validSlots, category)
end
return false
end
)
end


      if val1 ~= val2 then
local useStatChange = isEquipment or (string.upper(category) == 'POTION')
        local txt = string.gsub(subStr, '{V}', Shared.numStrWithSign(val1 - val2))
local resultPart = {}
        table.insert(changeArray, txt)
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
      end
table.insert(resultPart, '\r\n|- class="headerRow-0"')
    end
table.insert(resultPart, '\r\n!colspan="2"|Upgraded Item!!Ingredients')
if useStatChange then table.insert(resultPart, '!!Stat Change') end


  --Unfortunately just gonna have to manually check all the changes I think...
for i, upgrade in ipairs(upgradeArray) do
  local statList = {
local item = Items.getItemByID(upgrade.upgradedItemID)
    -- {'statName', 'statDescription'}
table.insert(resultPart, '\r\n|-')
    {'stabAttackBonus', '{V} '..Icons.Icon({'Melee', notext=true})..' Stab Bonus'},
table.insert(resultPart, '\r\n|'..Icons.Icon({item.name, type='item', size='50', notext=true}))
    {'slashAttackBonus', '{V} '..Icons.Icon({'Melee', notext=true})..' Slash Bonus'},
table.insert(resultPart, '||' .. Icons.getExpansionIcon(item.id) .. Icons.Icon({item.name, type='item', noicon=true}))
    {'blockAttackBonus', '{V} '..Icons.Icon({'Melee', notext=true})..' Block Bonus'},
    {'meleeStrengthBonus', '{V} '..Icons.Icon({'Strength', type='skill', notext=true})..' Strength Bonus'},
    {'rangedStrengthBonus', '{V} '..Icons.Icon({'Ranged', type='skill', notext=true})..' Strength Bonus'},
    {'magicStrengthBonus', '{V}% '..Icons.Icon({'Magic', type='skill', notext=true})..' Damage Bonus'},
    {'meleeDefenceBonus', '{V} '..Icons.Icon({'Defence', type='skill', notext=true})..' Defence Bonus'},
    {'rangedDefenceBonus', '{V} '..Icons.Icon({'Ranged', type='skill', notext=true})..' Defence Bonus'},
    {'magicDefenceBonus', '{V} '..Icons.Icon({'Magic', type='skill', notext=true})..' Defence Bonus'},
    {'damageReduction', '{V}% Damage Reduction'},
    {'increasedSlayerXP', '{V}% '..Icons.Icon({'Slayer', type='skill', notext=true})..' Bonus XP'},
    {'attackLevelRequired', '{V} '..Icons.Icon({'Attack', type='skill', notext=true})..' Level Required'},
    {'defenceLevelRequired', '{V} '..Icons.Icon({'Defence', type='skill', notext=true})..' Level Required'},
    {'rangedLevelRequired', '{V} '..Icons.Icon({'Ranged', type='skill', notext=true})..' Level Required'},
    {'magicLevelRequired', '{V} '..Icons.Icon({'Magic', type='skill', notext=true})..' Level Required'},
  }
  for i, stat in ipairs(statList) do
    if stat[1] == 'increasedSlayerXP' then
      getSpecificStatString(Items._getItemModifier(item1, stat[1], 'Slayer'), Items._getItemModifier(item2, stat[1], 'Slayer'), stat[2])
    else
      getSpecificStatString(Items._getItemStat(item1, stat[1]), Items._getItemStat(item2, stat[1]), stat[2])
    end
  end


  return table.concat(changeArray, '<br/>')
table.insert(resultPart, '|| ' .. Common.getCostString({ items = upgrade.itemCosts, gp = upgrade.gpCost, sc = upgrade.scCost}, 'None'))
end


function p.getItemUpgradeTable(frame)
if useStatChange then
  local category = frame.args ~= nil and frame.args[1] or frame
-- Generate stat change column
  local itemArray = {}
local statChangeString = ''
  local isEquipment = false
if not Shared.tableIsEmpty(upgrade.rootItemIDs) then
-- Some items (e.g. FEZ) may have multiple root items. Simply use the first one
local rootItem = Items.getItemByID(upgrade.rootItemIDs[1])
if rootItem ~= nil then
statChangeString = Items.getStatChangeString(item, rootItem)
end
end
table.insert(resultPart, '|| '..statChangeString)
end
end


  if string.upper(category) == 'POTION' then
table.insert(resultPart, '\r\n|}')
    itemArray = Items.getItems(function(item) return Shared.contains(item.name, 'Potion') and item.itemsRequired ~= nil end)
return table.concat(resultPart)
  elseif string.upper(category) == 'OTHER' then
end
    itemArray = Items.getItems(function(item)
          return not Shared.contains(item.name, 'Potion') and item.itemsRequired ~= nil and item.validSlots == nil
        end)
  else
    if Constants.getEquipmentSlotID(category) == nil then
      return 'ERROR: Invalid option. Choose either an equipment slot, Potion, or Other[[Category:Pages with script errors]]'
    end
    isEquipment = true
    itemArray = Items.getItems(function(item)
          return item.itemsRequired ~= nil and Shared.contains(item.validSlots, category)
        end)
  end
  table.sort(itemArray, function(a, b) return a.id < b.id end)


  local resultPart = {}
function p.getRuneProvidingItemTable(frame)
  table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
local itemArray = Items.getItems(function(item) return item.providedRunes ~= nil end)
  table.insert(resultPart, '\r\n|- class="headerRow-0"')
  table.insert(resultPart, '\r\n!colspan="2"|Upgraded Item!!Ingredients')
local resultPart = {}
  if isEquipment then table.insert(resultPart, '!!Stat Change') end
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\r\n|- class="headerRow-0"')
table.insert(resultPart, '\r\n!colspan="2"|Item!!Runes Provided')
for i, item in pairs(itemArray) do
local PR = item.providedRunes
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|style="text-align: centre;"|'..Icons.Icon({item.name, type='item', size=50, notext=true}))
table.insert(resultPart, '\r\n|' .. Icons.getExpansionIcon(item.id) .. Icons.Icon({item.name, type='item', noicon=true}))
local runeLines = {}
local sortVal = ''
for j, runePair in pairs(PR) do
local runeID = runePair.id
local qty = runePair.quantity
local rune = Items.getItemByID(runeID)
sortVal = sortVal..rune.name..qty
table.insert(runeLines, Icons.Icon({rune.name, type='item', qty=qty}))
end
table.insert(resultPart, '\r\n|data-sort-value="'..sortVal..'"|'..table.concat(runeLines, '<br/>'))
end
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end


  for i, item in Shared.skpairs(itemArray) do
function p._getDRTable(slots, items)
    table.insert(resultPart, '\r\n|-')
local resultPart = {}
    table.insert(resultPart, '\r\n|'..Icons.Icon({item.name, type='item', size='50', notext=true}))
    table.insert(resultPart, '||'..Icons.Icon({item.name, type='item', noicon=true}))
table.insert(resultPart, '{| class="wikitable sortable" style="width:90%;"')
 
table.insert(resultPart, '\r\n|-')
    local matArray = {}
table.insert(resultPart, '\r\n! style="width:4%"|DR%')
    local statChangeString = ''
for i, slot in pairs(slots) do
    for i, row in Shared.skpairs(item.itemsRequired) do
table.insert(resultPart, '\r\n! '..slot)
      local mat = Items.getItemByID(row[1])
end
      table.insert(matArray, Icons.Icon({mat.name, type='item', qty=row[2]}))
 
local DRTable = {}
      if item.validSlots ~= nil and mat.validSlots ~= nil and statChangeString == '' then
table.sort(items, function(a, b) return a.name < b.name end)
        statChangeString = p.getStatChangeString(item, mat)
      end
for i, item in pairs(items) do
    end
local DR = Items._getItemStat(item, 'damageReduction', true)
    if item.trimmedGPCost ~= nil and item.trimmedGPCost > 0 then
local EquipSlot = Items._getItemEquipSlot(item)
      table.insert(matArray, Icons.GP(item.trimmedGPCost))
if DRTable[DR] == nil then
    end
DRTable[DR] = {}
    table.insert(resultPart, '||'..table.concat(matArray, '<br/>'))
end
 
if DRTable[DR][EquipSlot] == nil then
    if isEquipment then
DRTable[DR][EquipSlot] = {}
      table.insert(resultPart, '||'..statChangeString)
end
    end
table.insert(DRTable[DR][EquipSlot], Icons.Icon({item.name, type='item', expicon = Icons.getExpansionIcon(item.id)}))
  end
end
for DR, SlotTables in Shared.skpairs(DRTable) do
table.insert(resultPart, '\r\n|-\r\n|'..DR..'%')
for i, SlotName in pairs(slots) do
table.insert(resultPart, '\r\n|')
if SlotTables[SlotName] ~= nil then
table.insert(resultPart, table.concat(SlotTables[SlotName], '<br/>'))
end
end
end
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end


  table.insert(resultPart, '\r\n|}')
function p.getDRTable(frame)
  return table.concat(resultPart)
local style = frame.args ~= nil and frame.args[1] or frame
local SlotNames = {}
local ItemList = {}
if style == 'Other' then
SlotNames = {'Helmet', 'Platelegs', 'Gloves', 'Shield', 'Cape', 'Amulet', 'Ring'}
else
SlotNames = {'Helmet', 'Platebody', 'Platelegs', 'Boots', 'Gloves', 'Weapon', 'Shield'}
end
ItemList =  Items.getItems(function(item)
local isMatch = true
if Items._getItemStat(item, 'damageReduction', true) <= 0 then
return false
end
-- Exclude Golbin raid exclusives for now, such that they don't
-- pollute various equipment tables
if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then
return false
end
--Using the same checks for Melee/Ranged/Magic that the Equipment Tables use
if style == 'Melee' then
if ((Items._getItemStat(item, 'defenceLevelRequired') == nil and Items._getItemStat(item, 'attackLevelRequired') == nil) and not Shared.contains(styleOverrides.Melee, item.name)) or Shared.contains(styleOverrides.NotMelee, item.name) then isMatch = false end
elseif style == 'Ranged' then
if (Items._getItemStat(item, 'rangedLevelRequired') == nil and not Shared.contains(styleOverrides.Ranged, item.name)) or Shared.contains(styleOverrides.NotRanged, item.name)  then isMatch = false end
elseif style == 'Magic' then
if (Items._getItemStat(item, 'magicLevelRequired') == nil and not Shared.contains(styleOverrides.Magic, item.name)) or Shared.contains(styleOverrides.NotMagic, item.name) then isMatch = false end
else
if (Items._getItemStat(item, 'attackLevelRequired') ~= nil or Items._getItemStat(item, 'defenceLevelRequired') ~= nil or Items._getItemStat(item, 'rangedLevelRequired') ~= nil or Items._getItemStat(item, 'magicLevelRequired') ~= nil or
Shared.contains(styleOverrides.Melee, item.name) or Shared.contains(styleOverrides.Ranged, item.name) or Shared.contains(styleOverrides.Magic, item.name)) and
not Shared.contains(styleOverrides.None, item.name) then
isMatch = false
end
end
if isMatch and not Shared.contains(SlotNames, Items._getItemEquipSlot(item)) then
isMatch = false
end
return isMatch
end)
return p._getDRTable(SlotNames, ItemList)
end
end


return p
return p