Anonymous

Module:Items: Difference between revisions

From Melvor Idle
Add gem link to gem equipment slot
(more formatting fixes)
(Add gem link to gem equipment slot)
(214 intermediate revisions by 8 users not shown)
Line 1: Line 1:
--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 p = {}


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


local EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon'}
p.EasterEggs = {'Amulet of Calculated Promotion', 'Clue Chasers Insignia', '8', 'Lemon', 'Easter Egg',
local OtherShopItems = {'Cooking Gloves', 'Mining Gloves', 'Gem Gloves', 'Smithing Gloves', 'Thieving Gloves'}
'Abnormal Log', 'Red Herring', 'Cool Glasses'}
p.EventItems = {'Christmas Cracker', 'Christmas Coal', 'Christmas Sweater',
'Christmas Wreath', 'Candy Cane', 'Santa Hat',
'Friendship Bracelet', 'Event Clue 1', 'Event Clue 2',
'Event Clue 3', 'Event Clue 4', 'Candle', 'Cake Base',
'Magical Flavouring', 'Magical Icing', 'Birthday Cake',
'Purple Party Hat', 'Birthday Token', 'Christmas Present (Yellow)',
'Christmas Present (Blue)', 'Christmas Present (Green)', 'Christmas Present (White)',
'Christmas Present (Purple)', 'Christmas Present (Standard)', 'Event Token - Holiday 2021',
'Holiday Scarf', 'Gingerbread House', 'Gingerbread Man', 'Edible Candy Cane',
'Locked Chest', 'Locked Chest Key', 'Event Token (Holiday 2021)'}


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


function p.getItem(name)
function p.getItem(name)
  local result = nil
name = string.gsub(name, "%%27", "'")
  for i, item in pairs(ItemData) do
name = string.gsub(name, "'", "'")
    if(item.name == name) then
return GameData.getEntityByName('items', name)
      result = Shared.clone(item)
end
      --Make sure every item has an id, and account for Lua being 1-index
 
      result.id = i -1
function p.getItems(checkFunc)
    end
return GameData.getEntities('items', checkFunc)
  end
end
  return result
 
function p._canItemUseSlot(item, equipSlot)
--Function to easily check if an item can fit in a given equipment slot
--Ex: p._canItemUseSlot({Bronze Platebody}, 'Platebody') returns true
if type(item) == 'string' then
item = p.getItem(item)
end
return item.validSlots ~= nil and Shared.contains(item.validSlots, equipSlot)
end
 
function p._getItemEquipSlot(item)
--Function to return the (non-Passive) equipment slot that an item occupies
if type(item) == 'string' then
item = p.getItem(item)
end
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._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.attacBonus == nil then  
if item.equipmentStats ~= nil and item.equipmentStats[StatName] ~= nil then
      result = nil
result = item.equipmentStats[StatName]
    else
elseif StatName == 'attackSpeed' and item.validSlots ~= nil and Shared.contains(item.validSlots, 'Weapon') then
      result = item.attackBonus[1]
-- Item can be equipped as a weapon but has no attack speed, so use default of 4000ms
    end
result = 4000
  elseif StatName == 'slashAttackBonus' then
elseif StatName == 'isTwoHanded' then
    if item.attackBonus == nil then  
if item.validSlots ~= nil and item.occupiesSlots ~= nil then
      result = nil
result = Shared.contains(item.validSlots, 'Weapon') and Shared.contains(item.occupiesSlots, 'Shield')
    else
else
      result = item.attackBonus[2]
result = false
    end
end
  elseif StatName == 'blockAttackBonus' then
elseif string.find(StatName, '^(.+)LevelRequired$') ~= nil and item.equipRequirements ~= nil then
    if item.attackBonus == nil then  
local skillName = Shared.titleCase(string.match(StatName, '^(.+)LevelRequired$'))
      result = nil
if skillName ~= nil then
    else
local skillID = Constants.getSkillID(skillName)
      result = item.attackBonus[3]
if skillID ~= nil then
    end
for i, requirement in ipairs(item.equipRequirements) do
  elseif StatName == 'attackType' then
if requirement.type == "SkillLevel" and requirement.skillID == skillID then
    result = p._getWeaponAttackType(item)
result = requirement.level
  end
break
  if result == nil and ZeroIfNil then result = 0 end
