Module:Items: Difference between revisions

From Melvor Idle
(Moving p.GetOtherItemBoxText back over)
(getItemDataExport: Implement)
(56 intermediate revisions by 4 users not shown)
Line 2: Line 2:
--Several functions related to use tables can be found at Module:Items/UseTables
--Several functions related to use tables can be found at Module:Items/UseTables
--Functions related to source tables can be found at Module:Items/SourceTables
--Functions related to source tables can be found at Module:Items/SourceTables
--Other functions moved to Module:Items/ComparisonTables


local p = {}
local p = {}


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


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 EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon'}
p.EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon', 'Easter Egg',
local OtherShopItems = {'Cooking Gloves', 'Mining Gloves', 'Gem Gloves', 'Smithing Gloves', 'Thieving Gloves'}
'Abnormal Log', 'Red Herring', 'Cool Glasses'}
p.EventItems = {'Christmas Cracker', 'Christmas Coal', 'Christmas Sweater',
'Christmas Wreath', 'Candy Cane', 'Santa Hat',
'Friendship Bracelet', 'Event Clue 1', 'Event Clue 2',
'Event Clue 3', 'Event Clue 4', 'Candle', 'Cake Base',
'Magical Flavouring', 'Magical Icing', 'Birthday Cake',
'Purple Party Hat', 'Birthday Token', 'Christmas Present (Yellow)',
'Christmas Present (Blue)', 'Christmas Present (Green)', 'Christmas Present (White)',
'Christmas Present (Purple)', 'Christmas Present (Standard)', 'Event Token - Holiday 2021',
'Holiday Scarf', 'Gingerbread House', 'Gingerbread Man', 'Edible Candy Cane',
'Locked Chest', 'Locked Chest Key', 'Event Token (Holiday 2021)'}
--This is hardcoded, so there's no easy way to scrape it. Hopefully it doesn't change
--This is hardcoded, so there's no easy way to scrape it. Hopefully it doesn't change
local GemTable = {["Topaz"] = {name = 'Topaz', id = 128, chance = 50},  
p.GemTable = {["Topaz"] = {name = 'Topaz', id = 128, chance = 50},
                  ["Sapphire"] = {name = "Sapphire", id = 129, chance = 17.5},  
["Sapphire"] = {name = "Sapphire", id = 129, chance = 17.5},
                  ["Ruby"] = {name = "Ruby", id = 130, chance = 17.5},  
["Ruby"] = {name = "Ruby", id = 130, chance = 17.5},
                  ["Emerald"] = {name = "Emerald", id = 131, chance = 10},  
["Emerald"] = {name = "Emerald", id = 131, chance = 10},
                  ["Diamond"] = {name = "Diamond", id = 132, chance = 5}}
["Diamond"] = {name = "Diamond", id = 132, chance = 5}}
--The base chance to receive a gem while mining
--The base chance to receive a gem while mining
local GemChance = .01
p.GemChance = .01
--The number of different fishing junk items
local junkCount = 8
--Items (aside from bars & gems) which can be created via Alt Magic
local AltMagicProducts = {'Rune Essence', 'Bones', 'Holy Dust'}
--The kinds of gloves with cost & charges
p.GloveTable = {['Cooking Gloves'] = {cost=50000, charges=500},
                    ['Mining Gloves'] = {cost=75000, charges=500},
                    ['Smithing Gloves'] = {cost=100000, charges=500},
                    ['Thieving Gloves'] = {cost=100000, charges=500},
                    ['Gem Gloves'] = {cost=500000, charges=2000}}


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


p.specialFishWt = 6722
function p.getItem(name)
p.specialFishLoot = {{128, 2000}, {129, 1600}, {130, 1400}, {131, 1000}, {132, 400}, {667, 10}, {668, 10}, {902, 1}, {670, 1}, {669, 50}, {120, 250}}
local result = nil
name = string.gsub(name, "%%27", "'")
name = string.gsub(name, "'", "'")
for i, item in ipairs(ItemData.Items) do
local itemName = string.gsub(item.name, '#', '')
if name == itemName then
result = Shared.clone(item)
--Make sure every item has an id, and account for Lua being 1-index
result.id = i - 1
break
end
end
return result
end


function p.buildSpecialFishingTable()
function p.getItems(checkFunc)
  --This shouldn't ever be included in a page
local result = {}
  --This is for generating the above 'specialFishLoot' variable if it ever needs to change
local itemCount = 0
  --To re-run, edit the module, type in "console.log(p.buildSpecialFishingTable())" and copy+paste the result as the new value of the variable
for i, item in ipairs(ItemData.Items) do
  --Also gives you the total fishing weight for saving time later
if checkFunc(item) then
  local lootArray = {}
local newItem = Shared.clone(item)
  local totalWt = 0
newItem.id = i - 1
itemCount = itemCount + 1
result[itemCount] = newItem
end
end
return result
end


  for i, item in pairs(ItemData.Items) do
function p._getItemStat(item, StatName, ZeroIfNil)
    if item.fishingCatchWeight ~= nil then
local result = item[StatName]
      totalWt = totalWt + item.fishingCatchWeight
--Special Overrides:
      table.insert(lootArray, '{'..(i - 1)..', '..item.fishingCatchWeight..'}')
-- Equipment stats first
    end
if Shared.contains(ItemData.EquipmentStatKeys, StatName) and item.equipmentStats ~= nil then
  end
