Difference between revisions of "Module:Items"

From Melvor Idle
(GemTable is now a module level variable)
(Added a check for level requirements to the 'hasCombatStats' check for autoarmourstats just to be safe)
(46 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', 'Abnormal Log', 'Red Herring', 'Cool Glasses'}
local OtherShopItems = {'Cooking Gloves', 'Mining Gloves', 'Gem Gloves', 'Smithing Gloves', 'Thieving Gloves'}
+
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)'}
 +
p.OtherShopItems = {'Cooking Gloves', 'Mining Gloves', 'Gem Gloves', 'Smithing Gloves', 'Thieving Gloves'}
 
--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
p.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
 
--The number of different fishing junk items
local junkCount = 8
+
p.junkCount = 8
 
--Items (aside from bars & gems) which can be created via Alt Magic
 
--Items (aside from bars & gems) which can be created via Alt Magic
local AltMagicProducts = {'Rune Essence', 'Bones', 'Holy Dust'}
+
p.AltMagicProducts = {'Rune Essence', 'Bones', 'Holy Dust'}
 
--The kinds of gloves with cost & charges
 
--The kinds of gloves with cost & charges
 
p.GloveTable = {['Cooking Gloves'] = {cost=50000, charges=500},
 
p.GloveTable = {['Cooking Gloves'] = {cost=50000, charges=500},
                    ['Mining Gloves'] = {cost=75000, charges=500},
+
['Mining Gloves'] = {cost=75000, charges=500},
                    ['Smithing Gloves'] = {cost=100000, charges=500},
+
['Smithing Gloves'] = {cost=100000, charges=500},
                    ['Thieving Gloves'] = {cost=100000, charges=500},
+
['Thieving Gloves'] = {cost=100000, charges=500},
                    ['Gem Gloves'] = {cost=500000, charges=2000}}
+
['Gem Gloves'] = {cost=500000, charges=2000}}
  
  
Line 41: Line 48:
  
 
function p.buildSpecialFishingTable()
 
function p.buildSpecialFishingTable()
  --This shouldn't ever be included in a page
+
--This shouldn't ever be included in a page
  --This is for generating the above 'specialFishLoot' variable if it ever needs to change
+
--This is for generating the above 'specialFishLoot' variable if it ever needs to change
  --To re-run, edit the module, type in "console.log(p.buildSpecialFishingTable())" and copy+paste the result as the new value of the variable
+
--To re-run, edit the module, type in "console.log(p.buildSpecialFishingTable())" and copy+paste the result as the new value of the variable
  --Also gives you the total fishing weight for saving time later
+
--Also gives you the total fishing weight for saving time later
  local lootArray = {}
+
local lootArray = {}
  local totalWt = 0
+
local totalWt = 0
  
  for i, item in pairs(ItemData.Items) do
+
for i, item in pairs(ItemData.Items) do
    if item.fishingCatchWeight ~= nil then
+
if item.fishingCatchWeight ~= nil then
      totalWt = totalWt + item.fishingCatchWeight
+
totalWt = totalWt + item.fishingCatchWeight
      table.insert(lootArray, '{'..(i - 1)..', '..item.fishingCatchWeight..'}')
+
table.insert(lootArray, '{'..(i - 1)..', '..item.fishingCatchWeight..'}')
    end
+
end
  end
+
end
  
  local result = 'p.specialFishWt = '..totalWt..'\r\n'
+
local result = 'p.specialFishWt = '..totalWt..'\r\n'
  result = result..'p.specialFishLoot = {'..table.concat(lootArray, ', ')..'}'
+
result = result..'p.specialFishLoot = {'..table.concat(lootArray, ', ')..'}'
  return result
+
return result
end
 
 
 
function p.getSpecialAttackByID(ID)
 
  local result = Shared.clone(ItemData.SpecialAttacks[ID + 1])
 
  if result ~= nil then
 
    result.id = ID
 
  end
 
  return result
 
 