end
  return result
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
 
function p.getItemValue(item)
if type(item) == 'string' then
-- Specific check if the item is GP (value of 1)
if Shared.compareString('GP', item, true)
or Shared.compareString('Gold Pieces', item, true) then
return 1
end
 
item = p.getItem(item)
end
if item then
return item.sellsFor
end
return nil
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 item = p.getItem(ItemName)
local formatNum = args.formatNum ~= nil and args.formatNum ~= '' and args.formatNum ~= 'false'
  if item == nil then
local item = p.getItem(ItemName)
    return "ERROR: No item named "..ItemName.." exists in the data module"
if item == nil then
  end
return Shared.printError('No item named "' .. ItemName .. '" exists in the data module')
  return p._getItemStat(item, StatName, ZeroIfNil)
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 itemg
--asString is false by default, when true it writes the full bonus text
function p._getItemModifier(item, modifier, skillID, asString)
if asString == nil then asString = false end
if skillID == '' then
skillID = nil
elseif string.find(skillID, ':') == nil then
-- Try to find a skill ID if it looks like a skill name has been passed
skillID = Constants.getSkillID(skillID)
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] == skillID then
result = subVal[2]
break
end
end
else
result = item.modifiers[modifier]
end
end
 
if asString then
if skillID ~= nil then
return Constants._getModifierText(modifier, {skillID, result})
else
return Constants._getModifierText(modifier, result)
end
else
return result
end
end
 
function p.hasCombatStats(item)
-- Checks if the combat stat is a valid, non-zero combat stat
-- Ensure that, only in the case where the item is a Familar AND
-- the checked stat is summoningMaxhit, the result is ignored.
function isNonZeroStat(statName, statVal)
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
 
return false
end
 
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
 
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 Shared.printError('No item named "' .. itemName .. '" exists in the data module')
end
 
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
 
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 Shared.printError('No item named "' .. itemName .. '" exists in the data module')
end
return p._getWeaponAttackType(item)
end
 
local statChangeDefs = {
{
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'
}
}
 
-- Produces a list of stat & modifier changes between two items of equipmednt
function p.getStatChangeString(item1, item2)
local changeArray = {}
 
local equipStats = {
type(item1.equipmentStats) == 'table' and item1.equipmentStats or {},
type(item2.equipmentStats) == 'table' and item2.equipmentStats or {}
}
for i, statDef in ipairs(statChangeDefs) do
local val1, val2 = 0, 0
if statDef.stat == 'levelRequired' then
-- Iterate over equipment stats for both items, determining level requirements
local levelReqs = {}
for itemNum, item in ipairs({item1, item2}) do
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
 
-- Include differences in modifiers
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
 
function p._getOtherItemBoxText(item)
local resultPart = {}
--For equipment, show the slot they go in
local isPassive = false
if item.validSlots ~= nil then
local slotLinkMap = {
["Helmet"] = 'Helmets',
["Platebody"] = 'Platebodies',
["Platelegs"] = 'Platelegs',
["Boots"] = 'Boots',
["Weapon"] = 'Weapons',
["Shield"] = 'Shields',
["Amulet"] = 'Amulets',
["Ring"] = 'Rings',
["Gloves"] = 'Gloves',
["Quiver"] = 'Ammunition',
["Cape"] = 'Capes',
["Consumable"] = 'Consumables',
["Passive"] = 'Combat Passive Slot',
["Summon1"] = 'Summoning',
["Summon2"] = 'Summoning',
["Gem"] = "Gems_(Equipment)"
}
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
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)
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
return p._getOtherItemBoxText(item)
end


function p.getWeaponAttackType(frame)
function p._getItemCategories(item)
  local itemName = frame.args ~= nil and frame.args[1] or frame
local resultPart = {}
  local item = p.getItem(itemName)
local isEquipment = item.validSlots ~= nil or item.occupiesSlots ~= nil or item.equipmentStats ~= nil
  if item == nil then
local category = p._getItemStat(item, 'category', false)
    return "ERROR: No item named "..ItemName.." exists in the data module"
if category ~= nil and category ~= 'Skills' then
  end
table.insert(resultPart, '[[Category:'..category..']]')
  return p._getWeaponAttackType(item)
