Anonymous

Module:Items: Difference between revisions

From Melvor Idle
Add gem link to gem equipment slot
(Add some more recent Easter Egg items)
(Add gem link to gem equipment slot)
(75 intermediate revisions by 4 users not shown)
Line 6: Line 6:
local p = {}
local p = {}


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


p.EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon', 'Easter Egg', 'Abnormal Log', 'Red Herring'}
p.EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon', 'Easter Egg',
p.OtherShopItems = {'Cooking Gloves', 'Mining Gloves', 'Gem Gloves', 'Smithing Gloves', 'Thieving Gloves'}
'Abnormal Log', 'Red Herring', 'Cool Glasses'}
--This is hardcoded, so there's no easy way to scrape it. Hopefully it doesn't change
p.EventItems = {'Christmas Cracker', 'Christmas Coal', 'Christmas Sweater',
p.GemTable = {["Topaz"] = {name = 'Topaz', id = 128, chance = 50},  
'Christmas Wreath', 'Candy Cane', 'Santa Hat',
                  ["Sapphire"] = {name = "Sapphire", id = 129, chance = 17.5},  
'Friendship Bracelet', 'Event Clue 1', 'Event Clue 2',
                  ["Ruby"] = {name = "Ruby", id = 130, chance = 17.5},  
'Event Clue 3', 'Event Clue 4', 'Candle', 'Cake Base',
                  ["Emerald"] = {name = "Emerald", id = 131, chance = 10},  
'Magical Flavouring', 'Magical Icing', 'Birthday Cake',
                  ["Diamond"] = {name = "Diamond", id = 132, chance = 5}}
'Purple Party Hat', 'Birthday Token', 'Christmas Present (Yellow)',
--The base chance to receive a gem while mining
'Christmas Present (Blue)', 'Christmas Present (Green)', 'Christmas Present (White)',
p.GemChance = .01
'Christmas Present (Purple)', 'Christmas Present (Standard)', 'Event Token - Holiday 2021',
--The number of different fishing junk items
'Holiday Scarf', 'Gingerbread House', 'Gingerbread Man', 'Edible Candy Cane',
p.junkCount = 8
'Locked Chest', 'Locked Chest Key', 'Event Token (Holiday 2021)'}
--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)
return GameData.getEntityByID('items', ID)
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}}
name = string.gsub(name, "%%27", "'")
name = string.gsub(name, "'", "'")
return GameData.getEntityByName('items', name)
end


function p.buildSpecialFishingTable()
function p.getItems(checkFunc)
  --This shouldn't ever be included in a page
return GameData.getEntities('items', checkFunc)
  --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
end


function p.getSpecialAttackByID(ID)
function p._canItemUseSlot(item, equipSlot)
  local result = Shared.clone(ItemData.SpecialAttacks[ID + 1])
--Function to easily check if an item can fit in a given equipment slot
  if result ~= nil then
--Ex: p._canItemUseSlot({Bronze Platebody}, 'Platebody') returns true
    result.id = ID
if type(item) == 'string' then
  end
item = p.getItem(item)
  return result
end
return item.validSlots ~= nil and Shared.contains(item.validSlots, equipSlot)
end
end


function p.getItemByID(ID)
function p._getItemEquipSlot(item)
  local result = Shared.clone(ItemData.Items[ID + 1])
--Function to return the (non-Passive) equipment slot that an item occupies
  if result ~= nil then
if type(item) == 'string' then
    result.id = ID
item = p.getItem(item)
  end
end
  return result
if item == nil or item.validSlots == nil then
return 'Invalid'
end
for i, slot in pairs(item.validSlots) do
if slot ~= 'Passive' then
return slot
end
end
end
end


function p.getItem(name)
function p._getItemStat(item, StatName, ZeroIfNil)
  local result = nil
local result = item[StatName]
  name = string.gsub(name, "%%27", "'")
--Special Overrides:
  name = string.gsub(name, "'", "'")
-- Equipment stats first
  name = string.gsub(name, "'", "'")
if item.equipmentStats ~= nil and item.equipmentStats[StatName] ~= nil then
  for i, item in pairs(ItemData.Items) do
result = item.equipmentStats[StatName]
    local itemName = string.gsub(item.name, '#', '')
elseif StatName == 'attackSpeed' and item.validSlots ~= nil and Shared.contains(item.validSlots, 'Weapon') then
    if(name == itemName) then
