1,235
edits
Falterfire (talk | contribs) (Change to formatting on drop sources to try to fix spacing issue) |
(Add function for grabbing item.sellsFor value with mutliplier and rounding parameters) |
||
(210 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 | local GameData = require('Module:GameData') | ||
local Constants = require('Module:Constants') | |||
local Constants = | |||
local Shared = require('Module:Shared') | local Shared = require('Module:Shared') | ||
local Icons = require('Module:Icons') | local Icons = require('Module:Icons') | ||
local Num = require('Module:Number') | |||
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)'} | |||
function p.getItemByID(ID) | function p.getItemByID(ID) | ||
return GameData.getEntityByID('items', ID) | |||
end | end | ||
function p.getItem(name) | function p.getItem(name) | ||
name = string.gsub(name, "%%27", "'") | |||
name = string.gsub(name, "'", "'") | |||
return GameData.getEntityByName('items', name) | |||
end | |||
function p.getItems(checkFunc) | |||
return GameData.getEntities('items', checkFunc) | |||
end | |||
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] | |||
--Special Overrides: | |||
-- Equipment stats first | |||
if item.equipmentStats ~= nil and item.equipmentStats[StatName] ~= nil then | |||
result = item.equipmentStats[StatName] | |||
elseif StatName == 'attackSpeed' and item.validSlots ~= nil and Shared.contains(item.validSlots, 'Weapon') then | |||
-- Item can be equipped as a weapon but has no attack speed, so use default of 4000ms | |||
result = 4000 | |||
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 then | |||
local skillName = Shared.titleCase(string.match(StatName, '^(.+)LevelRequired$')) | |||
if skillName ~= nil then | |||
local skillID = Constants.getSkillID(skillName) | |||
if skillID ~= nil then | |||
for i, requirement in ipairs(item.equipRequirements) do | |||
if requirement.type == "SkillLevel" and requirement.skillID == skillID then | |||
result = requirement.level | |||
break | |||
end | |||
end | |||
end | |||
end | |||
elseif StatName == 'attackType' then | |||
result = p._getWeaponAttackType(item) | |||
elseif StatName == 'description' then | |||
result = item.customDescription | |||
if result == nil or result == '' then result = 'No Description' end | |||
elseif StatName == 'completionReq' then | |||
if item.ignoreCompletion == nil or not item.ignoreCompletion then | |||
result = 'Yes' | |||
else | |||
result = 'No' | |||
end | |||
elseif StatName == 'slayerBonusXP' then | |||
return p._getItemModifier(item, 'increasedSkillXP', 'Slayer', false) | |||
elseif StatName == 'hasCombatStats' then | |||
return tostring(p.hasCombatStats(item) or p._hasLevelRequirements(item)) | |||
elseif StatName == 'category' then | |||
-- Some categories have a namespace for some reason, remove it | |||
local _, localID = GameData.getLocalID(result) | |||
return localID | |||
end | |||
if result == nil and ZeroIfNil then result = 0 end | |||
return result | |||
end | |||
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 | |||
-- Function already exists, but without fame. | |||
-- Giving it a slightly different name since function overloading doesn't exist | |||
function p.getItemSellsFor(frame) | |||
local args = frame:getParent().args | |||
return p._getItemSellsFor(args[1], args[2], args.round) | |||
end | |||
function p._getItemSellsFor(itemName, multiplier, rounding) | |||
local itemValue = p.getItemValue(itemName) | |||
multiplier = tonumber(multiplier) or 1 | |||
rounding = tonumber(rounding) or 0 | |||
if itemValue == nil then | |||
error('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
return Num.round2(itemValue * multiplier, rounding) | |||
end | end | ||
function p.getItemStat(frame) | 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 Shared.printError('No item named "' .. ItemName .. '" exists in the data module') | |||
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.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 Shared.printError('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
return p._getWeaponAttackType(item) | |||
end | 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 | end | ||
function p. | 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 | |||
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._getItemCategories(item) | |||
local resultPart = {} | |||
local isEquipment = item.validSlots ~= nil or item.occupiesSlots ~= nil or item.equipmentStats ~= nil | |||
local category = p._getItemStat(item, 'category', false) | |||
if category ~= nil and category ~= 'Skills' then | |||
table.insert(resultPart, '[[Category:'..category..']]') | |||
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. | 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 Shared.printError('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
return p._getItemCategories(item) | |||
end | |||
function p.getItemGrid(frame) | |||
local resultPart = {} | |||
table.insert(resultPart, '{|') | |||
for i, item in ipairs(GameData.rawData.items) do | |||
if i % 17 == 1 then | |||
table.insert(resultPart, '\r\n|-\r\n|') | |||
else | |||
table.insert(resultPart, '||') | |||
end | |||
table.insert(resultPart, 'style="padding:3px"|'..Icons.Icon({item.name, type='item', notext=true, size='40'})) | |||
end | |||
table.insert(resultPart, '\r\n|}') | |||
return table.concat(resultPart) | |||
end | |||
function p.getEquipRequirementRow(req) | |||
local result = "" | |||
if req.type == "SkillLevel" then | |||
local skillName = Constants.getSkillName(req.skillID) | |||
local skillIcon = Icons.Icon({skillName, type='skill', notext=true}) | |||
result = '\r\n!style="text-align:right;"| '..skillIcon..' Level Required' | |||
result = result..'\r\n|style="text-align:right;"| '..req.level | |||
elseif req.type == "DungeonCompletion" then | |||
local dungeonName = GameData.getEntityByID("dungeons", req.dungeonID).name | |||
local dungeonIcon = Icons.Icon({dungeonName, type="dungeon", notext=true}) | |||
result = '\r\n!style="text-align:right;"| '..dungeonIcon..' Completions' | |||
result = result..'\r\n|style="text-align:right;"| '..req.count | |||
elseif req.type == "Completion" then | |||
local ns = GameData.getEntityByName('namespaces', req.namespace) | |||
if ns == nil then | |||
return '\r\n!style="text-align:right;" colspan=2|' .. Shared.printError('Invalid namespace for completion requirement "' .. req.namespace .. '"') | |||
else | |||
result = '\r\n!style="text-align:right;"| ' .. ns.displayName .. ' Completion' | |||
result = result .. '\r\n|style="text-align:right;"| ' .. req.percent .. '%' | |||
end | |||
else | |||
return '\r\n!style="text-align:right;" colspan=2|' .. Shared.printError('Invalid equip requirement type "' .. req.type .. '"') | |||
end | |||
return result | |||
end | end | ||
function p. | 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 Shared.printError('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
local ico = { | |||
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}), | |||
["Combat"] = Icons.Icon({'Combat', notext=true}), | |||
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}), | |||
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}), | |||
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}), | |||
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}), | |||
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true}) | |||
} | |||
local reqCount = item.equipRequirements ~= nil and Shared.tableCount(item.equipRequirements) or 0 | |||
local emptyRow = '\r\n!colspan="2"|' | |||
local resultPart = {} | |||
table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Weapon Stats') | |||
table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats') | |||
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats') | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Speed') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. Shared.round(p._getItemStat(item, 'attackSpeed', true) / 1000, 3, 1) .. 's') | |||
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true)) | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Attack Type') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'attackType')) | |||
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%') | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true)) | |||
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true)) | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', true)) | |||
table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true)) | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true)) | |||
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Equip Requirements') | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true)) | |||
if reqCount > 0 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[1])) | |||
else | |||
table.insert(resultPart, '\r\n|colspan=2 style="text-align:right"|None') | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true)) | |||
if reqCount > 1 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[2])) | |||
else | |||
table.insert(resultPart, emptyRow) | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true)) | |||
if reqCount > 2 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[3])) | |||
else | |||
table.insert(resultPart, emptyRow) | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true)) | |||
if reqCount > 3 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[4])) | |||
else | |||
table.insert(resultPart, emptyRow) | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%') | |||
if reqCount > 4 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[5])) | |||
else | |||
table.insert(resultPart, emptyRow) | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| Two Handed?') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. (p._getItemStat(item, 'isTwoHanded') and 'Yes' or 'No')) | |||
if reqCount > 5 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[6])) | |||
else | |||
table.insert(resultPart, emptyRow) | |||
end | |||
--Add extra rows at the end for items that have more than 3 different requirements | |||
if reqCount > 6 then | |||
for i = 7, reqCount, 1 do | |||
table.insert(resultPart,"\r\n|-") | |||
table.insert(resultPart, emptyRow) | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[i])) | |||
end | |||
end | |||
table.insert(resultPart, '\r\n|}') | |||
return table.concat(resultPart) | |||
end | end | ||
function p. | 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 Shared.printError('No item named "' .. itemName .. '" exists in the data module') | |||
end | |||
local ico = { | |||
["Attack"] = Icons.Icon({'Attack', type='skill', notext=true}), | |||
["Combat"] = Icons.Icon({'Combat', notext=true}), | |||
["Defence"] = Icons.Icon({'Defence', type='skill', notext=true}), | |||
["Magic"] = Icons.Icon({'Magic', type='skill', notext=true}), | |||
["Ranged"] = Icons.Icon({'Ranged', type='skill', notext=true}), | |||
["Strength"] = Icons.Icon({'Strength', type='skill', notext=true}), | |||
["Slayer"] = Icons.Icon({'Slayer', type='skill', notext=true}) | |||
} | |||
local reqCount = item.equipRequirements ~= nil and Shared.tableCount(item.equipRequirements) or 0 | |||
local emptyRow = '\r\n!colspan="2"|' | |||
local resultPart = {} | |||
table.insert(resultPart, '{| class="wikitable"\r\n|-\r\n!colspan="4" style="border-bottom:solid medium black;"| Armour Stats') | |||
table.insert(resultPart, '\r\n|-\r\n!colspan="2" style="border-bottom:solid thin black;"| Offensive Stats') | |||
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Defensive Stats') | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Strength'] .. ' Strength Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeStrengthBonus', true)) | |||
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Defence Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'meleeDefenceBonus', true)) | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Stab Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'stabAttackBonus', 0)) | |||
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Defence'] .. ' Damage Reduction') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'damageReduction', true) .. '%') | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Slash Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'slashAttackBonus', true)) | |||
table.insert(resultPart, '\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Defence Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedDefenceBonus', true)) | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Combat'] .. ' Block Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'blockAttackBonus', true)) | |||
table.insert(resultPart, '\r\n!style="text-align:right;border-bottom:solid thin black;"| ' .. ico['Magic'] .. ' Defence Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;border-bottom:solid thin black;"| ' .. p._getItemStat(item, 'magicDefenceBonus', true)) | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Attack Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedAttackBonus', true)) | |||
table.insert(resultPart, '\r\n!colspan="2" style="border-bottom:solid thin black;"| Equip Requirements') | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Ranged'] .. ' Strength Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'rangedStrengthBonus', true)) | |||
if reqCount > 0 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[1])) | |||
else | |||
table.insert(resultPart, '\r\n|colspan=2 style="text-align:right"|None') | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' Attack Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicAttackBonus', true)) | |||
if reqCount > 1 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[2])) | |||
else | |||
table.insert(resultPart, emptyRow) | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"| ' .. ico['Magic'] .. ' % Damage Bonus') | |||
table.insert(resultPart, '\r\n|style="text-align:right;"| ' .. p._getItemStat(item, 'magicDamageBonus', true) .. '%') | |||
if reqCount > 2 then | |||
table.insert(resultPart, p.getEquipRequirementRow(item.equipRequirements[3])) | |||
else | |||
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 | |||
table.insert(resultPart, '\r\n|}') | |||
return table.concat(resultPart) | |||
end | end | ||
function p. | function p.getItemDataExport(frame) | ||
local resultTable = mw.html.create('table') | |||
resultTable:addClass('wikitable') | |||
resultTable:tag('tr'):addClass('headerRow-0') | |||
:tag('th'):wikitext('ItemID'):done() | |||
:tag('th'):wikitext('ItemName'):done() | |||
:tag('th'):wikitext('GPValue'):done() | |||
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 | |||
--Returns the expansion icon for the item if it has one | |||
function p.getExpansionIcon(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 Icons.getExpansionIcon(item.id) | |||
end | |||
function p.buildSmithableArmourNav(frame) | |||
local resultPart = {} | |||
table.insert(resultPart, '{| class="wikitable mw-collapsible navigation-not-searchable" style="margin:auto; clear:both; width: 100%"') | |||
table.insert(resultPart, '\r\n!colspan = 2 style="background-color:#275C87;color:#FFFFFF;min-width:730px;"|') | |||
table.insert(resultPart, Icons.Icon({'Smithing', type='skill', notext=true})) | |||
table.insert(resultPart, ' Smithable Armour Sets') | |||
local metalTypes = {'Bronze', 'Iron', 'Steel', 'Mithril', {'Adamant', 'Adamantite'}, {'Rune', 'Runite'}, {'Dragon', 'Dragonite'}, | |||
{'Corundum', 'Corundumite', TotH = true}, {'Augite', 'Augite', TotH = true}, {'Divine', 'Divinite', TotH = true}} | |||
local pieces = {"Helmet", "Platebody", "Platelegs", "Boots", "Shield"} | |||
for i, metal in ipairs(metalTypes) do | |||
local metalName, barName | |||
local isTotH = false | |||
if type(metal) == 'table' then | |||
metalName = metal[1] | |||
barName = metal[2]..' Bar' | |||
isTotH = metal.TotH ~= nil and metal.TotH | |||
else | |||
metalName = metal | |||
barName = metal..' Bar' | |||
end | |||
table.insert(resultPart, '\r\n|-\r\n!') | |||
if isTotH then | |||
table.insert(resultPart, Icons.TotH()) | |||
end | |||
table.insert(resultPart, Icons.Icon({barName, type="item", notext=true})) | |||
table.insert(resultPart, " "..metalName) | |||
table.insert(resultPart, "\r\n|") | |||
for j, piece in ipairs(pieces) do | |||
if j > 1 then | |||
table.insert(resultPart, ' • ') | |||
end | |||
table.insert(resultPart, '<span style="display:inline-block">') | |||
table.insert(resultPart, Icons.Icon({metalName..' '..piece, piece, type='item'})) | |||
if isTotH then | |||
table.insert(resultPart, ' '..Icons.Icon({'(I) '..metalName..' '..piece, '(I)', type='item'})) | |||
table.insert(resultPart, ' '..Icons.Icon({'(P) '..metalName..' '..piece, '(P)', type='item'})) | |||
else | |||
table.insert(resultPart, ' '..Icons.Icon({'(S) '..metalName..' '..piece, '(S)', type='item'})) | |||
table.insert(resultPart, ' '..Icons.Icon({'(G) '..metalName..' '..piece, '(G)', type='item'})) | |||
end | |||
table.insert(resultPart, '</span>') | |||
end | |||
end | |||
table.insert(resultPart, '\r\n|}') | |||
return table.concat(resultPart) | |||
end | |||
function p.buildCraftableArmourNav(frame) | |||
local resultPart = {} | |||
table.insert(resultPart, '{| class="wikitable mw-collapsible"') | |||
table.insert(resultPart, '\r\n!colspan = 2 style="background-color:#275C87;color:#FFFFFF;min-width:730px;"|') | |||
table.insert(resultPart, Icons.Icon({'Crafting', type='skill', notext=true})) | |||
table.insert(resultPart, ' Craftable Armour Sets') | |||
local leatherTypes = {'Leather', 'Hard Leather'} | |||
local leatherPieces = {"Cowl", "Body", "Chaps", "Gloves", "Vambraces", "Boots"} | |||
table.insert(resultPart, '\r\n|-\r\n!') | |||
table.insert(resultPart, Icons.Icon({'Leather', type='item', notext=true})) | |||
table.insert(resultPart, ' Leather') | |||
for i, material in pairs(leatherTypes) do | |||
if i > 1 then table.insert(resultPart, '\r\n|-\r\n!Hard Leather') end | |||
table.insert(resultPart, '\r\n|') | |||
for j, piece in ipairs(leatherPieces) do | |||
if j > 1 then | |||
table.insert(resultPart, ' • ') | |||
end | |||
table.insert(resultPart, Icons.Icon({material..' '..piece, piece, type='item'})) | |||
end | |||
end | |||
local materialTypes = {{'Green D-hide', 'Green Dragonhide'}, {'Blue D-hide', 'Blue Dragonhide'}, {'Red D-hide', 'Red Dragonhide'}, {'Black D-hide', 'Black Dragonhide'}, | |||
{'Elderwood', 'Elderwood Logs', TotH = true}, {'Revenant', 'Revenant Logs', TotH = true}, {'Carrion', 'Carrion Logs', TotH = true}} | |||
local pieces = {"Body", "Chaps", "Vambraces", "Shield"} | |||
for i, material in ipairs(materialTypes) do | |||
local isTotH = false | |||
local craftName = material[1] | |||
local matName = material[2] | |||
isTotH = material.TotH ~= nil and material.TotH | |||
table.insert(resultPart, '\r\n|-\r\n!') | |||
if isTotH then | |||
table.insert(resultPart, Icons.TotH()) | |||
end | |||
table.insert(resultPart, Icons.Icon({matName, type="item", notext=true})) | |||
table.insert(resultPart, " "..craftName) | |||
table.insert(resultPart, "\r\n|") | |||
for j, piece in ipairs(pieces) do | |||
if j > 1 then | |||
table.insert(resultPart, ' • ') | |||
end | |||
table.insert(resultPart, '<span style="display:inline-block">') | |||
table.insert(resultPart, Icons.Icon({craftName..' '..piece, piece, type='item'})) | |||
table.insert(resultPart, ' '..Icons.Icon({'(U) '..craftName..' '..piece, '(U)', type='item'})) | |||
table.insert(resultPart, '</span>') | |||
end | |||
end | |||
table.insert(resultPart, '\r\n|}') | |||
return table.concat(resultPart) | |||
end | |||
function p.getLifestealWeapons() | |||
local items = p.getItems(function(item) | |||
if item.specialAttacks ~= nil and not Shared.tableIsEmpty(item.specialAttacks) then | |||
for i, spAttID in ipairs(item.specialAttacks) do | |||
local spAtt = GameData.getEntityByID('attacks', spAttID) | |||
if spAtt ~= nil then | |||
return spAtt.lifesteal > 0 | |||
end | |||
end | |||
end | |||
return false | |||
end) | |||
for i, item in ipairs(items) do | |||
mw.log(item.name) | |||
end | |||
end | end | ||
return p | return p |
edits