end
if item.type ~= nil then
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.getPotionTable(frame)
function p.getItemCategories(frame)
  local potionName = frame.args ~= nil and frame.args[1] or frame
local itemName = frame.args ~= nil and frame.args[1] or frame
  local tiers = {'I', 'II', 'III', 'IV'}
local item = p.getItem(itemName)
if item == nil then
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
end


  local result = '{| class="wikitable"'
return p._getItemCategories(item)
  result = result..'\r\n!Potion!!Tier!!Charges!!Effect'
end


  local tier1potion = p.getItem(potionName..' I')
function p.getItemGrid(frame)
  for i, tier in pairs(tiers) do
local resultPart = {}
    local tierName = potionName..' '..tier
table.insert(resultPart, '{|')
    local potion = p.getItemByID(tier1potion.id + i - 1)
for i, item in ipairs(GameData.rawData.items) do
    if potion == nil then
if i % 17 == 1 then
      mw.log("Failed to get tier "..tier)
table.insert(resultPart, '\r\n|-\r\n|')
    else
else
      result = result..'\r\n|-'
table.insert(resultPart, '||')
      result = result..'\r\n|'..Icons.Icon({tierName, type='item', notext='true', size='60'})
end
      result = result..'||'..'[['..tierName..'|'..tier..']]'
table.insert(resultPart, 'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'}))
      result = result..'||'..potion.potionCharges..'||'..potion.description
end
    end
table.insert(resultPart, '\r\n|}')
  end
return table.concat(resultPart)
end


  result = result..'\r\n|}'
function p.getEquipRequirementRow(req)
  return result
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.getCreationTable(frame)
function p.getWeaponStatsBox(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 Shared.printError('No item named "' .. itemName .. '" exists in the data module')
  end
end
 
local ico = {
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
["Combat"] = Icons.Icon({'Combat', notext=true}),
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
}
local 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


  local skill = ''
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
  local time = 0
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
  local lvl = 0
if reqCount > 3 then
  local xp = 0
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[4]))
  local qty = nil
else
  local req = {}
table.insert(resultPart, emptyRow)
  --First figure out what skill is used to make this...
end
  if item.smithingLevel ~= nil then
    skill = 'Smithing'
    lvl = item.smithingLevel
    xp = item.smithingXP
    req = item.smithReq
    qty = item.smithingQty
    time = 2
  elseif item.craftingLevel ~= nil then
    skill = 'Crafting'
    lvl = item.craftingLevel
    xp = item.craftingXP
    req = item.craftReq
    qty = item.craftQty
    time = 3
  elseif item.runecraftingLevel ~= nil then
    skill = 'Runecrafting'
    lvl = item.runecraftingLevel
    xp = item.runecraftingXP
    req = item.runecraftReq
    qty = item.runecraftQty
    time = 2
  elseif item.fletchingLevel ~= nil then
    skill = 'Fletching'
    lvl = item.fletchingLevel
    xp = item.fletchingXP
    req = item.fletchReq
    qty = item.fletchQty
    time = 2
  elseif item.herbloreReq ~= nil then
    skill = 'Herblore'
    req = item.herbloreReq
    --Currently using 'herbloreMasteryID' as shorthand to find details, could be a better method
    local potionID = item.herbloreMasteryID
    local potionData = SkillData.Herblore.ItemData[potionID + 1]
    lvl = potionData.herbloreLevel
    xp = potionData.herbloreXP
    time = 2
  else
    return "Failed to find creation requirements for this (Possibly the module isn't properly updated for this skill)"
  end
  if qty == nil then qty = 1 end


  local result = '{|class="wikitable"'
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
  result = result..'\r\n!colspan="2"|Item Creation\r\n|-'
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
  result = result..'\r\n|-\r\n!style="text-align: right;"|Requirements'
if reqCount > 4 then
  result = result..'\r\n|'..Icons.Icon({skill, type="skill", notext="true"}).." '''"..lvl.."'''"
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[5]))
  result = result..'\r\n|-\r\n!style="text-align: right;"|Materials\r\n|'
else
  for i, mat in pairs(req) do
table.insert(resultPart, emptyRow)
    if i > 1 then result = result..'<br/>' end
end
    local matItem = p.getItemByID(mat.id)
    if matItem == nil then
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Two Handed?')
      result = result..mat.qty..'x ?????'
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. (p._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No'))
    else
if reqCount > 5 then
      result = result..Icons.Icon({matItem.name, type='item', qty=mat.qty})
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[6]))
    end