-- Item can be equipped as a weapon but has no attack speed, so use default of 4000ms
      result = Shared.clone(item)
result = 4000
      --Make sure every item has an id, and account for Lua being 1-index
elseif StatName == 'isTwoHanded' then
      result.id = i - 1
if item.validSlots ~= nil and item.occupiesSlots ~= nil then
      break
result = Shared.contains(item.validSlots, 'Weapon') and Shared.contains(item.occupiesSlots, 'Shield')
    end
else
  end
result = false
  return result
end
elseif string.find(StatName, '^(.+)LevelRequired$') ~= nil and item.equipRequirements ~= nil then
local skillName = Shared.titleCase(string.match(StatName, '^(.+)LevelRequired$'))
if skillName ~= nil then
local skillID = Constants.getSkillID(skillName)
if skillID ~= nil then
for i, requirement in ipairs(item.equipRequirements) do
if requirement.type == "SkillLevel" and requirement.skillID == skillID then
result = requirement.level
break
end
end
end
end
elseif StatName == 'attackType' then
result = p._getWeaponAttackType(item)
elseif StatName == 'description' then
result = item.customDescription
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))
elseif StatName == 'category' then
-- Some categories have a namespace for some reason, remove it
local _, localID = GameData.getLocalID(result)
return localID
end
if result == nil and ZeroIfNil then result = 0 end
return result
end
end


function p.getItems(checkFunc)
function p.getItemValue(item)
  local result = {}
if type(item) == 'string' then
  for i, item in pairs(ItemData.Items) do
-- Specific check if the item is GP (value of 1)
    if checkFunc(item) then
if Shared.compareString('GP', item, true)  
      local newItem = Shared.clone(item)
or Shared.compareString('Gold Pieces', item, true) then
      newItem.id = i - 1
return 1
      table.insert(result, newItem)
end
    end
  end
  return result
end


function p._getItemStat(item, StatName, ZeroIfNil)
item = p.getItem(item)
  local result = item[StatName]
end
  --Special Overrides:
  if StatName == 'stabAttackBonus' then
if item then
    if item.attackBonus == nil then
return item.sellsFor
      result = nil
end
    else
      result = item.attackBonus[1]
return nil
    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
  elseif StatName == 'completionReq' then
    if item.ignoreCompletion == nil or not item.ignoreCompletion then
      return 'Yes'
    else
      return 'No'
    end
  elseif StatName == 'slayerBonusXP' then
    return p._getItemModifier(item, 'increasedSkillXP', 'Slayer', false)
  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[[Category:Pages with script errors]]"
return Shared.printError('No item named "' .. ItemName .. '" exists in the data module')
  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


--Gets the value of a given modifier for a given item
--Gets the value of a given modifier for a given itemg
--asString is false by default, when true it writes the full bonus text
--asString is false by default, when true it writes the full bonus text
function p._getItemModifier(item, modifier, skill, asString)
function p._getItemModifier(item, modifier, skillID, asString)
  if asString == nil then asString = false end
if asString == nil then asString = false end
  if skill == '' then
if skillID == '' then
    skill = nil
skillID = nil
  elseif type(skill) == 'string' then
elseif string.find(skillID, ':') == nil then
    skill = Constants.getSkillID(skill)
-- Try to find a skill ID if it looks like a skill name has been passed
  end
skillID = Constants.getSkillID(skillID)
 
end
  mw.log(item.name..', '..modifier)


  local result = 0
local result = 0


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


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


function p.hasCombatStats(item)
function p.hasCombatStats(item)
  if item.equipmentSlot == nil then
-- Checks if the combat stat is a valid, non-zero combat stat
    return false
-- Ensure that, only in the case where the item is a Familar AND
  elseif item.equipmentSlot == Constants.getEquipmentSlotID('Weapon') then
-- the checked stat is summoningMaxhit, the result is ignored.
    return true
function isNonZeroStat(statName, statVal)
  end
if statName == 'summoningMaxhit' and (p._canItemUseSlot(item, 'Summon1') or p._canItemUseSlot(item, 'Summon2')) then
return false
end
return statVal ~= 0
end
 