end
 
end
  
 
function p.getItemByID(ID)
 
function p.getItemByID(ID)
  local result = Shared.clone(ItemData.Items[ID + 1])
+
local result = Shared.clone(ItemData.Items[ID + 1])
  if result ~= nil then
+
if result ~= nil then
    result.id = ID
+
result.id = ID
  end
+
end
  return result
+
return result
 
end
 
end
  
 
function p.getItem(name)
 
function p.getItem(name)
  local result = nil
+
local result = nil
  name = string.gsub(name, "%%27", "'")
+
name = string.gsub(name, "%%27", "'")
  name = string.gsub(name, "'", "'")
+
name = string.gsub(name, "'", "'")
  name = string.gsub(name, "'", "'")
+
for i, item in pairs(ItemData.Items) do
  for i, item in pairs(ItemData.Items) do
+
local itemName = string.gsub(item.name, '#', '')
    local itemName = string.gsub(item.name, '#', '')
+
if name == itemName then
    if(name == itemName) then
+
result = Shared.clone(item)
      result = Shared.clone(item)
+
--Make sure every item has an id, and account for Lua being 1-index
      --Make sure every item has an id, and account for Lua being 1-index
+
result.id = i - 1
      result.id = i - 1
+
break
      break
+
end
    end
+
end
  end
+
return result
  return result
 
 
end
 
end
  
 
function p.getItems(checkFunc)
 
function p.getItems(checkFunc)
  local result = {}
+
local result = {}
  for i, item in pairs(ItemData.Items) do
+
for i, item in pairs(ItemData.Items) do
    if checkFunc(item) then
+
if checkFunc(item) then
      local newItem = Shared.clone(item)
+
local newItem = Shared.clone(item)
      newItem.id = i - 1
+
newItem.id = i - 1
      table.insert(result, newItem)
+
table.insert(result, newItem)
    end
+
end
  end
+
end
  return result
+
return result
 
end
 
end
  
 
function p._getItemStat(item, StatName, ZeroIfNil)
 
function p._getItemStat(item, StatName, ZeroIfNil)
  local result = item[StatName]
+
local result = item[StatName]
  --Special Overrides:
+
--Special Overrides:
  if StatName == 'stabAttackBonus' then
+
-- Equipment stats first
    if item.attackBonus == nil then  
+
if Shared.contains(ItemData.EquipmentStatKeys, StatName) and item.equipmentStats ~= nil then
      result = nil
+
result = item.equipmentStats[StatName]
    else
+
elseif StatName == 'isTwoHanded' then
      result = item.attackBonus[1]
+
if item.validSlots ~= nil and item.occupiesSlots ~= nil then
    end
+
result = Shared.contains(item.validSlots, 'Weapon') and Shared.contains(item.occupiesSlots, 'Shield')
  elseif StatName == 'slashAttackBonus' then
+
else
    if item.attackBonus == nil then  
+
result = false
      result = nil
+
end
    else
+
elseif string.find(StatName, '^(.+)LevelRequired$') ~= nil and item.equipRequirements ~= nil and item.equipRequirements.Level ~= nil then
      result = item.attackBonus[2]
+
local skillName = Shared.titleCase(string.match(StatName, '^(.+)LevelRequired$'))
    end
+
if skillName ~= nil then
  elseif StatName == 'blockAttackBonus' then
+
local skillID = Constants.getSkillID(skillName)
    if item.attackBonus == nil then  
+
if skillID ~= nil then
      result = nil
+
result = item.equipRequirements.Level[skillID]
    else
+
end
      result = item.attackBonus[3]
+
end
    end
+
elseif StatName == 'attackType' then
  elseif StatName == 'attackType' then
+
result = p._getWeaponAttackType(item)
    result = p._getWeaponAttackType(item)
+
elseif StatName == 'description' then
  elseif StatName == 'description' then
