Anonymous

Module:Items/ComparisonTables: Difference between revisions

From Melvor Idle
added code to show special attacks in the Modifiers table for equipment because it seemed like the thing to do
(Added level requirements to getItemUpgradeTable's comparisons)
(added code to show special attacks in the Modifiers table for equipment because it seemed like the thing to do)
(31 intermediate revisions by 3 users not shown)
Line 1: Line 1:
local p = {}
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 = require('Module:Constants')
local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local Magic = require('Module:Magic')
local Areas = require('Module:CombatAreas')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Items = require('Module:Items')
local ItemSourceTables = require('Module:Items/SourceTables')
local ItemUseTables = require('Module:Items/UseTables')


local weaponTypes = {'Magic Staff', 'Magic Wand', 'Ranged Weapon', 'Weapon'}
local weaponTypes = {'Magic Staff', 'Magic Wand', 'Ranged Weapon', 'Weapon'}


function p._getEquipmentTable(itemList)
local styleOverrides = {
  --Getting some lists set up here that will be used later
Melee = {'Slayer Helmet (Basic)', 'Slayer Platebody (Basic)', 'Paladin Gloves', 'Desert Wrappings', 'Almighty Lute', 'Candy Cane', 'Bob's Rake'},
  --First, the list of columns used by both weapons & armour
Ranged = {'Slayer Cowl (Basic)', 'Slayer Leather Body (Basic)', 'Ice Arrows'},
  local statColumns = {'stabAttackBonus', 'slashAttackBonus','blockAttackBonus','rangedAttackBonus', 'magicAttackBonus', 'strengthBonus', 'rangedStrengthBonus', 'magicDamageBonus', 'defenceBonus', 'rangedDefenceBonus', 'magicDefenceBonus', 'damageReduction', 'attackLevelRequired', 'defenceLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}
Magic = {'Slayer Wizard Hat (Basic)', 'Slayer Wizard Robes (Basic)', 'Enchanted Shield', 'Elementalist Gloves'},
 
None = {},
  if(Shared.tableCount(itemList) == 0) then
}
    return 'ERROR: you must select at least one item to get stats for'
  end


  local isWeaponType = Shared.contains(weaponTypes, itemList[1].type)
function p._getEquipmentTable(itemList, includeModifiers, includeDescription, sortByName)
if includeModifiers == nil then includeModifiers = false end
if sortByName == nil then sortByName = false end


  --Now that we have a preliminary list, let's figure out which columns are irrelevant (IE are zero for all items in the selection)
--Getting some lists set up here that will be used later
  local ignoreColumns = Shared.clone(statColumns)
--First, the list of columns used by both weapons & armour
  for i, item in pairs(itemList) do
local statColumns = {'stabAttackBonus', 'slashAttackBonus','blockAttackBonus','rangedAttackBonus', 'magicAttackBonus', 'meleeStrengthBonus', 'rangedStrengthBonus', 'magicDamageBonus', 'meleeDefenceBonus', 'rangedDefenceBonus', 'magicDefenceBonus', 'damageReduction', 'attackLevelRequired', 'defenceLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}
    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)
if(Shared.tableCount(itemList) == 0) then
  local attBonusCols = 5
return 'ERROR: you must select at least one item to get stats for[[Category:Pages with script errors]]'
  local strBonusCols = 2
end
  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
  local result = '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"'
  if isWeaponType then
    --Weapons have extra columns here for Attack Speed and "Two Handed?"
    result = result..'\r\n!colspan="4"|'
  else
    result = result..'\r\n!colspan="2"|'
  end
  if attBonusCols > 0 then
    result = result..'\r\n!colspan="'..attBonusCols..'"style="padding:0 0.5em 0 0.5em;"|Attack Bonus'
  end
  if strBonusCols > 0 then
    result = result..'\r\n!colspan="'..strBonusCols..'"style="padding:0 0.5em 0 0.5em;"|Str. Bonus'
  end
  if Shared.contains(statColumns, 'magicDamageBonus') then
    result = result..'\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|% Damage Bonus'
  end
  if defBonusCols > 0 then
    result = result..'\r\n!colspan="'..defBonusCols..'"style="padding:0 0.5em 0 0.5em;"|Defence Bonus'
  end
  if Shared.contains(statColumns, 'damageReduction') then
    result = result..'\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|DR'
  end
  if lvlReqCols > 0 then
    result = result..'\r\n!colspan="'..lvlReqCols..'"style="padding:0 0.5em 0 0.5em;"|Lvl Req'
  end
  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'
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Two Handed?'
  end
  --Attack bonuses
  if Shared.contains(statColumns, 'slashAttackBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'stabAttackBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'blockAttackBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'rangedAttackBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'magicAttackBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  end
  --Strength bonuses
  if Shared.contains(statColumns, 'strengthBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'rangedStrengthBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'magicDamageBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  end
  --Defence bonuses
  if Shared.contains(statColumns, 'defenceBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'rangedDefenceBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'magicDefenceBonus') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'damageReduction') then
    result = result..'\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
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'defenceLevelRequired') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'rangedLevelRequired') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  end
  if Shared.contains(statColumns, 'magicLevelRequired') then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  end
  --And finally Sources
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Sources'


  table.sort(itemList, function(a, b) return a.id < b.id end)
local isWeaponType = ((itemList[1].validSlots ~= nil and Shared.contains(itemList[1].validSlots, 'Weapon'))
  for i, item in pairs(itemList) do
or (itemList[1].occupiesSlots ~= nil and Shared.contains(itemList[1].occupiesSlots, 'Weapon'))) and Shared.contains(weaponTypes, itemList[1].type)
    if isWeaponType then
      --Building rows for weapons
      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)
      --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
      for j, statName in pairs(statColumns) do
        local statValue = Items._getItemStat(item, statName, true)
        result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
        if not Shared.contains(statName, 'LevelRequired') 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..ItemSourceTables._getItemSources(item)
    else
      --Building rows for armour
      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 = Items._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
      --Finally, the Sources
      result = result..'\r\n| style ="text-align: right;white-space: nowrap;padding: 0 0.5em 0 0.5em;" |'
      result = result..ItemSourceTables._getItemSources(item)
    end
  end


  result = result..'\r\n|}'
--Now that we have a preliminary list, let's figure out which columns are irrelevant (IE are zero for all items in the selection)
  return result
local ignoreColumns = Shared.clone(statColumns)
end
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 slotStr = args.slot
local lvlReqCols = 4
  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..'"style="padding:0 0.5em 0 0.5em;"|Attack Bonus')
    end