result = item.equipmentStats[StatName]
elseif StatName == 'isTwoHanded' then
if item.validSlots ~= nil and item.occupiesSlots ~= nil then
result = Shared.contains(item.validSlots, 'Weapon') and Shared.contains(item.occupiesSlots, 'Shield')
else
result = false
end
elseif string.find(StatName, '^(.+)LevelRequired$') ~= nil and item.equipRequirements ~= nil and item.equipRequirements.Level ~= nil then
local skillName = Shared.titleCase(string.match(StatName, '^(.+)LevelRequired$'))
if skillName ~= nil then
local skillID = Constants.getSkillID(skillName)
if skillID ~= nil then
result = item.equipRequirements.Level[skillID]
end
end
elseif StatName == 'attackType' then
result = p._getWeaponAttackType(item)
elseif StatName == 'description' then
result = item.description
if result == nil or result == '' then result = 'No Description' end
elseif StatName == 'completionReq' then
if item.ignoreCompletion == nil or not item.ignoreCompletion then
result = 'Yes'
else
result = 'No'
end
elseif StatName == 'slayerBonusXP' then
return p._getItemModifier(item, 'increasedSkillXP', 'Slayer', false)
elseif StatName == 'hasCombatStats' then
return tostring(p.hasCombatStats(item) or p._hasLevelRequirements(item))
end
if result == nil and ZeroIfNil then result = 0 end
return result
end


  local result = 'p.specialFishWt = '..totalWt..'\r\n'
function p.getItemStat(frame)
  result = result..'p.specialFishLoot = {'..table.concat(lootArray, ', ')..'}'
local args = frame.args ~= nil and frame.args or frame
  return result
local ItemName = args[1]
local StatName = args[2]
local ZeroIfNil = args.ForceZero ~= nil and args.ForceZero ~= '' and args.ForceZero ~= 'false'
local formatNum = args.formatNum ~= nil and args.formatNum ~= '' and args.formatNum ~= 'false'
local item = p.getItem(ItemName)
if item == nil then
return "ERROR: No item named "..ItemName.." exists in the data module[[Category:Pages with script errors]]"
end
local result = p._getItemStat(item, StatName, ZeroIfNil)
if formatNum then result = Shared.formatnum(result) end
return result
end
end


function p.getSpecialAttackByID(ID)
--Gets the value of a given modifier for a given item
  local result = Shared.clone(ItemData.SpecialAttacks[ID + 1])
--asString is false by default, when true it writes the full bonus text
  if result ~= nil then
function p._getItemModifier(item, modifier, skill, asString)
    result.id = ID
if asString == nil then asString = false end
  end
if skill == '' then
  return result
skill = nil
elseif type(skill) == 'string' then
skill = Constants.getSkillID(skill)
end
 
local result = 0
 
if item.modifiers ~= nil and item.modifiers[modifier] ~= nil then
if type(item.modifiers[modifier]) == 'table' then
for i, subVal in Shared.skpairs(item.modifiers[modifier]) do
if subVal[1] == skill then
result = subVal[2]
break
end
end
else
result = item.modifiers[modifier]
end
end
 
if asString then
if skill ~= nil then
return Constants._getModifierText(modifier, {skill, result})
else
return Constants._getModifierText(modifier, result)
end
else
return result
end
end
end


function p.getItemByID(ID)
function p.hasCombatStats(item)
  local result = Shared.clone(ItemData.Items[ID + 1])
if item.isEquipment or (item.validSlots == nil and item.equipmentStats ~= nil) then
  if result ~= nil then
-- Ensure at least one stat has a non-zero value
    result.id = ID
for statName, statVal in pairs(item.equipmentStats) do
  end
if statVal ~= 0 then return true end
  return result
end
end
return false
end
end


function p.getItem(name)
function p._hasLevelRequirements(item)
  local result = nil
--Function true if an item has at least one level requirement to equip
  name = string.gsub(name, "%%27", "'")
if item.equipRequirements ~= nil and item.equipRequirements.Level ~= nil then
  name = string.gsub(name, "'", "'")
for skillID, lvl in pairs(item.equipRequirements.Level) do
  name = string.gsub(name, "'", "'")
if lvl ~= nil and lvl > 1 then
  for i, item in pairs(ItemData.Items) do
return true
    local itemName = string.gsub(item.name, '#', '')
end
    if(name == itemName) then
end
      result = Shared.clone(item)
return false
      --Make sure every item has an id, and account for Lua being 1-index
else
      result.id = i - 1
return false
      break
end
    end
  end
  return result
end
end


function p.getItems(checkFunc)
function p.getItemModifier(frame)
  local result = {}
local itemName = frame.args ~= nil and frame.args[1] or frame[1]
  for i, item in pairs(ItemData.Items) do
local modName = frame.args ~= nil and frame.args[2] or frame[2]
    if checkFunc(item) then
local skillName = frame.args ~= nil and frame.args[3] or frame[3]
      local newItem = Shared.clone(item)
local asString = frame.args ~= nil and frame.args[4] or frame[4]
      newItem.id = i - 1
if asString ~= nil then
      table.insert(result, newItem)
asString = (string.upper(asString) ~= 'FALSE')
    end
end
  end
  return result
end


function p._getItemStat(item, StatName, ZeroIfNil)
local item = p.getItem(itemName)
  local result = item[StatName]
if item == nil then
  --Special Overrides:
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
  if StatName == 'stabAttackBonus' then
end
    if item.attackBonus == nil then  
      result = nil
    else
      result = item.attackBonus[1]
    end
  elseif StatName == 'slashAttackBonus' then
    if item.attackBonus == nil then
      result = nil
    else
      result = item.attackBonus[2]
    end
  elseif StatName == 'blockAttackBonus' then
    if item.attackBonus == nil then
      result = nil
    else
      result = item.attackBonus[3]
    end
  elseif StatName == 'attackType' then
    result = p._getWeaponAttackType(item)
  elseif StatName == 'description' then
    result = item.description
    if result == nil or result == '' then result = 'No Description' end
  end
  if result == nil and ZeroIfNil then result = 0 end
  return result
end


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


function p._getWeaponAttackType(item)
function p._getWeaponAttackType(item)
  if item.type == 'Weapon' then
