Module:Items
From Melvor Idle
Lua module containing all sorts of functions for getting data on items. Pulls data from Module:GameData/data.
Some functions were split to submodules:
--This module contains all sorts of functions for getting data on items
--Several functions related to use tables can be found at Module:Items/UseTables
--Functions related to source tables can be found at Module:Items/SourceTables
--Other functions moved to Module:Items/ComparisonTables
local p = {}
local ItemData = mw.loadData('Module:Items/data')
local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Icons = require('Module:Icons')
p.EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon', 'Easter Egg',
'Abnormal Log', 'Red Herring', 'Cool Glasses'}
p.EventItems = {'Christmas Cracker', 'Christmas Coal', 'Christmas Sweater',
'Christmas Wreath', 'Candy Cane', 'Santa Hat',
'Friendship Bracelet', 'Event Clue 1', 'Event Clue 2',
'Event Clue 3', 'Event Clue 4', 'Candle', 'Cake Base',
'Magical Flavouring', 'Magical Icing', 'Birthday Cake',
'Purple Party Hat', 'Birthday Token', 'Christmas Present (Yellow)',
'Christmas Present (Blue)', 'Christmas Present (Green)', 'Christmas Present (White)',
'Christmas Present (Purple)', 'Christmas Present (Standard)', 'Event Token - Holiday 2021',
'Holiday Scarf', 'Gingerbread House', 'Gingerbread Man', 'Edible Candy Cane',
'Locked Chest', 'Locked Chest Key', 'Event Token (Holiday 2021)'}
--This is hardcoded, so there's no easy way to scrape it. Hopefully it doesn't change
p.GemTable = {["Topaz"] = {name = 'Topaz', id = 128, chance = 50},
["Sapphire"] = {name = "Sapphire", id = 129, chance = 17.5},
["Ruby"] = {name = "Ruby", id = 130, chance = 17.5},
["Emerald"] = {name = "Emerald", id = 131, chance = 10},
["Diamond"] = {name = "Diamond", id = 132, chance = 5}}
--The base chance to receive a gem while mining
p.GemChance = .01
function p.getItemByID(ID)
local result = Shared.clone(ItemData.Items[ID + 1])
if result ~= nil then
result.id = ID
end
return result
end
function p.getItem(name)
local result = nil
name = string.gsub(name, "%%27", "'")
name = string.gsub(name, "'", "'")
for i, item in ipairs(ItemData.Items) do
local itemName = string.gsub(item.name, '#', '')
if name == itemName then
result = Shared.clone(item)
--Make sure every item has an id, and account for Lua being 1-index
result.id = i - 1
break
end
end
return result
end
function p.getItems(checkFunc)
local result = {}
local itemCount = 0
for i, item in ipairs(ItemData.Items) do
if checkFunc(item) then
local newItem = Shared.clone(item)
newItem.id = i - 1
itemCount = itemCount + 1
result[itemCount] = newItem
end
end
return result
end
function p._getItemStat(item, StatName, ZeroIfNil)
local result = item[StatName]
--Special Overrides:
-- Equipment stats first
if Shared.contains(ItemData.EquipmentStatKeys, StatName) and item.equipmentStats ~= nil then
result = item.equipmentStats[StatName]
elseif StatName == 'isTwoHanded' then
if item.validSlots ~= nil and item.occupiesSlots ~= nil then
result = Shared.contains(item.validSlots, 'Weapon') and Shared.contains(item.occupiesSlots, 'Shield')
else
result = false
end
elseif string.find(StatName, '^(.+)LevelRequired$') ~= nil and item.equipRequirements ~= nil and item.equipRequirements.Level ~= nil then
local skillName = Shared.titleCase(string.match(StatName, '^(.+)LevelRequired$'))
if skillName ~= nil then
local skillID = Constants.getSkillID(skillName)
if skillID ~= nil then
result = item.equipRequirements.Level[skillID]
end
end
elseif StatName == 'attackType' then
result = p._getWeaponAttackType(item)
elseif StatName == 'description' then
result = item.description
if result == nil or result == '' then result = 'No Description' end
elseif StatName == 'completionReq' then
if item.ignoreCompletion == nil or not item.ignoreCompletion then
result = 'Yes'
else
result = 'No'
end
elseif StatName == 'slayerBonusXP' then
return p._getItemModifier(item, 'increasedSkillXP', 'Slayer', false)
elseif StatName == 'hasCombatStats' then
return tostring(p.hasCombatStats(item) or p._hasLevelRequirements(item))
end
if result == nil and ZeroIfNil then result = 0 end
return result
end
function p.getItemStat(frame)
local args = frame.args ~= nil and frame.args or frame
local ItemName = args[1]
local StatName = args[2]
local ZeroIfNil = args.ForceZero ~= nil and args.ForceZero ~= '' and args.ForceZero ~= 'false'
local formatNum = args.formatNum ~= nil and args.formatNum ~= '' and args.formatNum ~= 'false'
local item = p.getItem(ItemName)
if item == nil then
return "ERROR: No item named "..ItemName.." exists in the data module[[Category:Pages with script errors]]"
end
local result = p._getItemStat(item, StatName, ZeroIfNil)
if formatNum then result = Shared.formatnum(result) end
return result
end
--Gets the value of a given modifier for a given item
--asString is false by default, when true it writes the full bonus text
function p._getItemModifier(item, modifier, skill, asString)
if asString == nil then asString = false end
if skill == '' then
skill = nil
elseif type(skill) == 'string' then
skill = Constants.getSkillID(skill)
end
local result = 0
if item.modifiers ~= nil and item.modifiers[modifier] ~= nil then
if type(item.modifiers[modifier]) == 'table' then
for i, subVal in Shared.skpairs(item.modifiers[modifier]) do
if subVal[1] == skill then
result = subVal[2]
break
end
end
else
result = item.modifiers[modifier]
end
end
if asString then
if skill ~= nil then
return Constants._getModifierText(modifier, {skill, result})
else
return Constants._getModifierText(modifier, result)
end
else
return result
end
end
function p.hasCombatStats(item)
if item.isEquipment or (item.validSlots == nil and item.equipmentStats ~= nil) then
-- Ensure at least one stat has a non-zero value
for statName, statVal in pairs(item.equipmentStats) do
if statVal ~= 0 then return true end
end
end
return false
end
function p._hasLevelRequirements(item)
--Function true if an item has at least one level requirement to equip
if item.equipRequirements ~= nil and item.equipRequirements.Level ~= nil then
for skillID, lvl in pairs(item.equipRequirements.Level) do
if lvl ~= nil and lvl > 1 then
return true
end
end
return false
else
return false
end
end
function p.getItemModifier(frame)
local itemName = frame.args ~= nil and frame.args[1] or frame[1]
local modName = frame.args ~= nil and frame.args[2] or frame[2]
local skillName = frame.args ~= nil and frame.args[3] or frame[3]
local asString = frame.args ~= nil and frame.args[4] or frame[4]
if asString ~= nil then
asString = (string.upper(asString) ~= 'FALSE')
end
local item = p.getItem(itemName)
if item == nil then
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
end
return p._getItemModifier(item, modName, skillName, asString)
end
function p._getWeaponAttackType(item)
if item.isEquipment == true and (item.validSlots ~= nil and Shared.contains(item.validSlots, 'Weapon')) or
(item.occupiesSlots ~= nil and Shared.contains(item.occupiesSlots, 'Weapon')) then
if Shared.contains({'melee', 'ranged', 'magic'}, item.attackType) then
local iconType = item.attackType ~= 'melee' and 'skill' or nil
return Icons.Icon({Shared.titleCase(item.attackType), type=iconType, nolink='true'})
end
end
return 'Invalid'
end
function p.getWeaponAttackType(frame)
local itemName = frame.args ~= nil and frame.args[1] or frame
local item = p.getItem(itemName)
if item == nil then
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
end
return p._getWeaponAttackType(item)
end
function p.getPotionTable(frame)
local potionName = frame.args ~= nil and frame.args[1] or frame
local tiers = {'I', 'II', 'III', 'IV'}
local resultPart = {}
table.insert(resultPart, '{| class="wikitable"')
table.insert(resultPart, '\r\n!Potion!!Tier!!Charges!!Effect')
local tier1potion = p.getItem(potionName..' I')
if tier1potion == nil then
return 'ERROR: No potion named "' .. potionName .. '" was found[[Category:Pages with script errors]]'
end
for i, tier in ipairs(tiers) do
local tierName = potionName..' '..tier
local potion = p.getItemByID(tier1potion.id + i - 1)
if potion ~= nil then
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|'..Icons.Icon({tierName, type='item', notext=true, size='60'}))
table.insert(resultPart, '||'..Icons.Icon({tierName, tier, type='item', noicon=true}))
table.insert(resultPart, '||'..potion.potionCharges..'||'..potion.description)
end
end
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
function p._getOtherItemBoxText(item)
resultPart = {}
--For equipment, show the slot they go in
if item.validSlots ~= nil then
local slotLinkMap = {
["Helmet"] = 'Equipment#Helmets',
["Platebody"] = 'Equipment#Platebodies',
["Platelegs"] = 'Equipment#Platelegs',
["Boots"] = 'Equipment#Boots',
["Weapon"] = 'Equipment#Weapons',
["Shield"] = 'Equipment#Offhand',
["Amulet"] = 'Equipment#Amulets',
["Ring"] = 'Equipment#Rings',
["Gloves"] = 'Equipment#Gloves',
["Quiver"] = 'Equipment#Ammunition',
["Cape"] = 'Equipment#Capes',
["Passive"] = 'Combat Passive Slot',
["Summon1"] = 'Summoning',
["Summon2"] = 'Summoning'
}
local slotText = {}
for i, slot in ipairs(item.validSlots) do
local slotLink = slotLinkMap[slot]
if slotLink == nil then
table.insert(slotText, slot)
else
table.insert(slotText, '[[' .. slotLink .. '|' .. slot .. ']]')
end
end
table.insert(resultPart, "\r\n|-\r\n|'''Equipment Slot:''' "..table.concat(slotText, ', '))
end
--For weapons with a special attack, show the details
if item.hasSpecialAttack then
table.insert(resultPart, "\r\n|-\r\n|'''Special Attack:'''")
for i, spAtt in ipairs(item.specialAttacks) do
table.insert(resultPart, '\r\n* ' .. spAtt.defaultChance .. '% chance for ' .. spAtt.name .. ':')
table.insert(resultPart, '\r\n** ' .. spAtt.description)
end
end
--For potions, show the number of charges
if item.potionCharges ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''Charges:''' "..item.potionCharges)
end
--For food, show how much it heals for
if item.healsFor ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''Heals for:''' "..Icons.Icon({"Hitpoints", type="skill", notext="true"})..' '..(item.healsFor * 10))
end
--For Prayer Points, show how many you get
if item.prayerPoints ~= nil then
table.insert(resultPart, "\r\n|-\r\n|'''"..Icons.Icon({'Prayer', type='skill'}).." Points:''' "..item.prayerPoints)
end
--For items with modifiers, show what those are
if item.modifiers ~= nil and Shared.tableCount(item.modifiers) > 0 then
table.insert(resultPart, "\r\n|-\r\n|'''Modifiers:'''\r\n"..Constants.getModifiersText(item.modifiers, true))
end
return table.concat(resultPart)
end
function p.getOtherItemBoxText(frame)
local itemName = frame.args ~= nil and frame.args[1] or frame
local item = p.getItem(itemName)
local asList = false
if frame.args ~= nil then
asList = frame.args.asList ~= nil and frame.args.asList ~= '' and frame.args.asList ~= 'false'
end
if item == nil then
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
end
return p._getOtherItemBoxText(item, asList)
end
function p._getItemCategories(item)
local resultPart = {}
if item.category ~= nil then table.insert(resultPart, '[[Category:'..item.category..']]') end
if item.type ~= nil then table.insert(resultPart, '[[Category:'..item.type..']]') end
if item.tier ~= nil then table.insert(resultPart, '[[Category:'..Shared.titleCase(item.tier)..' '..item.type..']]') end
if item.hasSpecialAttack then table.insert(resultPart, '[[Category:Items With Special Attacks]]') end
if item.validSlots ~= nil then
local slotRemap = {
['Passive'] = 'Passive Items',
['Summon1'] = 'Summoning Familiars',
['Summon2'] = ''
}
for i, slotName in ipairs(item.validSlots) do
local slotRemapName = slotName
if slotRemap[slotName] ~= nil then slotRemapName = slotRemap[slotName] end
if slotRemapName ~= '' then table.insert(resultPart, '[[Category:' .. slotRemapName .. ']]') end
end
end
if item.modifiers ~= nil then
local modsDL = {
'increasedChanceToDoubleLootCombat',
'decreasedChanceToDoubleLootCombat',
'increasedChanceToDoubleLootThieving',
'decreasedChanceToDoubleLootThieving',
'increasedChanceToDoubleItemsGlobal',
'decreasedChanceToDoubleItemsGlobal'
}
for modName, val in pairs(item.modifiers) do
if Shared.contains(modsDL, modName) then
table.insert(resultPart, '[[Category:Double Loot Chance Items]]')
break
end
end
end
return table.concat(resultPart)
end
function p.getItemCategories(frame)
local itemName = frame.args ~= nil and frame.args[1] or frame
local item = p.getItem(itemName)
if item == nil then
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
end
return p._getItemCategories(item)
end
function p.getSkillcapeTable(frame)
local skillName = frame.args ~= nil and frame.args[1] or frame
local cape = p.getItem(skillName..' Skillcape')
if cape == nil then
return ''
else
local resultPart = {}
table.insert(resultPart, '{| class="wikitable"\r\n')
table.insert(resultPart, '!Skillcape!!Name!!Effect')
table.insert(resultPart, '\r\n|-\r\n|'..Icons.Icon({cape.name, type='item', size='60', notext=true}))
table.insert(resultPart, '||'..Icons.Icon({cape.name, type='item', noicon=true})..'||'..cape.description)
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
end
function p.getItemGrid(frame)
local resultPart = {}
table.insert(resultPart, '{|')
for i, item in Shared.skpairs(ItemData.Items) do
if i % 17 == 1 then
table.insert(resultPart, '\r\n|-\r\n|')
else
table.insert(resultPart, '||')
end
table.insert(resultPart, 'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'}))
end
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
function p.getWeaponStatsBox(frame)
local itemName = frame.args ~= nil and frame.args[1] or frame
local item = p.getItem(itemName)
if item == nil then
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
end
local ico = {
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
["Combat"] = Icons.Icon({'Combat', notext=true}),
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
}
local resultPart = {}
table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Weapon Stats')
table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats')
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Speed')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. Shared.round(p._getItemStat(item, 'attackSpeed', true) / 1000, 3, 1) .. 's')
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Type')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'attackType'))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true))
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Other')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Slayer'] .. ' Bonus Slayer XP')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slayerBonusXP', true) .. '%')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Attack'] .. ' Level Required')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'attackLevelRequired', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Level Required')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedLevelRequired', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Level Required')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicLevelRequired', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
table.insert(resultPart, '\r\n!style="text-align:right;"| Two Handed?')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. (p._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No'))
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
function p.getArmourStatsBox(frame)
local itemName = frame.args ~= nil and frame.args[1] or frame
local item = p.getItem(itemName)
if item == nil then
return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
end
local ico = {
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
["Combat"] = Icons.Icon({'Combat', notext=true}),
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
}
local resultPart = {}
table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Armour Stats')
table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats')
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', 0))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true))
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Other')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Slayer'] .. ' Bonus Slayer XP')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slayerBonusXP', true) .. '%')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Level Required')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'defenceLevelRequired', true))
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Level Required')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedLevelRequired', true))
table.insert(resultPart, '\r\n|-\r\n| colspan="2"|')
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Level Required')
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicLevelRequired', true))
table.insert(resultPart, '\r\n|}')
return table.concat(resultPart)
end
return p