+
result = item.description
    result = item.description
+
if result == nil or result == '' then result = 'No Description' end
    if result == nil or result == '' then result = 'No Description' end
+
elseif StatName == 'completionReq' then
  end
+
if item.ignoreCompletion == nil or not item.ignoreCompletion then
  if result == nil and ZeroIfNil then result = 0 end
+
result = 'Yes'
  return result
+
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
 
end
  
 
function p.getItemStat(frame)
 
function p.getItemStat(frame)
  local args = frame.args ~= nil and frame.args or frame
+
local args = frame.args ~= nil and frame.args or frame
  local ItemName = args[1]
+
local ItemName = args[1]
  local StatName = args[2]
+
local StatName = args[2]
  local ZeroIfNil = args.ForceZero ~= nil and args.ForceZero ~= '' and args.ForceZero ~= 'false'
+
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 formatNum = args.formatNum ~= nil and args.formatNum ~= '' and args.formatNum ~= 'false'
  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
  local result = p._getItemStat(item, StatName, ZeroIfNil)
+
local result = p._getItemStat(item, StatName, ZeroIfNil)
  if formatNum then result = Shared.formatnum(result) end
+
if formatNum then result = Shared.formatnum(result) end
  return result
+
return result
 
end
 
end
  
function p._getWeaponAttackType(item)
+
--Gets the value of a given modifier for a given item
  if item.type == 'Weapon' then
+
--asString is false by default, when true it writes the full bonus text
    return Icons.Icon({'Melee', nolink='true'})
+
function p._getItemModifier(item, modifier, skill, asString)
  elseif item.type == 'Ranged Weapon' then
+
if asString == nil then asString = false end
    return Icons.Icon({'Ranged', type='skill', nolink='true'})
+
if skill == '' then
  elseif item.type == 'Magic Staff' or item.type == 'Magic Wand' then
+
skill = nil
    return Icons.Icon({'Magic', type='skill', nolink='true'})
+
elseif type(skill) == 'string' then
  else
+
skill = Constants.getSkillID(skill)
    return "Invalid"
+
end
  end
+
 
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
  
function p.getWeaponAttackType(frame)
+
if asString then
  local itemName = frame.args ~= nil and frame.args[1] or frame
+
if skill ~= nil then
  local item = p.getItem(itemName)
+
return Constants._getModifierText(modifier, {skill, result})
  if item == nil then
+
else
    return "ERROR: No item named "..ItemName.." exists in the data module"
+
return Constants._getModifierText(modifier, result)
  end
+
end
  return p._getWeaponAttackType(item)
+
else
 +
return result
 +
end
 
end
 
end
  
function p.getPotionTable(frame)
+
function p.hasCombatStats(item)
  local potionName = frame.args ~= nil and frame.args[1] or frame
+
if item.isEquipment or (item.validSlots == nil and item.equipmentStats ~= nil) then
  local tiers = {'I', 'II', 'III', 'IV'}
+
-- 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
  
  local result = '{| class="wikitable"'
+
function p._hasLevelRequirements(item)
  result = result..'\r\n!Potion!!Tier!!Charges!!Effect'
+
--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
  
  local tier1potion = p.getItem(potionName..' I')
+
function p.getItemModifier(frame)
  for i, tier in pairs(tiers) do
+
local itemName = frame.args ~= nil and frame.args[1] or frame[1]
    local tierName = potionName..' '..tier
+
local modName = frame.args ~= nil and frame.args[2] or frame[2]
    local potion = p.getItemByID(tier1potion.id + i - 1)
+
local skillName = frame.args ~= nil and frame.args[3] or frame[3]
    if potion ~= nil then
+
local asString = frame.args ~= nil and frame.args[4] or frame[4]
      result = result..'\r\n|-'
+
if asString ~= nil then
      result = result..'\r\n|'..Icons.Icon({tierName, type='item', notext='true', size='60'})