if item.isEquipment == true and (item.validSlots ~= nil and Shared.contains(item.validSlots, 'Weapon')) or
    return Icons.Icon({'Melee', nolink='true'})
(item.occupiesSlots ~= nil and Shared.contains(item.occupiesSlots, 'Weapon')) then
  elseif item.type == 'Ranged Weapon' then
if Shared.contains({'melee', 'ranged', 'magic'}, item.attackType) then
    return Icons.Icon({'Ranged', type='skill', nolink='true'})
local iconType = item.attackType ~= 'melee' and 'skill' or nil
  elseif item.type == 'Magic Staff' or item.type == 'Magic Wand' then
return Icons.Icon({Shared.titleCase(item.attackType), type=iconType, nolink='true'})
    return Icons.Icon({'Magic', type='skill', nolink='true'})
end
  else
end
    return "Invalid"
return 'Invalid'
  end
end
end


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


function p.getPotionTable(frame)
function p.getPotionTable(frame)
  local potionName = frame.args ~= nil and frame.args[1] or frame
local potionName = frame.args ~= nil and frame.args[1] or frame
  local tiers = {'I', 'II', 'III', 'IV'}
local tiers = {'I', 'II', 'III', 'IV'}
 
local resultPart = {}
table.insert(resultPart, '{| class="wikitable"')
table.insert(resultPart, '\r\n!Potion!!Tier!!Charges!!Effect')
 
local tier1potion = p.getItem(potionName..' I')
if tier1potion == nil then
return 'ERROR: No potion named "' .. potionName .. '" was found[[Category:Pages with script errors]]'
end
for i, tier in ipairs(tiers) do
local tierName = potionName..' '..tier
local potion = p.getItemByID(tier1potion.id + i - 1)
if potion ~= nil then
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|'..Icons.Icon({tierName, type='item', notext=true, size='60'}))
table.insert(resultPart, '||'..Icons.Icon({tierName, tier, type='item', noicon=true}))
table.insert(resultPart, '||'..potion.potionCharges..'||'..potion.description)
end
end
 
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end


  local result = '{| class="wikitable"'
function p._getOtherItemBoxText(item)
  result = result..'\r\n!Potion!!Tier!!Charges!!Effect'