if item.equipmentStats ~= nil then
-- Ensure at least one stat has a non-zero value
for statName, statVal in pairs(item.equipmentStats) do
if isNonZeroStat(statName, statVal) then
return true
end
end
end


  local combatStatList = {'strengthBonus', 'defenceBonus', 'stabAttackBonus', 'slashAttackBonus', 'blockAttackBonus', 'damageReduction',
return false
                          'rangedDefenceBonus', 'magicDefenceBonus', 'rangedAttackBonus', 'rangedStrengthBonus', 'magicAttackBonus', 'magicDamageBonus'}
end
 
  for i, stat in Shared.skpairs(combatStatList) do
    if p._getItemStat(item, stat, true) > 0 then
      return true
    end
  end


  return false
function p._hasLevelRequirements(item)
--Function true if an item has at least one level requirement to equip
if item.equipRequirements ~= nil then
for idx, requirement in ipairs(item.equipRequirements) do
if requirement.type == 'SkillLevel' and requirement.level > 1 then
return true
end
end
end
return false
end
end


function p.getItemModifier(frame)
function p.getItemModifier(frame)
  local itemName = frame.args ~= nil and frame.args[1] or frame[1]
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 modName = frame.args ~= nil and frame.args[2] or frame[2]
  local skillName = frame.args ~= nil and frame.args[3] or frame[3]
local skillName = frame.args ~= nil and frame.args[3] or frame[3]
  local asString = frame.args ~= nil and frame.args[4] or frame[4]
local asString = frame.args ~= nil and frame.args[4] or frame[4]
  if asString ~= nil then
if asString ~= nil then
    if string.upper(asString) == 'FALSE' then
asString = (string.upper(asString) ~= 'FALSE')
    asString = false
end
    else
    asString = true
    end
  end


  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[[Category:Pages with script errors]]"
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
  end
end


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


function p._getWeaponAttackType(item)
function p._getWeaponAttackType(item)
  if item.type == 'Weapon' then