end
  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


  --Find out what slot we're working with
if sortByName then
  local slot = nil
table.sort(itemList, function(a, b) return a.name < b.name end)
  if slotStr ~= nil then
else
    slot = Constants.getEquipmentSlotID(slotStr)
table.sort(itemList, function(a, b) return a.id < b.id end)
  end
end
 
for i, item in pairs(itemList) do
  local isWeaponType = Shared.contains(weaponTypes, type)
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: 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| data-sort-value="' .. atkSpeed .. '" style ="text-align: right;padding: 0 0.5em 0 0;" |'..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;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;padding:0 0.5em 0 0.5em;"|')
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.hasSpecialAttack then
table.insert(txtLines, "'''Special Attack:'''")
for i, spAtt in ipairs(item.specialAttacks) do
table.insert(txtLines, spAtt.defaultChance .. '% 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|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;padding:0 0.5em 0 0.5em;"|')
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.hasSpecialAttack then
table.insert(txtLines, "'''Special Attack:'''")
for i, spAtt in ipairs(item.specialAttacks) do
table.insert(txtLines, spAtt.defaultChance .. '% 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|style="text-align:left;padding:0 0.5em 0 0.5em;"|')
table.insert(resultPart, item.description ~= nil and item.description 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 = item.defenceLevelRequired ~= nil or (item.category == 'Combat' and item.type == 'Armour')
      elseif type == "Ranged Armour" or type == "Ranged" then
        listItem = item.rangedLevelRequired ~= nil or (item.category == 'Combat' and item.type == 'Ranged Armour')
      elseif type == "Magic Armour" or type == "Magic" then
        listItem = item.magicLevelRequired ~= nil 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 item.equipmentSlot == slot end
    end
    if listItem then
      table.insert(itemList, item)
    end
  end


  return p._getEquipmentTable(itemList)
return table.concat(resultPart)
end
end


function p.getTableForList(frame)
function p._getCategoryTable(style, slot, other, includeModifiers, includeDescription, sortByName)
  local stuffString = frame.args ~= nil and frame.args[1] or frame
if type(slot) == 'number' then
  local itemNames = Shared.splitString(stuffString, ',')
slot = Constants.getEquipmentSlotName(slot)
end
 
local itemList = Items.getItems(function(item)
-- 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
local isMatch = true
if style == 'Melee' then
if (Items._getItemStat(item, 'defenceLevelRequired') == nil and Items._getItemStat(item, 'attackLevelRequired') == nil) and not Shared.contains(styleOverrides.Melee, item.name) then isMatch = false end
elseif style == 'Ranged' then
if Items._getItemStat(item, 'rangedLevelRequired') == nil and not Shared.contains(styleOverrides.Ranged, item.name) then isMatch = false end
elseif style == 'Magic' then
if Items._getItemStat(item, 'magicLevelRequired') == nil and not Shared.contains(styleOverrides.Magic, item.name) then isMatch = false end
elseif style == 'None' then
if (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 slot == nil or not Shared.contains(item.validSlots, slot) then isMatch = false end


  local itemList = {}
if isMatch and other ~= nil then
  local errMsg = 'ERROR: Some items not found in database: '
if slot == 'Cape' then
  local hasErr = false
local isSkillcape = Shared.contains(item.name, 'Skillcape') or item.name == 'Cape of Completion'
  for i, name in Shared.skpairs(itemNames) do
if other == 'Skillcapes' then
    local nextItem = Items.getItem(Shared.trim(name))
isMatch = isSkillcape
    if nextItem == nil then
elseif other == 'No Skillcapes' then
      errMsg = errMsg.." '"..name.."'"
isMatch = not isSkillcape
      hasErr = true
end
    else
end
      table.insert(itemList, nextItem)
if slot == 'Weapon' then --For quiver slot or weapon slot, 'other' is the ammo type
    end
if other == 'Arrows' then
  end
if item.ammoTypeRequired ~= 0 then isMatch = false end
elseif other == 'Bolts' then
if item.ammoTypeRequired ~= 1 then isMatch = false end
end
elseif slot == 'Quiver' then
if other == 'Arrows' then
if item.ammoType ~= 0 then isMatch = false end
elseif other == 'Bolts' then
if item.ammoType ~= 1 then isMatch = false end
elseif other == 'Javelins' then
if item.ammoType ~= 2 then isMatch = false end
elseif other == 'Throwing Knives' then
if item.ammoType ~= 3 then isMatch = false end
elseif other == 'Thrown' then
if item.ammoType ~= 2 and item.ammoType ~= 3 then isMatch = false end
end
end
end


  if hasErr then
return isMatch
    return errMsg
end)
  else
    return p._getEquipmentTable(itemList)
return p._getEquipmentTable(itemList, includeModifiers, includeDescription, sortByName)
  end
end
end


function p.getDoubleLootTable(frame)
function p.getCategoryTable(frame)
  local itemList = Items.getItems(function(item) return item.chanceToDoubleLoot ~= nil and item.chanceToDoubleLoot > 0 end)
local style = frame.args ~= nil and frame.args[1] or frame[1]
  table.sort(itemList, function(a, b) return a.id < b.id end)
local slot = frame.args ~= nil and frame.args[2] or frame[2]
  local result = '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"'
local other = frame.args ~= nil and frame.args[3] or frame[3]
  result = result..'\r\n!colspan="2"|Name!!Bonus!!Description!!Sources'
local includeModifiers = frame.args ~= nil and frame.args.includeModifiers or frame.includeModifiers
  for i, item in Shared.skpairs(itemList) do
local includeDescription = frame.args ~= nil and frame.args.includeDescription or frame.includeDescription
    result = result..'\r\n|-'
local sortByName = frame.args ~= nil and frame.args.sortByName or frame.sortByName
    result = result..'\r\n|data-sort-value="'..item.name..'"|'..Icons.Icon({item.name, type='item', size=50, notext=true})
 
    result = result..'||[['..item.name..']]'
includeModifiers = includeModifiers ~= nil and string.upper(includeModifiers) == 'TRUE' or false
    result = result..'||style ="text-align: right;" data-sort-value="'..item.chanceToDoubleLoot..'"|'..item.chanceToDoubleLoot..'%'
includeDescription = includeDescription ~= nil and string.upper(includeDescription) == 'TRUE' or false
    result = result..'||'..item.description
sortByName = sortByName ~= nil and string.upper(sortByName) == 'TRUE' or false
    result = result..'\r\n| style ="text-align: right;white-space: nowrap;padding: 0 0.5em 0 0.5em;" |'
    result = result..ItemSourceTables._getItemSources(item)
  end


  result = result..'\r\n|}'
return p._getCategoryTable(style, slot, other, includeModifiers, includeDescription, sortByName)
  return result
end
end


function p.getItemTableRows(frame)
function p.getTableForList(frame)
  local startID = frame.args ~= nil and frame.args[1] or frame[1]
local stuffString = frame.args ~= nil and frame.args[1] or frame[1]
  local rowCount = frame.args ~= nil and frame.args[2] or frame[2]
local itemNames = Shared.splitString(stuffString, ',')
  if type(startID ) == 'string' then startID = tonumber(startID) end
 
  if rowCount == nil then rowCount = 200 end
local includeModifiers = frame.args ~= nil and frame.args[2] or frame[2]
  if type(rowCount) == 'string' then rowCount = tonumber(rowCount) end
includeModifiers = includeModifiers ~= nil and string.upper(includeModifiers) == 'TRUE' or false
 
  local rowResult = {}
  for i = startID, startID + rowCount - 1, 1 do
    local item = Items.getItemByID(i)
    if item == nil then break end
    local rowTxt = '|-\r\n|'..Icons.Icon({item.name, type='item', size='50', notext=true})..'||[['..item.name..']]'
    rowTxt = rowTxt..'||style="text-align:right;"|'..i..'||'..item.category..'||'..item.type
    rowTxt = rowTxt..'||style="text-align:right;" data-sort-value="'..item.sellsFor..'"|'..Icons.GP(item.sellsFor)
    rowTxt = rowTxt..'||style="text-align:right;"|'..ItemSourceTables._getItemSources(item, false, 'false')
    rowTxt = rowTxt..'||style="text-align:right;"|'..ItemUseTables._getItemUses(item, false, 'false')
    table.insert(rowResult, rowTxt)
  end


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


function p.numStrWithSign(number)
if hasErr then
  if number >= 0 then
return errMsg
    return '+'..Shared.formatnum(number)
else
  else
return p._getEquipmentTable(itemList, includeModifiers)
    return Shared.formatnum(number)
end
  end
end
end


function p.getStatChangeString(item1, item2)
function p.getDoubleLootTable(frame)
  --Used by getItemUpgradeTable to get the stat change between two items
local modsDL = {
  local changeArray = {}
'increasedChanceToDoubleLootCombat',
'decreasedChanceToDoubleLootCombat',
'increasedChanceToDoubleLootThieving',
'decreasedChanceToDoubleLootThieving',
'increasedChanceToDoubleItemsGlobal',
'decreasedChanceToDoubleItemsGlobal'
}
local modDetail = {}
for i, modName in pairs(modsDL) do
local mName, mText, mSign, mIsNeg, mValUnsigned = Constants.getModifierDetails(modName)
modDetail[modName] = { mult = (mSign == "+" and 1 or -1) }
end


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


      if val1 ~= val2 then
local resultPart = {}
        local txt = string.gsub(subStr, '{V}', p.numStrWithSign(val1 - val2))
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"')
        table.insert(changeArray, txt)
table.insert(resultPart, '\r\n!colspan="2"|Name!!Bonus!!Description')
      end
for i, item in Shared.skpairs(itemList) do
    end
local lootValue = 0
for modName, modDet in pairs(modDetail) do
lootValue = lootValue + (item.modifiers[modName] or 0) * modDet.mult
end
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, '||'..Icons.Icon({item.name, type='item', noicon=true}))
table.insert(resultPart, '||style ="text-align: right;" data-sort-value="'..lootValue..'"|'..lootValue..'%')
table.insert(resultPart, '||'..item.description)
end


  --Unfortunately just gonna have to manually check all the changes I think...
table.insert(resultPart, '\r\n|}')
  local attBon1 = item1.attackBonus ~= nil and item1.attackBonus or {0, 0, 0}
return table.concat(resultPart)
  local attBon2 = item2.attackBonus ~= nil and item2.attackBonus or {0, 0, 0}
end
  getSpecificStatString(attBon1[1], attBon2[1], '{V} '..Icons.Icon({'Melee', notext=true})..' Stab Bonus')
  getSpecificStatString(attBon1[2], attBon2[2], '{V} '..Icons.Icon({'Melee', notext=true})..' Slash Bonus')
  getSpecificStatString(attBon1[3], attBon2[3], '{V} '..Icons.Icon({'Melee', notext=true})..' Block Bonus')


  getSpecificStatString(item1.strengthBonus, item2.strengthBonus, '{V} '..Icons.Icon({'Strength', type='skill', notext=true})..' Strength Bonus')
function p.getStatChangeString(item1, item2)
  getSpecificStatString(item1.rangedStrengthBonus, item2.rangedStrengthBonus, '{V} '..Icons.Icon({'Ranged', type='skill', notext=true})..' Strength Bonus')
--Used by getItemUpgradeTable to get the stat change between two items
  getSpecificStatString(item1.magicDamageBonus, item2.magicDamageBonus, '{V}% '..Icons.Icon({'Magic', type='skill', notext=true})..' Damage Bonus')
local changeArray = {}


  getSpecificStatString(item1.defenceBonus, item2.defenceBonus, '{V} '..Icons.Icon({'Defence', type='skill', notext=true})..' Defence Bonus')
local getSpecificStatString = function(val1, val2, subStr)
  getSpecificStatString(item1.rangedDefenceBonus, item2.rangedDefenceBonus, '{V} '..Icons.Icon({'Ranged', type='skill', notext=true})..' Defence Bonus')
if val1 == nil then val1 = 0 end
  getSpecificStatString(item1.magicDefenceBonus, item2.magicDefenceBonus, '{V} '..Icons.Icon({'Magic', type='skill', notext=true})..' Defence Bonus')
if val2 == nil then val2 = 0 end
  getSpecificStatString(item1.damageReduction, item2.damageReduction, '{V}% Damage Reduction')


  local SlayBon1 = Items._getItemModifier(item1, 'increasedSkillXP', 'Slayer')
if val1 ~= val2 then
  local SlayBon2 = Items._getItemModifier(item2, 'increasedSkillXP', 'Slayer')
local txt = string.gsub(subStr, '{V}', Shared.numStrWithSign(val1 - val2))
  getSpecificStatString(SlayBon1, SlayBon2, '{V}% '..Icons.Icon({'Slayer', type='skill', notext=true})..' Bonus XP')
table.insert(changeArray, txt)
end
end


  getSpecificStatString(item1.attackLevelRequired, item1.attackLevelRequired, '{V} '..Icons.Icon({'Attack', type='skill', notext=true})..' Level Required')
--Unfortunately just gonna have to manually check all the changes I think...
  getSpecificStatString(item1.defenceLevelRequired, item1.defenceLevelRequired, '{V} '..Icons.Icon({'Defence', type='skill', notext=true})..' Level Required')
local statList = {
  getSpecificStatString(item1.rangedLevelRequired, item1.rangedLevelRequired, '{V} '..Icons.Icon({'Ranged', type='skill', notext=true})..' Level Required')
-- {'statName', 'statDescription'}
  getSpecificStatString(item1.magicLevelRequired, item1.magicLevelRequired, '{V} '..Icons.Icon({'Magic', type='skill', notext=true})..' Level Required')
{'stabAttackBonus', '{V} '..Icons.Icon({'Melee', notext=true})..' Stab Bonus'},
{'slashAttackBonus', '{V} '..Icons.Icon({'Melee', notext=true})..' Slash Bonus'},
{'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/>')
return table.concat(changeArray, '<br/>')
end
end


function p.getItemUpgradeTable(frame)
function p.getItemUpgradeTable(frame)
  local category = frame.args ~= nil and frame.args[1] or frame
local category = frame.args ~= nil and frame.args[1] or frame
  local itemArray = {}
local itemArray = {}
  local isEquipment = false
local isEquipment = false


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


  local result = '{| class="wikitable sortable stickyHeader"'
local resultPart = {}
  result = result..'\r\n|- class="headerRow-0"'
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
  result = result..'\r\n!colspan="2"|Upgraded Item!!Ingredients'
table.insert(resultPart, '\r\n|- class="headerRow-0"')
  if isEquipment then result = result..'!!Stat Change' end
table.insert(resultPart, '\r\n!colspan="2"|Upgraded Item!!Ingredients')
if isEquipment then table.insert(resultPart, '!!Stat Change') end


  for i, item in Shared.skpairs(itemArray) do
for i, item in Shared.skpairs(itemArray) do
    result = result..'\r\n|-'
table.insert(resultPart, '\r\n|-')
    result = result..'\r\n|'..Icons.Icon({item.name, type='item', size='50', notext=true})..'||'..item.name
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}))


    local matArray = {}