resultPart = {}
--For equipment, show the slot they go in
if item.validSlots ~= nil then
local slotLinkMap = {
["Helmet"] = 'Equipment#Helmets',
["Platebody"] = 'Equipment#Platebodies',
["Platelegs"] = 'Equipment#Platelegs',
["Boots"] = 'Equipment#Boots',
["Weapon"] = 'Equipment#Weapons',
["Shield"] = 'Equipment#Offhand',
["Amulet"] = 'Equipment#Amulets',
["Ring"] = 'Equipment#Rings',
["Gloves"] = 'Equipment#Gloves',
["Quiver"] = 'Equipment#Ammunition',
["Cape"] = 'Equipment#Capes',
["Passive"] = 'Combat Passive Slot',
["Summon1"] = 'Summoning',
["Summon2"] = 'Summoning'
}
local slotText = {}
for i, slot in ipairs(item.validSlots) do
local slotLink = slotLinkMap[slot]
if slotLink == nil then
table.insert(slotText, slot)
else
table.insert(slotText, '[[' .. slotLink .. '|' .. slot .. ']]')
end
end
table.insert(resultPart, "\r\n|-\r\n|'''Equipment Slot:''' "..table.concat(slotText, ', '))
end
--For weapons with a special attack, show the details
if item.hasSpecialAttack then
table.insert(resultPart, "\r\n|-\r\n|'''Special Attack:'''")
for i, spAtt in ipairs(item.specialAttacks) do
table.insert(resultPart, '\r\n* ' .. spAtt.defaultChance .. '% chance for ' .. spAtt.name .. ':')
table.insert(resultPart, '\r\n** ' .. spAtt.description)
end
end
--For potions, show the number of charges
if item.potionCharges ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''Charges:''' "..item.potionCharges)
end
--For food, show how much it heals for
if item.healsFor ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''Heals for:''' "..Icons.Icon({"Hitpoints", type="skill", notext="true"})..' '..(item.healsFor * 10))
end
--For Prayer Points, show how many you get
if item.prayerPoints ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''"..Icons.Icon({'Prayer', type='skill'}).." Points:''' "..item.prayerPoints)
end
--For items with modifiers, show what those are
if item.modifiers ~= nil and Shared.tableCount(item.modifiers) > 0 then
table.insert(resultPart, "\r\n|-\r\n|'''Modifiers:'''\r\n"..Constants.getModifiersText(item.modifiers, true))
end
return table.concat(resultPart)
end


  local tier1potion = p.getItem(potionName..' I')
function p.getOtherItemBoxText(frame)
  for i, tier in pairs(tiers) do
local itemName = frame.args ~= nil and frame.args[1] or frame
    local tierName = potionName..' '..tier
local item = p.getItem(itemName)
    local potion = p.getItemByID(tier1potion.id + i - 1)
local asList = false
    if potion ~= nil then
if frame.args ~= nil then
      result = result..'\r\n|-'
asList = frame.args.asList ~= nil and frame.args.asList ~= '' and frame.args.asList ~= 'false'
      result = result..'\r\n|'..Icons.Icon({tierName, type='item', notext='true', size='60'})
end
      result = result..'||'..'[['..tierName..'|'..tier..']]'
if item == nil then
      result = result..'||'..potion.potionCharges..'||'..potion.description
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
    end
end
  end


  result = result..'\r\n|}'
return p._getOtherItemBoxText(item, asList)
  return result
end
end


function p.getEquipmentSlotName(id)
function p._getItemCategories(item)
  for slotName, i in Shared.skpairs(Constants.equipmentSlot) do
local resultPart = {}
    if i == id then
if item.category ~= nil then table.insert(resultPart, '[[Category:'..item.category..']]') end
      return slotName
if item.type ~= nil then table.insert(resultPart, '[[Category:'..item.type..']]') end
    end
if item.tier ~= nil then table.insert(resultPart, '[[Category:'..Shared.titleCase(item.tier)..' '..item.type..']]') end
  end
if item.hasSpecialAttack then table.insert(resultPart, '[[Category:Items With Special Attacks]]') end
  return 'Invalid'
if item.validSlots ~= nil then
local slotRemap = {
['Passive'] = 'Passive Items',
['Summon1'] = 'Summoning Familiars',
['Summon2'] = ''
}
for i, slotName in ipairs(item.validSlots) do
local slotRemapName = slotName
if slotRemap[slotName] ~= nil then slotRemapName = slotRemap[slotName] end
if slotRemapName ~= '' then table.insert(resultPart, '[[Category:' .. slotRemapName .. ']]') end
end
end
if item.modifiers ~= nil then
local modsDL = {
'increasedChanceToDoubleLootCombat',
'decreasedChanceToDoubleLootCombat',
'increasedChanceToDoubleLootThieving',
'decreasedChanceToDoubleLootThieving',
'increasedChanceToDoubleItemsGlobal',
'decreasedChanceToDoubleItemsGlobal'
}
for modName, val in pairs(item.modifiers) do
if Shared.contains(modsDL, modName) then
table.insert(resultPart, '[[Category:Double Loot Chance Items]]')
break
end
end
end
return table.concat(resultPart)
end
end


function p._getOtherItemBoxText(item)
function p.getItemCategories(frame)
  result = ''
local itemName = frame.args ~= nil and frame.args[1] or frame
  --For equipment, show the slot they go in
local item = p.getItem(itemName)
  if item.equipmentSlot ~= nil then
if item == nil then
    result = result..'\r\n|-\r\n|Equipment Slot: '..p.getEquipmentSlotName(item.equipmentSlot)
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
  end
end
  --For weapons with a special attack, show the details
 
  if item.hasSpecialAttack then
return p._getItemCategories(item)
    local spAtt = p.getSpecialAttackByID(item.specialAttackID)
    result = result..'\r\n|-\r\n|Special Attack:'
    result = result..'\r\n* '..spAtt.chance..'% chance for '..spAtt.name..':'
    result = result..'\r\n** '..spAtt.description
  end
  --For potions, show the number of charges
  if item.potionCharges ~= nil then
    result = result..'\r\n|-\r\n|Charges: '..item.potionCharges
  end
  --For food, show how much it heals for
  if item.healsFor ~= nil then
    result = result..'\r\n|-\r\n|Heals for: '..Icons.Icon({"Hitpoints", type="skill", notext="true"})..' '..(item.healsFor * 10)
  end
  --For Prayer Points, show how many you get
  if item.prayerPoints ~= nil then
    result = result..'\r\n|-\r\n|'..Icons.Icon({'Prayer', type='skill'})..' Points: '..item.prayerPoints
  end
  return result
end
end


function p.getOtherItemBoxText(frame)
function p.getSkillcapeTable(frame)
  local itemName = frame.args ~= nil and frame.args[1] or frame
local skillName = frame.args ~= nil and frame.args[1] or frame
  local item = p.getItem(itemName)
local cape = p.getItem(skillName..' Skillcape')
  local asList = false
if cape == nil then
  if frame.args ~= nil then  
return ''
    asList = frame.args.asList ~= nil and frame.args.asList ~= '' and frame.args.asList ~= 'false'
else
  end
local resultPart = {}
  if item == nil then
table.insert(resultPart, '{| class="wikitable"\r\n')
    return "ERROR: No item named "..itemName.." exists in the data module"
table.insert(resultPart, '!Skillcape!!Name!!Effect')
  end
table.insert(resultPart, '\r\n|-\r\n|'..Icons.Icon({cape.name, type='item', size='60', notext=true}))
table.insert(resultPart, '||'..Icons.Icon({cape.name, type='item', noicon=true})..'||'..cape.description)
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
end


  return p._getOtherItemBoxText(item, asList)
function p.getItemGrid(frame)
local resultPart = {}
table.insert(resultPart, '{|')
for i, item in Shared.skpairs(ItemData.Items) do
if i % 17 == 1 then
table.insert(resultPart, '\r\n|-\r\n|')
else
table.insert(resultPart, '||')
end
table.insert(resultPart, 'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'}))
end
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
end


function p.getEquipmentTable(frame)
function p.getWeaponStatsBox(frame)
  local args = frame.args ~= nil and frame.args or frame
local itemName = frame.args ~= nil and frame.args[1] or frame
  local type = args.type
local item = p.getItem(itemName)
  local tier = args.tier
if item == nil then
  local slotStr = args.slot
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
  local ammoTypeStr = args.ammoType
end
  local category = args.category ~= nil and args.category or 'Combat'
 
local ico = {
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
["Combat"] = Icons.Icon({'Combat', notext=true}),
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
}
local resultPart = {}
table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Weapon Stats')
table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats')
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats')
 
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Speed')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. Shared.round(p._getItemStat(item, 'attackSpeed', true) / 1000, 3, 1) .. 's')
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true))


  --Find out what Ammo Type we're working with
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Type')
  local ammoType = nil
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'attackType'))
  if ammoTypeStr ~= nil then
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction')
    if ammoTypeStr == "Arrows" then
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%')
      ammoType = 0
    elseif ammoTypeStr == 'Bolts' then
      ammoType = 1
    elseif ammoTypeStr == 'Javelins' then
      ammoType = 2
    elseif ammoTypeStr == 'Throwing Knives' then
      ammoType = 3
    end
  end


  --Find out what slot we're working with
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus')
  local slot = nil
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true))
  if slotStr ~= nil then
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus')
    slot = Constants.equipmentSlot[slotStr]
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true))
  end
 


  --Getting some lists set up here that will be used later
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus')
  --First, the list of columns used by both weapons & armour
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', true))
  local statColumns = {'stabAttackBonus', 'slashAttackBonus','blockAttackBonus','rangedAttackBonus', 'magicAttackBonus', 'strengthBonus', 'rangedStrengthBonus', 'magicDamageBonus', 'defenceBonus', 'rangedDefenceBonus', 'magicDefenceBonus', 'damageReduction', 'attackLevelRequired', 'defenceLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}
table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus')
  --Then the lists for just weapons/just armour
table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true))
  --Then the list of weapon types
  local weaponTypes = {'Magic Staff', 'Magic Wand', 'Ranged Weapon', 'Weapon'}


  local isWeaponType = Shared.contains(weaponTypes, type)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true))
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Other')


  --Now we need to figure out which items are in this list
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus')
  local itemList = {}
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true))
  for i, itemBase in pairs(ItemData.Items) do
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Slayer'] .. ' Bonus Slayer XP')
    local item = Shared.clone(itemBase)
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slayerBonusXP', true) .. '%')
    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


  --Now that we have a preliminary list, let's figure out which columns are irrelevant (IE are zero for all items in the selection)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus')
  local ignoreColumns = Shared.clone(statColumns)
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true))
  for i, item in pairs(itemList) do
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Attack'] .. ' Level Required')
    local ndx = 1
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'attackLevelRequired', true))
    while Shared.tableCount(ignoreColumns) >= ndx do
      if p._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)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus')
  local attBonusCols = 5
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true))
  local strBonusCols = 2
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Level Required')
  local defBonusCols = 3
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedLevelRequired', true))
  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;"|Strength 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;"|Damage Reduction'
  end
  if lvlReqCols > 0 then
    result = result..'\r\n!colspan="'..lvlReqCols..'"style="padding:0 0.5em 0 0.5em;"|Levels Required'
  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)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
  for i, item in pairs(itemList) do
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
    if isWeaponType then
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Level Required')
      --Building rows for weapons
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicLevelRequired', true))
      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 = p._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..p._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 = p._getItemStat(item, statName, true)
        result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
        if statValue > 0 then
          result = result..'background-color:lightgreen;'
        elseif statValue < 0 then
          result = result..'background-color:lightpink;'
        end
        result = result..'"|'..Shared.formatnum(statValue)
        if statName == 'magicDamageBonus' or statName == 'damageReduction' then result = result..'%' end
      end
      --Finally, the Sources
      result = result..'\r\n| style ="text-align: right;white-space: nowrap;padding: 0 0.5em 0 0.5em;" |'
      result = result..p._getItemSources(item)
    end
  end


  result = result..'\r\n|}'
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
  return result
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
table.insert(resultPart, '\r\n!style="text-align:right;"| Two Handed?')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. (p._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No'))
 
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
end


function p._getItemCategories(item)
function p.getArmourStatsBox(frame)
  local result = ''
local itemName = frame.args ~= nil and frame.args[1] or frame
  if item.category ~= nil then result = result..'[[Category:'..item.category..']]' end
local item = p.getItem(itemName)
  if item.type ~= nil then result = result..'[[Category:'..item.type..']]' end
if item == nil then
  return result
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
end
end
 
local ico = {
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
["Combat"] = Icons.Icon({'Combat', notext=true}),
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
}
local resultPart = {}
table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Armour Stats')
table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats')
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats')
 
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true))
 
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', 0))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%')


function p.getItemCategories(frame)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus')
  local itemName = frame.args ~= nil and frame.args[1] or frame
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true))
  local item = p.getItem(itemName)
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus')
  if item == nil then
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true))
    return "ERROR: No item named "..itemName.." exists in the data module"
  end


  return p._getItemCategories(item)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus')
end
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true))


function p.getSkillcapeTable(frame)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus')
  local skillName = frame.args ~= nil and frame.args[1] or frame
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true))
  local cape = p.getItem(skillName..' Skillcape')
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Other')
  local result = '{| class="wikitable"\r\n'
  result = result..'!Skillcape!!Name!!Effect'
  result = result..'\r\n|-\r\n|'..Icons.Icon({cape.name, type='item', size='60', notext=true})
  result = result..'||[['..cape.name..']]||'..cape.description
  result = result..'\r\n|}'
  return result
end


function p.getShopSkillcapeTable()
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus')
  local result = ''
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Slayer'] .. ' Bonus Slayer XP')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slayerBonusXP', true) .. '%')


  local capeList = {}
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
  for i, item in pairs(ItemData.Items) do
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
    if Shared.contains(item.name, 'Skillcape') or item.name == 'Cape of Completion' then
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Level Required')
      table.insert(capeList, item)
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'defenceLevelRequired', true))
    end
  end


  result = result..'\r\n{|class="wikitable sortable"'
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
  result = result..'\r\n!colspan="2" style="width:200px"|Cape'
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
  result = result..'!!Description!!style="width:120px"|Price'
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Level Required')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedLevelRequired', true))


  --Sort the table by cost and then name
table.insert(resultPart, '\r\n|-\r\n| colspan="2"|')
  table.sort(capeList, function(a, b)
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Level Required')
                        if a.buysFor == b.buysFor then
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicLevelRequired', true))
                          return a.name < b.name
                        else
                          return a.sellsFor < b.buysFor
                        end
                      end)
  for i, thisItem in pairs(capeList) do
    result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item', size='50', notext=true})
    result = result..'||[['..thisItem.name..']]'
    result = result..'\r\n||'..thisItem.description
    result = result..'||style="text-align:left" data-sort-value="'..thisItem.buysFor..'"'
    result = result..'|'..Icons.GP(thisItem.buysFor)
  end
  result = result..'\r\n|}'


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


function p.getItemGrid(frame)
function p.getItemDataExport(frame)
  result = '{|'
local resultTable = mw.html.create('table')
  for i, item in Shared.skpairs(ItemData.Items) do
resultTable:addClass('wikitable')
    if i % 17 == 1 then
resultTable:tag('tr'):addClass('headerRow-0')
      result = result..'\r\n|-\r\n|'
:tag('th'):wikitext('ItemID'):done()
    else
:tag('th'):wikitext('ItemName'):done()
      result = result..'||'
:tag('th'):wikitext('GPValue'):done()
    end
    result = result..'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'})
for i, item in ipairs(ItemData.Items) do
  end
resultTable:tag('tr')
  result = result..'\r\n|}'
:tag('td'):wikitext(item.id):done()
  return result
:tag('td'):wikitext(item.name):done()
:tag('td'):wikitext(item.sellsFor):done()
end
return tostring(resultTable)
end
end


return p
return p

Revision as of 20:53, 9 March 2022

Lua module for generating various item tables. Pulls data from Module:GameData/data


--This module contains all sorts of functions for getting data on items
--Several functions related to use tables can be found at Module:Items/UseTables
--Functions related to source tables can be found at Module:Items/SourceTables
--Other functions moved to Module:Items/ComparisonTables

local p = {}

local ItemData = mw.loadData('Module:Items/data')

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

p.EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon', 'Easter Egg',
				'Abnormal Log', 'Red Herring', 'Cool Glasses'}
p.EventItems = {'Christmas Cracker', 'Christmas Coal', 'Christmas Sweater',
				'Christmas Wreath', 'Candy Cane', 'Santa Hat',
				'Friendship Bracelet', 'Event Clue 1', 'Event Clue 2',
				'Event Clue 3', 'Event Clue 4', 'Candle', 'Cake Base',
				'Magical Flavouring', 'Magical Icing', 'Birthday Cake',
				'Purple Party Hat', 'Birthday Token', 'Christmas Present (Yellow)',
				'Christmas Present (Blue)', 'Christmas Present (Green)', 'Christmas Present (White)',
				'Christmas Present (Purple)', 'Christmas Present (Standard)', 'Event Token - Holiday 2021',
				'Holiday Scarf', 'Gingerbread House', 'Gingerbread Man', 'Edible Candy Cane',
				'Locked Chest', 'Locked Chest Key', 'Event Token (Holiday 2021)'}
--This is hardcoded, so there's no easy way to scrape it. Hopefully it doesn't change
p.GemTable = {["Topaz"] = {name = 'Topaz', id = 128, chance = 50},
				["Sapphire"] = {name = "Sapphire", id = 129, chance = 17.5},
				["Ruby"] = {name = "Ruby", id = 130, chance = 17.5},
				["Emerald"] = {name = "Emerald", id = 131, chance = 10},
				["Diamond"] = {name = "Diamond", id = 132, chance = 5}}
--The base chance to receive a gem while mining
p.GemChance = .01

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

function p.getItem(name)
	local result = nil
	name = string.gsub(name, "%%27", "'")
	name = string.gsub(name, "&#39;", "'")
	for i, item in ipairs(ItemData.Items) do
		local itemName = string.gsub(item.name, '#', '')
		if name == itemName then
			result = Shared.clone(item)
			--Make sure every item has an id, and account for Lua being 1-index
			result.id = i - 1
			break
		end
	end
	return result
end

function p.getItems(checkFunc)
	local result = {}
	local itemCount = 0
	for i, item in ipairs(ItemData.Items) do
		if checkFunc(item) then
			local newItem = Shared.clone(item)
			newItem.id = i - 1
			itemCount = itemCount + 1
			result[itemCount] = newItem
		end
	end
	return result
end

function p._getItemStat(item, StatName, ZeroIfNil)
	local result = item[StatName]
	--Special Overrides:
	-- Equipment stats first
	if Shared.contains(ItemData.EquipmentStatKeys, StatName) and item.equipmentStats ~= nil then
		result = item.equipmentStats[StatName]
	elseif StatName == 'isTwoHanded' then
		if item.validSlots ~= nil and item.occupiesSlots ~= nil then
			result = Shared.contains(item.validSlots, 'Weapon') and Shared.contains(item.occupiesSlots, 'Shield')
		else
			result = false
		end
	elseif string.find(StatName, '^(.+)LevelRequired$') ~= nil and item.equipRequirements ~= nil and item.equipRequirements.Level ~= nil then
		local skillName = Shared.titleCase(string.match(StatName, '^(.+)LevelRequired$'))
		if skillName ~= nil then
			local skillID = Constants.getSkillID(skillName)
			if skillID ~= nil then
				result = item.equipRequirements.Level[skillID]
			end
		end
	elseif StatName == 'attackType' then
		result = p._getWeaponAttackType(item)
	elseif StatName == 'description' then
		result = item.description
		if result == nil or result == '' then result = 'No Description' end
	elseif StatName == 'completionReq' then
		if item.ignoreCompletion == nil or not item.ignoreCompletion then
			result = 'Yes'
		else
			result = 'No'
		end
	elseif StatName == 'slayerBonusXP' then
		return p._getItemModifier(item, 'increasedSkillXP', 'Slayer', false)
	elseif StatName == 'hasCombatStats' then
		return tostring(p.hasCombatStats(item) or p._hasLevelRequirements(item))
	end
	if result == nil and ZeroIfNil then result = 0 end
	return result
end

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

--Gets the value of a given modifier for a given item
--asString is false by default, when true it writes the full bonus text
function p._getItemModifier(item, modifier, skill, asString)
	if asString == nil then asString = false end
	if skill == '' then
		skill = nil
	elseif type(skill) == 'string' then
		skill = Constants.getSkillID(skill)
	end

	local result = 0

	if item.modifiers ~= nil and item.modifiers[modifier] ~= nil then
		if type(item.modifiers[modifier]) == 'table' then
			for i, subVal in Shared.skpairs(item.modifiers[modifier]) do
				if subVal[1] == skill then
					result = subVal[2]
					break
				end
			end
		else
			result = item.modifiers[modifier]
		end
	end

	if asString then
		if skill ~= nil then
			return Constants._getModifierText(modifier, {skill, result})
		else
			return Constants._getModifierText(modifier, result)
		end
	else
		return result
	end
end

function p.hasCombatStats(item)
	if item.isEquipment or (item.validSlots == nil and item.equipmentStats ~= nil) then
		-- Ensure at least one stat has a non-zero value
		for statName, statVal in pairs(item.equipmentStats) do
			if statVal ~= 0 then return true end
		end
	end
	return false
end

function p._hasLevelRequirements(item)
	--Function true if an item has at least one level requirement to equip
	if item.equipRequirements ~= nil and item.equipRequirements.Level ~= nil then
		for skillID, lvl in pairs(item.equipRequirements.Level) do
			if lvl ~= nil and lvl > 1 then
				return true
			end
		end
		return false
	else
		return false
	end
end

function p.getItemModifier(frame)
	local itemName = frame.args ~= nil and frame.args[1] or frame[1]
	local modName = frame.args ~= nil and frame.args[2] or frame[2]
	local skillName = frame.args ~= nil and frame.args[3] or frame[3]
	local asString = frame.args ~= nil and frame.args[4] or frame[4]
	if asString ~= nil then
		asString = (string.upper(asString) ~= 'FALSE')
	end

	local item = p.getItem(itemName)
	if item == nil then
		return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
	end

	return p._getItemModifier(item, modName, skillName, asString)
end

function p._getWeaponAttackType(item)
	if item.isEquipment == true and (item.validSlots ~= nil and Shared.contains(item.validSlots, 'Weapon')) or
									(item.occupiesSlots ~= nil and Shared.contains(item.occupiesSlots, 'Weapon')) then
		if Shared.contains({'melee', 'ranged', 'magic'}, item.attackType) then
			local iconType = item.attackType ~= 'melee' and 'skill' or nil
			return Icons.Icon({Shared.titleCase(item.attackType), type=iconType, nolink='true'})
		end
	end
	return 'Invalid'
end

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

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

	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable"')
	table.insert(resultPart, '\r\n!Potion!!Tier!!Charges!!Effect')

	local tier1potion = p.getItem(potionName..' I')
	if tier1potion == nil then
		return 'ERROR: No potion named "' .. potionName .. '" was found[[Category:Pages with script errors]]'
	end
	for i, tier in ipairs(tiers) do
		local tierName = potionName..' '..tier
		local potion = p.getItemByID(tier1potion.id + i - 1)
		if potion ~= nil then
			table.insert(resultPart, '\r\n|-')
			table.insert(resultPart, '\r\n|'..Icons.Icon({tierName, type='item', notext=true, size='60'}))
			table.insert(resultPart, '||'..Icons.Icon({tierName, tier, type='item', noicon=true}))
			table.insert(resultPart, '||'..potion.potionCharges..'||'..potion.description)
		end
	end

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

function p._getOtherItemBoxText(item)
	resultPart = {}
	--For equipment, show the slot they go in
	if item.validSlots ~= nil then
		local slotLinkMap = {
			["Helmet"] = 'Equipment#Helmets',
			["Platebody"] = 'Equipment#Platebodies',
			["Platelegs"] = 'Equipment#Platelegs',
			["Boots"] = 'Equipment#Boots',
			["Weapon"] = 'Equipment#Weapons',
			["Shield"] = 'Equipment#Offhand',
			["Amulet"] = 'Equipment#Amulets',
			["Ring"] = 'Equipment#Rings',
			["Gloves"] = 'Equipment#Gloves',
			["Quiver"] = 'Equipment#Ammunition',
			["Cape"] = 'Equipment#Capes',
			["Passive"] = 'Combat Passive Slot',
			["Summon1"] = 'Summoning',
			["Summon2"] = 'Summoning'
		}
		local slotText = {}
		for i, slot in ipairs(item.validSlots) do
			local slotLink = slotLinkMap[slot]
			if slotLink == nil then
				table.insert(slotText, slot)
			else
				table.insert(slotText, '[[' .. slotLink .. '|' .. slot .. ']]')
			end
		end
		table.insert(resultPart, "\r\n|-\r\n|'''Equipment Slot:''' "..table.concat(slotText, ', '))
	end
	--For weapons with a special attack, show the details
	if item.hasSpecialAttack then
		table.insert(resultPart, "\r\n|-\r\n|'''Special Attack:'''")
		for i, spAtt in ipairs(item.specialAttacks) do
			table.insert(resultPart, '\r\n* ' .. spAtt.defaultChance .. '% chance for ' .. spAtt.name .. ':')
			table.insert(resultPart, '\r\n** ' .. spAtt.description)
		end
	end
	--For potions, show the number of charges
	if item.potionCharges ~= nil then
		table.insert(resultPart, "\r\n|-\r\n|'''Charges:''' "..item.potionCharges)
	end
	--For food, show how much it heals for
	if item.healsFor ~= nil then
		table.insert(resultPart, "\r\n|-\r\n|'''Heals for:''' "..Icons.Icon({"Hitpoints", type="skill", notext="true"})..' '..(item.healsFor * 10))
	end
	--For Prayer Points, show how many you get
	if item.prayerPoints ~= nil then
		table.insert(resultPart, "\r\n|-\r\n|'''"..Icons.Icon({'Prayer', type='skill'}).." Points:''' "..item.prayerPoints)
	end
	--For items with modifiers, show what those are
	if item.modifiers ~= nil and Shared.tableCount(item.modifiers) > 0 then
		table.insert(resultPart, "\r\n|-\r\n|'''Modifiers:'''\r\n"..Constants.getModifiersText(item.modifiers, true))
	end
	return table.concat(resultPart)
end

function p.getOtherItemBoxText(frame)
	local itemName = frame.args ~= nil and frame.args[1] or frame
	local item = p.getItem(itemName)
	local asList = false
	if frame.args ~= nil then
		asList = frame.args.asList ~= nil and frame.args.asList ~= '' and frame.args.asList ~= 'false'
	end
	if item == nil then
		return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
	end

	return p._getOtherItemBoxText(item, asList)
end

function p._getItemCategories(item)
	local resultPart = {}
	if item.category ~= nil then table.insert(resultPart, '[[Category:'..item.category..']]') end
	if item.type ~= nil then table.insert(resultPart, '[[Category:'..item.type..']]') end
	if item.tier ~= nil then table.insert(resultPart, '[[Category:'..Shared.titleCase(item.tier)..' '..item.type..']]') end
	if item.hasSpecialAttack then table.insert(resultPart, '[[Category:Items With Special Attacks]]') end
	if item.validSlots ~= nil then
		local slotRemap = {
			['Passive'] = 'Passive Items',
			['Summon1'] = 'Summoning Familiars',
			['Summon2'] = ''
		}
		for i, slotName in ipairs(item.validSlots) do
			local slotRemapName = slotName
			if slotRemap[slotName] ~= nil then slotRemapName = slotRemap[slotName] end
			if slotRemapName ~= '' then table.insert(resultPart, '[[Category:' .. slotRemapName .. ']]') end
		end
	end
	if item.modifiers ~= nil then
		local modsDL = {
			'increasedChanceToDoubleLootCombat',
			'decreasedChanceToDoubleLootCombat',
			'increasedChanceToDoubleLootThieving',
			'decreasedChanceToDoubleLootThieving',
			'increasedChanceToDoubleItemsGlobal',
			'decreasedChanceToDoubleItemsGlobal'
		}
		for modName, val in pairs(item.modifiers) do
			if Shared.contains(modsDL, modName) then
				table.insert(resultPart, '[[Category:Double Loot Chance Items]]')
				break
			end
		end
	end
	return table.concat(resultPart)
end

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

	return p._getItemCategories(item)
end

function p.getSkillcapeTable(frame)
	local skillName = frame.args ~= nil and frame.args[1] or frame
	local cape = p.getItem(skillName..' Skillcape')
	if cape == nil then
		return ''
	else
		local resultPart = {}
		table.insert(resultPart, '{| class="wikitable"\r\n')
		table.insert(resultPart, '!Skillcape!!Name!!Effect')
		table.insert(resultPart, '\r\n|-\r\n|'..Icons.Icon({cape.name, type='item', size='60', notext=true}))
		table.insert(resultPart, '||'..Icons.Icon({cape.name, type='item', noicon=true})..'||'..cape.description)
		table.insert(resultPart, '\r\n|}')
		return table.concat(resultPart)
	end
end

function p.getItemGrid(frame)
	local resultPart = {}
	table.insert(resultPart, '{|')
	for i, item in Shared.skpairs(ItemData.Items) do
		if i % 17 == 1 then
			table.insert(resultPart, '\r\n|-\r\n|')
		else
			table.insert(resultPart, '||')
		end
		table.insert(resultPart, 'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'}))
	end
	table.insert(resultPart, '\r\n|}')
	return table.concat(resultPart)
end

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

	local ico = {
		["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
		["Combat"] = Icons.Icon({'Combat', notext=true}),
		["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
		["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
		["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
		["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
		["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
	}
	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Weapon Stats')
	table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats')
	table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Speed')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. Shared.round(p._getItemStat(item, 'attackSpeed', true) / 1000, 3, 1) .. 's')
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Type')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'attackType'))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true))
	table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Other')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Slayer'] .. ' Bonus Slayer XP')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slayerBonusXP', true) .. '%')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Attack'] .. ' Level Required')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'attackLevelRequired', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Level Required')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedLevelRequired', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Level Required')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicLevelRequired', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
	table.insert(resultPart, '\r\n!style="text-align:right;"| Two Handed?')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. (p._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No'))

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

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

	local ico = {
		["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
		["Combat"] = Icons.Icon({'Combat', notext=true}),
		["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
		["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
		["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
		["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
		["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
	}
	local resultPart = {}
	table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Armour Stats')
	table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats')
	table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', 0))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true))
	table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Other')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Slayer'] .. ' Bonus Slayer XP')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slayerBonusXP', true) .. '%')

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Level Required')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'defenceLevelRequired', true))

	table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Level Required')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedLevelRequired', true))

	table.insert(resultPart, '\r\n|-\r\n| colspan="2"|')
	table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Level Required')
	table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicLevelRequired', true))

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

function p.getItemDataExport(frame)
	local resultTable = mw.html.create('table')
	resultTable:addClass('wikitable')
	resultTable:tag('tr'):addClass('headerRow-0')
		:tag('th'):wikitext('ItemID'):done()
		:tag('th'):wikitext('ItemName'):done()
		:tag('th'):wikitext('GPValue'):done()
	
	for i, item in ipairs(ItemData.Items) do
		resultTable:tag('tr')
			:tag('td'):wikitext(item.id):done()
			:tag('td'):wikitext(item.name):done()
			:tag('td'):wikitext(item.sellsFor):done()
	end
	return tostring(resultTable)
end

return p