if (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[[Category:Pages with script errors]]"
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
  end
end
  return p._getWeaponAttackType(item)
return p._getWeaponAttackType(item)
end
end


function p.getPotionTable(frame)
local statChangeDefs = {
  local potionName = frame.args ~= nil and frame.args[1] or frame
{
  local tiers = {'I', 'II', 'III', 'IV'}
stat = 'stabAttackBonus',
suffix = ' ' .. Icons.Icon({'Melee', notext=true}) .. ' Stab Bonus'
},
{
stat = 'slashAttackBonus',
suffix =  ' ' .. Icons.Icon({'Melee', notext=true}) .. ' Slash Bonus'
},
{
stat = 'blockAttackBonus',
suffix = ' ' .. Icons.Icon({'Melee', notext=true}) .. ' Block Bonus'
},
{
stat = 'meleeStrengthBonus',
suffix = ' ' .. Icons.Icon({'Strength', type='skill', notext=true}) .. ' Strength Bonus'
},
{
stat = 'rangedStrengthBonus',
suffix =  ' ' .. Icons.Icon({'Ranged', type='skill', notext=true}) .. ' Strength Bonus'
},
{
stat = 'magicStrengthBonus',
suffix = '% ' .. Icons.Icon({'Magic', type='skill', notext=true}) .. ' Damage Bonus'
},
{
stat = 'meleeDefenceBonus',
suffix = ' ' .. Icons.Icon({'Defence', type='skill', notext=true}) .. ' Defence Bonus' },
{
stat = 'rangedDefenceBonus',
suffix = ' ' .. Icons.Icon({'Ranged', type='skill', notext=true}) .. ' Defence Bonus'
},
{
stat = 'magicDefenceBonus',
suffix = ' ' .. Icons.Icon({'Magic', type='skill', notext=true}) .. ' Defence Bonus'
},
{
stat = 'damageReduction',
suffix = '% Damage Reduction'
},
{
stat = 'levelRequired',
suffix = ' Level Required'
}
}


  local result = '{| class="wikitable"'
-- Produces a list of stat & modifier changes between two items of equipmednt
  result = result..'\r\n!Potion!!Tier!!Charges!!Effect'
function p.getStatChangeString(item1, item2)
local changeArray = {}


  local tier1potion = p.getItem(potionName..' I')
local equipStats = {
  for i, tier in pairs(tiers) do
type(item1.equipmentStats) == 'table' and item1.equipmentStats or {},
    local tierName = potionName..' '..tier
type(item2.equipmentStats) == 'table' and item2.equipmentStats or {}
    local potion = p.getItemByID(tier1potion.id + i - 1)
}
    if potion ~= nil then
for i, statDef in ipairs(statChangeDefs) do
      result = result..'\r\n|-'
local val1, val2 = 0, 0
      result = result..'\r\n|'..Icons.Icon({tierName, type='item', notext='true', size='60'})
if statDef.stat == 'levelRequired' then
      result = result..'||'..'[['..tierName..'|'..tier..']]'
-- Iterate over equipment stats for both items, determining level requirements
      result = result..'||'..potion.potionCharges..'||'..potion.description
local levelReqs = {}
    end
for itemNum, item in ipairs({item1, item2}) do
  end
levelReqs[itemNum] = {}
if item.equipRequirements ~= nil then
for j, req in ipairs(item.equipRequirements) do
if req.type == 'SkillLevel' then
levelReqs[itemNum][req.skillID] = req.level
end
end
end
end
-- Iterate over all skills, checking if there are requirements for these in either skill
for j, skillData in ipairs(GameData.rawData.skillData) do
local skillID = skillData.skillID
val1, val2 = levelReqs[1][skillID] or 0, levelReqs[2][skillID] or 0
if val1 ~= val2 then
table.insert(changeArray, Shared.numStrWithSign(val1 - val2) .. ' ' .. Icons.Icon({skillData.data.name, type='skill', notext=true}) .. (statDef.suffix or ''))
end
end
else
-- Equipment stats
val1, val2 = equipStats[1][statDef.stat] or 0, equipStats[2][statDef.stat] or 0
if val1 ~= val2 then
table.insert(changeArray, Shared.numStrWithSign(val1 - val2) .. (statDef.suffix or ''))
end
end
end


  result = result..'\r\n|}'
-- Include differences in modifiers
  return result
local modDiff = Constants.getModifiersText(Constants.getModifiersDifference(item2.modifiers, item1.modifiers))
if modDiff ~= nil and modDiff ~= '' then
table.insert(changeArray, modDiff)
end
 
return table.concat(changeArray, '<br/>')
end
end


function p._getOtherItemBoxText(item)
function p._getOtherItemBoxText(item)
  result = ''
local resultPart = {}
  --For equipment, show the slot they go in
--For equipment, show the slot they go in
  if item.equipmentSlot ~= nil then
local isPassive = false
    result = result.."\r\n|-\r\n|'''Equipment Slot:''' "..Constants.getEquipmentSlotName(item.equipmentSlot)
if item.validSlots ~= nil then
    if item.isPassiveItem then
local slotLinkMap = {
      result = result..', Passive'
["Helmet"] = 'Helmets',
    end
["Platebody"] = 'Platebodies',
  end
["Platelegs"] = 'Platelegs',
  --For weapons with a special attack, show the details
["Boots"] = 'Boots',
  if item.hasSpecialAttack then
["Weapon"] = 'Weapons',
    local spAtt = p.getSpecialAttackByID(item.specialAttackID)
["Shield"] = 'Shields',
    result = result.."\r\n|-\r\n|'''Special Attack:'''"
["Amulet"] = 'Amulets',
    result = result..'\r\n* '..spAtt.chance..'% chance for '..spAtt.name..':'
["Ring"] = 'Rings',
    result = result..'\r\n** '..spAtt.description
["Gloves"] = 'Gloves',
  end
["Quiver"] = 'Ammunition',
  --For potions, show the number of charges
["Cape"] = 'Capes',
  if item.potionCharges ~= nil then
["Consumable"] = 'Consumables',
    result = result.."\r\n|-\r\n|'''Charges:''' "..item.potionCharges
["Passive"] = 'Combat Passive Slot',
  end
["Summon1"] = 'Summoning',
  --For food, show how much it heals for
["Summon2"] = 'Summoning',
  if item.healsFor ~= nil then
["Gem"] = "Gems_(Equipment)"
    result = result.."\r\n|-\r\n|'''Heals for:''' "..Icons.Icon({"Hitpoints", type="skill", notext="true"})..' '..(item.healsFor * 10)
}
  end
local slotText = {}
  --For Prayer Points, show how many you get
for i, slot in ipairs(item.validSlots) do
  if item.prayerPoints ~= nil then
local slotLink = slotLinkMap[slot]
    result = result.."\r\n|-\r\n|'''"..Icons.Icon({'Prayer', type='skill'}).." Points:''' "..item.prayerPoints
if slotLink == nil then
  end
table.insert(slotText, slot)
  --For items with modifiers, show what those are
else
  if item.modifiers ~= nil and Shared.tableCount(item.modifiers) > 0 then
table.insert(slotText, '[[' .. slotLink .. '|' .. slot .. ']]')
    result = result.."\r\n|-\r\n|'''Modifiers:'''\r\n"..Constants.getModifiersText(item.modifiers, true)
end
  end
  return result
if slot == 'Passive' then
isPassive = true
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.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) then
table.insert(resultPart, "\r\n|-\r\n|'''Special Attack:'''")
for i, spAttID in ipairs(item.specialAttacks) do
local spAtt = GameData.getEntityByID('attacks', spAttID)
if spAtt ~= nil then
local spAttChance = spAtt.defaultChance
if type(item.overrideSpecialChances) == 'table' and item.overrideSpecialChances[i] ~= nil then
spAttChance = item.overrideSpecialChances[i]
end
local spAttDesc = string.gsub(spAtt.description, '<Attack> ', '')
table.insert(resultPart, '\r\n* ' .. spAttChance .. '% chance for ' .. spAtt.name .. ':')
table.insert(resultPart, '\r\n** ' .. spAttDesc)
end
end
end
-- For Summoning combat familiars, show the max hit
if item.equipmentStats ~= nil and item.equipmentStats.summoningMaxhit ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''Max Hit:''' " .. Shared.formatnum(item.equipmentStats.summoningMaxhit * 10))
end
--For potions, show the number of charges
if item.charges ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''Charges:''' "..item.charges)
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 that provide runes, show which runes are provided
if item.providedRunes ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''Runes Provided:''' ")
local runeLines = {}
local sortVal = ''
for j, runePair in pairs(item.providedRunes) do
local runeID = runePair.id
local qty = runePair.quantity
local rune = p.getItemByID(runeID)
sortVal = sortVal..rune.name..qty
table.insert(runeLines, Icons.Icon({rune.name, type='item', qty=qty}))
end
table.insert(resultPart, table.concat(runeLines, ', '))
end
--For items with modifiers, show what those are
if item.modifiers ~= nil and not Shared.tableIsEmpty(item.modifiers) then
table.insert(resultPart, "\r\n|-\r\n|'''Modifiers:'''\r\n")
if isPassive then
table.insert(resultPart, '<span style="color:green">Passive:</span><br/>')
end
table.insert(resultPart, Constants.getModifiersText(item.modifiers, true, false, 10))
end
return table.concat(resultPart)
end
end


function p.getOtherItemBoxText(frame)
function p.getOtherItemBoxText(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 Shared.printError('No item named "' .. itemName .. '" exists in the data module')
    asList = frame.args.asList ~= nil and frame.args.asList ~= '' and frame.args.asList ~= 'false'
end
  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)
return p._getOtherItemBoxText(item)
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
local isEquipment = item.validSlots ~= nil or item.occupiesSlots ~= nil or item.equipmentStats ~= nil
  if item.type ~= nil then result = result..'[[Category:'..item.type..']]' end
local category = p._getItemStat(item, 'category', false)
  if item.tier ~= nil then result = result..'[[Category:'..Shared.titleCase(item.tier)..' '..item.type..']]' end
if category ~= nil and category ~= 'Skills' then
  if item.hasSpecialAttack then result = result..'[[Category:Items With Special Attacks]]' end
table.insert(resultPart, '[[Category:'..category..']]')
  if item.isPassiveItem then result = result..'[[Category:Passive Items]]' end
end
  if item.chanceToDoubleLoot ~= nil and item.chanceToDoubleLoot > 0 then result = result..'[[Category:Double Loot Chance Items]]' end
if item.type ~= nil then
  return result
table.insert(resultPart, '[[Category:'..item.type..']]')
end
if isEquipment and item.tier ~= nil then
table.insert(resultPart, '[[Category:'..Shared.titleCase(item.tier)..' '..item.type..']]')
end
if item.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) 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[[Category:Pages with script errors]]"
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
  end
end
 
return p._getItemCategories(item)
end
 
function p.getItemGrid(frame)
local resultPart = {}
table.insert(resultPart, '{|')
for i, item in ipairs(GameData.rawData.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


  return p._getItemCategories(item)
function p.getEquipRequirementRow(req)
local result = ""
if req.type == "SkillLevel" then
local skillName = Constants.getSkillName(req.skillID)
local skillIcon = Icons.Icon({skillName, type='skill', notext=true})
result = '\r\n!style="text-align:right;"| '..skillIcon..' Level Required'
result = result..'\r\n|style="text-align:right;"| '..req.level
elseif req.type == "DungeonCompletion" then
local dungeonName = GameData.getEntityByID("dungeons", req.dungeonID).name
local dungeonIcon = Icons.Icon({dungeonName, type="dungeon", notext=true})
result = '\r\n!style="text-align:right;"| '..dungeonIcon..' Completions'
result = result..'\r\n|style="text-align:right;"| '..req.count
elseif req.type == "Completion" then
local ns = GameData.getEntityByName('namespaces', req.namespace)
if ns == nil then
return '\r\n!style="text-align:right;" colspan=2|' .. Shared.printError('Invalid namespace for completion requirement "' .. req.namespace .. '"')
else
result = '\r\n!style="text-align:right;"| ' .. ns.displayName .. ' Completion'
result = result .. '\r\n|style="text-align:right;"| ' .. req.percent .. '%'
end
else
return '\r\n!style="text-align:right;" colspan=2|' .. Shared.printError('Invalid equip requirement type "' .. req.type .. '"')
end
return result
end
end


function p.getSkillcapeTable(frame)
function p.getWeaponStatsBox(frame)
  local skillName = frame.args ~= nil and frame.args[1] or frame
local itemName = frame.args ~= nil and frame.args[1] or frame
  local cape = p.getItem(skillName..' Skillcape')
local item = p.getItem(itemName)
  local result = '{| class="wikitable"\r\n'
if item == nil then
  result = result..'!Skillcape!!Name!!Effect'
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
  result = result..'\r\n|-\r\n|'..Icons.Icon({cape.name, type='item', size='60', notext=true})
end
  result = result..'||[['..cape.name..']]||'..cape.description
 
  result = result..'\r\n|}'
local ico = {
  return result
["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 reqCount = item.equipRequirements ~= nil and Shared.tableCount(item.equipRequirements) or 0
local emptyRow = '\r\n!colspan="2"|'
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;"| Equip Requirements')
 
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))
if reqCount > 0 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[1]))
else
table.insert(resultPart, '\r\n|colspan=2 style="text-align:right"|None')
end
 
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))
if reqCount > 1 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[2]))
else
table.insert(resultPart, emptyRow)
end
 
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))
if reqCount > 2 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[3]))
else
table.insert(resultPart, emptyRow)
end
 
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))
if reqCount > 3 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[4]))
else
table.insert(resultPart, emptyRow)
end
 
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) .. '%')
if reqCount > 4 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[5]))
else
table.insert(resultPart, emptyRow)
end
table.insert(resultPart, '\r\n|-\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'))
if reqCount > 5 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[6]))
else
table.insert(resultPart, emptyRow)
end
--Add extra rows at the end for items that have more than 3 different requirements
if reqCount > 6 then
for i = 7, reqCount, 1 do
table.insert(resultPart,"\r\n|-")
table.insert(resultPart, emptyRow)
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[i]))
end
end
 
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
end


function p.getShopSkillcapeTable()
function p.getArmourStatsBox(frame)
  local result = ''
local itemName = frame.args ~= nil and frame.args[1] or frame
local item = p.getItem(itemName)
if item == nil then
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
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 reqCount = item.equipRequirements ~= nil and Shared.tableCount(item.equipRequirements) or 0
local emptyRow = '\r\n!colspan="2"|'
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;"| Equip Requirements')
 
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))
if reqCount > 0 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[1]))
else
table.insert(resultPart, '\r\n|colspan=2 style="text-align:right"|None')
end
 
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))
if reqCount > 1 then
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[2]))
else
table.insert(resultPart, emptyRow)
end


  local capeList = {}
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
  for i, item in pairs(ItemData.Items) do
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
    if Shared.contains(item.name, 'Skillcape') or item.name == 'Cape of Completion' then
if reqCount > 2 then
      table.insert(capeList, item)
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[3]))
    end
else
  end
table.insert(resultPart, emptyRow)
end
--Add extra rows at the end for items that have more than 3 different requirements
if reqCount > 3 then
for i = 4, reqCount, 1 do
table.insert(resultPart, "\r\n|-")
table.insert(resultPart, emptyRow)
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[i]))
end
end


  result = result..'\r\n{|class="wikitable sortable"'
table.insert(resultPart, '\r\n|}')
  result = result..'\r\n!colspan="2" style="width:200px"|Cape'
return table.concat(resultPart)
  result = result..'!!Description!!style="width:120px"|Price'
end


  --Sort the table by cost and then name
function p.getItemDataExport(frame)
  table.sort(capeList, function(a, b)  
local resultTable = mw.html.create('table')
                        if a.buysFor == b.buysFor then
resultTable:addClass('wikitable')
                          return a.name < b.name
resultTable:tag('tr'):addClass('headerRow-0')
                        else
:tag('th'):wikitext('ItemID'):done()
                          return a.sellsFor < b.buysFor
:tag('th'):wikitext('ItemName'):done()
                        end
:tag('th'):wikitext('GPValue'):done()
                      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
for i, item in ipairs(GameData.rawData.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
end


function p.getItemGrid(frame)
--Returns the expansion icon for the item if it has one
  result = '{|'
function p.getExpansionIcon(frame)
  for i, item in Shared.skpairs(ItemData.Items) do
local itemName = frame.args ~= nil and frame.args[1] or frame
    if i % 17 == 1 then
local item = p.getItem(itemName)
      result = result..'\r\n|-\r\n|'
if item == nil then
    else
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
      result = result..'||'
end
    end
 
    result = result..'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'})
return Icons.getExpansionIcon(item.id)
  end
end
  result = result..'\r\n|}'
 
  return result
function p.buildSmithableArmourNav(frame)
local resultPart = {}
table.insert(resultPart, '{| class="wikitable mw-collapsible navigation-not-searchable" style="margin:auto; clear:both; width: 100%"')
table.insert(resultPart, '\r\n!colspan = 2 style="background-color:#275C87;color:#FFFFFF;min-width:730px;"|')
table.insert(resultPart, Icons.Icon({'Smithing', type='skill', notext=true}))
table.insert(resultPart, ' Smithable Armour Sets')
 
local metalTypes = {'Bronze', 'Iron', 'Steel', 'Mithril', {'Adamant', 'Adamantite'}, {'Rune', 'Runite'}, {'Dragon', 'Dragonite'},
{'Corundum', 'Corundumite', TotH = true}, {'Augite', 'Augite', TotH = true}, {'Divine', 'Divinite', TotH = true}}
local pieces = {"Helmet", "Platebody", "Platelegs", "Boots", "Shield"}
for i, metal in ipairs(metalTypes) do
local metalName, barName
local isTotH = false
if type(metal) == 'table' then
metalName = metal[1]
barName = metal[2]..' Bar'
isTotH = metal.TotH ~= nil and metal.TotH
else
metalName = metal
barName = metal..' Bar'
end
table.insert(resultPart, '\r\n|-\r\n!')
if isTotH then
table.insert(resultPart, Icons.TotH())
end
table.insert(resultPart, Icons.Icon({barName, type="item", notext=true}))
table.insert(resultPart, " "..metalName)
table.insert(resultPart, "\r\n|")
 
for j, piece in ipairs(pieces) do
if j > 1 then
table.insert(resultPart, ' ')
end
table.insert(resultPart, '<span style="display:inline-block">')
table.insert(resultPart, Icons.Icon({metalName..' '..piece, piece, type='item'}))
if isTotH then
table.insert(resultPart, ' '..Icons.Icon({'(I) '..metalName..' '..piece, '(I)', type='item'}))
table.insert(resultPart, ' '..Icons.Icon({'(P) '..metalName..' '..piece, '(P)', type='item'}))
else
table.insert(resultPart, ' '..Icons.Icon({'(S) '..metalName..' '..piece, '(S)', type='item'}))
table.insert(resultPart, ' '..Icons.Icon({'(G) '..metalName..' '..piece, '(G)', type='item'}))
end
table.insert(resultPart, '</span>')
end
end
 
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
end


function p.getSpecialAttackTable(frame)
function p.buildCraftableArmourNav(frame)
  local spAttTable = {}
local resultPart = {}
 
table.insert(resultPart, '{| class="wikitable mw-collapsible"')
  for i, item in Shared.skpairs(ItemData.Items) do
table.insert(resultPart, '\r\n!colspan = 2 style="background-color:#275C87;color:#FFFFFF;min-width:730px;"|')
    if item.hasSpecialAttack then
table.insert(resultPart, Icons.Icon({'Crafting', type='skill', notext=true}))
      if spAttTable[item.specialAttackID] == nil then spAttTable[item.specialAttackID] = {sortName=item.name, Icons = {}} end
table.insert(resultPart, ' Craftable Armour Sets')
      table.insert(spAttTable[item.specialAttackID].Icons, Icons.Icon({item.name, type='item'}))
    end
  end 


  local result = '{|class="wikitable sortable stickyHeader"'
local leatherTypes = {'Leather', 'Hard Leather'}
  result = result..'\r\n|-class="headerRow-0"'
local leatherPieces = {"Cowl", "Body", "Chaps", "Gloves", "Vambraces", "Boots"}
  result = result..'\r\n!style="min-width:180px"|Weapon(s)!!Name!!Chance!!Effect'
table.insert(resultPart, '\r\n|-\r\n!')
  for i, spAttData in Shared.skpairs(spAttTable) do
table.insert(resultPart, Icons.Icon({'Leather', type='item', notext=true}))
    local spAtt = p.getSpecialAttackByID(i)
table.insert(resultPart, ' Leather')
    table.sort(spAttData.Icons, function(a, b) return a < b end)
for i, material in pairs(leatherTypes) do
    result = result..'\r\n|-'
if i > 1 then table.insert(resultPart, '\r\n|-\r\n!Hard Leather') end
    result = result..'\r\n|data-sort-value="'..spAttData.sortName..'"|'..table.concat(spAttData.Icons, '<br/>')
table.insert(resultPart, '\r\n|')
    result = result..'||'..spAtt.name..'||data-sort-value="'..spAtt.chance..'"|'..spAtt.chance..'%'
for j, piece in ipairs(leatherPieces) do
    result = result..'||'..spAtt.description
if j > 1 then
  end
table.insert(resultPart, ' • ')
  result = result..'\r\n|}'
end
table.insert(resultPart, Icons.Icon({material..' '..piece, piece, type='item'}))
end
end
 
local materialTypes = {{'Green D-hide', 'Green Dragonhide'}, {'Blue D-hide', 'Blue Dragonhide'}, {'Red D-hide', 'Red Dragonhide'}, {'Black D-hide', 'Black Dragonhide'},
{'Elderwood', 'Elderwood Logs', TotH = true}, {'Revenant', 'Revenant Logs', TotH = true}, {'Carrion', 'Carrion Logs', TotH = true}}
local pieces = {"Body", "Chaps", "Vambraces", "Shield"}
for i, material in ipairs(materialTypes) do
local isTotH = false
local craftName = material[1]
local matName = material[2]
isTotH = material.TotH ~= nil and material.TotH
table.insert(resultPart, '\r\n|-\r\n!')
if isTotH then
table.insert(resultPart, Icons.TotH())
end
table.insert(resultPart, Icons.Icon({matName, type="item", notext=true}))
table.insert(resultPart, " "..craftName)
table.insert(resultPart, "\r\n|")
 
for j, piece in ipairs(pieces) do
if j > 1 then
table.insert(resultPart, ' ')
end
table.insert(resultPart, '<span style="display:inline-block">')
table.insert(resultPart, Icons.Icon({craftName..' '..piece, piece, type='item'}))
table.insert(resultPart, ' '..Icons.Icon({'(U) '..craftName..' '..piece, '(U)', type='item'}))
table.insert(resultPart, '</span>')
end
end
 
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end


  return result
function p.getLifestealWeapons()
local items = p.getItems(function(item)
if item.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) then
for i, spAttID in ipairs(item.specialAttacks) do
local spAtt = GameData.getEntityByID('attacks', spAttID)
if spAtt ~= nil then
return spAtt.lifesteal > 0
end
end
end
return false
end)
for i, item in ipairs(items) do
mw.log(item.name)
end
end
end


return p
return p
915

edits