|
|
Line 20: |
Line 20: |
| NotMagic = {'Torrential Blast Crossbow', 'Spectral Ice Sword', 'Lightning Strike 1H Sword', 'FrostSpark 1H Sword'} | | NotMagic = {'Torrential Blast Crossbow', 'Spectral Ice Sword', 'Lightning Strike 1H Sword', 'FrostSpark 1H Sword'} |
| } | | } |
| | |
| | -- Special ID to identify two-handed weapons |
| | local twoHandedWeaponID = '2hWeapons' |
|
| |
|
| local function getSlotID(slot) | | local function getSlotID(slot) |
| -- If slot is a slot name, convert it to the slot ID instead
| |
| local slotID = Shared.getNamespacedID('melvorD', slot) | | local slotID = Shared.getNamespacedID('melvorD', slot) |
| local slotData = GameData.getEntityByID('equipmentSlots', slotID) | | local slotData = GameData.getEntityByID('equipmentSlots', slotID) |
| -- Validate slotID
| | |
| if slotData == nil then | | if slotData == nil then |
| | -- Special case for 2h weapons. Assume 1h weapons otherwise. |
| | if slot == twoHandedWeaponID then |
| | return 'melvorD:' .. twoHandedWeaponID |
| | end |
| | |
| -- slotID invalid, check if user provided a slot name | | -- slotID invalid, check if user provided a slot name |
| slotData = GameData.getEntityByProperty('equipmentSlots', 'emptyName', slot) | | slotData = GameData.getEntityByProperty('equipmentSlots', 'emptyName', slot) |
Line 47: |
Line 54: |
| end | | end |
|
| |
|
| function p._getEquipmentTable(itemList, includeModifiers, includeDescription, sortByName) | | local function getAttackSpeed(item) |
| if includeModifiers == nil then includeModifiers = false end | | if item.equipmentStats ~= nil and item.equipmentStats['attackSpeed'] ~= nil then |
| if sortByName == nil then sortByName = false end | | return item.equipmentStats['attackSpeed'] or 4000 |
| | end |
| | return 0 |
| | end |
|
| |
|
| --Getting some lists set up here that will be used later | | local function getItems(slotID) |
| --First, the list of columns used by both weapons & armour | | local _, slotLocalID = Shared.getLocalID(slotID) |
| local statColumns = { | | |
| 'stabAttackBonus', 'slashAttackBonus', 'blockAttackBonus', | | local sortFunc = function(item) |
| 'rangedAttackBonus', 'magicAttackBonus', 'meleeStrengthBonus', | | -- Exclude the debug item |
| 'rangedStrengthBonus', 'magicDamageBonus', 'meleeDefenceBonus',
| | if item.id == 'melvorD:DEBUG_ITEM' then |
| 'rangedDefenceBonus', 'magicDefenceBonus', 'damageReduction', | | return false |
| 'resistanceAbyssal', 'resistanceEternal', 'attackLevelRequired', | | end |
| 'strengthLevelRequired', 'defenceLevelRequired', 'rangedLevelRequired', | | -- Exclude Golbin raid exclusives for now, such that they don't pollute various equipment tables |
| 'magicLevelRequired', 'attackAbyssalLevel', 'strengthAbyssalLevel',
| | if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then |
| 'defenceAbyssalLevel', 'rangedAbyssalLevel', 'magicAbyssalLevel' | | return false |
| }
| | end |
|
| |
|
| if Shared.tableIsEmpty(itemList) then
| | if not Shared.contains(item.validSlots, slotLocalID) then |
| return Shared.printError('You must select at least one item to get stats for')
| | if slotLocalID == twoHandedWeaponID then |
| end
| | return Items._getItemStat(item, 'isTwoHanded') |
| | end |
| | end |
|
| |
|
| local isWeaponType = ((itemList[1].validSlots ~= nil and Shared.contains(itemList[1].validSlots, 'Weapon'))
| | if slotLocalID == 'Weapon' then --For quiver slot or weapon slot, 'other' is the ammo type |
| or (itemList[1].occupiesSlots ~= nil and Shared.contains(itemList[1].occupiesSlots, 'Weapon'))) and Shared.contains(weaponTypes, itemList[1].type)
| | return other == item.ammoTypeRequired |
| | | elseif slotLocalID == 'Quiver' then |
| --Now that we have a preliminary list, let's figure out which columns are irrelevant (IE are zero for all items in the selection)
| | if other == 'Thrown' and Shared.contains({'Javelins', 'ThrowingKnives'}, item.ammoType) then |
| local ignoreColumns = Shared.clone(statColumns)
| | return true |
| for i, item in pairs(itemList) do
| |
| local ndx = 1 | |
| while Shared.tableCount(ignoreColumns) >= ndx do
| |
| if Items._getItemStat(item, ignoreColumns[ndx], true) ~= 0 then | |
| table.remove(ignoreColumns, ndx) | |
| else | | else |
| ndx = ndx + 1 | | return other == item.ammoType |
| end | | end |
| end | | end |
| | |
| | return false |
| end | | end |
|
| |
|
| --Now to remove the ignored columns (and also we need to track groups like defence bonuses to see how many remain) | | return Items.getItems(sortFunc) |
| local attBonusCols = 5
| | end |
| local strBonusCols = 2
| | |
| local defBonusCols = 3
| | --== Helper Functions for getCategoryTable ==-- |
| local lvlReqCols = 5
| | local function createStatCell(row, statVal) |
| local abyssalLvlReqCols = 5
| | local cell = row:tag('td') |
| local ndx = 1
| | if statVal > 0 then |
| while Shared.tableCount(statColumns) >= ndx do
| | cell:addClass('table-positive') |
| local colName = statColumns[ndx]
| | elseif statVal < 0 then |
| if Shared.contains(ignoreColumns, colName) then
| | cell:addClass('table-negative') |
| if Shared.contains(colName, 'AttackBonus') then attBonusCols = attBonusCols - 1 end
| |
| if Shared.contains(colName, 'trengthBonus') then strBonusCols = strBonusCols - 1 end
| |
| if Shared.contains(colName, 'efenceBonus') then defBonusCols = defBonusCols - 1 end
| |
| if Shared.contains(colName, 'AbyssalLevel') then abyssalLvlReqCols = abyssalLvlReqCols - 1 end
| |
| if Shared.contains(colName, 'LevelRequired') then lvlReqCols = lvlReqCols - 1 end
| |
| table.remove(statColumns, ndx)
| |
| else
| |
| ndx = ndx + 1
| |
| end
| |
| end | | end |
| | cell:css('text-align', 'right') |
| | return cell |
| | end |
|
| |
|
| --Alright, let's start the table by building the shared header
| | local function addStatCell(row, item, stat) |
| local resultPart = {} | | local statVal = 0 |
| table.insert(resultPart, '{| class="wikitable sortable stickyHeader"\r\n|-class="headerRow-0"') | | if item.equipmentStats ~= nil then |
| if isWeaponType then
| | statVal = item.equipmentStats[stat] or 0 |
| --Weapons have extra columns here for Attack Speed and "Two Handed?" | |
| table.insert(resultPart, '\r\n!colspan="5"|')
| |
| else
| |
| table.insert(resultPart, '\r\n!colspan="3"|')
| |
| end | | end |
| if attBonusCols > 0 then | | |
| table.insert(resultPart, '\r\n!colspan="'..attBonusCols..'"|Attack Bonus') | | return createStatCell(row, statVal) |
| | :wikitext(statVal) |
| | end |
| | |
| | local function addDRCell(row, item) |
| | local dr = 0 |
| | local icon = nil |
| | |
| | -- Grab damage reduction figure |
| | if item.equipmentStats ~= nil then |
| | if item.equipmentStats.damageReduction then |
| | dr, icon = item.equipmentStats.damageReduction, 'Damage Reduction' |
| | elseif item.equipmentStats.resistanceAbyssal then |
| | dr, icon = item.equipmentStats.resistanceAbyssal, 'Abyssal Resistance' |
| | elseif item.equipmentStats.resistanceEternal then |
| | dr, icon = item.equipmentStats.resistanceEternal, 'Eternal Resistance' |
| | end |
| end | | end |
| if strBonusCols > 0 then | | |
| table.insert(resultPart, '\r\n!colspan="'..strBonusCols..'"|Str. Bonus') | | local cell = createStatCell(row, dr) |
| | |
| | -- Add DR icons, if there's any value |
| | if dr ~= 0 then |
| | cell:wikitext(Icons.Icon({icon, size=15, notext='true'}) .. ' ') |
| end | | end |
| if Shared.contains(statColumns, 'magicDamageBonus') then | | |
| table.insert(resultPart, '\r\n!colspan="1"|% Dmg Bonus') | | -- Add DR value |
| | cell:wikitext(dr .. '%') |
| | return cell |
| | end |
| | |
| | local function getRequirements(item) |
| | if item.equipRequirements == nil then |
| | return nil |
| end | | end |
| if defBonusCols > 0 then | | |
| table.insert(resultPart, '\r\n!colspan="'..defBonusCols..'"|Defence Bonus') | | local function getSkillName(skillID) |
| | local _, localSkillID = GameData.getLocalID(skillID) |
| | return localSkillID |
| end | | end |
| if Shared.contains(statColumns, 'damageReduction') then | | |
| table.insert(resultPart, '\r\n!colspan="1"|DR')
| | local iconFuncs = { |
| end
| | ['AbyssalLevel'] = function(x) |
| if Shared.contains(statColumns, 'resistanceAbyssal') then
| | return Icons._SkillRealmIcon(getSkillName(x.skillID), 'melvorItA:Abyssal') .. ' ' .. x.level |
| table.insert(resultPart, '\r\n!colspan="1"|AR') | | end, |
| end
| | ['SkillLevel'] = function(x) |
| if Shared.contains(statColumns, 'resistanceEternal') then
| | return Icons._SkillRealmIcon(getSkillName(x.skillID)) .. ' ' .. x.level |
| table.insert(resultPart, '\r\n!colspan="1"|ER') | | end, |
| end | | } |
| if lvlReqCols > 0 then | | |
| table.insert(resultPart, '\r\n!colspan="'..lvlReqCols..'"|Lvl Req')
| | local reqs = {} |
| end | | local abyssalSkills = {} |
| if abyssalLvlReqCols > 0 then | | local highestLvReq = 0 |
| table.insert(resultPart, '\r\n!colspan="'..abyssalLvlReqCols..'"|A. Lvl Req') | | |
| end
| | -- Filter out all Abyssal Levels |
| if includeModifiers and includeDescription then
| | for _, req in ipairs(item.equipRequirements) do |
| table.insert(resultPart, '\r\n!colspan="2"|')
| | if req.type == 'AbyssalLevel' then abyssalSkills[req.skillID] = true end |
| elseif includeModifiers or includeDescription then
| | end |
| table.insert(resultPart, '\r\n!colspan="1"|') | | |
| end
| | -- If the req is a SkillLevel, but the skillID is already an AbyssalLevel, skip the entry |
| --One header row down, one to go | | -- These are likely 99 Level requirements in addition to the AbyssalLevel requirement. |
| table.insert(resultPart, '\r\n|-class="headerRow-1"')
| | for _, req in ipairs(item.equipRequirements) do |
| table.insert(resultPart, '\r\n!Item') | | if not (req.type == 'SkillLevel' and abyssalSkills[req.skillID] == true) then |
| table.insert(resultPart, '\r\n!Name') | | -- Add requirement via factory function. |
| table.insert(resultPart, '\r\n![[DLC]]') | | local func = iconFuncs[req.type] |
| --Weapons have Attack Speed here | | if func then table.insert(reqs, func(req)) end |
| if isWeaponType then | | |
| table.insert(resultPart, '\r\n!Attack Speed')
| | -- Track highest level for data sorting. |
| table.insert(resultPart, '\r\n!Two Handed?') | | local lv = req.level or 0 |
| end
| | if lv > highestLvReq then highestLvReq = lv end |
| --Attack bonuses
| | end |
| if Shared.contains(statColumns, 'slashAttackBonus') then | | end |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Attack', type='skill', size=20, notext='true'}))
| | |
| end | | if Shared.tableIsEmpty(abyssalSkills) == false then |
| if Shared.contains(statColumns, 'stabAttackBonus') then
| | highestLvReq = highestLvReq + 99 |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Strength', type='skill', size=20, notext='true'}))
| | end |
| end
| | |
| if Shared.contains(statColumns, 'blockAttackBonus') then | | return { |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', size=20, notext='true'}))
| | ['datasortvalue'] = highestLvReq, |
| end | | ['requirements'] = table.concat(reqs, '<br>') |
| if Shared.contains(statColumns, 'rangedAttackBonus') then
| | } |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', size=20, notext='true'}))
| | end |
| end
| | |
| if Shared.contains(statColumns, 'magicAttackBonus') then | | function p._getCategoryTable(itemList, slot) |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', size=20, notext='true'})) | | local iconSize = 20 |
| | |
| | local isWeapon = (slot == 'Weapon' or slot == twoHandedWeaponID) |
| | local itemColspan = 3 |
| | if isWeapon == true then itemColspan = 4 end |
| | |
| | local html = mw.html.create('table') |
| | :addClass('wikitable sortable stickyHeader') |
| | :addClass('col-1-center col-3-center') |
| | |
| | local header0 = html:tag('tr'):addClass('headerRow-0') |
| | header0:tag('th'):attr('colspan', itemColspan) |
| | header0:tag('th'):attr('colspan', 5) |
| | :wikitext("Attack Bonus") |
| | header0:tag('th'):attr('colspan', 3) |
| | :wikitext("Strength Bonus") |
| | header0:tag('th'):attr('colspan', 3) |
| | :wikitext("Defence Bonus") |
| | |
| | header0:tag('th'):wikitext("DR/AR") |
| | |
| | local header1 = html:tag('tr'):addClass('headerRow-1') |
| | header1:tag('th'):wikitext('Name') |
| | :attr('colspan', 2) |
| | header1:tag('th'):wikitext('DLC') |
| | if isWeapon == true then |
| | header1:tag('th'):wikitext('Attack<br>Speed') |
| end | | end |
| | |
| | -- Attack bonuses |
| | header1:tag('th'):wikitext(Icons.Icon({'Attack', type='skill', size=iconSize, notext='true'})) |
| | header1:tag('th'):wikitext(Icons.Icon({'Strength', type='skill', size=iconSize, notext='true'})) |
| | header1:tag('th'):wikitext(Icons.Icon({'Defence', type='skill', size=iconSize, notext='true'})) |
| | header1:tag('th'):wikitext(Icons.Icon({'Ranged', type='skill', size=iconSize, notext='true'})) |
| | header1:tag('th'):wikitext(Icons.Icon({'Magic', type='skill', size=iconSize, notext='true'})) |
| | |
| --Strength bonuses | | --Strength bonuses |
| if Shared.contains(statColumns, 'meleeStrengthBonus') then | | header1:tag('th'):wikitext(Icons.Icon({'Strength', type='skill', size=iconSize, notext='true'})) |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Strength', type='skill', size=20, notext='true'}))
| | header1:tag('th'):wikitext(Icons.Icon({'Ranged', type='skill', size=iconSize, notext='true'})) |
| end | | header1:tag('th'):wikitext(Icons.Icon({'Magic', type='skill', size=iconSize, notext='true'})) |
| if Shared.contains(statColumns, 'rangedStrengthBonus') then
| | |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', size=20, notext='true'}))
| |
| end | |
| if Shared.contains(statColumns, 'magicDamageBonus') then
| |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', size=20, notext='true'}))
| |
| end
| |
| --Defence bonuses | | --Defence bonuses |
| if Shared.contains(statColumns, 'meleeDefenceBonus') then | | header1:tag('th'):wikitext(Icons.Icon({'Strength', type='skill', size=iconSize, notext='true'})) |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', size=20, notext='true'}))
| | header1:tag('th'):wikitext(Icons.Icon({'Ranged', type='skill', size=iconSize, notext='true'})) |
| end | | header1:tag('th'):wikitext(Icons.Icon({'Magic', type='skill', size=iconSize, notext='true'})) |
| if Shared.contains(statColumns, 'rangedDefenceBonus') then
| | |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', size=20, notext='true'}))
| | -- Damage reduction |
| end | | header1:tag('th'):wikitext(Icons.Icon({'Damage Reduction', size=iconSize, notext='true'})) |
| if Shared.contains(statColumns, 'magicDefenceBonus') then
| | |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', size=20, notext='true'}))
| |
| end | |
| if Shared.contains(statColumns, 'damageReduction') then | |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Damage Reduction', size=20, notext='true'}))
| |
| end | |
| if Shared.contains(statColumns, 'resistanceAbyssal') then
| |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Abyssal Resistance', size=20, notext='true'}))
| |
| end
| |
| if Shared.contains(statColumns, 'resistanceEternal') then
| |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Eternal Resistance', size=20, notext='true'}))
| |
| end | |
| --Level requirements | | --Level requirements |
| if Shared.contains(statColumns, 'attackLevelRequired') then | | header1:tag('th'):wikitext('Equip Req') |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Attack', type='skill', size=20, notext='true'}))
| | |
| end | | -- Fill the table with all items |
| if Shared.contains(statColumns, 'strengthLevelRequired') then | | for _, item in ipairs(itemList) do |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Strength', type='skill', size=20, notext='true'})) | | local row = html:tag('tr') |
| end
| | row:tag('td'):wikitext(Icons.Icon({item.name, type='item', notext=true})) |
| if Shared.contains(statColumns, 'defenceLevelRequired') then
| | :attr('data-sort-value', item.name) |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', size=20, notext='true'})) | | row:tag('td'):wikitext(Icons.Icon({item.name, type='item', noicon=true})) |
| end
| | :attr('data-sort-value', item.name) |
| if Shared.contains(statColumns, 'rangedLevelRequired') then
| | row:tag('td'):wikitext(Icons.getDLCColumnIcon(item.id)) |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', size=20, notext='true'})) | | :attr('data-sort-value', Icons.getExpansionID(item.id)) |
| end
| | |
| if Shared.contains(statColumns, 'magicLevelRequired') then
| | -- Add attack speed. |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', size=20, notext='true'})) | | if isWeapon == true then |
| end
| | local atkSpeed = getAttackSpeed(item) |
| if Shared.contains(statColumns, 'attackAbyssalLevel') then
| | row:tag('td'):wikitext(Num.round(atkSpeed / 1000, 3, 1) .. 's') |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Attack', type='skill', size=20, class='abyss-icon', notext='true'}))
| | :attr('data-sort-value', atkSpeed) |
| end
| | :css('text-align', 'right') |
| if Shared.contains(statColumns, 'strengthAbyssalLevel') then
| | end |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Strength', type='skill', size=20, class='abyss-icon', notext='true'})) | | |
| end
| | -- Attack bonuses |
| if Shared.contains(statColumns, 'defenceAbyssalLevel') then
| | addStatCell(row, item, 'stabAttackBonus') |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Defence', type='skill', size=20, class='abyss-icon', notext='true'})) | | addStatCell(row, item, 'slashAttackBonus') |
| end
| | addStatCell(row, item, 'blockAttackBonus') |
| if Shared.contains(statColumns, 'rangedAbyssalLevel') then
| | addStatCell(row, item, 'rangedAttackBonus') |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Ranged', type='skill', size=20, class='abyss-icon', notext='true'})) | | addStatCell(row, item, 'magicAttackBonus') |
| end
| | |
| if Shared.contains(statColumns, 'magicAbyssalLevel') then
| | -- Strength bonuses |
| table.insert(resultPart, '\r\n!'..Icons.Icon({'Magic', type='skill', size=20, class='abyss-icon', notext='true'})) | | addStatCell(row, item, 'meleeStrengthBonus') |
| end
| | addStatCell(row, item, 'rangedStrengthBonus') |
| --If includeModifiers is set to 'true', add the Modifiers column
| | addStatCell(row, item, 'magicDamageBonus'):wikitext('%') |
| if includeModifiers then
| | |
| table.insert(resultPart, '\r\n!Modifiers') | | -- Defence bonuses |
| end
| | addStatCell(row, item, 'meleeDefenceBonus') |
| --If includeDescription is set to 'true', add the Description column
| | addStatCell(row, item, 'rangedDefenceBonus') |
| if includeDescription then
| | addStatCell(row, item, 'magicDefenceBonus') |
| table.insert(resultPart, '\r\n!Description') | | |
| end
| | -- Add Damage Reduction / Abyssal Resistance |
| | addDRCell(row, item) |
|
| |
|
| if sortByName then
| | local reqs = getRequirements(item) |
| table.sort(itemList, function(a, b) return a.name < b.name end) | | if reqs == nil then |
| end
| | row:tag('td'):wikitext('None') |
| for i, item in ipairs(itemList) do
| | :attr('data-sort-value', 0) |
| if isWeaponType then | |
| --Building rows for weapons | |
| local atkSpeed = Items._getItemStat(item, 'attackSpeed', true)
| |
| table.insert(resultPart, '\r\n|-')
| |
| table.insert(resultPart, '\r\n|style="text-align: centre;"|'..Icons.Icon({item.name, type='item', size=32, notext=true}))
| |
| table.insert(resultPart, '\r\n|'..Icons.Icon({item.name, type='item', noicon=true}))
| |
| table.insert(resultPart, '\r\n|'..Icons.getDLCColumnIcon(item.id))
| |
| table.insert(resultPart, '\r\n| data-sort-value="' .. atkSpeed .. '" style="text-align:right;" |'..Num.round(atkSpeed / 1000, 3, 1) .. 's')
| |
| --That's the first list out of the way, now for 2-Handed
| |
| table.insert(resultPart, '\r\n| style="text-align: right;"|')
| |
| table.insert(resultPart, Items._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No')
| |
| for j, statName in pairs(statColumns) do
| |
| local statValue = Items._getItemStat(item, statName, true)
| |
| table.insert(resultPart, '\r\n| style="text-align:right;" class="')
| |
| if string.find(statName, '^(.+)LevelRequired$') == nil or string.find(statName, '^(.+)Abyssallevel$') == nil then
| |
| if statValue > 0 then
| |
| table.insert(resultPart, 'table-positive')
| |
| elseif statValue < 0 then
| |
| table.insert(resultPart, 'table-negative')
| |
| end
| |
| end
| |
| table.insert(resultPart, '"|'..Num.formatnum(statValue))
| |
| if statName == 'magicDamageBonus' or statName == 'damageReduction' or Shared.contains(statName, 'resistance') then table.insert(resultPart, '%') end
| |
| end
| |
| --If requested, add the item Modifiers
| |
| if includeModifiers then
| |
| table.insert(resultPart, '\r\n| ')
| |
| local txtLines = {}
| |
| if item.modifiers ~= nil then
| |
| table.insert(txtLines, Modifiers.getModifiersText(item.modifiers, true, false, 10))
| |
| end
| |
| --For items with a special attack, show the details
| |
| if item.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) then
| |
| table.insert(txtLines, "'''Special Attack:'''")
| |
| for i, spAttID in ipairs(item.specialAttacks) do
| |
| local spAtt = GameData.getEntityByID('attacks', spAttID)
| |
| local attChance = spAtt.defaultChance
| |
| if item.overrideSpecialChances ~= nil then
| |
| attChance = item.overrideSpecialChances[i]
| |
| end
| |
| table.insert(txtLines, attChance .. '% chance for ' .. spAtt.name .. ':')
| |
| table.insert(txtLines, spAtt.description)
| |
| end
| |
| end
| |
| table.insert(resultPart, table.concat(txtLines, '<br/>'))
| |
| end
| |
| --If requested, add description
| |
| if includeDescription then
| |
| table.insert(resultPart, '\r\n| ' .. getItemDesc(item))
| |
| end
| |
| else | | else |
| --Building rows for armour | | row:tag('td'):wikitext(reqs.requirements) |
| table.insert(resultPart, '\r\n|-')
| | :attr('data-sort-value', reqs.datasortvalue) |
| table.insert(resultPart, '\r\n|'..Icons.Icon({(item.name or 'Unknown'), type='item', notext=true}))
| |
| table.insert(resultPart, '\r\n|'..Icons.Icon({item.name, type='item', noicon=true}))
| |
| table.insert(resultPart, '\r\n|'..Icons.getDLCColumnIcon(item.id))
| |
| for j, statName in pairs(statColumns) do
| |
| local statValue = Items._getItemStat(item, statName, true)
| |
| table.insert(resultPart, '\r\n|style="text-align:right;" class="')
| |
| if statValue > 0 then
| |
| table.insert(resultPart, 'table-positive')
| |
| elseif statValue < 0 then
| |
| table.insert(resultPart, 'table-negative')
| |
| end
| |
| table.insert(resultPart, '"|'..Num.formatnum(statValue))
| |
| if statName == 'magicDamageBonus' or statName == 'damageReduction' or Shared.contains(statName, 'resistance') then table.insert(resultPart, '%') end
| |
| end
| |
| --If requested, add the item Modifiers
| |
| if includeModifiers then
| |
| table.insert(resultPart, '\r\n| ')
| |
| local txtLines = {}
| |
| if item.modifiers ~= nil then
| |
| table.insert(txtLines, Modifiers.getModifiersText(item.modifiers, true, false, 10))
| |
| end
| |
| --For items with a special attack, show the details
| |
| if item.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) then
| |
| table.insert(txtLines, "'''Special Attack:'''")
| |
| for i, spAttID in ipairs(item.specialAttacks) do
| |
| local spAtt = GameData.getEntityByID('attacks', spAttID)
| |
| local attChance = spAtt.defaultChance
| |
| if item.overrideSpecialChances ~= nil then
| |
| attChance = item.overrideSpecialChances[i]
| |
| end
| |
| table.insert(txtLines, attChance .. '% chance for ' .. spAtt.name .. ':')
| |
| table.insert(txtLines, spAtt.description)
| |
| end
| |
| end
| |
| table.insert(resultPart, table.concat(txtLines, '<br/>'))
| |
| end
| |
| --If requested, add description
| |
| if includeDescription then
| |
| table.insert(resultPart, '\r\n| ' .. getItemDesc(item))
| |
| end
| |
| end | | end |
| end | | end |
|
| |
|
| table.insert(resultPart, '\r\n|}')
| | return tostring(html) |
| | |
| return table.concat(resultPart) | |
| end | | end |
|
| |
|
| function p._getCategoryTable(style, slot, other, includeModifiers, includeDescription, sortByName) | | function p.getCategoryTable(frame) |
| -- If slot is a slot name, convert it to the slot ID instead | | local slot = frame.args ~= nil and frame.args[1] or frame[1] |
| local slotID = getSlotID(slot) | | local slotID = getSlotID(slot) |
| if slotID == nil then | | if slotID == nil then |
| return Shared.printError('Invalid slot ID: ' .. (slot or 'nil')) | | return Shared.printError('Invalid slot ID: ' .. (slot or 'nil')) |
| end | | end |
| local slotNS, slotLocalID = Shared.getLocalID(slotID) | | |
| | | -- Always sort by name. |
| local itemList = Items.getItems(function(item) | | local itemList = getItems(slotID) |
| -- Exclude the debug item
| | table.sort(itemList, function(a, b) return a.name < b.name end) |
| if item.id == 'melvorD:DEBUG_ITEM' then
| | |
| return false
| | return p._getCategoryTable(itemList, slot) |
| end
| |
| -- Exclude Golbin raid exclusives for now, such that they don't
| |
| -- pollute various equipment tables
| |
| if item.golbinRaidExclusive ~= nil and item.golbinRaidExclusive then
| |
| return false
| |
| end
| |
| local isMatch = true
| |
| if style == 'Melee' then
| |
| if ((Items._getItemStat(item, 'defenceLevelRequired') == nil and Items._getItemStat(item, 'attackLevelRequired') == nil) and not Shared.contains(styleOverrides.Melee, item.name)) or Shared.contains(styleOverrides.NotMelee, item.name) then isMatch = false end
| |
| elseif style == 'Ranged' then
| |
| if (Items._getItemStat(item, 'rangedLevelRequired') == nil and not Shared.contains(styleOverrides.Ranged, item.name)) or Shared.contains(styleOverrides.NotRanged, item.name) then isMatch = false end
| |
| elseif style == 'Magic' then
| |
| if (Items._getItemStat(item, 'magicLevelRequired') == nil and not Shared.contains(styleOverrides.Magic, item.name)) or Shared.contains(styleOverrides.NotMagic, item.name) then isMatch = false end
| |
| elseif style == 'None' then
| |
| if (Items._getItemStat(item, 'defenceLevelRequired') ~= nil or Items._getItemStat(item, 'rangedLevelRequired') ~= nil or Items._getItemStat(item, 'magicLevelRequired') ~= nil or
| |
| Shared.contains(styleOverrides.Melee, item.name) or Shared.contains(styleOverrides.Ranged, item.name) or Shared.contains(styleOverrides.Magic, item.name)) and
| |
| not Shared.contains(styleOverrides.None, item.name) then
| |
| isMatch = false
| |
| end
| |
| end
| |
| local sID = slotLocalID
| |
| if sID == nil or not Shared.contains(item.validSlots, sID) then isMatch = false end
| |
| | |
| if isMatch and other ~= nil then
| |
| if slot == 'Cape' then
| |
| -- TODO Would be more reliable if based on items appearing within the relevant shop categories instead
| |
| local isSkillcape = Shared.contains(item.name, 'Skillcape') or Shared.contains(item.name, 'Cape of Completion')
| |
| if other == 'Skillcapes' then
| |
| isMatch = isSkillcape
| |
| elseif other == 'No Skillcapes' then
| |
| isMatch = not isSkillcape
| |
| end
| |
| end
| |
| if slotLocalID == 'Weapon' then --For quiver slot or weapon slot, 'other' is the ammo type
| |
| isMatch = other == item.ammoTypeRequired
| |
| elseif slotLocalID == 'Quiver' then
| |
| if other == 'Thrown' and Shared.contains({'Javelins', 'ThrowingKnives'}, item.ammoType) then
| |
| isMatch = true
| |
| else
| |
| isMatch = other == item.ammoType
| |
| end
| |
| end
| |
| end
| |
| | |
| return isMatch
| |
| end)
| |
|
| |
| return p._getEquipmentTable(itemList, includeModifiers, includeDescription, sortByName) | |
| end
| |
| | |
| function p.getCategoryTable(frame)
| |
| local style = frame.args ~= nil and frame.args[1] or frame[1]
| |
| local slot = frame.args ~= nil and frame.args[2] or frame[2]
| |
| local other = frame.args ~= nil and frame.args[3] or frame[3]
| |
| local includeModifiers = frame.args ~= nil and frame.args.includeModifiers or frame.includeModifiers
| |
| local includeDescription = frame.args ~= nil and frame.args.includeDescription or frame.includeDescription
| |
| local sortByName = frame.args ~= nil and frame.args.sortByName or frame.sortByName
| |
| | |
| includeModifiers = includeModifiers ~= nil and string.upper(includeModifiers) == 'TRUE' or false
| |
| includeDescription = includeDescription ~= nil and string.upper(includeDescription) == 'TRUE' or false
| |
| sortByName = sortByName ~= nil and string.upper(sortByName) == 'TRUE' or false
| |
| | |
| return p._getCategoryTable(style, slot, other, includeModifiers, includeDescription, sortByName) | |
| end | | end |
|
| |
|