local matArray = {}
    local statChangeString = ''
local statChangeString = ''
    for i, row in Shared.skpairs(item.itemsRequired) do
for i, row in Shared.skpairs(item.itemsRequired) do
      local mat = Items.getItemByID(row[1])
local mat = Items.getItemByID(row[1])
      table.insert(matArray, Icons.Icon({mat.name, type='item', qty=row[2]}))
table.insert(matArray, Icons.Icon({mat.name, type='item', qty=row[2]}))


      if item.equipmentSlot ~= nil and mat.equipmentSlot ~= nil and statChangeString == '' then
if item.validSlots ~= nil and mat.validSlots ~= nil and statChangeString == '' then
        statChangeString = p.getStatChangeString(item, mat)
statChangeString = p.getStatChangeString(item, mat)
      end
end
    end
end
    if item.trimmedGPCost ~= nil and item.trimmedGPCost > 0 then
if item.trimmedGPCost ~= nil and item.trimmedGPCost > 0 then
      table.insert(matArray, Icons.GP(item.trimmedGPCost))
table.insert(matArray, Icons.GP(item.trimmedGPCost))
    end
end
    result = result..'||'..table.concat(matArray, '<br/>')
table.insert(resultPart, '||'..table.concat(matArray, '<br/>'))


    if isEquipment then
if isEquipment then
      result = result..'||'..statChangeString
table.insert(resultPart, '||'..statChangeString)
    end
end
  end
end


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


return p
return p