+
asString = (string.upper(asString) ~= 'FALSE')
      result = result..'||'..'[['..tierName..'|'..tier..']]'
+
end
      result = result..'||'..potion.potionCharges..'||'..potion.description
 
    end
 
  end
 
  
  result = result..'\r\n|}'
+
local item = p.getItem(itemName)
  return result
+
if item == nil then
end
+
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
 +
end
  
function p.getEquipmentSlotName(id)
+
return p._getItemModifier(item, modName, skillName, asString)
  for slotName, i in Shared.skpairs(Constants.equipmentSlot) do
 
    if i == id then
 
      return slotName
 
    end
 
  end
 
  return 'Invalid'
 
 
end
 
end
  
function p._getOtherItemBoxText(item)
+
function p._getWeaponAttackType(item)
  result = ''
+
if item.isEquipment == true and (item.validSlots ~= nil and Shared.contains(item.validSlots, 'Weapon')) or
  --For equipment, show the slot they go in
+
(item.occupiesSlots ~= nil and Shared.contains(item.occupiesSlots, 'Weapon')) then
  if item.equipmentSlot ~= nil then
+
if Shared.contains({'melee', 'ranged', 'magic'}, item.attackType) then
    result = result..'\r\n|-\r\n|Equipment Slot: '..p.getEquipmentSlotName(item.equipmentSlot)
+
local iconType = item.attackType ~= 'melee' and 'skill' or nil
  end
+
return Icons.Icon({Shared.titleCase(item.attackType), type=iconType, nolink='true'})
  --For weapons with a special attack, show the details
+
end
  if item.hasSpecialAttack then
+
end
    local spAtt = p.getSpecialAttackByID(item.specialAttackID)
+
return 'Invalid'
    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.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)
  local asList = false
+
if item == nil then
  if frame.args ~= nil then
+
return "ERROR: No item named "..ItemName.." exists in the data module[[Category:Pages with script errors]]"
    asList = frame.args.asList ~= nil and frame.args.asList ~= '' and frame.args.asList ~= 'false'
+
end
  end
+
return p._getWeaponAttackType(item)
  if item == nil then
 
    return "ERROR: No item named "..itemName.." exists in the data module"
 
  end
 
 
 
  return p._getOtherItemBoxText(item, asList)
 
 
end
 
end
  
function p.getEquipmentTable(frame)
+
function p.getPotionTable(frame)
  local args = frame.args ~= nil and frame.args or frame
+
local potionName = frame.args ~= nil and frame.args[1] or frame
  local type = args.type
+
local tiers = {'I', 'II', 'III', 'IV'}
  local tier = args.tier
 
  local slotStr = args.slot
 
  local ammoTypeStr = args.ammoType
 
  local category = args.category ~= nil and args.category or 'Combat'
 
  
  --Find out what Ammo Type we're working with
+
local resultPart = {}
  local ammoType = nil
+
table.insert(resultPart, '{| class="wikitable"')
  if ammoTypeStr ~= nil then
+
table.insert(resultPart, '\r\n!Potion!!Tier!!Charges!!Effect')
    if ammoTypeStr == "Arrows" then
 
      ammoType = 0
 
    elseif ammoTypeStr == 'Bolts' then
 
      ammoType = 1
 
    elseif ammoTypeStr == 'Javelins' then
 
      ammoType = 2
 
    elseif ammoTypeStr == 'Throwing Knives' then
 
      ammoType = 3
 
    end
 
  end
 
  
  --Find out what slot we're working with
+
local tier1potion = p.getItem(potionName..' I')
  local slot = nil
+
if tier1potion == nil then
  if slotStr ~= nil then
+
return 'ERROR: No potion named "' .. potionName .. '" was found[[Category:Pages with script errors]]'
    slot = Constants.equipmentSlot[slotStr]
+
end
  end