else
  end
table.insert(resultPart, emptyRow)
  result = result..'\r\n|-\r\n!style="text-align:right;"|Base Quantity'
end
  result = result..'\r\n|'..qty
  result = result..'\r\n|-\r\n!style="text-align:right;"|Base Experience'
--Add extra rows at the end for items that have more than 3 different requirements
  result = result..'\r\n|'..xp..' XP'
if reqCount > 6 then
  result = result..'\r\n|-\r\n!style="text-align:right;"|Base Creation Time'
for i = 7, reqCount, 1 do
  result = result..'\r\n|'..time..'.0 s'
table.insert(resultPart,"\r\n|-")
  result = result..'\r\n|}'
table.insert(resultPart, emptyRow)
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[i]))
end
end


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


function p._getItemSources(item)
function p.getArmourStatsBox(frame)
  local result = ''
local itemName = frame.args ~= nil and frame.args[1] or frame
  --Alright, time to go through all the ways you can get an item...
local item = p.getItem(itemName)
  --First up: Can we kill somebody and take theirs?
if item == nil then
  local killFound = false
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
  for i, monster in pairs(MonsterData.Monsters) do
end
    if monster.lootTable ~= nil then
      for j, loot in pairs(monster.lootTable) do
        if loot[1] == item.id then
          if killFound then
            result = result..','..Icons.Icon({monster.name, type="monster", notext="true"})
          else
            result = result..'Killing: '..Icons.Icon({monster.name, type="monster", notext="true"})
            killFound = true
          end
        end
      end
    end
  end


  --Next: Can we find it in a box?
local ico = {
  local boxFound = false
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}),
  for i, chest in pairs(ItemData) do
["Combat"] = Icons.Icon({'Combat', notext=true}),
    if chest.dropTable ~= nil then
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}),
      for j, loot in pairs(chest.dropTable) do
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}),
        if loot[1] == item.id then
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}),
          if boxFound then
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}),
            result = result..','..Icons.Icon({chest.name, type="item", notext="true"})
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true})
          else
}
            if string.len(result) > 0 then result = result..'\r\n<br/>' end
            result = result..'Opening: '..Icons.Icon({chest.name, type="item", notext="true"})
local reqCount = item.equipRequirements ~= nil and Shared.tableCount(item.equipRequirements) or 0
            boxFound = true
local emptyRow = '\r\n!colspan="2"|'
          end
        end
local resultPart = {}
      end
table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Armour Stats')
    end
table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats')
  end
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats')


  --Next: Can we take it from somebody else -without- killing them?
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus')
  for i, npc in pairs(SkillData.Thieving) do
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true))
    if npc.lootTable ~= nil then
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus')
      for j, loot in pairs(npc.lootTable) do
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true))
        if loot[1] == item.id then
          if string.len(result) > 0 then result = result..'\r\n<br/>' end
          result = result..'Pickpocketing: '..Icons.Icon({npc.name, type="thieving", notext="true"})
          boxFound = true
        end
      end
    end
  end


  --Next: Can we get to it via upgrading?
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus')
  local upgradeFound = false
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', 0))
  if item.itemsRequired ~= nil then
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction')
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%')
    result = result..'Upgrading: '
    for i, req in pairs(item.itemsRequired) do
      local reqItem = p.getItemByID(req[1])
      if reqItem.canUpgrade then
        if upgradeFound then result = result..', ' else upgradeFound = true end
        result = result..Icons.Icon({reqItem.name, type='item', notext='true'})
      end
    end
  end


  --If all else fails, I guess we should check if we can make it ourselves
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus')
  --SmithCheck:
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true))
  if item.smithingLevel ~= nil then
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus')
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true))
    result = result..Icons._SkillReq("Smithing", item.smithingLevel)
  end


  --CraftCheck:
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus')
  if item.craftingLevel ~= nil then
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true))
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus')
    result = result..Icons._SkillReq("Crafting", item.craftingLevel)
table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true))
  end


  --FletchCheck:
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus')
  if item.fletchingLevel ~= nil then
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true))
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Equip Requirements')
    result = result..Icons._SkillReq("Fletching", item.fletchingLevel)
  end


  --RunecraftCheck:
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus')
  if item.runecraftingLevel ~= nil then
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true))
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
if reqCount > 0 then
    result = result..Icons._SkillReq("Runecrafting", item.runecraftingLevel)
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[1]))
  end