+
for i, tier in pairs(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
  
  --Getting some lists set up here that will be used later
+
table.insert(resultPart, '\r\n|}')
  --First, the list of columns used by both weapons & armour
+
return table.concat(resultPart)
  local statColumns = {'stabAttackBonus', 'slashAttackBonus','blockAttackBonus','rangedAttackBonus', 'magicAttackBonus', 'strengthBonus', 'rangedStrengthBonus', 'magicDamageBonus', 'defenceBonus', 'rangedDefenceBonus', 'magicDefenceBonus', 'damageReduction', 'attackLevelRequired', 'defenceLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}
+
end
  --Then the lists for just weapons/just armour
 
  --Then the list of weapon types
 
  local weaponTypes = {'Magic Staff', 'Magic Wand', 'Ranged Weapon', 'Weapon'}
 
  
  local isWeaponType = Shared.contains(weaponTypes, type)
+
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',
 +
["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
  
  --Now we need to figure out which items are in this list
+
function p.getOtherItemBoxText(frame)
  local itemList = {}
+
local itemName = frame.args ~= nil and frame.args[1] or frame
  for i, itemBase in pairs(ItemData.Items) do
+
local item = p.getItem(itemName)
    local item = Shared.clone(itemBase)
+
local asList = false
    item.id = i - 1
+
if frame.args ~= nil then
    local listItem = false
+
asList = frame.args.asList ~= nil and frame.args.asList ~= '' and frame.args.asList ~= 'false'
    if isWeaponType then
+
end
    listItem = item.type == type and item.category == category
+
if item == nil then
      if ammoType ~= nil then listItem = listItem and item.ammoTypeRequired == ammoType end
+
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
    else
+
end
      --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)
 
  local ignoreColumns = Shared.clone(statColumns)
 
  for i, item in pairs(itemList) do
 
    local ndx = 1
 
    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)
 
  local attBonusCols = 5
 
  local strBonusCols = 2
 
  local defBonusCols = 3
 
  local lvlReqCols = 4
 
  local ndx = 1
 
  while Shared.tableCount(statColumns) >= ndx do
 
    local colName = statColumns[ndx]
 
    if Shared.contains(ignoreColumns, colName) then
 
      if Shared.contains(colName, 'AttackBonus') then attBonusCols = attBonusCols - 1 end
 
      if Shared.contains(colName, 'trengthBonus') then strBonusCols = strBonusCols - 1 end
 
      if Shared.contains(colName, 'efenceBonus') then defBonusCols = defBonusCols - 1 end
 
      if Shared.contains(colName, 'LevelRequired') then lvlReqCols = lvlReqCols - 1 end
 
      table.remove(statColumns, ndx)
 
    else
 
      ndx = ndx + 1
 
    end
 
  end
 
 
 
 
 
  --Alright, let's start the table by building the shared header
 
  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)
 
  for i, item in pairs(itemList) do
 
    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 = 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|}'
+
return p._getOtherItemBoxText(item, asList)
  return result
 
 
end
 
end
  
 
function p._getItemCategories(item)
 
function p._getItemCategories(item)
  local result = ''
+
local resultPart = {}
  if item.category ~= nil then result = result..'[[Category:'..item.category..']]' end
+
if item.category ~= nil then table.insert(resultPart, '[[Category:'..item.category..']]') end
  if item.type ~= nil then result = result..'[[Category:'..item.type..']]' end
+
if item.type ~= nil then table.insert(resultPart, '[[Category:'..item.type..']]') end
  return result
+
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
 
end
  
 
function p.getItemCategories(frame)
 