else
table.insert(resultPart, '\r\n|colspan=2 style="text-align:right"|None')
end


  --FishCheck:
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus')
  if (item.category == "Fishing" and (item.type == "Junk" or item.type == "Special")) or item.category == "Gem" then
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true))
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
if reqCount > 1 then
    result = result..Icons._SkillReq("Fishing", 1)
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[2]))
  elseif item.category == 'Fishing' then
else
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
table.insert(resultPart, emptyRow)
    result = result..Icons._SkillReq("Fishing", item.fishingLevel)
end
  end


  --Finally there are some weird exceptions:
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus')
  --Shop items
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%')
  if item.slayerCost ~= nil or item.buysFor ~= nil then
if reqCount > 2 then
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[3]))
    result = result..'[[Shop]]'
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


  --Special Shop Items (ie gloves, which don't technically exist in the shop)
table.insert(resultPart, '\r\n|}')
  if Shared.contains(OtherShopItems, item.name) then
return table.concat(resultPart)
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
end
    result = result..'[[Shop]]'
  end


  --Easter Eggs (manual list 'cause don't have a better way to do that)
function p.getItemDataExport(frame)
  if Shared.contains(EasterEggs, item.name) then
local resultTable = mw.html.create('table')
    if string.len(result) > 0 then result = result..'\r\n<br/>' end
resultTable:addClass('wikitable')
    result = result..'[[Easter Eggs]]'
resultTable:tag('tr'):addClass('headerRow-0')
  end
:tag('th'):wikitext('ItemID'):done()
:tag('th'):wikitext('ItemName'):done()
:tag('th'):wikitext('GPValue'):done()


  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.getItemSources(frame)
--Returns the expansion icon for the item if it has one
  local itemName = frame.args ~= nil and frame[1] or frame
function p.getExpansionIcon(frame)
  local item = p.getItem(itemName)
local itemName = frame.args ~= nil and frame.args[1] or frame
  if item == nil then
local item = p.getItem(itemName)
    return "ERROR: No item named "..itemName.." exists in the data module"
if item == nil then
  end
return Shared.printError('No item named "' .. itemName .. '" exists in the data module')
end


  return p._getItemSources(item)
return Icons.getExpansionIcon(item.id)
end
end


function p.getEquipmentTable(frame)
function p.buildSmithableArmourNav(frame)
  local args = frame.args ~= nil and frame.args or frame
local resultPart = {}
  local type = args.type
table.insert(resultPart, '{| class="wikitable mw-collapsible navigation-not-searchable" style="margin:auto; clear:both; width: 100%"')
  local tier = args.tier
table.insert(resultPart, '\r\n!colspan = 2 style="background-color:#275C87;color:#FFFFFF;min-width:730px;"|')
  local slotStr = args.slot
table.insert(resultPart, Icons.Icon({'Smithing', type='skill', notext=true}))
  local ammoTypeStr = args.ammoType
table.insert(resultPart, ' Smithable Armour Sets')
  local category = args.category ~= nil and args.category or 'Combat'


  --Find out what Ammo Type we're working with
local metalTypes = {'Bronze', 'Iron', 'Steel', 'Mithril', {'Adamant', 'Adamantite'}, {'Rune', 'Runite'}, {'Dragon', 'Dragonite'},
  local ammoType = nil
{'Corundum', 'Corundumite', TotH = true}, {'Augite', 'Augite', TotH = true}, {'Divine', 'Divinite', TotH = true}}
  if ammoTypeStr ~= nil then
local pieces = {"Helmet", "Platebody", "Platelegs", "Boots", "Shield"}
    if ammoTypeStr == "Arrows" then
for i, metal in ipairs(metalTypes) do
      ammoType = 0
local metalName, barName
    elseif ammoTypeStr == 'Bolts' then
local isTotH = false
      ammoType = 1
if type(metal) == 'table' then
    elseif ammoTypeStr == 'Javelins' then
metalName = metal[1]
      ammoType = 2
barName = metal[2]..' Bar'
    elseif ammoTypeStr == 'Throwing Knives' then
isTotH = metal.TotH ~= nil and metal.TotH
      ammoType = 3
else
    end
metalName = metal
  end
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|")


  --Find out what slot we're working with
for j, piece in ipairs(pieces) do
  local slot = nil
if j > 1 then
  if slotStr ~= nil then
table.insert(resultPart, ' • ')
    slot = Constants.equipmentSlot[slotStr]
end
  end
table.insert(resultPart, '<span style="display:inline-block">')
  mw.log("Type = "..(type ~= nil and type or '')..", Slot = "..(slot ~= nil and slot or '')..", AmmoType = "..(ammoType ~= nil and ammoType or ''))
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


  --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 & armor
return table.concat(resultPart)
  local statColumns = {'slashAttackBonus', 'stabAttackBonus','blockAttackBonus','rangedAttackBonus', 'magicAttackBonus', 'strengthBonus', 'rangedStrengthBonus', 'magicDamageBonus', 'defenceBonus', 'rangedDefenceBonus', 'magicDefenceBonus'}
end
  --Then the lists for just weapons/just armor
  local weaponStatColumns = {'attackLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}  
  local armorStatColumns = {'damageReduction', 'defenceLevelRequired', 'rangedLevelRequired', 'magicLevelRequired'}
  --Then the list of weapon types
  local weaponTypes = {'Magic Staff', 'Magic Wand', 'Ranged Weapon', 'Weapon'}


  local isWeaponType = Shared.contains(weaponTypes, type)
function p.buildCraftableArmourNav(frame)
 
local resultPart = {}
  --Alright, let's start the table by building the shared header
table.insert(resultPart, '{| class="wikitable mw-collapsible"')
  local result = '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"'
table.insert(resultPart, '\r\n!colspan = 2 style="background-color:#275C87;color:#FFFFFF;min-width:730px;"|')
  if isWeaponType then
table.insert(resultPart, Icons.Icon({'Crafting', type='skill', notext=true}))
    --Weapons have an extra column here for Attack Speed
table.insert(resultPart, ' Craftable Armour Sets')
    result = result..'\r\n!colspan="2"|'
  else
    result = result..'\r\n!colspan="1"|'
  end
  result = result..'\r\n!colspan="5"style="padding:0 0.5em 0 0.5em;"|Attack Bonus'
  result = result..'\r\n!colspan="2"style="padding:0 0.5em 0 0.5em;"|Strength Bonus'
  result = result..'\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|% Damage Bonus'
  result = result..'\r\n!colspan="3"style="padding:0 0.5em 0 0.5em;"|Defence Bonus'
  if isWeaponType then
    --Weapons have an extra columns here for "Two Handed?"
    result = result..'\r\n!colspan="1"|'
  else
    --Only armor pieces have DR right now, so ignore that column for weapons
    result = result..'\r\n!colspan="1"style="padding:0 0.5em 0 0.5em;"|Damage Reduction'
  end
  result = result..'\r\n!colspan="3"style="padding:0 0.5em 0 0.5em;"|Levels Required'
  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'
  --Weapons have Attack Speed here
  if isWeaponType then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Attack Speed'
  end
  --Attack bonuses
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --Strength bonuses
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Strength', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --Defence bonuses
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --Damage Reduction/Defence Req for armor, 2-handed/Attack Req for weapons
  if isWeaponType then
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Two Handed?'
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Attack', type='skill', notext='true'})
  else
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
    result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Defence', type='skill', notext='true'})
  end
  --Then Ranged/Magic requirements
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Ranged', type='skill', notext='true'})
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|'..Icons.Icon({'Magic', type='skill', notext='true'})
  --And finally Sources
  result = result..'\r\n!style="padding:0 1em 0 0.5em;"|Sources'


  --And with all the header out of the way, finally time to actually build the table itself.
local leatherTypes = {'Leather', 'Hard Leather'}
  for i, item in pairs(ItemData) do
local leatherPieces = {"Cowl", "Body", "Chaps", "Gloves", "Vambraces", "Boots"}
    local listItem = false
table.insert(resultPart, '\r\n|-\r\n!')
    if isWeaponType then
table.insert(resultPart, Icons.Icon({'Leather', type='item', notext=true}))
      listItem = item.type == type and item.category == category
table.insert(resultPart, ' Leather')
      if ammoType ~= nil then listItem = listItem and item.ammoTypeRequired == ammoType end
for i, material in pairs(leatherTypes) do
      if listItem then
if i > 1 then table.insert(resultPart, '\r\n|-\r\n!Hard Leather') end
        result = result..'\r\n|-'
table.insert(resultPart, '\r\n|')
        result = result..'\r\n|style="text-align:left;padding:0 0.5em 0 0.5em;"|'..Icons.Icon({item.name, type='item'})
for j, piece in ipairs(leatherPieces) do
        result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;" |'..Shared.formatnum(item.attackSpeed)
if j > 1 then
        for j, statName in pairs(statColumns) do
table.insert(resultPart, ' ')
          local statValue = p._getItemStat(item, statName, true)
end
          result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
table.insert(resultPart, Icons.Icon({material..' '..piece, piece, type='item'}))
          if statValue > 0 then
end
            result = result..'background-color:lightgreen;'
end
          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
        --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
        --Now the weapon exclusive columns
        for j, statName in pairs(weaponStatColumns) 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
    else
      --Now for handling armor
      listItem = item.type == type and item.category == category
      if ammoType ~= nil then listItem = listItem and item.ammoType == ammoType end
      if slot ~= nil then listItem = listItem and item.equipmentSlot == slot end


      if listItem then
local materialTypes = {{'Green D-hide', 'Green Dragonhide'}, {'Blue D-hide', 'Blue Dragonhide'}, {'Red D-hide', 'Red Dragonhide'}, {'Black D-hide', 'Black Dragonhide'},
        result = result..'\r\n|-'
{'Elderwood', 'Elderwood Logs', TotH = true}, {'Revenant', 'Revenant Logs', TotH = true}, {'Carrion', 'Carrion Logs', TotH = true}}
        result = result..'\r\n|style="text-align:left;padding:0 0.5em 0 0.5em;"|'..Icons.Icon({item.name, type='item'})
local pieces = {"Body", "Chaps", "Vambraces", "Shield"}
        for j, statName in pairs(statColumns) do
for i, material in ipairs(materialTypes) do
          local statValue = p._getItemStat(item, statName, true)
local isTotH = false
          result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
local craftName = material[1]
          if statValue > 0 then
local matName = material[2]
            result = result..'background-color:lightgreen;'
isTotH = material.TotH ~= nil and material.TotH
          elseif statValue < 0 then
table.insert(resultPart, '\r\n|-\r\n!')
            result = result..'background-color:lightpink;'
if isTotH then
          end
table.insert(resultPart, Icons.TotH())
          result = result..'"|'..Shared.formatnum(statValue)
end
          if statName == 'magicDamageBonus' or statName == 'damageReduction' then result = result..'%' end
table.insert(resultPart, Icons.Icon({matName, type="item", notext=true}))
        end
table.insert(resultPart, " "..craftName)
        --That's the first list out of the way, now for armor specific things
table.insert(resultPart, "\r\n|")
        for j, statName in pairs(armorStatColumns) do
 
          local statValue = p._getItemStat(item, statName, true)
for j, piece in ipairs(pieces) do
          result = result..'\r\n| style ="text-align: right;padding: 0 0.5em 0 0;'
if j > 1 then
          if statValue > 0 then
table.insert(resultPart, ' • ')
            result = result..'background-color:lightgreen;'
end
          elseif statValue < 0 then
table.insert(resultPart, '<span style="display:inline-block">')
            result = result..'background-color:lightpink;'
table.insert(resultPart, Icons.Icon({craftName..' '..piece, piece, type='item'}))
          end
table.insert(resultPart, ' '..Icons.Icon({'(U) '..craftName..' '..piece, '(U)', type='item'}))
          result = result..'"|'..Shared.formatnum(statValue)
table.insert(resultPart, '</span>')
          if statName == 'magicDamageBonus' or statName == 'damageReduction' then result = result..'%' end
end
        end
end
        --Finally, the Sources
 
        result = result..'\r\n| style ="text-align: right;white-space: nowrap;padding: 0 0.5em 0 0.5em;" |'
table.insert(resultPart, '\r\n|}')
        result = result..p._getItemSources(item)
return table.concat(resultPart)
      end
end
    end
  end


  result = result..'|}'
function p.getLifestealWeapons()
  return result
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
914

edits