function p.getItemCategories(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._getItemCategories(item)
+
return p._getItemCategories(item)
 
end
 
end
  
 
function p.getSkillcapeTable(frame)
 
function p.getSkillcapeTable(frame)
  local skillName = frame.args ~= nil and frame.args[1] or frame
+
local skillName = frame.args ~= nil and frame.args[1] or frame
  local cape = p.getItem(skillName..' Skillcape')
+
local cape = p.getItem(skillName..' Skillcape')
  local result = '{| class="wikitable"\r\n'
+
local resultPart = {}
  result = result..'!Skillcape!!Name!!Effect'
+
table.insert(resultPart, '{| class="wikitable"\r\n')
  result = result..'\r\n|-\r\n|'..Icons.Icon({cape.name, type='item', size='60', notext=true})
+
table.insert(resultPart, '!Skillcape!!Name!!Effect')
  result = result..'||[['..cape.name..']]||'..cape.description
+
table.insert(resultPart, '\r\n|-\r\n|'..Icons.Icon({cape.name, type='item', size='60', notext=true}))
  result = result..'\r\n|}'
+
table.insert(resultPart, '||'..Icons.Icon({cape.name, type='item', noicon=true})..'||'..cape.description)
  return result
+
table.insert(resultPart, '\r\n|}')
 +
return table.concat(resultPart)
 
end
 
end
  
function p.getShopSkillcapeTable()
+
function p.getItemGrid(frame)
  local result = ''
+
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
  
  local capeList = {}
+
function p.getSpecialAttackTable(frame)
  for i, item in pairs(ItemData.Items) do
+
local spAttTable = {}
    if Shared.contains(item.name, 'Skillcape') or item.name == 'Cape of Completion' then
 
      table.insert(capeList, item)
 
    end
 
  end
 
  
  result = result..'\r\n{|class="wikitable sortable"'
+
for i, item in Shared.skpairs(ItemData.Items) do
  result = result..'\r\n!colspan="2" style="width:200px"|Cape'
+
if item.hasSpecialAttack then
  result = result..'!!Description!!style="width:120px"|Price'
+
for i, spAtt in ipairs(item.specialAttacks) do
 +
if spAttTable[spAtt.id] == nil then spAttTable[spAtt.id] = {sortName=item.name, defn = spAtt, Icons = {}} end
 +
table.insert(spAttTable[spAtt.id].Icons, Icons.Icon({item.name, type='item'}))
 +
end
 +
end
 +
end
  
  --Sort the table by cost and then name
+
local resultPart = {}
  table.sort(capeList, function(a, b)  
+
table.insert(resultPart, '{|class="wikitable sortable stickyHeader"')
                        if a.buysFor == b.buysFor then
+
table.insert(resultPart, '\r\n|-class="headerRow-0"')
                          return a.name < b.name
+
table.insert(resultPart, '\r\n!style="min-width:180px"|Weapon(s)!!Name!!Chance!!Effect')
                        else
+
for i, spAttData in Shared.skpairs(spAttTable) do
                          return a.sellsFor < b.buysFor
+
local spAtt = spAttData.defn
                        end
+
table.sort(spAttData.Icons, function(a, b) return a < b end)
                      end)
+
table.insert(resultPart, '\r\n|-')
  for i, thisItem in pairs(capeList) do
+
table.insert(resultPart, '\r\n|data-sort-value="'..spAttData.sortName..'"|'..table.concat(spAttData.Icons, '<br/>'))
    result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item', size='50', notext=true})
+
table.insert(resultPart, '||'..spAtt.name..'||data-sort-value="'..spAtt.defaultChance..'"|'..spAtt.defaultChance..'%')
    result = result..'||[['..thisItem.name..']]'
+
table.insert(resultPart, '||'..spAtt.description)
    result = result..'\r\n||'..thisItem.description
+
end
    result = result..'||style="text-align:left" data-sort-value="'..thisItem.buysFor..'"'
+
table.insert(resultPart, '\r\n|}')
    result = result..'|'..Icons.GP(thisItem.buysFor)
 
  end
 
  result = result..'\r\n|}'
 
  
  return result
+
return table.concat(resultPart)
 
end
 
end
  
function p.getItemGrid(frame)
+
function p.getWeaponStatsBox(frame)
  result = '{|'
+
local itemName = frame.args ~= nil and frame.args[1] or frame
  for i, item in Shared.skpairs(ItemData.Items) do
+
local item = p.getItem(itemName)
    if i % 17 == 1 then
+
if item == nil then
      result = result..'\r\n|-\r\n|'
+
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
    else
+
end
      result = result..'||'
+
    end
+
local ico = {
    result = result..'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'})
+
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
  end
+
["Combat"] = Icons.Icon({'Combat', notext=true}),
  result = result..'\r\n|}'
+
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
  return result
+
["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
 
end
  
 
return p
 
return p

Revision as of 00:45, 12 January 2022

Lua module for generating various item tables. Pulls data from Module:Items/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)'}
p.OtherShopItems = {'Cooking Gloves', 'Mining Gloves', 'Gem Gloves', 'Smithing Gloves', 'Thieving Gloves'}
--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
--The number of different fishing junk items
p.junkCount = 8
--Items (aside from bars & gems) which can be created via Alt Magic
p.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}}


p.specialFishWt = 6722
p.specialFishLoot = {{128, 2000}, {129, 1600}, {130, 1400}, {131, 1000}, {132, 400}, {667, 10}, {668, 10}, {902, 1}, {670, 1}, {669, 50}, {120, 250}}

function p.buildSpecialFishingTable()
	--This shouldn't ever be included in a page
	--This is for generating the above 'specialFishLoot' variable if it ever needs to change
	--To re-run, edit the module, type in "console.log(p.buildSpecialFishingTable())" and copy+paste the result as the new value of the variable
	--Also gives you the total fishing weight for saving time later
	local lootArray = {}
	local totalWt = 0

	for i, item in pairs(ItemData.Items) do
		if item.fishingCatchWeight ~= nil then
			totalWt = totalWt + item.fishingCatchWeight
			table.insert(lootArray, '{'..(i - 1)..', '..item.fishingCatchWeight..'}')
		end
	end

	local result = 'p.specialFishWt = '..totalWt..'\r\n'
	result = result..'p.specialFishLoot = {'..table.concat(lootArray, ', ')..'}'
	return result
end

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 pairs(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 = {}
	for i, item in pairs(ItemData.Items) do
		if checkFunc(item) then
			local newItem = Shared.clone(item)
			newItem.id = i - 1
			table.insert(result, 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 pairs(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',
			["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')
	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

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.getSpecialAttackTable(frame)
	local spAttTable = {}

	for i, item in Shared.skpairs(ItemData.Items) do
		if item.hasSpecialAttack then
			for i, spAtt in ipairs(item.specialAttacks) do
				if spAttTable[spAtt.id] == nil then spAttTable[spAtt.id] = {sortName=item.name, defn = spAtt, Icons = {}} end
				table.insert(spAttTable[spAtt.id].Icons, Icons.Icon({item.name, type='item'}))
			end
		end
	end

	local resultPart = {}
	table.insert(resultPart, '{|class="wikitable sortable stickyHeader"')
	table.insert(resultPart, '\r\n|-class="headerRow-0"')
	table.insert(resultPart, '\r\n!style="min-width:180px"|Weapon(s)!!Name!!Chance!!Effect')
	for i, spAttData in Shared.skpairs(spAttTable) do
		local spAtt = spAttData.defn
		table.sort(spAttData.Icons, function(a, b) return a < b end)
		table.insert(resultPart, '\r\n|-')
		table.insert(resultPart, '\r\n|data-sort-value="'..spAttData.sortName..'"|'..table.concat(spAttData.Icons, '<br/>'))
		table.insert(resultPart, '||'..spAtt.name..'||data-sort-value="'..spAtt.defaultChance..'"|'..spAtt.defaultChance..'%')
		table.insert(resultPart, '||'..spAtt.description)
	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

return p